diff --git a/spine-as3/spine-as3-example/src/spine/examples/Main.as b/spine-as3/spine-as3-example/src/spine/examples/Main.as index 1ebfb48b5a..0ef2512a39 100644 --- a/spine-as3/spine-as3-example/src/spine/examples/Main.as +++ b/spine-as3/spine-as3-example/src/spine/examples/Main.as @@ -1,97 +1,96 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.examples { - -import flash.display.Sprite; - -import spine.*; -import spine.animation.AnimationStateData; -import spine.atlas.Atlas; -import spine.attachments.AtlasAttachmentLoader; -import spine.flash.FlashTextureLoader; -import spine.flash.SkeletonAnimation; - -[SWF(width = "800", height = "600", frameRate = "60", backgroundColor = "#dddddd")] -public class Main extends Sprite { - [Embed(source = "/spineboy.atlas", mimeType = "application/octet-stream")] - static public const SpineboyAtlas:Class; - - [Embed(source = "/spineboy.png")] - static public const SpineboyAtlasTexture:Class; - - [Embed(source = "/spineboy.json", mimeType = "application/octet-stream")] - static public const SpineboyJson:Class; - - private var skeleton:SkeletonAnimation; - - public function Main () { - var atlas:Atlas = new Atlas(new SpineboyAtlas(), new FlashTextureLoader(new SpineboyAtlasTexture())); - var json:SkeletonJson = new SkeletonJson(new AtlasAttachmentLoader(atlas)); - json.scale = 0.6; - var skeletonData:SkeletonData = json.readSkeletonData(new SpineboyJson()); - - var stateData:AnimationStateData = new AnimationStateData(skeletonData); - stateData.setMixByName("walk", "jump", 0.2); - stateData.setMixByName("jump", "run", 0.4); - stateData.setMixByName("jump", "jump", 0.2); - - skeleton = new SkeletonAnimation(skeletonData, stateData); - skeleton.x = 400; - skeleton.y = 560; - - skeleton.state.onStart.add(function (trackIndex:int) : void { - trace(trackIndex + " fuu start: " + skeleton.state.getCurrent(trackIndex)); - }); - skeleton.state.onEnd.add(function (trackIndex:int) : void { - trace(trackIndex + " end: " + skeleton.state.getCurrent(trackIndex)); - }); - skeleton.state.onComplete.add(function (trackIndex:int, count:int) : void { - trace(trackIndex + " complete: " + skeleton.state.getCurrent(trackIndex) + ", " + count); - }); - skeleton.state.onEvent.add(function (trackIndex:int, event:Event) : void { - trace(trackIndex + " event: " + skeleton.state.getCurrent(trackIndex) + ", " - + event.data.name + ": " + event.intValue + ", " + event.floatValue + ", " + event.stringValue); - }); - - if (false) { - skeleton.state.setAnimationByName(0, "test", true); - } else { - skeleton.state.setAnimationByName(0, "walk", true); - skeleton.state.addAnimationByName(0, "jump", false, 3); - skeleton.state.addAnimationByName(0, "run", true, 0); - } - - addChild(skeleton); - } -} - +package spine.examples { + +import flash.display.Sprite; + +import spine.*; +import spine.animation.AnimationStateData; +import spine.atlas.Atlas; +import spine.attachments.AtlasAttachmentLoader; +import spine.flash.FlashTextureLoader; +import spine.flash.SkeletonAnimation; + +[SWF(width = "800", height = "600", frameRate = "60", backgroundColor = "#dddddd")] +public class Main extends Sprite { + [Embed(source = "/spineboy.atlas", mimeType = "application/octet-stream")] + static public const SpineboyAtlas:Class; + + [Embed(source = "/spineboy.png")] + static public const SpineboyAtlasTexture:Class; + + [Embed(source = "/spineboy.json", mimeType = "application/octet-stream")] + static public const SpineboyJson:Class; + + private var skeleton:SkeletonAnimation; + + public function Main () { + var atlas:Atlas = new Atlas(new SpineboyAtlas(), new FlashTextureLoader(new SpineboyAtlasTexture())); + var json:SkeletonJson = new SkeletonJson(new AtlasAttachmentLoader(atlas)); + json.scale = 0.6; + var skeletonData:SkeletonData = json.readSkeletonData(new SpineboyJson()); + + var stateData:AnimationStateData = new AnimationStateData(skeletonData); + stateData.setMixByName("walk", "jump", 0.2); + stateData.setMixByName("jump", "run", 0.4); + stateData.setMixByName("jump", "jump", 0.2); + + skeleton = new SkeletonAnimation(skeletonData, stateData); + skeleton.x = 400; + skeleton.y = 560; + + skeleton.state.onStart.add(function (trackIndex:int) : void { + trace(trackIndex + " fuu start: " + skeleton.state.getCurrent(trackIndex)); + }); + skeleton.state.onEnd.add(function (trackIndex:int) : void { + trace(trackIndex + " end: " + skeleton.state.getCurrent(trackIndex)); + }); + skeleton.state.onComplete.add(function (trackIndex:int, count:int) : void { + trace(trackIndex + " complete: " + skeleton.state.getCurrent(trackIndex) + ", " + count); + }); + skeleton.state.onEvent.add(function (trackIndex:int, event:Event) : void { + trace(trackIndex + " event: " + skeleton.state.getCurrent(trackIndex) + ", " + + event.data.name + ": " + event.intValue + ", " + event.floatValue + ", " + event.stringValue); + }); + + if (false) { + skeleton.state.setAnimationByName(0, "test", true); + } else { + skeleton.state.setAnimationByName(0, "walk", true); + skeleton.state.addAnimationByName(0, "jump", false, 3); + skeleton.state.addAnimationByName(0, "run", true, 0); + } + + addChild(skeleton); + } +} + } diff --git a/spine-as3/spine-as3/src/spine/BlendMode.as b/spine-as3/spine-as3/src/spine/BlendMode.as index 49f05bd924..be1711a89e 100644 --- a/spine-as3/spine-as3/src/spine/BlendMode.as +++ b/spine-as3/spine-as3/src/spine/BlendMode.as @@ -1,47 +1,46 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { - -public class BlendMode { - public static const normal:BlendMode = new BlendMode(0); - public static const additive:BlendMode = new BlendMode(1); - public static const multiply:BlendMode = new BlendMode(2); - public static const screen:BlendMode = new BlendMode(3); - - public var ordinal:int; - - public function BlendMode (ordinal:int) { - this.ordinal = ordinal; - } -} - +package spine { + +public class BlendMode { + public static const normal:BlendMode = new BlendMode(0); + public static const additive:BlendMode = new BlendMode(1); + public static const multiply:BlendMode = new BlendMode(2); + public static const screen:BlendMode = new BlendMode(3); + + public var ordinal:int; + + public function BlendMode (ordinal:int) { + this.ordinal = ordinal; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/Bone.as b/spine-as3/spine-as3/src/spine/Bone.as index c5cc50db2c..2b33e046d4 100644 --- a/spine-as3/spine-as3/src/spine/Bone.as +++ b/spine-as3/spine-as3/src/spine/Bone.as @@ -1,357 +1,356 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { - -public class Bone implements Updatable { - static public var yDown:Boolean; - - internal var _data:BoneData; - internal var _skeleton:Skeleton; - internal var _parent:Bone; - internal var _children:Vector. = new Vector.(); - public var x:Number; - public var y:Number; - public var rotation:Number; - public var scaleX:Number; - public var scaleY:Number; - public var shearX:Number; - public var shearY:Number; - public var appliedRotation:Number; - - internal var _a:Number; - internal var _b:Number; - internal var _c:Number; - internal var _d:Number; - internal var _worldX:Number; - internal var _worldY:Number; - internal var _worldSignX:Number; - internal var _worldSignY:Number; - - internal var _sorted:Boolean; - - /** @param parent May be null. */ - public function Bone (data:BoneData, skeleton:Skeleton, parent:Bone) { - if (data == null) throw new ArgumentError("data cannot be null."); - if (skeleton == null) throw new ArgumentError("skeleton cannot be null."); - _data = data; - _skeleton = skeleton; - _parent = parent; - setToSetupPose(); - } - - /** Same as updateWorldTransform(). This method exists for Bone to implement Updatable. */ - public function update () : void { - updateWorldTransformWith(x, y, rotation, scaleX, scaleY, shearX, shearY); - } - - /** Computes the world SRT using the parent bone and this bone's local SRT. */ - public function updateWorldTransform () : void { - updateWorldTransformWith(x, y, rotation, scaleX, scaleY, shearX, shearY); - } - - /** Computes the world SRT using the parent bone and the specified local SRT. */ - public function updateWorldTransformWith (x:Number, y:Number, rotation:Number, scaleX:Number, scaleY:Number, shearX:Number, shearY:Number) : void { - appliedRotation = rotation; - - var rotationY:Number = rotation + 90 + shearY; - var la:Number = MathUtils.cosDeg(rotation + shearX) * scaleX, lb:Number = MathUtils.cosDeg(rotationY) * scaleY; - var lc:Number = MathUtils.sinDeg(rotation + shearX) * scaleX, ld:Number = MathUtils.sinDeg(rotationY) * scaleY; - - var parent:Bone = _parent; - if (!parent) { // Root bone. - var skeleton:Skeleton = _skeleton; - if (skeleton.flipX) { - x = -x; - la = -la; - lb = -lb; - } - if (skeleton.flipY != yDown) { - y = -y; - lc = -lc; - ld = -ld; - } - _a = la; - _b = lb; - _c = lc; - _d = ld; - _worldX = x; - _worldY = y; - _worldSignX = scaleX < 0 ? -1 : 1; - _worldSignY = scaleY < 0 ? -1 : 1; - return; - } - - var pa:Number = parent._a, pb:Number = parent._b, pc:Number = parent._c, pd:Number = parent._d; - _worldX = pa * x + pb * y + parent._worldX; - _worldY = pc * x + pd * y + parent._worldY; - _worldSignX = parent._worldSignX * (scaleX < 0 ? -1 : 1); - _worldSignY = parent._worldSignY * (scaleY < 0 ? -1 : 1); - - if (data.inheritRotation && data.inheritScale) { - _a = pa * la + pb * lc; - _b = pa * lb + pb * ld; - _c = pc * la + pd * lc; - _d = pc * lb + pd * ld; - } else { - if (data.inheritRotation) { // No scale inheritance. - pa = 1; - pb = 0; - pc = 0; - pd = 1; - do { - var cos:Number = MathUtils.cosDeg(parent.appliedRotation), sin:Number = MathUtils.sinDeg(parent.appliedRotation); - var temp:Number = pa * cos + pb * sin; - pb = pb * cos - pa * sin; - pa = temp; - temp = pc * cos + pd * sin; - pd = pd * cos - pc * sin; - pc = temp; - - if (!parent.data.inheritRotation) break; - parent = parent.parent; - } while (parent != null); - _a = pa * la + pb * lc; - _b = pa * lb + pb * ld; - _c = pc * la + pd * lc; - _d = pc * lb + pd * ld; - } else if (data.inheritScale) { // No rotation inheritance. - pa = 1; - pb = 0; - pc = 0; - pd = 1; - do { - cos = MathUtils.cosDeg(parent.appliedRotation), sin = MathUtils.sinDeg(parent.appliedRotation); - var psx:Number = parent.scaleX, psy:Number = parent.scaleY; - var za:Number = cos * psx, zb:Number = sin * psy, zc:Number = sin * psx, zd:Number = cos * psy; - temp = pa * za + pb * zc; - pb = pb * zd - pa * zb; - pa = temp; - temp = pc * za + pd * zc; - pd = pd * zd - pc * zb; - pc = temp; - - if (psx >= 0) sin = -sin; - temp = pa * cos + pb * sin; - pb = pb * cos - pa * sin; - pa = temp; - temp = pc * cos + pd * sin; - pd = pd * cos - pc * sin; - pc = temp; - - if (!parent.data.inheritScale) break; - parent = parent.parent; - } while (parent != null); - _a = pa * la + pb * lc; - _b = pa * lb + pb * ld; - _c = pc * la + pd * lc; - _d = pc * lb + pd * ld; - } else { - _a = la; - _b = lb; - _c = lc; - _d = ld; - } - if (_skeleton.flipX) { - _a = -_a; - _b = -_b; - } - if (_skeleton.flipY != yDown) { - _c = -_c; - _d = -_d; - } - } - } - - public function setToSetupPose () : void { - x = _data.x; - y = _data.y; - rotation = _data.rotation; - scaleX = _data.scaleX; - scaleY = _data.scaleY; - shearX = _data.shearX; - shearY = _data.shearY; - } - - public function get data () : BoneData { - return _data; - } - - public function get skeleton () : Skeleton { - return _skeleton; - } - - public function get parent () : Bone { - return _parent; - } - - public function get children () : Vector. {; - return _children; - } - - public function get a () : Number { - return _a; - } - - public function get b () : Number { - return _b; - } - - public function get c () : Number { - return _c; - } - - public function get d () : Number { - return _d; - } - - public function get worldX () : Number { - return _worldX; - } - - public function get worldY () : Number { - return _worldY; - } - - public function get worldSignX () : Number { - return _worldSignX; - } - - public function get worldSignY () : Number { - return _worldSignY; - } - - public function get worldRotationX () : Number { - return Math.atan2(_c, _a) * MathUtils.radDeg; - } - - public function get worldRotationY () : Number { - return Math.atan2(_d, _b) * MathUtils.radDeg; - } - - public function get worldScaleX () : Number { - return Math.sqrt(_a * _a + _b * _b) * _worldSignX; - } - - public function get worldScaleY () : Number { - return Math.sqrt(_c * _c + _d * _d) * _worldSignY; - } - - public function worldToLocalRotationX () : Number { - var parent:Bone = _parent; - if (parent == null) return rotation; - var pa:Number = parent.a, pb:Number = parent.b, pc:Number = parent.c, pd:Number = parent.d, a:Number = this.a, c:Number = this.c; - return Math.atan2(pa * c - pc * a, pd * a - pb * c) * MathUtils.radDeg; - } - - public function worldToLocalRotationY () : Number { - var parent:Bone = _parent; - if (parent == null) return rotation; - var pa:Number = parent.a, pb:Number = parent.b, pc:Number = parent.c, pd:Number = parent.d, b:Number = this.b, d:Number = this.d; - return Math.atan2(pa * d - pc * b, pd * b - pb * d) * MathUtils.radDeg; - } - - public function rotateWorld (degrees:Number) : void { - var a:Number = this.a, b:Number = this.b, c:Number = this.c, d:Number = this.d; - var cos:Number = MathUtils.cosDeg(degrees), sin:Number = MathUtils.sinDeg(degrees); - this._a = cos * a - sin * c; - this._b = cos * b - sin * d; - this._c = sin * a + cos * c; - this._d = sin * b + cos * d; - } - - /** Computes the local transform from the world transform. This can be useful to perform processing on the local transform - * after the world transform has been modified directly (eg, by a constraint). - *

- * Some redundant information is lost by the world transform, such as -1,-1 scale versus 180 rotation. The computed local - * transform values may differ from the original values but are functionally the same. */ - public function updateLocalTransform () : void { - var parent:Bone = this.parent; - if (parent == null) { - x = worldX; - y = worldY; - rotation = Math.atan2(c, a) * MathUtils.radDeg; - scaleX = Math.sqrt(a * a + c * c); - scaleY = Math.sqrt(b * b + d * d); - var det:Number = a * d - b * c; - shearX = 0; - shearY = Math.atan2(a * b + c * d, det) * MathUtils.radDeg; - return; - } - var pa:Number = parent.a, pb:Number = parent.b, pc:Number = parent.c, pd:Number = parent.d; - var pid:Number = 1 / (pa * pd - pb * pc); - var dx:Number = worldX - parent.worldX, dy:Number = worldY - parent.worldY; - x = (dx * pd * pid - dy * pb * pid); - y = (dy * pa * pid - dx * pc * pid); - var ia:Number = pid * pd; - var id:Number = pid * pa; - var ib:Number = pid * pb; - var ic:Number = pid * pc; - var ra:Number = ia * a - ib * c; - var rb:Number = ia * b - ib * d; - var rc:Number = id * c - ic * a; - var rd:Number = id * d - ic * b; - shearX = 0; - scaleX = Math.sqrt(ra * ra + rc * rc); - if (scaleX > 0.0001) { - det = ra * rd - rb * rc; - scaleY = det / scaleX; - shearY = Math.atan2(ra * rb + rc * rd, det) * MathUtils.radDeg; - rotation = Math.atan2(rc, ra) * MathUtils.radDeg; - } else { - scaleX = 0; - scaleY = Math.sqrt(rb * rb + rd * rd); - shearY = 0; - rotation = 90 - Math.atan2(rd, rb) * MathUtils.radDeg; - } - appliedRotation = rotation; - } - - public function worldToLocal (world:Vector.) : void { - var a:Number = _a, b:Number = _b, c:Number = _c, d:Number = _d; - var invDet:Number = 1 / (a * d - b * c); - var x:Number = world[0] - _worldX, y:Number = world[1] - _worldY; - world[0] = (x * d * invDet - y * b * invDet); - world[1] = (y * a * invDet - x * c * invDet); - } - - public function localToWorld (local:Vector.) : void { - var localX:Number = local[0], localY:Number = local[1]; - local[0] = localX * _a + localY * _b + _worldX; - local[1] = localX * _c + localY * _d + _worldY; - } - - public function toString () : String { - return _data._name; - } -} - +package spine { + +public class Bone implements Updatable { + static public var yDown:Boolean; + + internal var _data:BoneData; + internal var _skeleton:Skeleton; + internal var _parent:Bone; + internal var _children:Vector. = new Vector.(); + public var x:Number; + public var y:Number; + public var rotation:Number; + public var scaleX:Number; + public var scaleY:Number; + public var shearX:Number; + public var shearY:Number; + public var appliedRotation:Number; + + internal var _a:Number; + internal var _b:Number; + internal var _c:Number; + internal var _d:Number; + internal var _worldX:Number; + internal var _worldY:Number; + internal var _worldSignX:Number; + internal var _worldSignY:Number; + + internal var _sorted:Boolean; + + /** @param parent May be null. */ + public function Bone (data:BoneData, skeleton:Skeleton, parent:Bone) { + if (data == null) throw new ArgumentError("data cannot be null."); + if (skeleton == null) throw new ArgumentError("skeleton cannot be null."); + _data = data; + _skeleton = skeleton; + _parent = parent; + setToSetupPose(); + } + + /** Same as updateWorldTransform(). This method exists for Bone to implement Updatable. */ + public function update () : void { + updateWorldTransformWith(x, y, rotation, scaleX, scaleY, shearX, shearY); + } + + /** Computes the world SRT using the parent bone and this bone's local SRT. */ + public function updateWorldTransform () : void { + updateWorldTransformWith(x, y, rotation, scaleX, scaleY, shearX, shearY); + } + + /** Computes the world SRT using the parent bone and the specified local SRT. */ + public function updateWorldTransformWith (x:Number, y:Number, rotation:Number, scaleX:Number, scaleY:Number, shearX:Number, shearY:Number) : void { + appliedRotation = rotation; + + var rotationY:Number = rotation + 90 + shearY; + var la:Number = MathUtils.cosDeg(rotation + shearX) * scaleX, lb:Number = MathUtils.cosDeg(rotationY) * scaleY; + var lc:Number = MathUtils.sinDeg(rotation + shearX) * scaleX, ld:Number = MathUtils.sinDeg(rotationY) * scaleY; + + var parent:Bone = _parent; + if (!parent) { // Root bone. + var skeleton:Skeleton = _skeleton; + if (skeleton.flipX) { + x = -x; + la = -la; + lb = -lb; + } + if (skeleton.flipY != yDown) { + y = -y; + lc = -lc; + ld = -ld; + } + _a = la; + _b = lb; + _c = lc; + _d = ld; + _worldX = x; + _worldY = y; + _worldSignX = scaleX < 0 ? -1 : 1; + _worldSignY = scaleY < 0 ? -1 : 1; + return; + } + + var pa:Number = parent._a, pb:Number = parent._b, pc:Number = parent._c, pd:Number = parent._d; + _worldX = pa * x + pb * y + parent._worldX; + _worldY = pc * x + pd * y + parent._worldY; + _worldSignX = parent._worldSignX * (scaleX < 0 ? -1 : 1); + _worldSignY = parent._worldSignY * (scaleY < 0 ? -1 : 1); + + if (data.inheritRotation && data.inheritScale) { + _a = pa * la + pb * lc; + _b = pa * lb + pb * ld; + _c = pc * la + pd * lc; + _d = pc * lb + pd * ld; + } else { + if (data.inheritRotation) { // No scale inheritance. + pa = 1; + pb = 0; + pc = 0; + pd = 1; + do { + var cos:Number = MathUtils.cosDeg(parent.appliedRotation), sin:Number = MathUtils.sinDeg(parent.appliedRotation); + var temp:Number = pa * cos + pb * sin; + pb = pb * cos - pa * sin; + pa = temp; + temp = pc * cos + pd * sin; + pd = pd * cos - pc * sin; + pc = temp; + + if (!parent.data.inheritRotation) break; + parent = parent.parent; + } while (parent != null); + _a = pa * la + pb * lc; + _b = pa * lb + pb * ld; + _c = pc * la + pd * lc; + _d = pc * lb + pd * ld; + } else if (data.inheritScale) { // No rotation inheritance. + pa = 1; + pb = 0; + pc = 0; + pd = 1; + do { + cos = MathUtils.cosDeg(parent.appliedRotation), sin = MathUtils.sinDeg(parent.appliedRotation); + var psx:Number = parent.scaleX, psy:Number = parent.scaleY; + var za:Number = cos * psx, zb:Number = sin * psy, zc:Number = sin * psx, zd:Number = cos * psy; + temp = pa * za + pb * zc; + pb = pb * zd - pa * zb; + pa = temp; + temp = pc * za + pd * zc; + pd = pd * zd - pc * zb; + pc = temp; + + if (psx >= 0) sin = -sin; + temp = pa * cos + pb * sin; + pb = pb * cos - pa * sin; + pa = temp; + temp = pc * cos + pd * sin; + pd = pd * cos - pc * sin; + pc = temp; + + if (!parent.data.inheritScale) break; + parent = parent.parent; + } while (parent != null); + _a = pa * la + pb * lc; + _b = pa * lb + pb * ld; + _c = pc * la + pd * lc; + _d = pc * lb + pd * ld; + } else { + _a = la; + _b = lb; + _c = lc; + _d = ld; + } + if (_skeleton.flipX) { + _a = -_a; + _b = -_b; + } + if (_skeleton.flipY != yDown) { + _c = -_c; + _d = -_d; + } + } + } + + public function setToSetupPose () : void { + x = _data.x; + y = _data.y; + rotation = _data.rotation; + scaleX = _data.scaleX; + scaleY = _data.scaleY; + shearX = _data.shearX; + shearY = _data.shearY; + } + + public function get data () : BoneData { + return _data; + } + + public function get skeleton () : Skeleton { + return _skeleton; + } + + public function get parent () : Bone { + return _parent; + } + + public function get children () : Vector. {; + return _children; + } + + public function get a () : Number { + return _a; + } + + public function get b () : Number { + return _b; + } + + public function get c () : Number { + return _c; + } + + public function get d () : Number { + return _d; + } + + public function get worldX () : Number { + return _worldX; + } + + public function get worldY () : Number { + return _worldY; + } + + public function get worldSignX () : Number { + return _worldSignX; + } + + public function get worldSignY () : Number { + return _worldSignY; + } + + public function get worldRotationX () : Number { + return Math.atan2(_c, _a) * MathUtils.radDeg; + } + + public function get worldRotationY () : Number { + return Math.atan2(_d, _b) * MathUtils.radDeg; + } + + public function get worldScaleX () : Number { + return Math.sqrt(_a * _a + _b * _b) * _worldSignX; + } + + public function get worldScaleY () : Number { + return Math.sqrt(_c * _c + _d * _d) * _worldSignY; + } + + public function worldToLocalRotationX () : Number { + var parent:Bone = _parent; + if (parent == null) return rotation; + var pa:Number = parent.a, pb:Number = parent.b, pc:Number = parent.c, pd:Number = parent.d, a:Number = this.a, c:Number = this.c; + return Math.atan2(pa * c - pc * a, pd * a - pb * c) * MathUtils.radDeg; + } + + public function worldToLocalRotationY () : Number { + var parent:Bone = _parent; + if (parent == null) return rotation; + var pa:Number = parent.a, pb:Number = parent.b, pc:Number = parent.c, pd:Number = parent.d, b:Number = this.b, d:Number = this.d; + return Math.atan2(pa * d - pc * b, pd * b - pb * d) * MathUtils.radDeg; + } + + public function rotateWorld (degrees:Number) : void { + var a:Number = this.a, b:Number = this.b, c:Number = this.c, d:Number = this.d; + var cos:Number = MathUtils.cosDeg(degrees), sin:Number = MathUtils.sinDeg(degrees); + this._a = cos * a - sin * c; + this._b = cos * b - sin * d; + this._c = sin * a + cos * c; + this._d = sin * b + cos * d; + } + + /** Computes the local transform from the world transform. This can be useful to perform processing on the local transform + * after the world transform has been modified directly (eg, by a constraint). + *

+ * Some redundant information is lost by the world transform, such as -1,-1 scale versus 180 rotation. The computed local + * transform values may differ from the original values but are functionally the same. */ + public function updateLocalTransform () : void { + var parent:Bone = this.parent; + if (parent == null) { + x = worldX; + y = worldY; + rotation = Math.atan2(c, a) * MathUtils.radDeg; + scaleX = Math.sqrt(a * a + c * c); + scaleY = Math.sqrt(b * b + d * d); + var det:Number = a * d - b * c; + shearX = 0; + shearY = Math.atan2(a * b + c * d, det) * MathUtils.radDeg; + return; + } + var pa:Number = parent.a, pb:Number = parent.b, pc:Number = parent.c, pd:Number = parent.d; + var pid:Number = 1 / (pa * pd - pb * pc); + var dx:Number = worldX - parent.worldX, dy:Number = worldY - parent.worldY; + x = (dx * pd * pid - dy * pb * pid); + y = (dy * pa * pid - dx * pc * pid); + var ia:Number = pid * pd; + var id:Number = pid * pa; + var ib:Number = pid * pb; + var ic:Number = pid * pc; + var ra:Number = ia * a - ib * c; + var rb:Number = ia * b - ib * d; + var rc:Number = id * c - ic * a; + var rd:Number = id * d - ic * b; + shearX = 0; + scaleX = Math.sqrt(ra * ra + rc * rc); + if (scaleX > 0.0001) { + det = ra * rd - rb * rc; + scaleY = det / scaleX; + shearY = Math.atan2(ra * rb + rc * rd, det) * MathUtils.radDeg; + rotation = Math.atan2(rc, ra) * MathUtils.radDeg; + } else { + scaleX = 0; + scaleY = Math.sqrt(rb * rb + rd * rd); + shearY = 0; + rotation = 90 - Math.atan2(rd, rb) * MathUtils.radDeg; + } + appliedRotation = rotation; + } + + public function worldToLocal (world:Vector.) : void { + var a:Number = _a, b:Number = _b, c:Number = _c, d:Number = _d; + var invDet:Number = 1 / (a * d - b * c); + var x:Number = world[0] - _worldX, y:Number = world[1] - _worldY; + world[0] = (x * d * invDet - y * b * invDet); + world[1] = (y * a * invDet - x * c * invDet); + } + + public function localToWorld (local:Vector.) : void { + var localX:Number = local[0], localY:Number = local[1]; + local[0] = localX * _a + localY * _b + _worldX; + local[1] = localX * _c + localY * _d + _worldY; + } + + public function toString () : String { + return _data._name; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/BoneData.as b/spine-as3/spine-as3/src/spine/BoneData.as index fc53fb77ae..335dbec83e 100644 --- a/spine-as3/spine-as3/src/spine/BoneData.as +++ b/spine-as3/spine-as3/src/spine/BoneData.as @@ -1,76 +1,75 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { - -public class BoneData { - internal var _index:int; - internal var _name:String; - internal var _parent:BoneData; - public var length:Number; - public var x:Number; - public var y:Number; - public var rotation:Number; - public var scaleX:Number = 1; - public var scaleY:Number = 1; - public var shearX:Number; - public var shearY:Number; - public var inheritRotation:Boolean = true; - public var inheritScale:Boolean = true; - - /** @param parent May be null. */ - public function BoneData (index:int, name:String, parent:BoneData) { - if (index < 0) throw new ArgumentError("index must be >= 0"); - if (name == null) throw new ArgumentError("name cannot be null."); - _index = index; - _name = name; - _parent = parent; - } - - public function get index () : int { - return _index; - } - - public function get name () : String { - return _name; - } - - /** @return May be null. */ - public function get parent () : BoneData { - return _parent; - } - - public function toString () : String { - return _name; - } -} - +package spine { + +public class BoneData { + internal var _index:int; + internal var _name:String; + internal var _parent:BoneData; + public var length:Number; + public var x:Number; + public var y:Number; + public var rotation:Number; + public var scaleX:Number = 1; + public var scaleY:Number = 1; + public var shearX:Number; + public var shearY:Number; + public var inheritRotation:Boolean = true; + public var inheritScale:Boolean = true; + + /** @param parent May be null. */ + public function BoneData (index:int, name:String, parent:BoneData) { + if (index < 0) throw new ArgumentError("index must be >= 0"); + if (name == null) throw new ArgumentError("name cannot be null."); + _index = index; + _name = name; + _parent = parent; + } + + public function get index () : int { + return _index; + } + + public function get name () : String { + return _name; + } + + /** @return May be null. */ + public function get parent () : BoneData { + return _parent; + } + + public function toString () : String { + return _name; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/Event.as b/spine-as3/spine-as3/src/spine/Event.as index cd2ecabaac..562e75918b 100644 --- a/spine-as3/spine-as3/src/spine/Event.as +++ b/spine-as3/spine-as3/src/spine/Event.as @@ -1,56 +1,55 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { - -public class Event { - internal var _data:EventData; - public var time:Number; - public var intValue:int; - public var floatValue:Number; - public var stringValue:String; - - public function Event (time:Number, data:EventData) { - if (data == null) throw new ArgumentError("data cannot be null."); - this.time = time; - _data = data; - } - - public function get data () : EventData { - return _data; - } - - public function toString () : String { - return _data._name; - } -} - +package spine { + +public class Event { + internal var _data:EventData; + public var time:Number; + public var intValue:int; + public var floatValue:Number; + public var stringValue:String; + + public function Event (time:Number, data:EventData) { + if (data == null) throw new ArgumentError("data cannot be null."); + this.time = time; + _data = data; + } + + public function get data () : EventData { + return _data; + } + + public function toString () : String { + return _data._name; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/EventData.as b/spine-as3/spine-as3/src/spine/EventData.as index 2077b52cac..5b9ceccb9c 100644 --- a/spine-as3/spine-as3/src/spine/EventData.as +++ b/spine-as3/spine-as3/src/spine/EventData.as @@ -1,54 +1,53 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { - -public class EventData { - internal var _name:String; - public var intValue:int;; - public var floatValue:Number; - public var stringValue:String; - - public function EventData (name:String) { - if (name == null) throw new ArgumentError("name cannot be null."); - _name = name; - } - - public function get name () : String { - return _name; - } - - public function toString () : String { - return _name; - } -} - +package spine { + +public class EventData { + internal var _name:String; + public var intValue:int;; + public var floatValue:Number; + public var stringValue:String; + + public function EventData (name:String) { + if (name == null) throw new ArgumentError("name cannot be null."); + _name = name; + } + + public function get name () : String { + return _name; + } + + public function toString () : String { + return _name; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/IkConstraint.as b/spine-as3/spine-as3/src/spine/IkConstraint.as index 58593e2281..4955545d51 100644 --- a/spine-as3/spine-as3/src/spine/IkConstraint.as +++ b/spine-as3/spine-as3/src/spine/IkConstraint.as @@ -1,231 +1,230 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { - -public class IkConstraint implements Updatable { - internal var _data:IkConstraintData; - public var bones:Vector.; - public var target:Bone; - public var mix:Number; - public var bendDirection:int; - - public var level:int; - - public function IkConstraint (data:IkConstraintData, skeleton:Skeleton) { - if (data == null) throw new ArgumentError("data cannot be null."); - if (skeleton == null) throw new ArgumentError("skeleton cannot be null."); - _data = data; - mix = data.mix; - bendDirection = data.bendDirection; - - bones = new Vector.(); - for each (var boneData:BoneData in data.bones) - bones[bones.length] = skeleton.findBone(boneData.name); - target = skeleton.findBone(data.target._name); - } - - public function apply () : void { - update(); - } - - public function update () : void { - switch (bones.length) { - case 1: - apply1(bones[0], target._worldX, target._worldY, mix); - break; - case 2: - apply2(bones[0], bones[1], target._worldX, target._worldY, bendDirection, mix); - break; - } - } - - public function get data () : IkConstraintData { - return _data; - } - - public function toString () : String { - return _data._name; - } - - /** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world - * coordinate system. */ - static public function apply1 (bone:Bone, targetX:Number, targetY:Number, alpha:Number) : void { - var pp:Bone = bone.parent; - var id:Number = 1 / (pp.a * pp.d - pp.b * pp.c); - var x:Number = targetX - pp.worldX, y:Number = targetY - pp.worldY; - var tx:Number = (x * pp.d - y * pp.b) * id - bone.x, ty:Number = (y * pp.a - x * pp.c) * id - bone.y; - var rotationIK:Number = Math.atan2(ty, tx) * MathUtils.radDeg - bone.shearX - bone.rotation; - if (bone.scaleX < 0) rotationIK += 180; - if (rotationIK > 180) - rotationIK -= 360; - else if (rotationIK < -180) rotationIK += 360; - bone.updateWorldTransformWith(bone.x, bone.y, bone.rotation + rotationIK * alpha, bone.scaleX, bone.scaleY, bone.shearX, - bone.shearY); - } - - /** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The - * target is specified in the world coordinate system. - * @param child Any descendant bone of the parent. */ - static public function apply2 (parent:Bone, child:Bone, targetX:Number, targetY:Number, bendDir:int, alpha:Number) : void { - if (alpha == 0) { - child.updateWorldTransform(); - return; - } - var px:Number = parent.x, py:Number = parent.y, psx:Number = parent.scaleX, psy:Number = parent.scaleY, csx:Number = child.scaleX;; - var os1:int, os2:int, s2:int; - if (psx < 0) { - psx = -psx; - os1 = 180; - s2 = -1; - } else { - os1 = 0; - s2 = 1; - } - if (psy < 0) { - psy = -psy; - s2 = -s2; - } - if (csx < 0) { - csx = -csx; - os2 = 180; - } else - os2 = 0; - var cx:Number = child.x, cy:Number, cwx:Number, cwy:Number, a:Number = parent.a, b:Number = parent.b, c:Number = parent.c, d:Number = parent.d; - var u:Boolean = Math.abs(psx - psy) <= 0.0001; - if (!u) { - cy = 0; - cwx = a * cx + parent.worldX; - cwy = c * cx + parent.worldY; - } else { - cy = child.y; - cwx = a * cx + b * cy + parent.worldX; - cwy = c * cx + d * cy + parent.worldY; - } - var pp:Bone = parent.parent; - a = pp.a; - b = pp.b; - c = pp.c; - d = pp.d; - var id:Number = 1 / (a * d - b * c), x:Number = targetX - pp.worldX, y:Number = targetY - pp.worldY; - var tx:Number = (x * d - y * b) * id - px, ty:Number = (y * a - x * c) * id - py; - x = cwx - pp.worldX; - y = cwy - pp.worldY; - var dx:Number = (x * d - y * b) * id - px, dy:Number = (y * a - x * c) * id - py; - var l1:Number = Math.sqrt(dx * dx + dy * dy), l2:Number = child.data.length * csx, a1:Number, a2:Number; - outer: - if (u) { - l2 *= psx; - var cos:Number = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2); - if (cos < -1) - cos = -1; - else if (cos > 1) cos = 1; - a2 = Math.acos(cos) * bendDir; - a = l1 + l2 * cos; - b = l2 * Math.sin(a2); - a1 = Math.atan2(ty * a - tx * b, tx * a + ty * b); - } else { - a = psx * l2; - b = psy * l2; - var aa:Number = a * a, bb:Number = b * b, dd:Number = tx * tx + ty * ty, ta:Number = Math.atan2(ty, tx); - c = bb * l1 * l1 + aa * dd - aa * bb; - var c1:Number = -2 * bb * l1, c2:Number = bb - aa; - d = c1 * c1 - 4 * c2 * c; - if (d >= 0) { - var q:Number = Math.sqrt(d); - if (c1 < 0) q = -q; - q = -(c1 + q) / 2; - var r0:Number = q / c2, r1:Number = c / q; - var r:Number = Math.abs(r0) < Math.abs(r1) ? r0 : r1; - if (r * r <= dd) { - y = Math.sqrt(dd - r * r) * bendDir; - a1 = ta - Math.atan2(y, r); - a2 = Math.atan2(y / psy, (r - l1) / psx); - break outer; - } - } - var minAngle:Number = 0, minDist:Number = Number.MAX_VALUE, minX:Number = 0, minY:Number = 0; - var maxAngle:Number = 0, maxDist:Number = 0, maxX:Number = 0, maxY:Number = 0; - x = l1 + a; - d = x * x; - if (d > maxDist) { - maxAngle = 0; - maxDist = d; - maxX = x; - } - x = l1 - a; - d = x * x; - if (d < minDist) { - minAngle = Math.PI; - minDist = d; - minX = x; - } - var angle:Number = Math.acos(-a * l1 / (aa - bb)); - x = a * Math.cos(angle) + l1; - y = b * Math.sin(angle); - d = x * x + y * y; - if (d < minDist) { - minAngle = angle; - minDist = d; - minX = x; - minY = y; - } - if (d > maxDist) { - maxAngle = angle; - maxDist = d; - maxX = x; - maxY = y; - } - if (dd <= (minDist + maxDist) / 2) { - a1 = ta - Math.atan2(minY * bendDir, minX); - a2 = minAngle * bendDir; - } else { - a1 = ta - Math.atan2(maxY * bendDir, maxX); - a2 = maxAngle * bendDir; - } - } - var os:Number = Math.atan2(cy, cx) * s2; - var rotation:Number = parent.rotation; - a1 = (a1 - os) * MathUtils.radDeg + os1 - rotation; - if (a1 > 180) - a1 -= 360; - else if (a1 < -180) a1 += 360; - parent.updateWorldTransformWith(px, py, rotation + a1 * alpha, parent.scaleX, parent.scaleY, 0, 0); - rotation = child.rotation; - a2 = ((a2 + os) * MathUtils.radDeg - child.shearX) * s2 + os2 - rotation; - if (a2 > 180) - a2 -= 360; - else if (a2 < -180) a2 += 360; - child.updateWorldTransformWith(cx, cy, rotation + a2 * alpha, child.scaleX, child.scaleY, child.shearX, child.shearY); - } -} - +package spine { + +public class IkConstraint implements Updatable { + internal var _data:IkConstraintData; + public var bones:Vector.; + public var target:Bone; + public var mix:Number; + public var bendDirection:int; + + public var level:int; + + public function IkConstraint (data:IkConstraintData, skeleton:Skeleton) { + if (data == null) throw new ArgumentError("data cannot be null."); + if (skeleton == null) throw new ArgumentError("skeleton cannot be null."); + _data = data; + mix = data.mix; + bendDirection = data.bendDirection; + + bones = new Vector.(); + for each (var boneData:BoneData in data.bones) + bones[bones.length] = skeleton.findBone(boneData.name); + target = skeleton.findBone(data.target._name); + } + + public function apply () : void { + update(); + } + + public function update () : void { + switch (bones.length) { + case 1: + apply1(bones[0], target._worldX, target._worldY, mix); + break; + case 2: + apply2(bones[0], bones[1], target._worldX, target._worldY, bendDirection, mix); + break; + } + } + + public function get data () : IkConstraintData { + return _data; + } + + public function toString () : String { + return _data._name; + } + + /** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world + * coordinate system. */ + static public function apply1 (bone:Bone, targetX:Number, targetY:Number, alpha:Number) : void { + var pp:Bone = bone.parent; + var id:Number = 1 / (pp.a * pp.d - pp.b * pp.c); + var x:Number = targetX - pp.worldX, y:Number = targetY - pp.worldY; + var tx:Number = (x * pp.d - y * pp.b) * id - bone.x, ty:Number = (y * pp.a - x * pp.c) * id - bone.y; + var rotationIK:Number = Math.atan2(ty, tx) * MathUtils.radDeg - bone.shearX - bone.rotation; + if (bone.scaleX < 0) rotationIK += 180; + if (rotationIK > 180) + rotationIK -= 360; + else if (rotationIK < -180) rotationIK += 360; + bone.updateWorldTransformWith(bone.x, bone.y, bone.rotation + rotationIK * alpha, bone.scaleX, bone.scaleY, bone.shearX, + bone.shearY); + } + + /** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The + * target is specified in the world coordinate system. + * @param child Any descendant bone of the parent. */ + static public function apply2 (parent:Bone, child:Bone, targetX:Number, targetY:Number, bendDir:int, alpha:Number) : void { + if (alpha == 0) { + child.updateWorldTransform(); + return; + } + var px:Number = parent.x, py:Number = parent.y, psx:Number = parent.scaleX, psy:Number = parent.scaleY, csx:Number = child.scaleX;; + var os1:int, os2:int, s2:int; + if (psx < 0) { + psx = -psx; + os1 = 180; + s2 = -1; + } else { + os1 = 0; + s2 = 1; + } + if (psy < 0) { + psy = -psy; + s2 = -s2; + } + if (csx < 0) { + csx = -csx; + os2 = 180; + } else + os2 = 0; + var cx:Number = child.x, cy:Number, cwx:Number, cwy:Number, a:Number = parent.a, b:Number = parent.b, c:Number = parent.c, d:Number = parent.d; + var u:Boolean = Math.abs(psx - psy) <= 0.0001; + if (!u) { + cy = 0; + cwx = a * cx + parent.worldX; + cwy = c * cx + parent.worldY; + } else { + cy = child.y; + cwx = a * cx + b * cy + parent.worldX; + cwy = c * cx + d * cy + parent.worldY; + } + var pp:Bone = parent.parent; + a = pp.a; + b = pp.b; + c = pp.c; + d = pp.d; + var id:Number = 1 / (a * d - b * c), x:Number = targetX - pp.worldX, y:Number = targetY - pp.worldY; + var tx:Number = (x * d - y * b) * id - px, ty:Number = (y * a - x * c) * id - py; + x = cwx - pp.worldX; + y = cwy - pp.worldY; + var dx:Number = (x * d - y * b) * id - px, dy:Number = (y * a - x * c) * id - py; + var l1:Number = Math.sqrt(dx * dx + dy * dy), l2:Number = child.data.length * csx, a1:Number, a2:Number; + outer: + if (u) { + l2 *= psx; + var cos:Number = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2); + if (cos < -1) + cos = -1; + else if (cos > 1) cos = 1; + a2 = Math.acos(cos) * bendDir; + a = l1 + l2 * cos; + b = l2 * Math.sin(a2); + a1 = Math.atan2(ty * a - tx * b, tx * a + ty * b); + } else { + a = psx * l2; + b = psy * l2; + var aa:Number = a * a, bb:Number = b * b, dd:Number = tx * tx + ty * ty, ta:Number = Math.atan2(ty, tx); + c = bb * l1 * l1 + aa * dd - aa * bb; + var c1:Number = -2 * bb * l1, c2:Number = bb - aa; + d = c1 * c1 - 4 * c2 * c; + if (d >= 0) { + var q:Number = Math.sqrt(d); + if (c1 < 0) q = -q; + q = -(c1 + q) / 2; + var r0:Number = q / c2, r1:Number = c / q; + var r:Number = Math.abs(r0) < Math.abs(r1) ? r0 : r1; + if (r * r <= dd) { + y = Math.sqrt(dd - r * r) * bendDir; + a1 = ta - Math.atan2(y, r); + a2 = Math.atan2(y / psy, (r - l1) / psx); + break outer; + } + } + var minAngle:Number = 0, minDist:Number = Number.MAX_VALUE, minX:Number = 0, minY:Number = 0; + var maxAngle:Number = 0, maxDist:Number = 0, maxX:Number = 0, maxY:Number = 0; + x = l1 + a; + d = x * x; + if (d > maxDist) { + maxAngle = 0; + maxDist = d; + maxX = x; + } + x = l1 - a; + d = x * x; + if (d < minDist) { + minAngle = Math.PI; + minDist = d; + minX = x; + } + var angle:Number = Math.acos(-a * l1 / (aa - bb)); + x = a * Math.cos(angle) + l1; + y = b * Math.sin(angle); + d = x * x + y * y; + if (d < minDist) { + minAngle = angle; + minDist = d; + minX = x; + minY = y; + } + if (d > maxDist) { + maxAngle = angle; + maxDist = d; + maxX = x; + maxY = y; + } + if (dd <= (minDist + maxDist) / 2) { + a1 = ta - Math.atan2(minY * bendDir, minX); + a2 = minAngle * bendDir; + } else { + a1 = ta - Math.atan2(maxY * bendDir, maxX); + a2 = maxAngle * bendDir; + } + } + var os:Number = Math.atan2(cy, cx) * s2; + var rotation:Number = parent.rotation; + a1 = (a1 - os) * MathUtils.radDeg + os1 - rotation; + if (a1 > 180) + a1 -= 360; + else if (a1 < -180) a1 += 360; + parent.updateWorldTransformWith(px, py, rotation + a1 * alpha, parent.scaleX, parent.scaleY, 0, 0); + rotation = child.rotation; + a2 = ((a2 + os) * MathUtils.radDeg - child.shearX) * s2 + os2 - rotation; + if (a2 > 180) + a2 -= 360; + else if (a2 < -180) a2 += 360; + child.updateWorldTransformWith(cx, cy, rotation + a2 * alpha, child.scaleX, child.scaleY, child.shearX, child.shearY); + } +} + } diff --git a/spine-as3/spine-as3/src/spine/IkConstraintData.as b/spine-as3/spine-as3/src/spine/IkConstraintData.as index 04f3ea0996..6a8e6c42be 100644 --- a/spine-as3/spine-as3/src/spine/IkConstraintData.as +++ b/spine-as3/spine-as3/src/spine/IkConstraintData.as @@ -1,55 +1,54 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { - -public class IkConstraintData { - internal var _name:String; - public var bones:Vector. = new Vector.(); - public var target:BoneData; - public var bendDirection:int = 1; - public var mix:Number = 1; - - public function IkConstraintData (name:String) { - if (name == null) throw new ArgumentError("name cannot be null."); - _name = name; - } - - public function get name () : String { - return _name; - } - - public function toString () : String { - return _name; - } -} - +package spine { + +public class IkConstraintData { + internal var _name:String; + public var bones:Vector. = new Vector.(); + public var target:BoneData; + public var bendDirection:int = 1; + public var mix:Number = 1; + + public function IkConstraintData (name:String) { + if (name == null) throw new ArgumentError("name cannot be null."); + _name = name; + } + + public function get name () : String { + return _name; + } + + public function toString () : String { + return _name; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/MathUtils.as b/spine-as3/spine-as3/src/spine/MathUtils.as index b9ad40cf12..f89107fcb5 100644 --- a/spine-as3/spine-as3/src/spine/MathUtils.as +++ b/spine-as3/spine-as3/src/spine/MathUtils.as @@ -1,53 +1,52 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { - -public class MathUtils { - static public var radDeg:Number = 180 / Math.PI; - static public var degRad:Number = Math.PI / 180; - - static public function cosDeg(degrees:Number): Number { - return Math.cos(degrees * degRad); - } - - static public function sinDeg(degrees:Number): Number { - return Math.sin(degrees * degRad); - } - - static public function clamp (value:Number, min:Number, max:Number) : Number { - if (value < min) return min; - if (value > max) return max; - return value; - } -} - +package spine { + +public class MathUtils { + static public var radDeg:Number = 180 / Math.PI; + static public var degRad:Number = Math.PI / 180; + + static public function cosDeg(degrees:Number): Number { + return Math.cos(degrees * degRad); + } + + static public function sinDeg(degrees:Number): Number { + return Math.sin(degrees * degRad); + } + + static public function clamp (value:Number, min:Number, max:Number) : Number { + if (value < min) return min; + if (value > max) return max; + return value; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/PathConstraint.as b/spine-as3/spine-as3/src/spine/PathConstraint.as index b31c57235a..3fea8f3b0f 100644 --- a/spine-as3/spine-as3/src/spine/PathConstraint.as +++ b/spine-as3/spine-as3/src/spine/PathConstraint.as @@ -1,420 +1,419 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { -import spine.attachments.PathAttachment; - -public class PathConstraint implements Updatable { - private static const NONE:int = -1, BEFORE:int = -2, AFTER:int = -3; - - internal var _data:PathConstraintData; - internal var _bones:Vector.; - public var target:Slot; - public var position:Number, spacing:Number, rotateMix:Number, translateMix:Number; - - internal const _spaces:Vector. = new Vector.(); - internal const _positions:Vector. = new Vector.(); - internal const _world:Vector. = new Vector.(); - internal const _curves:Vector. = new Vector.(); - internal const _lengths:Vector. = new Vector.(); - internal const _segments:Vector. = new Vector.(10); - - public function PathConstraint (data:PathConstraintData, skeleton:Skeleton) { - if (data == null) throw new ArgumentError("data cannot be null."); - if (skeleton == null) throw new ArgumentError("skeleton cannot be null."); - _data = data; - _bones = new Vector.(); - for each (var boneData:BoneData in data.bones) - _bones.push(skeleton.findBone(boneData.name)); - target = skeleton.findSlot(data.target.name); - position = data.position; - spacing = data.spacing; - rotateMix = data.rotateMix; - translateMix = data.translateMix; - } - - public function apply () : void { - update(); - } - - public function update () : void { - var attachment:PathAttachment = target.attachment as PathAttachment; - if (attachment == null) return; - - var rotateMix:Number = this.rotateMix, translateMix:Number = this.translateMix; - var translate:Boolean = translateMix > 0, rotate:Boolean = rotateMix > 0; - if (!translate && !rotate) return; - - var data:PathConstraintData = this._data; - var spacingMode:SpacingMode = data.spacingMode; - var lengthSpacing:Boolean = spacingMode == SpacingMode.length; - var rotateMode:RotateMode = data.rotateMode; - var tangents:Boolean = rotateMode == RotateMode.tangent, scale:Boolean = rotateMode == RotateMode.chainScale; - var boneCount:int = this._bones.length, spacesCount:int = tangents ? boneCount : boneCount + 1; - var bones:Vector. = this._bones; - this._spaces.length = spacesCount; - var spaces:Vector. = this._spaces, lengths:Vector. = null; - var spacing:Number = this.spacing; - if (scale || lengthSpacing) { - if (scale) { - this._lengths.length = boneCount; - lengths = this._lengths; - } - for (var i:int = 0, n:int = spacesCount - 1; i < n;) { - var bone:Bone = bones[i]; - var length:Number = bone.data.length, x:Number = length * bone.a, y:Number = length * bone.c; - length = Math.sqrt(x * x + y * y); - if (scale) lengths[i] = length; - spaces[++i] = lengthSpacing ? Math.max(0, length + spacing) : spacing; - } - } else { - for (i = 1; i < spacesCount; i++) - spaces[i] = spacing; - } - - var positions:Vector. = computeWorldPositions(attachment, spacesCount, tangents, - data.positionMode == PositionMode.percent, spacingMode == SpacingMode.percent); - var skeleton:Skeleton = target.skeleton; - var skeletonX:Number = skeleton.x, skeletonY:Number = skeleton.y; - var boneX:Number = positions[0], boneY:Number = positions[1], offsetRotation:Number = data.offsetRotation; - var tip:Boolean = rotateMode == RotateMode.chain && offsetRotation == 0; - var p:Number; - for (i = 0, p = 3; i < boneCount; i++, p += 3) { - bone = bones[i]; - bone._worldX += (boneX - skeletonX - bone.worldX) * translateMix; - bone._worldY += (boneY - skeletonY - bone.worldY) * translateMix; - x = positions[p]; y = positions[p + 1]; var dx:Number = x - boneX, dy:Number = y - boneY; - if (scale) { - length = lengths[i]; - if (length != 0) { - var s:Number = (Math.sqrt(dx * dx + dy * dy) / length - 1) * rotateMix + 1; - bone._a *= s; - bone._c *= s; - } - } - boneX = x; - boneY = y; - if (rotate) { - var a:Number = bone.a, b:Number = bone.b, c:Number = bone.c, d:Number = bone.d, r:Number, cos:Number, sin:Number; - if (tangents) - r = positions[p - 1]; - else if (spaces[i + 1] == 0) - r = positions[p + 2]; - else - r = Math.atan2(dy, dx); - r -= Math.atan2(c, a) - offsetRotation * MathUtils.degRad; - if (tip) { - cos = Math.cos(r); - sin = Math.sin(r); - length = bone.data.length; - boneX += (length * (cos * a - sin * c) - dx) * rotateMix; - boneY += (length * (sin * a + cos * c) - dy) * rotateMix; - } - if (r > Math.PI) - r -= (Math.PI * 2); - else if (r < -Math.PI) // - r += (Math.PI * 2); - r *= rotateMix; - cos = Math.cos(r); - sin = Math.sin(r); - bone._a = cos * a - sin * c; - bone._b = cos * b - sin * d; - bone._c = sin * a + cos * c; - bone._d = sin * b + cos * d; - } - } - } - - protected function computeWorldPositions (path:PathAttachment, spacesCount:int, tangents:Boolean, percentPosition:Boolean, - percentSpacing:Boolean) : Vector. { - var target:Slot = this.target; - var position:Number = this.position; - var spaces:Vector. = this._spaces; - this._positions.length = spacesCount * 3 + 2; - var out:Vector. = this._positions, world:Vector.; - var closed:Boolean = path.closed; - var verticesLength:int = path.worldVerticesLength, curveCount:int = verticesLength / 6, prevCurve:int = NONE; - - if (!path.constantSpeed) { - var lengths:Vector. = path.lengths; - curveCount -= closed ? 1 : 2; - var pathLength:Number = lengths[curveCount]; - if (percentPosition) position *= pathLength; - if (percentSpacing) { - for (var i:int = 0; i < spacesCount; i++) - spaces[i] *= pathLength; - } - this._world.length = 8; - world = this._world; - var o:int, curve:int; - for (i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) { - var space:Number = spaces[i]; - position += space; - var p:Number = position; - - if (closed) { - p %= pathLength; - if (p < 0) p += pathLength; - curve = 0; - } else if (p < 0) { - if (prevCurve != BEFORE) { - prevCurve = BEFORE; - path.computeWorldVertices2(target, 2, 4, world, 0); - } - addBeforePosition(p, world, 0, out, o); - continue; - } else if (p > pathLength) { - if (prevCurve != AFTER) { - prevCurve = AFTER; - path.computeWorldVertices2(target, verticesLength - 6, 4, world, 0); - } - addAfterPosition(p - pathLength, world, 0, out, o); - continue; - } - - // Determine curve containing position. - for (;; curve++) { - var length:Number = lengths[curve]; - if (p > length) continue; - if (curve == 0) - p /= length; - else { - var prev:Number = lengths[curve - 1]; - p = (p - prev) / (length - prev); - } - break; - } - if (curve != prevCurve) { - prevCurve = curve; - if (closed && curve == curveCount) { - path.computeWorldVertices2(target, verticesLength - 4, 4, world, 0); - path.computeWorldVertices2(target, 0, 4, world, 4); - } else - path.computeWorldVertices2(target, curve * 6 + 2, 8, world, 0); - } - addCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], out, o, - tangents || (i > 0 && space == 0)); - } - return out; - } - - // World vertices. - if (closed) { - verticesLength += 2; - this._world.length = verticesLength; - world = this._world; - path.computeWorldVertices2(target, 2, verticesLength - 4, world, 0); - path.computeWorldVertices2(target, 0, 2, world, verticesLength - 4); - world[verticesLength - 2] = world[0]; - world[verticesLength - 1] = world[1]; - } else { - curveCount--; - verticesLength -= 4; - this._world.length = verticesLength; - world = this._world; - path.computeWorldVertices2(target, 2, verticesLength, world, 0); - } - - // Curve lengths. - this._curves.length = curveCount; - var curves:Vector. = this._curves; - pathLength = 0; - var x1:Number = world[0], y1:Number = world[1], cx1:Number = 0, cy1:Number = 0, cx2:Number = 0, cy2:Number = 0, x2:Number = 0, y2:Number = 0; - var tmpx:Number, tmpy:Number, dddfx:Number, dddfy:Number, ddfx:Number, ddfy:Number, dfx:Number, dfy:Number; - var w:int; - for (i = 0, w = 2; i < curveCount; i++, w += 6) { - cx1 = world[w]; - cy1 = world[w + 1]; - cx2 = world[w + 2]; - cy2 = world[w + 3]; - x2 = world[w + 4]; - y2 = world[w + 5]; - tmpx = (x1 - cx1 * 2 + cx2) * 0.1875; - tmpy = (y1 - cy1 * 2 + cy2) * 0.1875; - dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375; - dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375; - ddfx = tmpx * 2 + dddfx; - ddfy = tmpy * 2 + dddfy; - dfx = (cx1 - x1) * 0.75 + tmpx + dddfx * 0.16666667; - dfy = (cy1 - y1) * 0.75 + tmpy + dddfy * 0.16666667; - pathLength += Math.sqrt(dfx * dfx + dfy * dfy); - dfx += ddfx; - dfy += ddfy; - ddfx += dddfx; - ddfy += dddfy; - pathLength += Math.sqrt(dfx * dfx + dfy * dfy); - dfx += ddfx; - dfy += ddfy; - pathLength += Math.sqrt(dfx * dfx + dfy * dfy); - dfx += ddfx + dddfx; - dfy += ddfy + dddfy; - pathLength += Math.sqrt(dfx * dfx + dfy * dfy); - curves[i] = pathLength; - x1 = x2; - y1 = y2; - } - if (percentPosition) position *= pathLength; - if (percentSpacing) { - for (i = 0; i < spacesCount; i++) - spaces[i] *= pathLength; - } - - var segments:Vector. = this._segments; - var curveLength:Number = 0; - var segment:int; - for (i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) { - space = spaces[i]; - position += space; - p = position; - - if (closed) { - p %= pathLength; - if (p < 0) p += pathLength; - curve = 0; - } else if (p < 0) { - addBeforePosition(p, world, 0, out, o); - continue; - } else if (p > pathLength) { - addAfterPosition(p - pathLength, world, verticesLength - 4, out, o); - continue; - } - - // Determine curve containing position. - for (;; curve++) { - length = curves[curve]; - if (p > length) continue; - if (curve == 0) - p /= length; - else { - prev = curves[curve - 1]; - p = (p - prev) / (length - prev); - } - break; - } - - // Curve segment lengths. - if (curve != prevCurve) { - prevCurve = curve; - var ii:int = curve * 6; - x1 = world[ii]; - y1 = world[ii + 1]; - cx1 = world[ii + 2]; - cy1 = world[ii + 3]; - cx2 = world[ii + 4]; - cy2 = world[ii + 5]; - x2 = world[ii + 6]; - y2 = world[ii + 7]; - tmpx = (x1 - cx1 * 2 + cx2) * 0.03; - tmpy = (y1 - cy1 * 2 + cy2) * 0.03; - dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006; - dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006; - ddfx = tmpx * 2 + dddfx; - ddfy = tmpy * 2 + dddfy; - dfx = (cx1 - x1) * 0.3 + tmpx + dddfx * 0.16666667; - dfy = (cy1 - y1) * 0.3 + tmpy + dddfy * 0.16666667; - curveLength = Math.sqrt(dfx * dfx + dfy * dfy); - segments[0] = curveLength; - for (ii = 1; ii < 8; ii++) { - dfx += ddfx; - dfy += ddfy; - ddfx += dddfx; - ddfy += dddfy; - curveLength += Math.sqrt(dfx * dfx + dfy * dfy); - segments[ii] = curveLength; - } - dfx += ddfx; - dfy += ddfy; - curveLength += Math.sqrt(dfx * dfx + dfy * dfy); - segments[8] = curveLength; - dfx += ddfx + dddfx; - dfy += ddfy + dddfy; - curveLength += Math.sqrt(dfx * dfx + dfy * dfy); - segments[9] = curveLength; - segment = 0; - } - - // Weight by segment length. - p *= curveLength; - for (;; segment++) { - length = segments[segment]; - if (p > length) continue; - if (segment == 0) - p /= length; - else { - prev = segments[segment - 1]; - p = segment + (p - prev) / (length - prev); - } - break; - } - addCurvePosition(p * 0.1, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || (i > 0 && space == 0)); - } - return out; - } - - private function addBeforePosition (p:Number, temp:Vector., i:int, out:Vector., o:int) : void { - var x1:Number = temp[i], y1:Number = temp[i + 1], dx:Number = temp[i + 2] - x1, dy:Number = temp[i + 3] - y1, r:Number = Math.atan2(dy, dx); - out[o] = x1 + p * Math.cos(r); - out[o + 1] = y1 + p * Math.sin(r); - out[o + 2] = r; - } - - private function addAfterPosition (p:Number, temp:Vector., i:int, out:Vector., o:int) : void { - var x1:Number = temp[i + 2], y1:Number = temp[i + 3], dx:Number = x1 - temp[i], dy:Number = y1 - temp[i + 1], r:Number = Math.atan2(dy, dx); - out[o] = x1 + p * Math.cos(r); - out[o + 1] = y1 + p * Math.sin(r); - out[o + 2] = r; - } - - private function addCurvePosition (p:Number, x1:Number, y1:Number, cx1:Number, cy1:Number, cx2:Number, cy2:Number, x2:Number, y2:Number, - out:Vector., o:int, tangents:Boolean) : void { - if (p == 0) p = 0.0001; - var tt:Number = p * p, ttt:Number = tt * p, u:Number = 1 - p, uu:Number = u * u, uuu:Number = uu * u; - var ut:Number = u * p, ut3:Number = ut * 3, uut3:Number = u * ut3, utt3:Number = ut3 * p; - var x:Number = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y:Number = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt; - out[o] = x; - out[o + 1] = y; - if (tangents) out[o + 2] = Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); - } - - public function get bones () : Vector. { - return _bones; - } - - public function get data () : PathConstraintData { - return _data; - } - - public function toString () : String { - return _data.name; - } -} - +package spine { +import spine.attachments.PathAttachment; + +public class PathConstraint implements Updatable { + private static const NONE:int = -1, BEFORE:int = -2, AFTER:int = -3; + + internal var _data:PathConstraintData; + internal var _bones:Vector.; + public var target:Slot; + public var position:Number, spacing:Number, rotateMix:Number, translateMix:Number; + + internal const _spaces:Vector. = new Vector.(); + internal const _positions:Vector. = new Vector.(); + internal const _world:Vector. = new Vector.(); + internal const _curves:Vector. = new Vector.(); + internal const _lengths:Vector. = new Vector.(); + internal const _segments:Vector. = new Vector.(10); + + public function PathConstraint (data:PathConstraintData, skeleton:Skeleton) { + if (data == null) throw new ArgumentError("data cannot be null."); + if (skeleton == null) throw new ArgumentError("skeleton cannot be null."); + _data = data; + _bones = new Vector.(); + for each (var boneData:BoneData in data.bones) + _bones.push(skeleton.findBone(boneData.name)); + target = skeleton.findSlot(data.target.name); + position = data.position; + spacing = data.spacing; + rotateMix = data.rotateMix; + translateMix = data.translateMix; + } + + public function apply () : void { + update(); + } + + public function update () : void { + var attachment:PathAttachment = target.attachment as PathAttachment; + if (attachment == null) return; + + var rotateMix:Number = this.rotateMix, translateMix:Number = this.translateMix; + var translate:Boolean = translateMix > 0, rotate:Boolean = rotateMix > 0; + if (!translate && !rotate) return; + + var data:PathConstraintData = this._data; + var spacingMode:SpacingMode = data.spacingMode; + var lengthSpacing:Boolean = spacingMode == SpacingMode.length; + var rotateMode:RotateMode = data.rotateMode; + var tangents:Boolean = rotateMode == RotateMode.tangent, scale:Boolean = rotateMode == RotateMode.chainScale; + var boneCount:int = this._bones.length, spacesCount:int = tangents ? boneCount : boneCount + 1; + var bones:Vector. = this._bones; + this._spaces.length = spacesCount; + var spaces:Vector. = this._spaces, lengths:Vector. = null; + var spacing:Number = this.spacing; + if (scale || lengthSpacing) { + if (scale) { + this._lengths.length = boneCount; + lengths = this._lengths; + } + for (var i:int = 0, n:int = spacesCount - 1; i < n;) { + var bone:Bone = bones[i]; + var length:Number = bone.data.length, x:Number = length * bone.a, y:Number = length * bone.c; + length = Math.sqrt(x * x + y * y); + if (scale) lengths[i] = length; + spaces[++i] = lengthSpacing ? Math.max(0, length + spacing) : spacing; + } + } else { + for (i = 1; i < spacesCount; i++) + spaces[i] = spacing; + } + + var positions:Vector. = computeWorldPositions(attachment, spacesCount, tangents, + data.positionMode == PositionMode.percent, spacingMode == SpacingMode.percent); + var skeleton:Skeleton = target.skeleton; + var skeletonX:Number = skeleton.x, skeletonY:Number = skeleton.y; + var boneX:Number = positions[0], boneY:Number = positions[1], offsetRotation:Number = data.offsetRotation; + var tip:Boolean = rotateMode == RotateMode.chain && offsetRotation == 0; + var p:Number; + for (i = 0, p = 3; i < boneCount; i++, p += 3) { + bone = bones[i]; + bone._worldX += (boneX - skeletonX - bone.worldX) * translateMix; + bone._worldY += (boneY - skeletonY - bone.worldY) * translateMix; + x = positions[p]; y = positions[p + 1]; var dx:Number = x - boneX, dy:Number = y - boneY; + if (scale) { + length = lengths[i]; + if (length != 0) { + var s:Number = (Math.sqrt(dx * dx + dy * dy) / length - 1) * rotateMix + 1; + bone._a *= s; + bone._c *= s; + } + } + boneX = x; + boneY = y; + if (rotate) { + var a:Number = bone.a, b:Number = bone.b, c:Number = bone.c, d:Number = bone.d, r:Number, cos:Number, sin:Number; + if (tangents) + r = positions[p - 1]; + else if (spaces[i + 1] == 0) + r = positions[p + 2]; + else + r = Math.atan2(dy, dx); + r -= Math.atan2(c, a) - offsetRotation * MathUtils.degRad; + if (tip) { + cos = Math.cos(r); + sin = Math.sin(r); + length = bone.data.length; + boneX += (length * (cos * a - sin * c) - dx) * rotateMix; + boneY += (length * (sin * a + cos * c) - dy) * rotateMix; + } + if (r > Math.PI) + r -= (Math.PI * 2); + else if (r < -Math.PI) // + r += (Math.PI * 2); + r *= rotateMix; + cos = Math.cos(r); + sin = Math.sin(r); + bone._a = cos * a - sin * c; + bone._b = cos * b - sin * d; + bone._c = sin * a + cos * c; + bone._d = sin * b + cos * d; + } + } + } + + protected function computeWorldPositions (path:PathAttachment, spacesCount:int, tangents:Boolean, percentPosition:Boolean, + percentSpacing:Boolean) : Vector. { + var target:Slot = this.target; + var position:Number = this.position; + var spaces:Vector. = this._spaces; + this._positions.length = spacesCount * 3 + 2; + var out:Vector. = this._positions, world:Vector.; + var closed:Boolean = path.closed; + var verticesLength:int = path.worldVerticesLength, curveCount:int = verticesLength / 6, prevCurve:int = NONE; + + if (!path.constantSpeed) { + var lengths:Vector. = path.lengths; + curveCount -= closed ? 1 : 2; + var pathLength:Number = lengths[curveCount]; + if (percentPosition) position *= pathLength; + if (percentSpacing) { + for (var i:int = 0; i < spacesCount; i++) + spaces[i] *= pathLength; + } + this._world.length = 8; + world = this._world; + var o:int, curve:int; + for (i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) { + var space:Number = spaces[i]; + position += space; + var p:Number = position; + + if (closed) { + p %= pathLength; + if (p < 0) p += pathLength; + curve = 0; + } else if (p < 0) { + if (prevCurve != BEFORE) { + prevCurve = BEFORE; + path.computeWorldVertices2(target, 2, 4, world, 0); + } + addBeforePosition(p, world, 0, out, o); + continue; + } else if (p > pathLength) { + if (prevCurve != AFTER) { + prevCurve = AFTER; + path.computeWorldVertices2(target, verticesLength - 6, 4, world, 0); + } + addAfterPosition(p - pathLength, world, 0, out, o); + continue; + } + + // Determine curve containing position. + for (;; curve++) { + var length:Number = lengths[curve]; + if (p > length) continue; + if (curve == 0) + p /= length; + else { + var prev:Number = lengths[curve - 1]; + p = (p - prev) / (length - prev); + } + break; + } + if (curve != prevCurve) { + prevCurve = curve; + if (closed && curve == curveCount) { + path.computeWorldVertices2(target, verticesLength - 4, 4, world, 0); + path.computeWorldVertices2(target, 0, 4, world, 4); + } else + path.computeWorldVertices2(target, curve * 6 + 2, 8, world, 0); + } + addCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], out, o, + tangents || (i > 0 && space == 0)); + } + return out; + } + + // World vertices. + if (closed) { + verticesLength += 2; + this._world.length = verticesLength; + world = this._world; + path.computeWorldVertices2(target, 2, verticesLength - 4, world, 0); + path.computeWorldVertices2(target, 0, 2, world, verticesLength - 4); + world[verticesLength - 2] = world[0]; + world[verticesLength - 1] = world[1]; + } else { + curveCount--; + verticesLength -= 4; + this._world.length = verticesLength; + world = this._world; + path.computeWorldVertices2(target, 2, verticesLength, world, 0); + } + + // Curve lengths. + this._curves.length = curveCount; + var curves:Vector. = this._curves; + pathLength = 0; + var x1:Number = world[0], y1:Number = world[1], cx1:Number = 0, cy1:Number = 0, cx2:Number = 0, cy2:Number = 0, x2:Number = 0, y2:Number = 0; + var tmpx:Number, tmpy:Number, dddfx:Number, dddfy:Number, ddfx:Number, ddfy:Number, dfx:Number, dfy:Number; + var w:int; + for (i = 0, w = 2; i < curveCount; i++, w += 6) { + cx1 = world[w]; + cy1 = world[w + 1]; + cx2 = world[w + 2]; + cy2 = world[w + 3]; + x2 = world[w + 4]; + y2 = world[w + 5]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.1875; + tmpy = (y1 - cy1 * 2 + cy2) * 0.1875; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.75 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.75 + tmpy + dddfy * 0.16666667; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + curves[i] = pathLength; + x1 = x2; + y1 = y2; + } + if (percentPosition) position *= pathLength; + if (percentSpacing) { + for (i = 0; i < spacesCount; i++) + spaces[i] *= pathLength; + } + + var segments:Vector. = this._segments; + var curveLength:Number = 0; + var segment:int; + for (i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) { + space = spaces[i]; + position += space; + p = position; + + if (closed) { + p %= pathLength; + if (p < 0) p += pathLength; + curve = 0; + } else if (p < 0) { + addBeforePosition(p, world, 0, out, o); + continue; + } else if (p > pathLength) { + addAfterPosition(p - pathLength, world, verticesLength - 4, out, o); + continue; + } + + // Determine curve containing position. + for (;; curve++) { + length = curves[curve]; + if (p > length) continue; + if (curve == 0) + p /= length; + else { + prev = curves[curve - 1]; + p = (p - prev) / (length - prev); + } + break; + } + + // Curve segment lengths. + if (curve != prevCurve) { + prevCurve = curve; + var ii:int = curve * 6; + x1 = world[ii]; + y1 = world[ii + 1]; + cx1 = world[ii + 2]; + cy1 = world[ii + 3]; + cx2 = world[ii + 4]; + cy2 = world[ii + 5]; + x2 = world[ii + 6]; + y2 = world[ii + 7]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.03; + tmpy = (y1 - cy1 * 2 + cy2) * 0.03; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.3 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.3 + tmpy + dddfy * 0.16666667; + curveLength = Math.sqrt(dfx * dfx + dfy * dfy); + segments[0] = curveLength; + for (ii = 1; ii < 8; ii++) { + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[ii] = curveLength; + } + dfx += ddfx; + dfy += ddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[8] = curveLength; + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[9] = curveLength; + segment = 0; + } + + // Weight by segment length. + p *= curveLength; + for (;; segment++) { + length = segments[segment]; + if (p > length) continue; + if (segment == 0) + p /= length; + else { + prev = segments[segment - 1]; + p = segment + (p - prev) / (length - prev); + } + break; + } + addCurvePosition(p * 0.1, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || (i > 0 && space == 0)); + } + return out; + } + + private function addBeforePosition (p:Number, temp:Vector., i:int, out:Vector., o:int) : void { + var x1:Number = temp[i], y1:Number = temp[i + 1], dx:Number = temp[i + 2] - x1, dy:Number = temp[i + 3] - y1, r:Number = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + } + + private function addAfterPosition (p:Number, temp:Vector., i:int, out:Vector., o:int) : void { + var x1:Number = temp[i + 2], y1:Number = temp[i + 3], dx:Number = x1 - temp[i], dy:Number = y1 - temp[i + 1], r:Number = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + } + + private function addCurvePosition (p:Number, x1:Number, y1:Number, cx1:Number, cy1:Number, cx2:Number, cy2:Number, x2:Number, y2:Number, + out:Vector., o:int, tangents:Boolean) : void { + if (p == 0) p = 0.0001; + var tt:Number = p * p, ttt:Number = tt * p, u:Number = 1 - p, uu:Number = u * u, uuu:Number = uu * u; + var ut:Number = u * p, ut3:Number = ut * 3, uut3:Number = u * ut3, utt3:Number = ut3 * p; + var x:Number = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y:Number = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt; + out[o] = x; + out[o + 1] = y; + if (tangents) out[o + 2] = Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); + } + + public function get bones () : Vector. { + return _bones; + } + + public function get data () : PathConstraintData { + return _data; + } + + public function toString () : String { + return _data.name; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/PathConstraintData.as b/spine-as3/spine-as3/src/spine/PathConstraintData.as index 45863d0c01..4004c14de9 100644 --- a/spine-as3/spine-as3/src/spine/PathConstraintData.as +++ b/spine-as3/spine-as3/src/spine/PathConstraintData.as @@ -1,62 +1,61 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { - -public dynamic class PathConstraintData { - internal var _name:String; - internal var _bones:Vector. = new Vector.(); - public var target:SlotData; - public var positionMode:PositionMode; - public var spacingMode:SpacingMode; - public var rotateMode:RotateMode; - public var offsetRotation:Number; - public var position:Number, spacing:Number, rotateMix:Number, translateMix:Number; - - public function PathConstraintData (name:String) { - if (name == null) throw new ArgumentError("name cannot be null."); - _name = name; - } - - public function get bones () : Vector. { - return _bones; - } - - public function get name () : String { - return _name; - } - - public function toString () : String { - return name; - } +package spine { + +public dynamic class PathConstraintData { + internal var _name:String; + internal var _bones:Vector. = new Vector.(); + public var target:SlotData; + public var positionMode:PositionMode; + public var spacingMode:SpacingMode; + public var rotateMode:RotateMode; + public var offsetRotation:Number; + public var position:Number, spacing:Number, rotateMix:Number, translateMix:Number; + + public function PathConstraintData (name:String) { + if (name == null) throw new ArgumentError("name cannot be null."); + _name = name; + } + + public function get bones () : Vector. { + return _bones; + } + + public function get name () : String { + return _name; + } + + public function toString () : String { + return name; + } +} + } - -} \ No newline at end of file diff --git a/spine-as3/spine-as3/src/spine/Polygon.as b/spine-as3/spine-as3/src/spine/Polygon.as index b7acb8ca70..d5af058ef6 100644 --- a/spine-as3/spine-as3/src/spine/Polygon.as +++ b/spine-as3/spine-as3/src/spine/Polygon.as @@ -1,83 +1,82 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { - -public class Polygon { - public var vertices:Vector. = new Vector.(); - - public function Polygon () { - } - - /** Returns true if the polygon contains the point. */ - public function containsPoint (x:Number, y:Number) : Boolean { - var nn:int = vertices.length; - - var prevIndex:int = nn - 2; - var inside:Boolean = false; - for (var ii:int = 0; ii < nn; ii += 2) { - var vertexY:Number = vertices[ii + 1]; - var prevY:Number = vertices[prevIndex + 1]; - if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { - var vertexX:Number = vertices[ii]; - if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside; - } - prevIndex = ii; - } - - return inside; - } - - /** Returns true if the polygon contains the line segment. */ - public function intersectsSegment (x1:Number, y1:Number, x2:Number, y2:Number) : Boolean { - var nn:int = vertices.length; - - var width12:Number = x1 - x2, height12:Number = y1 - y2; - var det1:Number = x1 * y2 - y1 * x2; - var x3:Number = vertices[nn - 2], y3:Number = vertices[nn - 1]; - for (var ii:int = 0; ii < nn; ii += 2) { - var x4:Number = vertices[ii], y4:Number = vertices[ii + 1]; - var det2:Number = x3 * y4 - y3 * x4; - var width34:Number = x3 - x4, height34:Number = y3 - y4; - var det3:Number = width12 * height34 - height12 * width34; - var x:Number = (det1 * width34 - width12 * det2) / det3; - if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { - var y:Number = (det1 * height34 - height12 * det2) / det3; - if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; - } - x3 = x4; - y3 = y4; - } - return false; - } -} - +package spine { + +public class Polygon { + public var vertices:Vector. = new Vector.(); + + public function Polygon () { + } + + /** Returns true if the polygon contains the point. */ + public function containsPoint (x:Number, y:Number) : Boolean { + var nn:int = vertices.length; + + var prevIndex:int = nn - 2; + var inside:Boolean = false; + for (var ii:int = 0; ii < nn; ii += 2) { + var vertexY:Number = vertices[ii + 1]; + var prevY:Number = vertices[prevIndex + 1]; + if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { + var vertexX:Number = vertices[ii]; + if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside; + } + prevIndex = ii; + } + + return inside; + } + + /** Returns true if the polygon contains the line segment. */ + public function intersectsSegment (x1:Number, y1:Number, x2:Number, y2:Number) : Boolean { + var nn:int = vertices.length; + + var width12:Number = x1 - x2, height12:Number = y1 - y2; + var det1:Number = x1 * y2 - y1 * x2; + var x3:Number = vertices[nn - 2], y3:Number = vertices[nn - 1]; + for (var ii:int = 0; ii < nn; ii += 2) { + var x4:Number = vertices[ii], y4:Number = vertices[ii + 1]; + var det2:Number = x3 * y4 - y3 * x4; + var width34:Number = x3 - x4, height34:Number = y3 - y4; + var det3:Number = width12 * height34 - height12 * width34; + var x:Number = (det1 * width34 - width12 * det2) / det3; + if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { + var y:Number = (det1 * height34 - height12 * det2) / det3; + if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; + } + x3 = x4; + y3 = y4; + } + return false; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/PositionMode.as b/spine-as3/spine-as3/src/spine/PositionMode.as index ac8dabb003..1d5894ddf4 100644 --- a/spine-as3/spine-as3/src/spine/PositionMode.as +++ b/spine-as3/spine-as3/src/spine/PositionMode.as @@ -1,39 +1,38 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { - -public class PositionMode { - public static const fixed:PositionMode = new PositionMode(); - public static const percent:PositionMode = new PositionMode(); +package spine { + +public class PositionMode { + public static const fixed:PositionMode = new PositionMode(); + public static const percent:PositionMode = new PositionMode(); +} + } - -} \ No newline at end of file diff --git a/spine-as3/spine-as3/src/spine/RotateMode.as b/spine-as3/spine-as3/src/spine/RotateMode.as index f869f79b9f..6e1e1333a0 100644 --- a/spine-as3/spine-as3/src/spine/RotateMode.as +++ b/spine-as3/spine-as3/src/spine/RotateMode.as @@ -1,40 +1,39 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { - -public class RotateMode { - public static const tangent:RotateMode = new RotateMode(); - public static const chain:RotateMode = new RotateMode(); - public static const chainScale:RotateMode = new RotateMode(); +package spine { + +public class RotateMode { + public static const tangent:RotateMode = new RotateMode(); + public static const chain:RotateMode = new RotateMode(); + public static const chainScale:RotateMode = new RotateMode(); +} + } - -} \ No newline at end of file diff --git a/spine-as3/spine-as3/src/spine/Skeleton.as b/spine-as3/spine-as3/src/spine/Skeleton.as index 18246e63b8..25a029c3e4 100644 --- a/spine-as3/spine-as3/src/spine/Skeleton.as +++ b/spine-as3/spine-as3/src/spine/Skeleton.as @@ -1,449 +1,448 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { -import flash.utils.Dictionary; -import spine.attachments.PathAttachment; -import spine.attachments.Attachment; - -public class Skeleton { - internal var _data:SkeletonData; - public var bones:Vector.; - public var slots:Vector.; - public var drawOrder:Vector.; - public var ikConstraints:Vector., ikConstraintsSorted:Vector.; - public var transformConstraints:Vector.; - public var pathConstraints:Vector.; - private var _updateCache:Vector. = new Vector.(); - private var _skin:Skin; - public var r:Number = 1, g:Number = 1, b:Number = 1, a:Number = 1; - public var time:Number = 0; - public var flipX:Boolean, flipY:Boolean; - public var x:Number = 0, y:Number = 0; - - public function Skeleton (data:SkeletonData) { - if (data == null) - throw new ArgumentError("data cannot be null."); - _data = data; - - bones = new Vector.(); - for each (var boneData:BoneData in data.bones) { - var bone:Bone; - if (boneData.parent == null) - bone = new Bone(boneData, this, null); - else { - var parent:Bone = bones[boneData.parent.index]; - bone = new Bone(boneData, this, parent); - parent.children.push(bone); - } - bones.push(bone); - } - - slots = new Vector.(); - drawOrder = new Vector.(); - for each (var slotData:SlotData in data.slots) { - bone = bones[slotData.boneData.index]; - var slot:Slot = new Slot(slotData, bone); - slots.push(slot); - drawOrder[drawOrder.length] = slot; - } - - ikConstraints = new Vector.(); - ikConstraintsSorted = new Vector.(); - for each (var ikConstraintData:IkConstraintData in data.ikConstraints) - ikConstraints.push(new IkConstraint(ikConstraintData, this)); - - transformConstraints = new Vector.(); - for each (var transformConstraintData:TransformConstraintData in data.transformConstraints) - transformConstraints.push(new TransformConstraint(transformConstraintData, this)); - - pathConstraints = new Vector.(); - for each (var pathConstraintData:PathConstraintData in data.pathConstraints) - pathConstraints.push(new PathConstraint(pathConstraintData, this)); - - updateCache(); - } - - /** Caches information about bones and constraints. Must be called if bones, constraints, or weighted path attachments are - * added or removed. */ - public function updateCache () : void { - var updateCache:Vector. = this._updateCache; - updateCache.length = 0; - - var bones:Vector. = this.bones; - for (var i:int = 0, n:int = bones.length; i < n; i++) - bones[i]._sorted = false; - - // IK first, lowest hierarchy depth first. - var ikConstraints:Vector. = this.ikConstraintsSorted; - ikConstraints.length = 0; - for each (var c:IkConstraint in this.ikConstraints) - ikConstraints.push(c); - var ikCount:int = ikConstraints.length; - var level:int; - for (i = 0, n = ikCount; i < n; i++) { - var ik:IkConstraint = ikConstraints[i]; - var bone:Bone = ik.bones[0].parent; - for (level = 0; bone != null; level++) - bone = bone.parent; - ik.level = level; - } - var ii:int; - for (i = 1; i < ikCount; i++) { - ik = ikConstraints[i]; - level = ik.level; - for (ii = i - 1; ii >= 0; ii--) { - var other:IkConstraint = ikConstraints[ii]; - if (other.level < level) break; - ikConstraints[ii + 1] = other; - } - ikConstraints[ii + 1] = ik; - } - for (i = 0, n = ikConstraints.length; i < n; i++) { - var ikConstraint:IkConstraint = ikConstraints[i]; - var target:Bone = ikConstraint.target; - sortBone(target); - - var constrained:Vector. = ikConstraint.bones; - var parent:Bone = constrained[0]; - sortBone(parent); - - updateCache.push(ikConstraint); - - sortReset(parent.children); - constrained[constrained.length - 1]._sorted = true; - } - - var pathConstraints:Vector. = this.pathConstraints; - for (i = 0, n = pathConstraints.length; i < n; i++) { - var pathConstraint:PathConstraint = pathConstraints[i]; - - var slot:Slot = pathConstraint.target; - var slotIndex:int = slot.data.index; - var slotBone:Bone = slot.bone; - if (skin != null) sortPathConstraintAttachment(skin, slotIndex, slotBone); - if (_data.defaultSkin != null && _data.defaultSkin != skin) - sortPathConstraintAttachment(_data.defaultSkin, slotIndex, slotBone); - - var nn:int; - for (ii = 0, nn = _data.skins.length; ii < nn; ii++) - sortPathConstraintAttachment(_data.skins[ii], slotIndex, slotBone); - - var attachment:PathAttachment = slot.attachment as PathAttachment; - if (attachment != null) sortPathConstraintAttachment2(attachment, slotBone); - - constrained = pathConstraint.bones; - var boneCount:int = constrained.length; - for (ii = 0; ii < boneCount; ii++) - sortBone(constrained[ii]); - - updateCache.push(pathConstraint); - - for (ii = 0; ii < boneCount; ii++) - sortReset(constrained[ii].children); - for (ii = 0; ii < boneCount; ii++) - constrained[ii]._sorted = true; - } - - var transformConstraints:Vector. = this.transformConstraints; - for (i = 0, n = transformConstraints.length; i < n; i++) { - var transformConstraint:TransformConstraint = transformConstraints[i]; - - sortBone(transformConstraint.target); - - constrained = transformConstraint.bones; - boneCount = constrained.length; - for (ii = 0; ii < boneCount; ii++) - sortBone(constrained[ii]); - - updateCache.push(transformConstraint); - - for (ii = 0; ii < boneCount; ii++) - sortReset(constrained[ii].children); - for (ii = 0; ii < boneCount; ii++) - constrained[ii]._sorted = true; - } - - for (i = 0, n = bones.length; i < n; i++) - sortBone(bones[i]); - } - - private function sortPathConstraintAttachment (skin:Skin, slotIndex:int, slotBone:Bone) : void { - var dict:Dictionary = skin.attachments[slotIndex]; - if (!dict) return; - - for each (var value:Attachment in dict) { - sortPathConstraintAttachment2(value, slotBone); - } - } - - private function sortPathConstraintAttachment2 (attachment:Attachment, slotBone:Bone) : void { - var pathAttachment:PathAttachment = attachment as PathAttachment; - if (!pathAttachment) return; - var pathBones:Vector. = pathAttachment.bones; - if (pathBones == null) - sortBone(slotBone); - else { - var bones:Vector. = this.bones; - var i:int = 0; - while (i < pathBones.length) { - var boneCount:int = pathBones[i++]; - for (var n:int = i + boneCount; i < n; i++) { - sortBone(bones[pathBones[i]]); - } - } - } - } - - private function sortBone (bone:Bone) : void { - if (bone._sorted) return; - var parent:Bone = bone.parent; - if (parent != null) sortBone(parent); - bone._sorted = true; - _updateCache.push(bone); - } - - private function sortReset (bones:Vector.) : void { - for (var i:int = 0, n:int = bones.length; i < n; i++) { - var bone:Bone = bones[i]; - if (bone._sorted) sortReset(bone.children); - bone._sorted = false; - } - } - - /** Updates the world transform for each bone and applies constraints. */ - public function updateWorldTransform () : void { - for each (var updatable:Updatable in _updateCache) - updatable.update(); - } - - /** Sets the bones, constraints, and slots to their setup pose values. */ - public function setToSetupPose () : void { - setBonesToSetupPose(); - setSlotsToSetupPose(); - } - - /** Sets the bones and constraints to their setup pose values. */ - public function setBonesToSetupPose () : void { - for each (var bone:Bone in bones) - bone.setToSetupPose(); - - for each (var ikConstraint:IkConstraint in ikConstraints) { - ikConstraint.bendDirection = ikConstraint._data.bendDirection; - ikConstraint.mix = ikConstraint._data.mix; - } - - for each (var transformConstraint:TransformConstraint in transformConstraints) { - transformConstraint.rotateMix = transformConstraint._data.rotateMix; - transformConstraint.translateMix = transformConstraint._data.translateMix; - transformConstraint.scaleMix = transformConstraint._data.scaleMix; - transformConstraint.shearMix = transformConstraint._data.shearMix; - } - - for each (var pathConstraint:PathConstraint in pathConstraints) { - pathConstraint.position = pathConstraint._data.position; - pathConstraint.spacing = pathConstraint._data.spacing; - pathConstraint.rotateMix = pathConstraint._data.rotateMix; - pathConstraint.translateMix = pathConstraint._data.translateMix; - } - } - - public function setSlotsToSetupPose () : void { - var i:int = 0; - for each (var slot:Slot in slots) { - drawOrder[i++] = slot; - slot.setToSetupPose(); - } - } - - public function get data () : SkeletonData { - return _data; - } - - public function get getUpdateCache () : Vector. { - return _updateCache; - } - - public function get rootBone () : Bone { - if (bones.length == 0) return null; - return bones[0]; - } - - /** @return May be null. */ - public function findBone (boneName:String) : Bone { - if (boneName == null) - throw new ArgumentError("boneName cannot be null."); - for each (var bone:Bone in bones) - if (bone._data._name == boneName) return bone; - return null; - } - - /** @return -1 if the bone was not found. */ - public function findBoneIndex (boneName:String) : int { - if (boneName == null) - throw new ArgumentError("boneName cannot be null."); - var i:int = 0; - for each (var bone:Bone in bones) { - if (bone._data._name == boneName) return i; - i++; - } - return -1; - } - - /** @return May be null. */ - public function findSlot (slotName:String) : Slot { - if (slotName == null) - throw new ArgumentError("slotName cannot be null."); - for each (var slot:Slot in slots) - if (slot._data._name == slotName) return slot; - return null; - } - - /** @return -1 if the bone was not found. */ - public function findSlotIndex (slotName:String) : int { - if (slotName == null) - throw new ArgumentError("slotName cannot be null."); - var i:int = 0; - for each (var slot:Slot in slots) { - if (slot._data._name == slotName) return i; - i++; - } - return -1; - } - - public function get skin () : Skin { - return _skin; - } - - public function set skinName (skinName:String) : void { - var skin:Skin = data.findSkin(skinName); - if (skin == null) throw new ArgumentError("Skin not found: " + skinName); - this.skin = skin; - } - - /** @return May be null. */ - public function get skinName () : String { - return _skin == null ? null : _skin._name; - } - - /** 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. */ - public function set skin (newSkin:Skin) : void { - if (newSkin) { - if (skin) - newSkin.attachAll(this, skin); - else { - var i:int = 0; - for each (var slot:Slot in slots) { - var name:String = slot._data.attachmentName; - if (name) { - var attachment:Attachment = newSkin.getAttachment(i, name); - if (attachment) slot.attachment = attachment; - } - i++; - } - } - } - _skin = newSkin; - } - - /** @return May be null. */ - public function getAttachmentForSlotName (slotName:String, attachmentName:String) : Attachment { - return getAttachmentForSlotIndex(data.findSlotIndex(slotName), attachmentName); - } - - /** @return May be null. */ - public function getAttachmentForSlotIndex (slotIndex:int, attachmentName:String) : Attachment { - if (attachmentName == null) throw new ArgumentError("attachmentName cannot be null."); - if (skin != null) { - var attachment:Attachment = skin.getAttachment(slotIndex, attachmentName); - if (attachment != null) return attachment; - } - if (data.defaultSkin != null) return data.defaultSkin.getAttachment(slotIndex, attachmentName); - return null; - } - - /** @param attachmentName May be null. */ - public function setAttachment (slotName:String, attachmentName:String) : void { - if (slotName == null) throw new ArgumentError("slotName cannot be null."); - var i:int = 0; - for each (var slot:Slot in slots) { - if (slot._data._name == slotName) { - var attachment:Attachment = null; - if (attachmentName != null) { - attachment = getAttachmentForSlotIndex(i, attachmentName); - if (attachment == null) - throw new ArgumentError("Attachment not found: " + attachmentName + ", for slot: " + slotName); - } - slot.attachment = attachment; - return; - } - i++; - } - throw new ArgumentError("Slot not found: " + slotName); - } - - /** @return May be null. */ - public function findIkConstraint (constraintName:String) : IkConstraint { - if (constraintName == null) throw new ArgumentError("constraintName cannot be null."); - for each (var ikConstraint:IkConstraint in ikConstraints) - if (ikConstraint._data._name == constraintName) return ikConstraint; - return null; - } - - /** @return May be null. */ - public function findTransformConstraint (constraintName:String) : TransformConstraint { - if (constraintName == null) throw new ArgumentError("constraintName cannot be null."); - for each (var transformConstraint:TransformConstraint in transformConstraints) - if (transformConstraint._data._name == constraintName) return transformConstraint; - return null; - } - - /** @return May be null. */ - public function findPathConstraint (constraintName:String) : PathConstraint { - if (constraintName == null) throw new ArgumentError("constraintName cannot be null."); - for each (var pathConstraint:PathConstraint in pathConstraints) - if (pathConstraint._data._name == constraintName) return pathConstraint; - return null; - } - - public function update (delta:Number) : void { - time += delta; - } - - public function toString () : String { - return _data.name != null ? _data.name : super.toString(); - } -} - +package spine { +import flash.utils.Dictionary; +import spine.attachments.PathAttachment; +import spine.attachments.Attachment; + +public class Skeleton { + internal var _data:SkeletonData; + public var bones:Vector.; + public var slots:Vector.; + public var drawOrder:Vector.; + public var ikConstraints:Vector., ikConstraintsSorted:Vector.; + public var transformConstraints:Vector.; + public var pathConstraints:Vector.; + private var _updateCache:Vector. = new Vector.(); + private var _skin:Skin; + public var r:Number = 1, g:Number = 1, b:Number = 1, a:Number = 1; + public var time:Number = 0; + public var flipX:Boolean, flipY:Boolean; + public var x:Number = 0, y:Number = 0; + + public function Skeleton (data:SkeletonData) { + if (data == null) + throw new ArgumentError("data cannot be null."); + _data = data; + + bones = new Vector.(); + for each (var boneData:BoneData in data.bones) { + var bone:Bone; + if (boneData.parent == null) + bone = new Bone(boneData, this, null); + else { + var parent:Bone = bones[boneData.parent.index]; + bone = new Bone(boneData, this, parent); + parent.children.push(bone); + } + bones.push(bone); + } + + slots = new Vector.(); + drawOrder = new Vector.(); + for each (var slotData:SlotData in data.slots) { + bone = bones[slotData.boneData.index]; + var slot:Slot = new Slot(slotData, bone); + slots.push(slot); + drawOrder[drawOrder.length] = slot; + } + + ikConstraints = new Vector.(); + ikConstraintsSorted = new Vector.(); + for each (var ikConstraintData:IkConstraintData in data.ikConstraints) + ikConstraints.push(new IkConstraint(ikConstraintData, this)); + + transformConstraints = new Vector.(); + for each (var transformConstraintData:TransformConstraintData in data.transformConstraints) + transformConstraints.push(new TransformConstraint(transformConstraintData, this)); + + pathConstraints = new Vector.(); + for each (var pathConstraintData:PathConstraintData in data.pathConstraints) + pathConstraints.push(new PathConstraint(pathConstraintData, this)); + + updateCache(); + } + + /** Caches information about bones and constraints. Must be called if bones, constraints, or weighted path attachments are + * added or removed. */ + public function updateCache () : void { + var updateCache:Vector. = this._updateCache; + updateCache.length = 0; + + var bones:Vector. = this.bones; + for (var i:int = 0, n:int = bones.length; i < n; i++) + bones[i]._sorted = false; + + // IK first, lowest hierarchy depth first. + var ikConstraints:Vector. = this.ikConstraintsSorted; + ikConstraints.length = 0; + for each (var c:IkConstraint in this.ikConstraints) + ikConstraints.push(c); + var ikCount:int = ikConstraints.length; + var level:int; + for (i = 0, n = ikCount; i < n; i++) { + var ik:IkConstraint = ikConstraints[i]; + var bone:Bone = ik.bones[0].parent; + for (level = 0; bone != null; level++) + bone = bone.parent; + ik.level = level; + } + var ii:int; + for (i = 1; i < ikCount; i++) { + ik = ikConstraints[i]; + level = ik.level; + for (ii = i - 1; ii >= 0; ii--) { + var other:IkConstraint = ikConstraints[ii]; + if (other.level < level) break; + ikConstraints[ii + 1] = other; + } + ikConstraints[ii + 1] = ik; + } + for (i = 0, n = ikConstraints.length; i < n; i++) { + var ikConstraint:IkConstraint = ikConstraints[i]; + var target:Bone = ikConstraint.target; + sortBone(target); + + var constrained:Vector. = ikConstraint.bones; + var parent:Bone = constrained[0]; + sortBone(parent); + + updateCache.push(ikConstraint); + + sortReset(parent.children); + constrained[constrained.length - 1]._sorted = true; + } + + var pathConstraints:Vector. = this.pathConstraints; + for (i = 0, n = pathConstraints.length; i < n; i++) { + var pathConstraint:PathConstraint = pathConstraints[i]; + + var slot:Slot = pathConstraint.target; + var slotIndex:int = slot.data.index; + var slotBone:Bone = slot.bone; + if (skin != null) sortPathConstraintAttachment(skin, slotIndex, slotBone); + if (_data.defaultSkin != null && _data.defaultSkin != skin) + sortPathConstraintAttachment(_data.defaultSkin, slotIndex, slotBone); + + var nn:int; + for (ii = 0, nn = _data.skins.length; ii < nn; ii++) + sortPathConstraintAttachment(_data.skins[ii], slotIndex, slotBone); + + var attachment:PathAttachment = slot.attachment as PathAttachment; + if (attachment != null) sortPathConstraintAttachment2(attachment, slotBone); + + constrained = pathConstraint.bones; + var boneCount:int = constrained.length; + for (ii = 0; ii < boneCount; ii++) + sortBone(constrained[ii]); + + updateCache.push(pathConstraint); + + for (ii = 0; ii < boneCount; ii++) + sortReset(constrained[ii].children); + for (ii = 0; ii < boneCount; ii++) + constrained[ii]._sorted = true; + } + + var transformConstraints:Vector. = this.transformConstraints; + for (i = 0, n = transformConstraints.length; i < n; i++) { + var transformConstraint:TransformConstraint = transformConstraints[i]; + + sortBone(transformConstraint.target); + + constrained = transformConstraint.bones; + boneCount = constrained.length; + for (ii = 0; ii < boneCount; ii++) + sortBone(constrained[ii]); + + updateCache.push(transformConstraint); + + for (ii = 0; ii < boneCount; ii++) + sortReset(constrained[ii].children); + for (ii = 0; ii < boneCount; ii++) + constrained[ii]._sorted = true; + } + + for (i = 0, n = bones.length; i < n; i++) + sortBone(bones[i]); + } + + private function sortPathConstraintAttachment (skin:Skin, slotIndex:int, slotBone:Bone) : void { + var dict:Dictionary = skin.attachments[slotIndex]; + if (!dict) return; + + for each (var value:Attachment in dict) { + sortPathConstraintAttachment2(value, slotBone); + } + } + + private function sortPathConstraintAttachment2 (attachment:Attachment, slotBone:Bone) : void { + var pathAttachment:PathAttachment = attachment as PathAttachment; + if (!pathAttachment) return; + var pathBones:Vector. = pathAttachment.bones; + if (pathBones == null) + sortBone(slotBone); + else { + var bones:Vector. = this.bones; + var i:int = 0; + while (i < pathBones.length) { + var boneCount:int = pathBones[i++]; + for (var n:int = i + boneCount; i < n; i++) { + sortBone(bones[pathBones[i]]); + } + } + } + } + + private function sortBone (bone:Bone) : void { + if (bone._sorted) return; + var parent:Bone = bone.parent; + if (parent != null) sortBone(parent); + bone._sorted = true; + _updateCache.push(bone); + } + + private function sortReset (bones:Vector.) : void { + for (var i:int = 0, n:int = bones.length; i < n; i++) { + var bone:Bone = bones[i]; + if (bone._sorted) sortReset(bone.children); + bone._sorted = false; + } + } + + /** Updates the world transform for each bone and applies constraints. */ + public function updateWorldTransform () : void { + for each (var updatable:Updatable in _updateCache) + updatable.update(); + } + + /** Sets the bones, constraints, and slots to their setup pose values. */ + public function setToSetupPose () : void { + setBonesToSetupPose(); + setSlotsToSetupPose(); + } + + /** Sets the bones and constraints to their setup pose values. */ + public function setBonesToSetupPose () : void { + for each (var bone:Bone in bones) + bone.setToSetupPose(); + + for each (var ikConstraint:IkConstraint in ikConstraints) { + ikConstraint.bendDirection = ikConstraint._data.bendDirection; + ikConstraint.mix = ikConstraint._data.mix; + } + + for each (var transformConstraint:TransformConstraint in transformConstraints) { + transformConstraint.rotateMix = transformConstraint._data.rotateMix; + transformConstraint.translateMix = transformConstraint._data.translateMix; + transformConstraint.scaleMix = transformConstraint._data.scaleMix; + transformConstraint.shearMix = transformConstraint._data.shearMix; + } + + for each (var pathConstraint:PathConstraint in pathConstraints) { + pathConstraint.position = pathConstraint._data.position; + pathConstraint.spacing = pathConstraint._data.spacing; + pathConstraint.rotateMix = pathConstraint._data.rotateMix; + pathConstraint.translateMix = pathConstraint._data.translateMix; + } + } + + public function setSlotsToSetupPose () : void { + var i:int = 0; + for each (var slot:Slot in slots) { + drawOrder[i++] = slot; + slot.setToSetupPose(); + } + } + + public function get data () : SkeletonData { + return _data; + } + + public function get getUpdateCache () : Vector. { + return _updateCache; + } + + public function get rootBone () : Bone { + if (bones.length == 0) return null; + return bones[0]; + } + + /** @return May be null. */ + public function findBone (boneName:String) : Bone { + if (boneName == null) + throw new ArgumentError("boneName cannot be null."); + for each (var bone:Bone in bones) + if (bone._data._name == boneName) return bone; + return null; + } + + /** @return -1 if the bone was not found. */ + public function findBoneIndex (boneName:String) : int { + if (boneName == null) + throw new ArgumentError("boneName cannot be null."); + var i:int = 0; + for each (var bone:Bone in bones) { + if (bone._data._name == boneName) return i; + i++; + } + return -1; + } + + /** @return May be null. */ + public function findSlot (slotName:String) : Slot { + if (slotName == null) + throw new ArgumentError("slotName cannot be null."); + for each (var slot:Slot in slots) + if (slot._data._name == slotName) return slot; + return null; + } + + /** @return -1 if the bone was not found. */ + public function findSlotIndex (slotName:String) : int { + if (slotName == null) + throw new ArgumentError("slotName cannot be null."); + var i:int = 0; + for each (var slot:Slot in slots) { + if (slot._data._name == slotName) return i; + i++; + } + return -1; + } + + public function get skin () : Skin { + return _skin; + } + + public function set skinName (skinName:String) : void { + var skin:Skin = data.findSkin(skinName); + if (skin == null) throw new ArgumentError("Skin not found: " + skinName); + this.skin = skin; + } + + /** @return May be null. */ + public function get skinName () : String { + return _skin == null ? null : _skin._name; + } + + /** 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. */ + public function set skin (newSkin:Skin) : void { + if (newSkin) { + if (skin) + newSkin.attachAll(this, skin); + else { + var i:int = 0; + for each (var slot:Slot in slots) { + var name:String = slot._data.attachmentName; + if (name) { + var attachment:Attachment = newSkin.getAttachment(i, name); + if (attachment) slot.attachment = attachment; + } + i++; + } + } + } + _skin = newSkin; + } + + /** @return May be null. */ + public function getAttachmentForSlotName (slotName:String, attachmentName:String) : Attachment { + return getAttachmentForSlotIndex(data.findSlotIndex(slotName), attachmentName); + } + + /** @return May be null. */ + public function getAttachmentForSlotIndex (slotIndex:int, attachmentName:String) : Attachment { + if (attachmentName == null) throw new ArgumentError("attachmentName cannot be null."); + if (skin != null) { + var attachment:Attachment = skin.getAttachment(slotIndex, attachmentName); + if (attachment != null) return attachment; + } + if (data.defaultSkin != null) return data.defaultSkin.getAttachment(slotIndex, attachmentName); + return null; + } + + /** @param attachmentName May be null. */ + public function setAttachment (slotName:String, attachmentName:String) : void { + if (slotName == null) throw new ArgumentError("slotName cannot be null."); + var i:int = 0; + for each (var slot:Slot in slots) { + if (slot._data._name == slotName) { + var attachment:Attachment = null; + if (attachmentName != null) { + attachment = getAttachmentForSlotIndex(i, attachmentName); + if (attachment == null) + throw new ArgumentError("Attachment not found: " + attachmentName + ", for slot: " + slotName); + } + slot.attachment = attachment; + return; + } + i++; + } + throw new ArgumentError("Slot not found: " + slotName); + } + + /** @return May be null. */ + public function findIkConstraint (constraintName:String) : IkConstraint { + if (constraintName == null) throw new ArgumentError("constraintName cannot be null."); + for each (var ikConstraint:IkConstraint in ikConstraints) + if (ikConstraint._data._name == constraintName) return ikConstraint; + return null; + } + + /** @return May be null. */ + public function findTransformConstraint (constraintName:String) : TransformConstraint { + if (constraintName == null) throw new ArgumentError("constraintName cannot be null."); + for each (var transformConstraint:TransformConstraint in transformConstraints) + if (transformConstraint._data._name == constraintName) return transformConstraint; + return null; + } + + /** @return May be null. */ + public function findPathConstraint (constraintName:String) : PathConstraint { + if (constraintName == null) throw new ArgumentError("constraintName cannot be null."); + for each (var pathConstraint:PathConstraint in pathConstraints) + if (pathConstraint._data._name == constraintName) return pathConstraint; + return null; + } + + public function update (delta:Number) : void { + time += delta; + } + + public function toString () : String { + return _data.name != null ? _data.name : super.toString(); + } +} + } diff --git a/spine-as3/spine-as3/src/spine/SkeletonBounds.as b/spine-as3/spine-as3/src/spine/SkeletonBounds.as index 0999131f06..08ece2d813 100644 --- a/spine-as3/spine-as3/src/spine/SkeletonBounds.as +++ b/spine-as3/spine-as3/src/spine/SkeletonBounds.as @@ -1,153 +1,152 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { -import spine.attachments.BoundingBoxAttachment; - -public class SkeletonBounds { - private var polygonPool:Vector. = new Vector.(); - - public var boundingBoxes:Vector. = new Vector.(); - public var polygons:Vector. = new Vector.(); - public var minX:Number, minY:Number, maxX:Number, maxY:Number; - - public function SkeletonBounds () { - } - - public function update (skeleton:Skeleton, updateAabb:Boolean) : void { - var slots:Vector. = skeleton.slots; - var slotCount:int = slots.length; - - boundingBoxes.length = 0; - for each (var polygon:Polygon in polygons) - polygonPool[polygonPool.length] = polygon; - polygons.length = 0; - - for (var i:int = 0; i < slotCount; i++) { - var slot:Slot = slots[i]; - var boundingBox:BoundingBoxAttachment = slot.attachment as BoundingBoxAttachment; - if (boundingBox == null) continue; - boundingBoxes[boundingBoxes.length] = boundingBox; - - var poolCount:int = polygonPool.length; - if (poolCount > 0) { - polygon = polygonPool[poolCount - 1]; - polygonPool.splice(poolCount - 1, 1); - } else - polygon = new Polygon(); - polygons[polygons.length] = polygon; - - polygon.vertices.length = boundingBox.worldVerticesLength; - boundingBox.computeWorldVertices(slot, polygon.vertices); - } - - if (updateAabb) aabbCompute(); - } - - private function aabbCompute () : void { - var minX:Number = Number.MAX_VALUE, minY:Number = Number.MAX_VALUE; - var maxX:Number = -Number.MAX_VALUE, maxY:Number = -Number.MAX_VALUE; - for (var i:int = 0, n:int = polygons.length; i < n; i++) { - var polygon:Polygon = polygons[i]; - var vertices:Vector. = polygon.vertices; - for (var ii:int = 0, nn:int = vertices.length; ii < nn; ii += 2) { - var x:Number = vertices[ii]; - var y:Number = vertices[ii + 1]; - minX = Math.min(minX, x); - minY = Math.min(minY, y); - maxX = Math.max(maxX, x); - maxY = Math.max(maxY, y); - } - } - this.minX = minX; - this.minY = minY; - this.maxX = maxX; - this.maxY = maxY; - } - - - /** Returns true if the axis aligned bounding box contains the point. */ - public function aabbContainsPoint (x:Number, y:Number) : Boolean { - return x >= minX && x <= maxX && y >= minY && y <= maxY; - } - - /** Returns true if the axis aligned bounding box intersects the line segment. */ - public function aabbIntersectsSegment (x1:Number, y1:Number, x2:Number, y2:Number) : Boolean { - if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) - return false; - var m:Number = (y2 - y1) / (x2 - x1); - var y:Number = m * (minX - x1) + y1; - if (y > minY && y < maxY) return true; - y = m * (maxX - x1) + y1; - if (y > minY && y < maxY) return true; - var x:Number = (minY - y1) / m + x1; - if (x > minX && x < maxX) return true; - x = (maxY - y1) / m + x1; - if (x > minX && x < maxX) return true; - return false; - } - - /** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */ - public function aabbIntersectsSkeleton (bounds:SkeletonBounds) : Boolean { - return minX < bounds.maxX && maxX > bounds.minX && minY < bounds.maxY && maxY > bounds.minY; - } - - /** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more - * efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. */ - public function containsPoint (x:Number, y:Number) : BoundingBoxAttachment { - for (var i:int = 0, n:int = polygons.length; i < n; i++) - if (polygons[i].containsPoint(x, y)) return boundingBoxes[i]; - return null; - } - - /** Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually - * more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns true. */ - public function intersectsSegment (x1:Number, y1:Number, x2:Number, y2:Number) : BoundingBoxAttachment { - for (var i:int = 0, n:int = polygons.length; i < n; i++) - if (polygons[i].intersectsSegment(x1, y1, x2, y2)) return boundingBoxes[i]; - return null; - } - - public function getPolygon (attachment:BoundingBoxAttachment) : Polygon { - var index:int = boundingBoxes.indexOf(attachment); - return index == -1 ? null : polygons[index]; - } - - public function get width () : Number { - return maxX - minX; - } - - public function get height () : Number { - return maxY - minY; - } -} - +package spine { +import spine.attachments.BoundingBoxAttachment; + +public class SkeletonBounds { + private var polygonPool:Vector. = new Vector.(); + + public var boundingBoxes:Vector. = new Vector.(); + public var polygons:Vector. = new Vector.(); + public var minX:Number, minY:Number, maxX:Number, maxY:Number; + + public function SkeletonBounds () { + } + + public function update (skeleton:Skeleton, updateAabb:Boolean) : void { + var slots:Vector. = skeleton.slots; + var slotCount:int = slots.length; + + boundingBoxes.length = 0; + for each (var polygon:Polygon in polygons) + polygonPool[polygonPool.length] = polygon; + polygons.length = 0; + + for (var i:int = 0; i < slotCount; i++) { + var slot:Slot = slots[i]; + var boundingBox:BoundingBoxAttachment = slot.attachment as BoundingBoxAttachment; + if (boundingBox == null) continue; + boundingBoxes[boundingBoxes.length] = boundingBox; + + var poolCount:int = polygonPool.length; + if (poolCount > 0) { + polygon = polygonPool[poolCount - 1]; + polygonPool.splice(poolCount - 1, 1); + } else + polygon = new Polygon(); + polygons[polygons.length] = polygon; + + polygon.vertices.length = boundingBox.worldVerticesLength; + boundingBox.computeWorldVertices(slot, polygon.vertices); + } + + if (updateAabb) aabbCompute(); + } + + private function aabbCompute () : void { + var minX:Number = Number.MAX_VALUE, minY:Number = Number.MAX_VALUE; + var maxX:Number = -Number.MAX_VALUE, maxY:Number = -Number.MAX_VALUE; + for (var i:int = 0, n:int = polygons.length; i < n; i++) { + var polygon:Polygon = polygons[i]; + var vertices:Vector. = polygon.vertices; + for (var ii:int = 0, nn:int = vertices.length; ii < nn; ii += 2) { + var x:Number = vertices[ii]; + var y:Number = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } + + + /** Returns true if the axis aligned bounding box contains the point. */ + public function aabbContainsPoint (x:Number, y:Number) : Boolean { + return x >= minX && x <= maxX && y >= minY && y <= maxY; + } + + /** Returns true if the axis aligned bounding box intersects the line segment. */ + public function aabbIntersectsSegment (x1:Number, y1:Number, x2:Number, y2:Number) : Boolean { + if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) + return false; + var m:Number = (y2 - y1) / (x2 - x1); + var y:Number = m * (minX - x1) + y1; + if (y > minY && y < maxY) return true; + y = m * (maxX - x1) + y1; + if (y > minY && y < maxY) return true; + var x:Number = (minY - y1) / m + x1; + if (x > minX && x < maxX) return true; + x = (maxY - y1) / m + x1; + if (x > minX && x < maxX) return true; + return false; + } + + /** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */ + public function aabbIntersectsSkeleton (bounds:SkeletonBounds) : Boolean { + return minX < bounds.maxX && maxX > bounds.minX && minY < bounds.maxY && maxY > bounds.minY; + } + + /** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more + * efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. */ + public function containsPoint (x:Number, y:Number) : BoundingBoxAttachment { + for (var i:int = 0, n:int = polygons.length; i < n; i++) + if (polygons[i].containsPoint(x, y)) return boundingBoxes[i]; + return null; + } + + /** Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually + * more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns true. */ + public function intersectsSegment (x1:Number, y1:Number, x2:Number, y2:Number) : BoundingBoxAttachment { + for (var i:int = 0, n:int = polygons.length; i < n; i++) + if (polygons[i].intersectsSegment(x1, y1, x2, y2)) return boundingBoxes[i]; + return null; + } + + public function getPolygon (attachment:BoundingBoxAttachment) : Polygon { + var index:int = boundingBoxes.indexOf(attachment); + return index == -1 ? null : polygons[index]; + } + + public function get width () : Number { + return maxX - minX; + } + + public function get height () : Number { + return maxY - minY; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/SkeletonData.as b/spine-as3/spine-as3/src/spine/SkeletonData.as index 99a9047de2..a7de051d08 100644 --- a/spine-as3/spine-as3/src/spine/SkeletonData.as +++ b/spine-as3/spine-as3/src/spine/SkeletonData.as @@ -1,181 +1,180 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { -import spine.animation.Animation; - -public class SkeletonData { - /** May be null. */ - public var name:String; - public var bones:Vector. = new Vector.(); // Ordered parents first. - public var slots:Vector. = new Vector.(); // Setup pose draw order. - public var skins:Vector. = new Vector.(); - public var defaultSkin:Skin; - public var events:Vector. = new Vector.(); - public var animations:Vector. = new Vector.(); - public var ikConstraints:Vector. = new Vector.(); - public var transformConstraints:Vector. = new Vector.(); - public var pathConstraints:Vector. = new Vector.(); - public var width:Number, height:Number; - public var version:String, hash:String; - - public function SkeletonData () { - } - - // --- Bones. - - /** @return May be null. */ - public function findBone (boneName:String) : BoneData { - if (boneName == null) throw new ArgumentError("boneName cannot be null."); - for (var i:int = 0, n:int = bones.length; i < n; i++) { - var bone:BoneData = bones[i]; - if (bone._name == boneName) return bone; - } - return null; - } - - /** @return -1 if the bone was not found. */ - public function findBoneIndex (boneName:String) : int { - if (boneName == null) throw new ArgumentError("boneName cannot be null."); - for (var i:int = 0, n:int = bones.length; i < n; i++) - if (bones[i]._name == boneName) return i; - return -1; - } - - // --- Slots. - - /** @return May be null. */ - public function findSlot (slotName:String) : SlotData { - if (slotName == null) throw new ArgumentError("slotName cannot be null."); - for (var i:int = 0, n:int = slots.length; i < n; i++) { - var slot:SlotData = slots[i]; - if (slot._name == slotName) return slot; - } - return null; - } - - /** @return -1 if the bone was not found. */ - public function findSlotIndex (slotName:String) : int { - if (slotName == null) throw new ArgumentError("slotName cannot be null."); - for (var i:int = 0, n:int = slots.length; i < n; i++) - if (slots[i]._name == slotName) return i; - return -1; - } - - // --- Skins. - - /** @return May be null. */ - public function findSkin (skinName:String) : Skin { - if (skinName == null) throw new ArgumentError("skinName cannot be null."); - for each (var skin:Skin in skins) - if (skin._name == skinName) return skin; - return null; - } - - // --- Events. - - /** @return May be null. */ - public function findEvent (eventName:String) : EventData { - if (eventName == null) throw new ArgumentError("eventName cannot be null."); - for each (var eventData:EventData in events) - if (eventData._name == eventName) return eventData; - return null; - } - - // --- Animations. - - /** @return May be null. */ - public function findAnimation (animationName:String) : Animation { - if (animationName == null) throw new ArgumentError("animationName cannot be null."); - for each (var animation:Animation in animations) - if (animation.name == animationName) return animation; - return null; - } - - // --- IK constraints. - - /** @return May be null. */ - public function findIkConstraint (constraintName:String) : IkConstraintData { - if (constraintName == null) throw new ArgumentError("constraintName cannot be null."); - for each (var ikConstraintData:IkConstraintData in ikConstraints) - if (ikConstraintData._name == constraintName) return ikConstraintData; - return null; - } - - // --- Transform constraints. - - /** @return May be null. */ - public function findTransformConstraint (constraintName:String) : TransformConstraintData { - if (constraintName == null) throw new ArgumentError("constraintName cannot be null."); - for each (var transformConstraintData:TransformConstraintData in transformConstraints) - if (transformConstraintData._name == constraintName) return transformConstraintData; - return null; - } - - /** @return -1 if the transform constraint was not found. */ - public function findTransformConstraintIndex (transformConstraintName:String) : int { - if (transformConstraintName == null) throw new ArgumentError("transformConstraintName cannot be null."); - var transformConstraints:Vector. = this.transformConstraints; - for (var i:int = 0, n:int = transformConstraints.length; i < n; i++) - if (transformConstraints[i].name == transformConstraintName) return i; - return -1; - } - - // --- Path constraints. - - /** @return May be null. */ - public function findPathConstraint (constraintName:String) : PathConstraintData { - if (constraintName == null) throw new ArgumentError("constraintName cannot be null."); - var pathConstraints:Vector. = this.pathConstraints; - for (var i:int = 0, n:int = pathConstraints.length; i < n; i++) { - var constraint:PathConstraintData = pathConstraints[i]; - if (constraint.name == constraintName) return constraint; - } - return null; - } - - /** @return -1 if the path constraint was not found. */ - public function findPathConstraintIndex (pathConstraintName:String) : int { - if (pathConstraintName == null) throw new ArgumentError("pathConstraintName cannot be null."); - var pathConstraints:Vector. = this.pathConstraints; - for (var i:int = 0, n:int = pathConstraints.length; i < n; i++) - if (pathConstraints[i].name == pathConstraintName) return i; - return -1; - } - - // --- - - public function toString () : String { - return name != null ? name : super.toString(); - } -} - +package spine { +import spine.animation.Animation; + +public class SkeletonData { + /** May be null. */ + public var name:String; + public var bones:Vector. = new Vector.(); // Ordered parents first. + public var slots:Vector. = new Vector.(); // Setup pose draw order. + public var skins:Vector. = new Vector.(); + public var defaultSkin:Skin; + public var events:Vector. = new Vector.(); + public var animations:Vector. = new Vector.(); + public var ikConstraints:Vector. = new Vector.(); + public var transformConstraints:Vector. = new Vector.(); + public var pathConstraints:Vector. = new Vector.(); + public var width:Number, height:Number; + public var version:String, hash:String; + + public function SkeletonData () { + } + + // --- Bones. + + /** @return May be null. */ + public function findBone (boneName:String) : BoneData { + if (boneName == null) throw new ArgumentError("boneName cannot be null."); + for (var i:int = 0, n:int = bones.length; i < n; i++) { + var bone:BoneData = bones[i]; + if (bone._name == boneName) return bone; + } + return null; + } + + /** @return -1 if the bone was not found. */ + public function findBoneIndex (boneName:String) : int { + if (boneName == null) throw new ArgumentError("boneName cannot be null."); + for (var i:int = 0, n:int = bones.length; i < n; i++) + if (bones[i]._name == boneName) return i; + return -1; + } + + // --- Slots. + + /** @return May be null. */ + public function findSlot (slotName:String) : SlotData { + if (slotName == null) throw new ArgumentError("slotName cannot be null."); + for (var i:int = 0, n:int = slots.length; i < n; i++) { + var slot:SlotData = slots[i]; + if (slot._name == slotName) return slot; + } + return null; + } + + /** @return -1 if the bone was not found. */ + public function findSlotIndex (slotName:String) : int { + if (slotName == null) throw new ArgumentError("slotName cannot be null."); + for (var i:int = 0, n:int = slots.length; i < n; i++) + if (slots[i]._name == slotName) return i; + return -1; + } + + // --- Skins. + + /** @return May be null. */ + public function findSkin (skinName:String) : Skin { + if (skinName == null) throw new ArgumentError("skinName cannot be null."); + for each (var skin:Skin in skins) + if (skin._name == skinName) return skin; + return null; + } + + // --- Events. + + /** @return May be null. */ + public function findEvent (eventName:String) : EventData { + if (eventName == null) throw new ArgumentError("eventName cannot be null."); + for each (var eventData:EventData in events) + if (eventData._name == eventName) return eventData; + return null; + } + + // --- Animations. + + /** @return May be null. */ + public function findAnimation (animationName:String) : Animation { + if (animationName == null) throw new ArgumentError("animationName cannot be null."); + for each (var animation:Animation in animations) + if (animation.name == animationName) return animation; + return null; + } + + // --- IK constraints. + + /** @return May be null. */ + public function findIkConstraint (constraintName:String) : IkConstraintData { + if (constraintName == null) throw new ArgumentError("constraintName cannot be null."); + for each (var ikConstraintData:IkConstraintData in ikConstraints) + if (ikConstraintData._name == constraintName) return ikConstraintData; + return null; + } + + // --- Transform constraints. + + /** @return May be null. */ + public function findTransformConstraint (constraintName:String) : TransformConstraintData { + if (constraintName == null) throw new ArgumentError("constraintName cannot be null."); + for each (var transformConstraintData:TransformConstraintData in transformConstraints) + if (transformConstraintData._name == constraintName) return transformConstraintData; + return null; + } + + /** @return -1 if the transform constraint was not found. */ + public function findTransformConstraintIndex (transformConstraintName:String) : int { + if (transformConstraintName == null) throw new ArgumentError("transformConstraintName cannot be null."); + var transformConstraints:Vector. = this.transformConstraints; + for (var i:int = 0, n:int = transformConstraints.length; i < n; i++) + if (transformConstraints[i].name == transformConstraintName) return i; + return -1; + } + + // --- Path constraints. + + /** @return May be null. */ + public function findPathConstraint (constraintName:String) : PathConstraintData { + if (constraintName == null) throw new ArgumentError("constraintName cannot be null."); + var pathConstraints:Vector. = this.pathConstraints; + for (var i:int = 0, n:int = pathConstraints.length; i < n; i++) { + var constraint:PathConstraintData = pathConstraints[i]; + if (constraint.name == constraintName) return constraint; + } + return null; + } + + /** @return -1 if the path constraint was not found. */ + public function findPathConstraintIndex (pathConstraintName:String) : int { + if (pathConstraintName == null) throw new ArgumentError("pathConstraintName cannot be null."); + var pathConstraints:Vector. = this.pathConstraints; + for (var i:int = 0, n:int = pathConstraints.length; i < n; i++) + if (pathConstraints[i].name == pathConstraintName) return i; + return -1; + } + + // --- + + public function toString () : String { + return name != null ? name : super.toString(); + } +} + } diff --git a/spine-as3/spine-as3/src/spine/SkeletonJson.as b/spine-as3/spine-as3/src/spine/SkeletonJson.as index 0a0b67a82d..6f0a2ba43d 100644 --- a/spine-as3/spine-as3/src/spine/SkeletonJson.as +++ b/spine-as3/spine-as3/src/spine/SkeletonJson.as @@ -1,737 +1,737 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { -import spine.animation.PathConstraintMixTimeline; -import spine.animation.PathConstraintSpacingTimeline; -import spine.animation.PathConstraintPositionTimeline; -import spine.animation.TransformConstraintTimeline; -import spine.animation.ShearTimeline; -import spine.attachments.PathAttachment; -import spine.attachments.VertexAttachment; -import flash.utils.ByteArray; -import spine.animation.Animation; -import spine.animation.AttachmentTimeline; -import spine.animation.ColorTimeline; -import spine.animation.CurveTimeline; -import spine.animation.DrawOrderTimeline; -import spine.animation.EventTimeline; -import spine.animation.DeformTimeline; -import spine.animation.IkConstraintTimeline; -import spine.animation.RotateTimeline; -import spine.animation.ScaleTimeline; -import spine.animation.Timeline; -import spine.animation.TranslateTimeline; -import spine.attachments.Attachment; -import spine.attachments.AttachmentLoader; -import spine.attachments.AttachmentType; -import spine.attachments.BoundingBoxAttachment; -import spine.attachments.MeshAttachment; -import spine.attachments.RegionAttachment; - -public class SkeletonJson { - public var attachmentLoader:AttachmentLoader; - public var scale:Number = 1; - private var linkedMeshes:Vector. = new Vector.(); - - public function SkeletonJson (attachmentLoader:AttachmentLoader = null) { - this.attachmentLoader = attachmentLoader; - } - - /** @param object A String or ByteArray. */ - public function readSkeletonData (object:*, name:String = null) : SkeletonData { - if (object == null) throw new ArgumentError("object cannot be null."); - - var root:Object; - if (object is String) - root = JSON.parse(String(object)); - else if (object is ByteArray) - root = JSON.parse(ByteArray(object).readUTFBytes(ByteArray(object).length)); - else if (object is Object) - root = object; - else - throw new ArgumentError("object must be a String, ByteArray or Object."); - - var skeletonData:SkeletonData = new SkeletonData(); - skeletonData.name = name; - - // Skeleton. - var skeletonMap:Object = root["skeleton"]; - if (skeletonMap) { - skeletonData.hash = skeletonMap["hash"]; - skeletonData.version = skeletonMap["spine"]; - skeletonData.width = skeletonMap["width"] || 0; - skeletonData.height = skeletonMap["height"] || 0; - } - - // Bones. - var boneData:BoneData; - for each (var boneMap:Object in root["bones"]) { - var parent:BoneData = null; - var parentName:String = boneMap["parent"]; - if (parentName) { - parent = skeletonData.findBone(parentName); - if (!parent) throw new Error("Parent bone not found: " + parentName); - } - boneData = new BoneData(skeletonData.bones.length, boneMap["name"], parent); - boneData.length = Number(boneMap["length"] || 0) * scale; - boneData.x = Number(boneMap["x"] || 0) * scale; - boneData.y = Number(boneMap["y"] || 0) * scale; - boneData.rotation = (boneMap["rotation"] || 0); - boneData.scaleX = boneMap.hasOwnProperty("scaleX") ? boneMap["scaleX"] : 1; - boneData.scaleY = boneMap.hasOwnProperty("scaleY") ? boneMap["scaleY"] : 1; - boneData.shearX = Number(boneMap["shearX"] || 0); - boneData.shearY = Number(boneMap["shearY"] || 0); - boneData.inheritRotation = boneMap.hasOwnProperty("inheritRotation") ? Boolean(boneMap["inheritRotation"]) : true; - boneData.inheritScale = boneMap.hasOwnProperty("inheritScale") ? Boolean(boneMap["inheritScale"]) : true; - skeletonData.bones.push(boneData); - } - - // Slots. - for each (var slotMap:Object in root["slots"]) { - var slotName:String = slotMap["name"]; - var boneName:String = slotMap["bone"]; - boneData = skeletonData.findBone(boneName); - if (!boneData) throw new Error("Slot bone not found: " + boneName); - var slotData:SlotData = new SlotData(skeletonData.slots.length, slotName, boneData); - - var color:String = slotMap["color"]; - if (color) { - slotData.r = toColor(color, 0); - slotData.g = toColor(color, 1); - slotData.b = toColor(color, 2); - slotData.a = toColor(color, 3); - } - - slotData.attachmentName = slotMap["attachment"]; - slotData.blendMode = BlendMode[slotMap["blend"] || "normal"]; - skeletonData.slots.push(slotData); - } - - // IK constraints. - for each (var constraintMap:Object in root["ik"]) { - var ikConstraintData:IkConstraintData = new IkConstraintData(constraintMap["name"]); - - for each (boneName in constraintMap["bones"]) { - var bone:BoneData = skeletonData.findBone(boneName); - if (!bone) throw new Error("IK constraint bone not found: " + boneName); - ikConstraintData.bones.push(bone); - } - - ikConstraintData.target = skeletonData.findBone(constraintMap["target"]); - if (!ikConstraintData.target) throw new Error("Target bone not found: " + constraintMap["target"]); - - ikConstraintData.bendDirection = (!constraintMap.hasOwnProperty("bendPositive") || constraintMap["bendPositive"]) ? 1 : -1; - ikConstraintData.mix = constraintMap.hasOwnProperty("mix") ? constraintMap["mix"] : 1; - - skeletonData.ikConstraints.push(ikConstraintData); - } - - // Transform constraints. - for each (constraintMap in root["transform"]) { - var transformConstraintData:TransformConstraintData = new TransformConstraintData(constraintMap["name"]); - - for each (boneName in constraintMap["bones"]) { - bone = skeletonData.findBone(boneName); - if (!bone) throw new Error("Transform constraint bone not found: " + boneName); - transformConstraintData.bones.push(bone); - } - - transformConstraintData.target = skeletonData.findBone(constraintMap["target"]); - if (!transformConstraintData.target) throw new Error("Target bone not found: " + constraintMap["target"]); - - transformConstraintData.offsetRotation = Number(constraintMap["rotation"] || 0); - transformConstraintData.offsetX = Number(constraintMap["x"] || 0) * scale; - transformConstraintData.offsetY = Number(constraintMap["y"] || 0) * scale; - transformConstraintData.offsetScaleX = Number(constraintMap["scaleX"] || 0); - transformConstraintData.offsetScaleY = Number(constraintMap["scaleY"] || 0); - transformConstraintData.offsetShearY = Number(constraintMap["shearY"] || 0); - - transformConstraintData.rotateMix = constraintMap.hasOwnProperty("rotateMix") ? constraintMap["rotateMix"] : 1; - transformConstraintData.translateMix = constraintMap.hasOwnProperty("translateMix") ? constraintMap["translateMix"] : 1; - transformConstraintData.scaleMix = constraintMap.hasOwnProperty("scaleMix") ? constraintMap["scaleMix"] : 1; - transformConstraintData.shearMix = constraintMap.hasOwnProperty("shearMix") ? constraintMap["shearMix"] : 1; - - skeletonData.transformConstraints.push(transformConstraintData); - } - - // Path constraints. - for each (constraintMap in root["path"]) { - var pathConstraintData:PathConstraintData = new PathConstraintData(constraintMap["name"]); - - for each (boneName in constraintMap["bones"]) { - bone = skeletonData.findBone(boneName); - if (!bone) throw new Error("Path constraint bone not found: " + boneName); - pathConstraintData.bones.push(bone); - } - - pathConstraintData.target = skeletonData.findSlot(constraintMap["target"]); - if (!pathConstraintData.target) throw new Error("Path target slot not found: " + constraintMap["target"]); - - pathConstraintData.positionMode = PositionMode[constraintMap["positionMode"] || "percent"]; - pathConstraintData.spacingMode = SpacingMode[constraintMap["spacingMode"] || "length"]; - pathConstraintData.rotateMode = RotateMode[constraintMap["rotateMode"] || "tangent"]; - pathConstraintData.offsetRotation = Number(constraintMap["rotation"] || 0); - pathConstraintData.position = Number(constraintMap["position"] || 0); - if (pathConstraintData.positionMode == PositionMode.fixed) pathConstraintData.position *= scale; - pathConstraintData.spacing = Number(constraintMap["spacing"] || 0); - if (pathConstraintData.spacingMode == SpacingMode.length || pathConstraintData.spacingMode == SpacingMode.fixed) pathConstraintData.spacing *= scale; - pathConstraintData.rotateMix = constraintMap.hasOwnProperty("rotateMix") ? constraintMap["rotateMix"] : 1; - pathConstraintData.translateMix = constraintMap.hasOwnProperty("translateMix") ? constraintMap["translateMix"] : 1; - - skeletonData.pathConstraints.push(pathConstraintData); - } - - // Skins. - var skins:Object = root["skins"]; - for (var skinName:String in skins) { - var skinMap:Object = skins[skinName]; - var skin:Skin = new Skin(skinName); - for (slotName in skinMap) { - var slotIndex:int = skeletonData.findSlotIndex(slotName); - var slotEntry:Object = skinMap[slotName]; - for (var attachmentName:String in slotEntry) { - var attachment:Attachment = readAttachment(slotEntry[attachmentName], skin, slotIndex, attachmentName); - if (attachment != null) - skin.addAttachment(slotIndex, attachmentName, attachment); - } - } - skeletonData.skins[skeletonData.skins.length] = skin; - if (skin.name == "default") - skeletonData.defaultSkin = skin; - } - - // Linked meshes. - var linkedMeshes:Vector. = this.linkedMeshes; - for each (var linkedMesh:LinkedMesh in linkedMeshes) { - var parentSkin:Skin = !linkedMesh.skin ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin); - if (!parentSkin) throw new Error("Skin not found: " + linkedMesh.skin); - var parentMesh:Attachment = parentSkin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); - if (!parentMesh) throw new Error("Parent mesh not found: " + linkedMesh.parent); - linkedMesh.mesh.parentMesh = MeshAttachment(parentMesh); - linkedMesh.mesh.updateUVs(); - } - linkedMeshes.length = 0; - - // Events. - var events:Object = root["events"]; - if (events) { - for (var eventName:String in events) { - var eventMap:Object = events[eventName]; - var eventData:EventData = new EventData(eventName); - eventData.intValue = eventMap["int"] || 0; - eventData.floatValue = eventMap["float"] || 0; - eventData.stringValue = eventMap["string"] || null; - skeletonData.events.push(eventData); - } - } - - // Animations. - var animations:Object = root["animations"]; - for (var animationName:String in animations) - readAnimation(animations[animationName], animationName, skeletonData); - - return skeletonData; - } - - private function readAttachment (map:Object, skin:Skin, slotIndex:int, name:String) : Attachment { - name = map["name"] || name; - - var typeName:String = map["type"] || "region"; - var type:AttachmentType = AttachmentType[typeName]; - - var scale:Number = this.scale; - var color:String; - switch (type) { - case AttachmentType.region: - var region:RegionAttachment = attachmentLoader.newRegionAttachment(skin, name, map["path"] || name); - if (!region) return null; - region.path = map["path"] || name; - region.x = Number(map["x"] || 0) * scale; - region.y = Number(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; - region.width = Number(map["width"] || 0) * scale; - region.height = Number(map["height"] || 0) * scale; - color = map["color"]; - if (color) { - region.r = toColor(color, 0); - region.g = toColor(color, 1); - region.b = toColor(color, 2); - region.a = toColor(color, 3); - } - region.updateOffset(); - return region; - case AttachmentType.mesh: - case AttachmentType.linkedmesh: - var mesh:MeshAttachment = attachmentLoader.newMeshAttachment(skin, name, map["path"] || name); - if (!mesh) return null; - mesh.path = map["path"] || name; - - color = map["color"]; - if (color) { - mesh.r = toColor(color, 0); - mesh.g = toColor(color, 1); - mesh.b = toColor(color, 2); - mesh.a = toColor(color, 3); - } - - mesh.width = Number(map["width"] || 0) * scale; - mesh.height = Number(map["height"] || 0) * scale; - - if (map["parent"]) { - mesh.inheritDeform = map.hasOwnProperty("deform") ? Boolean(map["deform"]) : true; - linkedMeshes.push(new LinkedMesh(mesh, map["skin"], slotIndex, map["parent"])); - return mesh; - } - - var uvs:Vector. = getFloatArray(map, "uvs", 1); - readVertices(map, mesh, uvs.length); - mesh.triangles = getUintArray(map, "triangles"); - mesh.regionUVs = uvs; - mesh.updateUVs(); - - mesh.hullLength = int(map["hull"] || 0) * 2; - if (map["edges"]) mesh.edges = getIntArray(map, "edges"); - return mesh; - case AttachmentType.boundingbox: - var box:BoundingBoxAttachment = attachmentLoader.newBoundingBoxAttachment(skin, name); - if (!box) return null; - readVertices(map, box, int(map["vertexCount"]) << 1); - return box; - case AttachmentType.path: - var path:PathAttachment = attachmentLoader.newPathAttachment(skin, name); - if (!path) return null; - path.closed = map.hasOwnProperty("closed") ? Boolean(map["closed"]) : false; - path.constantSpeed = map.hasOwnProperty("constantSpeed") ? Boolean(map["constantSpeed"]) : true; - - var vertexCount:int = int(map["vertexCount"]); - readVertices(map, path, vertexCount << 1); - - var lengths:Vector. = new Vector.(); - for each (var curves:Object in map["lengths"]) { - lengths.push(Number(curves) * scale); - } - path.lengths = lengths; - return path; - } - - return null; - } - - private function readVertices(map:Object, attachment:VertexAttachment, verticesLength:int) : void { - attachment.worldVerticesLength = verticesLength; - var vertices:Vector. = getFloatArray(map, "vertices", 1); - if (verticesLength == vertices.length) { - if (scale != 1) { - for (var i:int = 0, n:int = vertices.length; i < n; i++) { - vertices[i] *= scale; - } - } - attachment.vertices = vertices; - return; - } - - var weights:Vector. = new Vector.(verticesLength * 3 * 3); - weights.length = 0; - var bones:Vector. = new Vector.(verticesLength * 3); - bones.length = 0; - for (i = 0, n = vertices.length; i < n;) { - var boneCount:int = int(vertices[i++]); - bones.push(boneCount); - for (var nn:int = i + boneCount * 4; i < nn; i+=4) { - bones.push(int(vertices[i])); - weights.push(vertices[i + 1] * scale); - weights.push(vertices[i + 2] * scale); - weights.push(vertices[i + 3]); - } - } - attachment.bones = bones; - attachment.vertices = weights; - } - - private function readAnimation (map:Object, name:String, skeletonData:SkeletonData) : void { - var scale:Number = this.scale; - var timelines:Vector. = new Vector.(); - var duration:Number = 0; - - var slotMap:Object, slotIndex:int, slotName:String; - var values:Array, valueMap:Object, frameIndex:int; - var i:int; - var timelineName:String; - - var slots:Object = map["slots"]; - for (slotName in slots) { - slotMap = slots[slotName]; - slotIndex = skeletonData.findSlotIndex(slotName); - - for (timelineName in slotMap) { - values = slotMap[timelineName]; - if (timelineName == "color") { - var colorTimeline:ColorTimeline = new ColorTimeline(values.length); - colorTimeline.slotIndex = slotIndex; - - frameIndex = 0; - for each (valueMap in values) { - var color:String = valueMap["color"]; - var r:Number = toColor(color, 0); - var g:Number = toColor(color, 1); - var b:Number = toColor(color, 2); - var a:Number = toColor(color, 3); - colorTimeline.setFrame(frameIndex, valueMap["time"], r, g, b, a); - readCurve(valueMap, colorTimeline, frameIndex); - frameIndex++; - } - timelines[timelines.length] = colorTimeline; - duration = Math.max(duration, colorTimeline.frames[(colorTimeline.frameCount - 1) * ColorTimeline.ENTRIES]); - } else if (timelineName == "attachment") { - var attachmentTimeline:AttachmentTimeline = new AttachmentTimeline(values.length); - attachmentTimeline.slotIndex = slotIndex; - - frameIndex = 0; - for each (valueMap in values) - attachmentTimeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); - timelines[timelines.length] = attachmentTimeline; - duration = Math.max(duration, attachmentTimeline.frames[attachmentTimeline.frameCount - 1]); - } else - throw new Error("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"); - } - } - - var bones:Object = map["bones"]; - for (var boneName:String in bones) { - var boneIndex:int = skeletonData.findBoneIndex(boneName); - if (boneIndex == -1) throw new Error("Bone not found: " + boneName); - var boneMap:Object = bones[boneName]; - - for (timelineName in boneMap) { - values = boneMap[timelineName]; - if (timelineName == "rotate") { - var rotateTimeline:RotateTimeline = new RotateTimeline(values.length); - rotateTimeline.boneIndex = boneIndex; - - frameIndex = 0; - for each (valueMap in values) { - rotateTimeline.setFrame(frameIndex, valueMap["time"], valueMap["angle"]); - readCurve(valueMap, rotateTimeline, frameIndex); - frameIndex++; - } - timelines[timelines.length] = rotateTimeline; - duration = Math.max(duration, rotateTimeline.frames[(rotateTimeline.frameCount - 1) * RotateTimeline.ENTRIES]); - } else if (timelineName == "translate" || timelineName == "scale" || timelineName == "shear") { - var translateTimeline:TranslateTimeline; - var timelineScale:Number = 1; - if (timelineName == "scale") - translateTimeline = new ScaleTimeline(values.length); - else if (timelineName == "shear") - translateTimeline = new ShearTimeline(values.length); - else { - translateTimeline = new TranslateTimeline(values.length); - timelineScale = scale; - } - translateTimeline.boneIndex = boneIndex; - - frameIndex = 0; - for each (valueMap in values) { - var x:Number = Number(valueMap["x"] || 0) * timelineScale; - var y:Number = Number(valueMap["y"] || 0) * timelineScale; - translateTimeline.setFrame(frameIndex, valueMap["time"], x, y); - readCurve(valueMap, translateTimeline, frameIndex); - frameIndex++; - } - timelines[timelines.length] = translateTimeline; - duration = Math.max(duration, translateTimeline.frames[(translateTimeline.frameCount - 1) * TranslateTimeline.ENTRIES]); - } else - throw new Error("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"); - } - } - - var ikMap:Object = map["ik"]; - for (var ikConstraintName:String in ikMap) { - var ikConstraint:IkConstraintData = skeletonData.findIkConstraint(ikConstraintName); - values = ikMap[ikConstraintName]; - var ikTimeline:IkConstraintTimeline = new IkConstraintTimeline(values.length); - ikTimeline.ikConstraintIndex = skeletonData.ikConstraints.indexOf(ikConstraint); - frameIndex = 0; - for each (valueMap in values) { - var mix:Number = valueMap.hasOwnProperty("mix") ? valueMap["mix"] : 1; - var bendDirection:int = (!valueMap.hasOwnProperty("bendPositive") || valueMap["bendPositive"]) ? 1 : -1; - ikTimeline.setFrame(frameIndex, valueMap["time"], mix, bendDirection); - readCurve(valueMap, ikTimeline, frameIndex); - frameIndex++; - } - timelines[timelines.length] = ikTimeline; - duration = Math.max(duration, ikTimeline.frames[(ikTimeline.frameCount - 1) * IkConstraintTimeline.ENTRIES]); - } - - var transformMap:Object = map["transform"]; - for (var transformName:String in transformMap) { - var transformConstraint:TransformConstraintData = skeletonData.findTransformConstraint(transformName); - values = transformMap[transformName]; - var transformTimeline:TransformConstraintTimeline = new TransformConstraintTimeline(values.length); - transformTimeline.transformConstraintIndex = skeletonData.transformConstraints.indexOf(transformConstraint); - frameIndex = 0; - for each (valueMap in values) { - var rotateMix:Number = valueMap.hasOwnProperty("rotateMix") ? valueMap["rotateMix"] : 1; - var translateMix:Number = valueMap.hasOwnProperty("translateMix") ? valueMap["translateMix"] : 1; - var scaleMix:Number = valueMap.hasOwnProperty("scaleMix") ? valueMap["scaleMix"] : 1; - var shearMix:Number = valueMap.hasOwnProperty("shearMix") ? valueMap["shearMix"] : 1; - transformTimeline.setFrame(frameIndex, valueMap["time"], rotateMix, translateMix, scaleMix, shearMix); - readCurve(valueMap, transformTimeline, frameIndex); - frameIndex++; - } - timelines.push(transformTimeline); - duration = Math.max(duration, transformTimeline.frames[(transformTimeline.frameCount - 1) * TransformConstraintTimeline.ENTRIES]); - } - - // Path constraint timelines. - var paths:Object = map["paths"]; - for (var pathName:String in paths) { - var index:int = skeletonData.findPathConstraintIndex(pathName); - if (index == -1) throw new Error("Path constraint not found: " + pathName); - var data:PathConstraintData = skeletonData.pathConstraints[index]; - - var pathMap:Object = paths[pathName]; - for (timelineName in pathMap) { - values = pathMap[timelineName]; - - if (timelineName == "position" || timelineName == "spacing") { - var pathTimeline:PathConstraintPositionTimeline; - timelineScale = 1; - if (timelineName == "spacing") { - pathTimeline = new PathConstraintSpacingTimeline(values.length); - if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) timelineScale = scale; - } else { - pathTimeline = new PathConstraintPositionTimeline(values.length); - if (data.positionMode == PositionMode.fixed) timelineScale = scale; - } - pathTimeline.pathConstraintIndex = index; - frameIndex = 0; - for each (valueMap in values) { - var value:Number = valueMap[timelineName] || 0; - pathTimeline.setFrame(frameIndex, valueMap["time"], value * timelineScale); - readCurve(valueMap, pathTimeline, frameIndex); - frameIndex++; - } - timelines.push(pathTimeline); - duration = Math.max(duration, - pathTimeline.frames[(pathTimeline.frameCount - 1) * PathConstraintPositionTimeline.ENTRIES]); - } else if (timelineName == "mix") { - var pathMixTimeline:PathConstraintMixTimeline = new PathConstraintMixTimeline(values.length); - pathMixTimeline.pathConstraintIndex = index; - frameIndex = 0; - for each (valueMap in values) { - rotateMix = valueMap.hasOwnProperty("rotateMix") ? valueMap["rotateMix"] : 1; - translateMix = valueMap.hasOwnProperty("translateMix") ? valueMap["translateMix"] : 1; - pathMixTimeline.setFrame(frameIndex, valueMap["time"], rotateMix, translateMix); - readCurve(valueMap, pathMixTimeline, frameIndex); - frameIndex++; - } - timelines.push(pathMixTimeline); - duration = Math.max(duration, - pathMixTimeline.frames[(pathMixTimeline.frameCount - 1) * PathConstraintMixTimeline.ENTRIES]); - } - } - } - - var deformMap:Object = map["deform"]; - for (var skinName:String in deformMap) { - var skin:Skin = skeletonData.findSkin(skinName); - slotMap = deformMap[skinName]; - for (slotName in slotMap) { - slotIndex = skeletonData.findSlotIndex(slotName); - var timelineMap:Object = slotMap[slotName]; - for (timelineName in timelineMap) { - values = timelineMap[timelineName]; - - var attachment:VertexAttachment = skin.getAttachment(slotIndex, timelineName) as VertexAttachment; - if (attachment == null) throw new Error("Deform attachment not found: " + timelineName); - var weighted:Boolean = attachment.bones != null; - var vertices:Vector. = attachment.vertices; - var deformLength:int = weighted ? vertices.length / 3 * 2 : vertices.length; - - var deformTimeline:DeformTimeline = new DeformTimeline(values.length); - deformTimeline.slotIndex = slotIndex; - deformTimeline.attachment = attachment; - - frameIndex = 0; - for each (valueMap in values) { - var deform:Vector.; - var verticesValue:Object = valueMap["vertices"]; - if (verticesValue == null) - deform = weighted ? new Vector.(deformLength, true) : vertices; - else { - deform = new Vector.(deformLength, true); - var start:int = Number(valueMap["offset"] || 0); - var temp:Vector. = getFloatArray(valueMap, "vertices", 1); - for (i = 0; i < temp.length; i++) { - deform[start + i] = temp[i]; - } - if (scale != 1) { - var n:int; - for (i = start, n = i + temp.length; i < n; i++) - deform[i] *= scale; - } - if (!weighted) { - for (i = 0; i < deformLength; i++) - deform[i] += vertices[i]; - } - } - - deformTimeline.setFrame(frameIndex, valueMap["time"], deform); - readCurve(valueMap, deformTimeline, frameIndex); - frameIndex++; - } - timelines[timelines.length] = deformTimeline; - duration = Math.max(duration, deformTimeline.frames[deformTimeline.frameCount - 1]); - } - } - } - - var drawOrderValues:Array = map["drawOrder"]; - if (!drawOrderValues) drawOrderValues = map["draworder"]; - if (drawOrderValues) { - var drawOrderTimeline:DrawOrderTimeline = new DrawOrderTimeline(drawOrderValues.length); - var slotCount:int = skeletonData.slots.length; - frameIndex = 0; - for each (var drawOrderMap:Object in drawOrderValues) { - var drawOrder:Vector. = null; - if (drawOrderMap["offsets"]) { - drawOrder = new Vector.(slotCount); - for (i = slotCount - 1; i >= 0; i--) - drawOrder[i] = -1; - var offsets:Array = drawOrderMap["offsets"]; - var unchanged:Vector. = new Vector.(slotCount - offsets.length); - var originalIndex:int = 0, unchangedIndex:int = 0; - for each (var offsetMap:Object in offsets) { - slotIndex = skeletonData.findSlotIndex(offsetMap["slot"]); - if (slotIndex == -1) throw new Error("Slot not found: " + offsetMap["slot"]); - // Collect unchanged items. - while (originalIndex != slotIndex) - unchanged[unchangedIndex++] = originalIndex++; - // Set changed items. - drawOrder[originalIndex + offsetMap["offset"]] = originalIndex++; - } - // Collect remaining unchanged items. - while (originalIndex < slotCount) - unchanged[unchangedIndex++] = originalIndex++; - // Fill in unchanged items. - for (i = slotCount - 1; i >= 0; i--) - if (drawOrder[i] == -1) drawOrder[i] = unchanged[--unchangedIndex]; - } - drawOrderTimeline.setFrame(frameIndex++, drawOrderMap["time"], drawOrder); - } - timelines[timelines.length] = drawOrderTimeline; - duration = Math.max(duration, drawOrderTimeline.frames[drawOrderTimeline.frameCount - 1]); - } - - var eventsMap:Array = map["events"]; - if (eventsMap) { - var eventTimeline:EventTimeline = new EventTimeline(eventsMap.length); - frameIndex = 0; - for each (var eventMap:Object in eventsMap) { - var eventData:EventData = skeletonData.findEvent(eventMap["name"]); - if (!eventData) throw new Error("Event not found: " + eventMap["name"]); - var event:Event = new Event(eventMap["time"], eventData); - event.intValue = eventMap.hasOwnProperty("int") ? eventMap["int"] : eventData.intValue; - event.floatValue = eventMap.hasOwnProperty("float") ? eventMap["float"] : eventData.floatValue; - event.stringValue = eventMap.hasOwnProperty("string") ? eventMap["string"] : eventData.stringValue; - eventTimeline.setFrame(frameIndex++, event); - } - timelines[timelines.length] = eventTimeline; - duration = Math.max(duration, eventTimeline.frames[eventTimeline.frameCount - 1]); - } - - skeletonData.animations[skeletonData.animations.length] = new Animation(name, timelines, duration); - } - - static private function readCurve (map:Object, timeline:CurveTimeline, frameIndex:int) : void { - var curve:Object = map["curve"]; - if (!curve) return; - if (curve == "stepped") - timeline.setStepped(frameIndex); - else if (curve is Array) - timeline.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]); - } - - static private function toColor (hexString:String, colorIndex:int) : Number { - if (hexString.length != 8) throw new ArgumentError("Color hexidecimal length must be 8, recieved: " + hexString); - return parseInt(hexString.substring(colorIndex * 2, colorIndex * 2 + 2), 16) / 255; - } - - static private function getFloatArray (map:Object, name:String, scale:Number) : Vector. { - var list:Array = map[name]; - var values:Vector. = new Vector.(list.length, true); - var i:int = 0, n:int = list.length; - if (scale == 1) { - for (; i < n; i++) - values[i] = list[i]; - } else { - for (; i < n; i++) - values[i] = list[i] * scale; - } - return values; - } - - static private function getIntArray (map:Object, name:String) : Vector. { - var list:Array = map[name]; - var values:Vector. = new Vector.(list.length, true); - for (var i:int = 0, n:int = list.length; i < n; i++) - values[i] = int(list[i]); - return values; - } - - static private function getUintArray (map:Object, name:String) : Vector. { - var list:Array = map[name]; - var values:Vector. = new Vector.(list.length, true); - for (var i:int = 0, n:int = list.length; i < n; i++) - values[i] = int(list[i]); - return values; - } -} - -} - -import spine.attachments.MeshAttachment; - -internal class LinkedMesh { - internal var parent:String, skin:String; - internal var slotIndex:int; - internal var mesh:MeshAttachment; - - public function LinkedMesh (mesh:MeshAttachment, skin:String, slotIndex:int, parent:String) { - this.mesh = mesh; - this.skin = skin; - this.slotIndex = slotIndex; - this.parent = parent; - } +package spine { +import spine.animation.PathConstraintMixTimeline; +import spine.animation.PathConstraintSpacingTimeline; +import spine.animation.PathConstraintPositionTimeline; +import spine.animation.TransformConstraintTimeline; +import spine.animation.ShearTimeline; +import spine.attachments.PathAttachment; +import spine.attachments.VertexAttachment; +import flash.utils.ByteArray; + +import spine.animation.Animation; +import spine.animation.AttachmentTimeline; +import spine.animation.ColorTimeline; +import spine.animation.CurveTimeline; +import spine.animation.DrawOrderTimeline; +import spine.animation.EventTimeline; +import spine.animation.DeformTimeline; +import spine.animation.IkConstraintTimeline; +import spine.animation.RotateTimeline; +import spine.animation.ScaleTimeline; +import spine.animation.Timeline; +import spine.animation.TranslateTimeline; +import spine.attachments.Attachment; +import spine.attachments.AttachmentLoader; +import spine.attachments.AttachmentType; +import spine.attachments.BoundingBoxAttachment; +import spine.attachments.MeshAttachment; +import spine.attachments.RegionAttachment; + +public class SkeletonJson { + public var attachmentLoader:AttachmentLoader; + public var scale:Number = 1; + private var linkedMeshes:Vector. = new Vector.(); + + public function SkeletonJson (attachmentLoader:AttachmentLoader = null) { + this.attachmentLoader = attachmentLoader; + } + + /** @param object A String or ByteArray. */ + public function readSkeletonData (object:*, name:String = null) : SkeletonData { + if (object == null) throw new ArgumentError("object cannot be null."); + + var root:Object; + if (object is String) + root = JSON.parse(String(object)); + else if (object is ByteArray) + root = JSON.parse(ByteArray(object).readUTFBytes(ByteArray(object).length)); + else if (object is Object) + root = object; + else + throw new ArgumentError("object must be a String, ByteArray or Object."); + + var skeletonData:SkeletonData = new SkeletonData(); + skeletonData.name = name; + + // Skeleton. + var skeletonMap:Object = root["skeleton"]; + if (skeletonMap) { + skeletonData.hash = skeletonMap["hash"]; + skeletonData.version = skeletonMap["spine"]; + skeletonData.width = skeletonMap["width"] || 0; + skeletonData.height = skeletonMap["height"] || 0; + } + + // Bones. + var boneData:BoneData; + for each (var boneMap:Object in root["bones"]) { + var parent:BoneData = null; + var parentName:String = boneMap["parent"]; + if (parentName) { + parent = skeletonData.findBone(parentName); + if (!parent) throw new Error("Parent bone not found: " + parentName); + } + boneData = new BoneData(skeletonData.bones.length, boneMap["name"], parent); + boneData.length = Number(boneMap["length"] || 0) * scale; + boneData.x = Number(boneMap["x"] || 0) * scale; + boneData.y = Number(boneMap["y"] || 0) * scale; + boneData.rotation = (boneMap["rotation"] || 0); + boneData.scaleX = boneMap.hasOwnProperty("scaleX") ? boneMap["scaleX"] : 1; + boneData.scaleY = boneMap.hasOwnProperty("scaleY") ? boneMap["scaleY"] : 1; + boneData.shearX = Number(boneMap["shearX"] || 0); + boneData.shearY = Number(boneMap["shearY"] || 0); + boneData.inheritRotation = boneMap.hasOwnProperty("inheritRotation") ? Boolean(boneMap["inheritRotation"]) : true; + boneData.inheritScale = boneMap.hasOwnProperty("inheritScale") ? Boolean(boneMap["inheritScale"]) : true; + skeletonData.bones.push(boneData); + } + + // Slots. + for each (var slotMap:Object in root["slots"]) { + var slotName:String = slotMap["name"]; + var boneName:String = slotMap["bone"]; + boneData = skeletonData.findBone(boneName); + if (!boneData) throw new Error("Slot bone not found: " + boneName); + var slotData:SlotData = new SlotData(skeletonData.slots.length, slotName, boneData); + + var color:String = slotMap["color"]; + if (color) { + slotData.r = toColor(color, 0); + slotData.g = toColor(color, 1); + slotData.b = toColor(color, 2); + slotData.a = toColor(color, 3); + } + + slotData.attachmentName = slotMap["attachment"]; + slotData.blendMode = BlendMode[slotMap["blend"] || "normal"]; + skeletonData.slots.push(slotData); + } + + // IK constraints. + for each (var constraintMap:Object in root["ik"]) { + var ikConstraintData:IkConstraintData = new IkConstraintData(constraintMap["name"]); + + for each (boneName in constraintMap["bones"]) { + var bone:BoneData = skeletonData.findBone(boneName); + if (!bone) throw new Error("IK constraint bone not found: " + boneName); + ikConstraintData.bones.push(bone); + } + + ikConstraintData.target = skeletonData.findBone(constraintMap["target"]); + if (!ikConstraintData.target) throw new Error("Target bone not found: " + constraintMap["target"]); + + ikConstraintData.bendDirection = (!constraintMap.hasOwnProperty("bendPositive") || constraintMap["bendPositive"]) ? 1 : -1; + ikConstraintData.mix = constraintMap.hasOwnProperty("mix") ? constraintMap["mix"] : 1; + + skeletonData.ikConstraints.push(ikConstraintData); + } + + // Transform constraints. + for each (constraintMap in root["transform"]) { + var transformConstraintData:TransformConstraintData = new TransformConstraintData(constraintMap["name"]); + + for each (boneName in constraintMap["bones"]) { + bone = skeletonData.findBone(boneName); + if (!bone) throw new Error("Transform constraint bone not found: " + boneName); + transformConstraintData.bones.push(bone); + } + + transformConstraintData.target = skeletonData.findBone(constraintMap["target"]); + if (!transformConstraintData.target) throw new Error("Target bone not found: " + constraintMap["target"]); + + transformConstraintData.offsetRotation = Number(constraintMap["rotation"] || 0); + transformConstraintData.offsetX = Number(constraintMap["x"] || 0) * scale; + transformConstraintData.offsetY = Number(constraintMap["y"] || 0) * scale; + transformConstraintData.offsetScaleX = Number(constraintMap["scaleX"] || 0); + transformConstraintData.offsetScaleY = Number(constraintMap["scaleY"] || 0); + transformConstraintData.offsetShearY = Number(constraintMap["shearY"] || 0); + + transformConstraintData.rotateMix = constraintMap.hasOwnProperty("rotateMix") ? constraintMap["rotateMix"] : 1; + transformConstraintData.translateMix = constraintMap.hasOwnProperty("translateMix") ? constraintMap["translateMix"] : 1; + transformConstraintData.scaleMix = constraintMap.hasOwnProperty("scaleMix") ? constraintMap["scaleMix"] : 1; + transformConstraintData.shearMix = constraintMap.hasOwnProperty("shearMix") ? constraintMap["shearMix"] : 1; + + skeletonData.transformConstraints.push(transformConstraintData); + } + + // Path constraints. + for each (constraintMap in root["path"]) { + var pathConstraintData:PathConstraintData = new PathConstraintData(constraintMap["name"]); + + for each (boneName in constraintMap["bones"]) { + bone = skeletonData.findBone(boneName); + if (!bone) throw new Error("Path constraint bone not found: " + boneName); + pathConstraintData.bones.push(bone); + } + + pathConstraintData.target = skeletonData.findSlot(constraintMap["target"]); + if (!pathConstraintData.target) throw new Error("Path target slot not found: " + constraintMap["target"]); + + pathConstraintData.positionMode = PositionMode[constraintMap["positionMode"] || "percent"]; + pathConstraintData.spacingMode = SpacingMode[constraintMap["spacingMode"] || "length"]; + pathConstraintData.rotateMode = RotateMode[constraintMap["rotateMode"] || "tangent"]; + pathConstraintData.offsetRotation = Number(constraintMap["rotation"] || 0); + pathConstraintData.position = Number(constraintMap["position"] || 0); + if (pathConstraintData.positionMode == PositionMode.fixed) pathConstraintData.position *= scale; + pathConstraintData.spacing = Number(constraintMap["spacing"] || 0); + if (pathConstraintData.spacingMode == SpacingMode.length || pathConstraintData.spacingMode == SpacingMode.fixed) pathConstraintData.spacing *= scale; + pathConstraintData.rotateMix = constraintMap.hasOwnProperty("rotateMix") ? constraintMap["rotateMix"] : 1; + pathConstraintData.translateMix = constraintMap.hasOwnProperty("translateMix") ? constraintMap["translateMix"] : 1; + + skeletonData.pathConstraints.push(pathConstraintData); + } + + // Skins. + var skins:Object = root["skins"]; + for (var skinName:String in skins) { + var skinMap:Object = skins[skinName]; + var skin:Skin = new Skin(skinName); + for (slotName in skinMap) { + var slotIndex:int = skeletonData.findSlotIndex(slotName); + var slotEntry:Object = skinMap[slotName]; + for (var attachmentName:String in slotEntry) { + var attachment:Attachment = readAttachment(slotEntry[attachmentName], skin, slotIndex, attachmentName); + if (attachment != null) + skin.addAttachment(slotIndex, attachmentName, attachment); + } + } + skeletonData.skins[skeletonData.skins.length] = skin; + if (skin.name == "default") + skeletonData.defaultSkin = skin; + } + + // Linked meshes. + var linkedMeshes:Vector. = this.linkedMeshes; + for each (var linkedMesh:LinkedMesh in linkedMeshes) { + var parentSkin:Skin = !linkedMesh.skin ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin); + if (!parentSkin) throw new Error("Skin not found: " + linkedMesh.skin); + var parentMesh:Attachment = parentSkin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); + if (!parentMesh) throw new Error("Parent mesh not found: " + linkedMesh.parent); + linkedMesh.mesh.parentMesh = MeshAttachment(parentMesh); + linkedMesh.mesh.updateUVs(); + } + linkedMeshes.length = 0; + + // Events. + var events:Object = root["events"]; + if (events) { + for (var eventName:String in events) { + var eventMap:Object = events[eventName]; + var eventData:EventData = new EventData(eventName); + eventData.intValue = eventMap["int"] || 0; + eventData.floatValue = eventMap["float"] || 0; + eventData.stringValue = eventMap["string"] || null; + skeletonData.events.push(eventData); + } + } + + // Animations. + var animations:Object = root["animations"]; + for (var animationName:String in animations) + readAnimation(animations[animationName], animationName, skeletonData); + + return skeletonData; + } + + private function readAttachment (map:Object, skin:Skin, slotIndex:int, name:String) : Attachment { + name = map["name"] || name; + + var typeName:String = map["type"] || "region"; + var type:AttachmentType = AttachmentType[typeName]; + + var scale:Number = this.scale; + var color:String; + switch (type) { + case AttachmentType.region: + var region:RegionAttachment = attachmentLoader.newRegionAttachment(skin, name, map["path"] || name); + if (!region) return null; + region.path = map["path"] || name; + region.x = Number(map["x"] || 0) * scale; + region.y = Number(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; + region.width = Number(map["width"] || 0) * scale; + region.height = Number(map["height"] || 0) * scale; + color = map["color"]; + if (color) { + region.r = toColor(color, 0); + region.g = toColor(color, 1); + region.b = toColor(color, 2); + region.a = toColor(color, 3); + } + region.updateOffset(); + return region; + case AttachmentType.mesh: + case AttachmentType.linkedmesh: + var mesh:MeshAttachment = attachmentLoader.newMeshAttachment(skin, name, map["path"] || name); + if (!mesh) return null; + mesh.path = map["path"] || name; + + color = map["color"]; + if (color) { + mesh.r = toColor(color, 0); + mesh.g = toColor(color, 1); + mesh.b = toColor(color, 2); + mesh.a = toColor(color, 3); + } + + mesh.width = Number(map["width"] || 0) * scale; + mesh.height = Number(map["height"] || 0) * scale; + + if (map["parent"]) { + mesh.inheritDeform = map.hasOwnProperty("deform") ? Boolean(map["deform"]) : true; + linkedMeshes.push(new LinkedMesh(mesh, map["skin"], slotIndex, map["parent"])); + return mesh; + } + + var uvs:Vector. = getFloatArray(map, "uvs", 1); + readVertices(map, mesh, uvs.length); + mesh.triangles = getUintArray(map, "triangles"); + mesh.regionUVs = uvs; + mesh.updateUVs(); + + mesh.hullLength = int(map["hull"] || 0) * 2; + if (map["edges"]) mesh.edges = getIntArray(map, "edges"); + return mesh; + case AttachmentType.boundingbox: + var box:BoundingBoxAttachment = attachmentLoader.newBoundingBoxAttachment(skin, name); + if (!box) return null; + readVertices(map, box, int(map["vertexCount"]) << 1); + return box; + case AttachmentType.path: + var path:PathAttachment = attachmentLoader.newPathAttachment(skin, name); + if (!path) return null; + path.closed = map.hasOwnProperty("closed") ? Boolean(map["closed"]) : false; + path.constantSpeed = map.hasOwnProperty("constantSpeed") ? Boolean(map["constantSpeed"]) : true; + + var vertexCount:int = int(map["vertexCount"]); + readVertices(map, path, vertexCount << 1); + + var lengths:Vector. = new Vector.(); + for each (var curves:Object in map["lengths"]) { + lengths.push(Number(curves) * scale); + } + path.lengths = lengths; + return path; + } + + return null; + } + + private function readVertices(map:Object, attachment:VertexAttachment, verticesLength:int) : void { + attachment.worldVerticesLength = verticesLength; + var vertices:Vector. = getFloatArray(map, "vertices", 1); + if (verticesLength == vertices.length) { + if (scale != 1) { + for (var i:int = 0, n:int = vertices.length; i < n; i++) { + vertices[i] *= scale; + } + } + attachment.vertices = vertices; + return; + } + + var weights:Vector. = new Vector.(verticesLength * 3 * 3); + weights.length = 0; + var bones:Vector. = new Vector.(verticesLength * 3); + bones.length = 0; + for (i = 0, n = vertices.length; i < n;) { + var boneCount:int = int(vertices[i++]); + bones.push(boneCount); + for (var nn:int = i + boneCount * 4; i < nn; i+=4) { + bones.push(int(vertices[i])); + weights.push(vertices[i + 1] * scale); + weights.push(vertices[i + 2] * scale); + weights.push(vertices[i + 3]); + } + } + attachment.bones = bones; + attachment.vertices = weights; + } + + private function readAnimation (map:Object, name:String, skeletonData:SkeletonData) : void { + var scale:Number = this.scale; + var timelines:Vector. = new Vector.(); + var duration:Number = 0; + + var slotMap:Object, slotIndex:int, slotName:String; + var values:Array, valueMap:Object, frameIndex:int; + var i:int; + var timelineName:String; + + var slots:Object = map["slots"]; + for (slotName in slots) { + slotMap = slots[slotName]; + slotIndex = skeletonData.findSlotIndex(slotName); + + for (timelineName in slotMap) { + values = slotMap[timelineName]; + if (timelineName == "color") { + var colorTimeline:ColorTimeline = new ColorTimeline(values.length); + colorTimeline.slotIndex = slotIndex; + + frameIndex = 0; + for each (valueMap in values) { + var color:String = valueMap["color"]; + var r:Number = toColor(color, 0); + var g:Number = toColor(color, 1); + var b:Number = toColor(color, 2); + var a:Number = toColor(color, 3); + colorTimeline.setFrame(frameIndex, valueMap["time"], r, g, b, a); + readCurve(valueMap, colorTimeline, frameIndex); + frameIndex++; + } + timelines[timelines.length] = colorTimeline; + duration = Math.max(duration, colorTimeline.frames[(colorTimeline.frameCount - 1) * ColorTimeline.ENTRIES]); + } else if (timelineName == "attachment") { + var attachmentTimeline:AttachmentTimeline = new AttachmentTimeline(values.length); + attachmentTimeline.slotIndex = slotIndex; + + frameIndex = 0; + for each (valueMap in values) + attachmentTimeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); + timelines[timelines.length] = attachmentTimeline; + duration = Math.max(duration, attachmentTimeline.frames[attachmentTimeline.frameCount - 1]); + } else + throw new Error("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"); + } + } + + var bones:Object = map["bones"]; + for (var boneName:String in bones) { + var boneIndex:int = skeletonData.findBoneIndex(boneName); + if (boneIndex == -1) throw new Error("Bone not found: " + boneName); + var boneMap:Object = bones[boneName]; + + for (timelineName in boneMap) { + values = boneMap[timelineName]; + if (timelineName == "rotate") { + var rotateTimeline:RotateTimeline = new RotateTimeline(values.length); + rotateTimeline.boneIndex = boneIndex; + + frameIndex = 0; + for each (valueMap in values) { + rotateTimeline.setFrame(frameIndex, valueMap["time"], valueMap["angle"]); + readCurve(valueMap, rotateTimeline, frameIndex); + frameIndex++; + } + timelines[timelines.length] = rotateTimeline; + duration = Math.max(duration, rotateTimeline.frames[(rotateTimeline.frameCount - 1) * RotateTimeline.ENTRIES]); + } else if (timelineName == "translate" || timelineName == "scale" || timelineName == "shear") { + var translateTimeline:TranslateTimeline; + var timelineScale:Number = 1; + if (timelineName == "scale") + translateTimeline = new ScaleTimeline(values.length); + else if (timelineName == "shear") + translateTimeline = new ShearTimeline(values.length); + else { + translateTimeline = new TranslateTimeline(values.length); + timelineScale = scale; + } + translateTimeline.boneIndex = boneIndex; + + frameIndex = 0; + for each (valueMap in values) { + var x:Number = Number(valueMap["x"] || 0) * timelineScale; + var y:Number = Number(valueMap["y"] || 0) * timelineScale; + translateTimeline.setFrame(frameIndex, valueMap["time"], x, y); + readCurve(valueMap, translateTimeline, frameIndex); + frameIndex++; + } + timelines[timelines.length] = translateTimeline; + duration = Math.max(duration, translateTimeline.frames[(translateTimeline.frameCount - 1) * TranslateTimeline.ENTRIES]); + } else + throw new Error("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"); + } + } + + var ikMap:Object = map["ik"]; + for (var ikConstraintName:String in ikMap) { + var ikConstraint:IkConstraintData = skeletonData.findIkConstraint(ikConstraintName); + values = ikMap[ikConstraintName]; + var ikTimeline:IkConstraintTimeline = new IkConstraintTimeline(values.length); + ikTimeline.ikConstraintIndex = skeletonData.ikConstraints.indexOf(ikConstraint); + frameIndex = 0; + for each (valueMap in values) { + var mix:Number = valueMap.hasOwnProperty("mix") ? valueMap["mix"] : 1; + var bendDirection:int = (!valueMap.hasOwnProperty("bendPositive") || valueMap["bendPositive"]) ? 1 : -1; + ikTimeline.setFrame(frameIndex, valueMap["time"], mix, bendDirection); + readCurve(valueMap, ikTimeline, frameIndex); + frameIndex++; + } + timelines[timelines.length] = ikTimeline; + duration = Math.max(duration, ikTimeline.frames[(ikTimeline.frameCount - 1) * IkConstraintTimeline.ENTRIES]); + } + + var transformMap:Object = map["transform"]; + for (var transformName:String in transformMap) { + var transformConstraint:TransformConstraintData = skeletonData.findTransformConstraint(transformName); + values = transformMap[transformName]; + var transformTimeline:TransformConstraintTimeline = new TransformConstraintTimeline(values.length); + transformTimeline.transformConstraintIndex = skeletonData.transformConstraints.indexOf(transformConstraint); + frameIndex = 0; + for each (valueMap in values) { + var rotateMix:Number = valueMap.hasOwnProperty("rotateMix") ? valueMap["rotateMix"] : 1; + var translateMix:Number = valueMap.hasOwnProperty("translateMix") ? valueMap["translateMix"] : 1; + var scaleMix:Number = valueMap.hasOwnProperty("scaleMix") ? valueMap["scaleMix"] : 1; + var shearMix:Number = valueMap.hasOwnProperty("shearMix") ? valueMap["shearMix"] : 1; + transformTimeline.setFrame(frameIndex, valueMap["time"], rotateMix, translateMix, scaleMix, shearMix); + readCurve(valueMap, transformTimeline, frameIndex); + frameIndex++; + } + timelines.push(transformTimeline); + duration = Math.max(duration, transformTimeline.frames[(transformTimeline.frameCount - 1) * TransformConstraintTimeline.ENTRIES]); + } + + // Path constraint timelines. + var paths:Object = map["paths"]; + for (var pathName:String in paths) { + var index:int = skeletonData.findPathConstraintIndex(pathName); + if (index == -1) throw new Error("Path constraint not found: " + pathName); + var data:PathConstraintData = skeletonData.pathConstraints[index]; + + var pathMap:Object = paths[pathName]; + for (timelineName in pathMap) { + values = pathMap[timelineName]; + + if (timelineName == "position" || timelineName == "spacing") { + var pathTimeline:PathConstraintPositionTimeline; + timelineScale = 1; + if (timelineName == "spacing") { + pathTimeline = new PathConstraintSpacingTimeline(values.length); + if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) timelineScale = scale; + } else { + pathTimeline = new PathConstraintPositionTimeline(values.length); + if (data.positionMode == PositionMode.fixed) timelineScale = scale; + } + pathTimeline.pathConstraintIndex = index; + frameIndex = 0; + for each (valueMap in values) { + var value:Number = valueMap[timelineName] || 0; + pathTimeline.setFrame(frameIndex, valueMap["time"], value * timelineScale); + readCurve(valueMap, pathTimeline, frameIndex); + frameIndex++; + } + timelines.push(pathTimeline); + duration = Math.max(duration, + pathTimeline.frames[(pathTimeline.frameCount - 1) * PathConstraintPositionTimeline.ENTRIES]); + } else if (timelineName == "mix") { + var pathMixTimeline:PathConstraintMixTimeline = new PathConstraintMixTimeline(values.length); + pathMixTimeline.pathConstraintIndex = index; + frameIndex = 0; + for each (valueMap in values) { + rotateMix = valueMap.hasOwnProperty("rotateMix") ? valueMap["rotateMix"] : 1; + translateMix = valueMap.hasOwnProperty("translateMix") ? valueMap["translateMix"] : 1; + pathMixTimeline.setFrame(frameIndex, valueMap["time"], rotateMix, translateMix); + readCurve(valueMap, pathMixTimeline, frameIndex); + frameIndex++; + } + timelines.push(pathMixTimeline); + duration = Math.max(duration, + pathMixTimeline.frames[(pathMixTimeline.frameCount - 1) * PathConstraintMixTimeline.ENTRIES]); + } + } + } + + var deformMap:Object = map["deform"]; + for (var skinName:String in deformMap) { + var skin:Skin = skeletonData.findSkin(skinName); + slotMap = deformMap[skinName]; + for (slotName in slotMap) { + slotIndex = skeletonData.findSlotIndex(slotName); + var timelineMap:Object = slotMap[slotName]; + for (timelineName in timelineMap) { + values = timelineMap[timelineName]; + + var attachment:VertexAttachment = skin.getAttachment(slotIndex, timelineName) as VertexAttachment; + if (attachment == null) throw new Error("Deform attachment not found: " + timelineName); + var weighted:Boolean = attachment.bones != null; + var vertices:Vector. = attachment.vertices; + var deformLength:int = weighted ? vertices.length / 3 * 2 : vertices.length; + + var deformTimeline:DeformTimeline = new DeformTimeline(values.length); + deformTimeline.slotIndex = slotIndex; + deformTimeline.attachment = attachment; + + frameIndex = 0; + for each (valueMap in values) { + var deform:Vector.; + var verticesValue:Object = valueMap["vertices"]; + if (verticesValue == null) + deform = weighted ? new Vector.(deformLength, true) : vertices; + else { + deform = new Vector.(deformLength, true); + var start:int = Number(valueMap["offset"] || 0); + var temp:Vector. = getFloatArray(valueMap, "vertices", 1); + for (i = 0; i < temp.length; i++) { + deform[start + i] = temp[i]; + } + if (scale != 1) { + var n:int; + for (i = start, n = i + temp.length; i < n; i++) + deform[i] *= scale; + } + if (!weighted) { + for (i = 0; i < deformLength; i++) + deform[i] += vertices[i]; + } + } + + deformTimeline.setFrame(frameIndex, valueMap["time"], deform); + readCurve(valueMap, deformTimeline, frameIndex); + frameIndex++; + } + timelines[timelines.length] = deformTimeline; + duration = Math.max(duration, deformTimeline.frames[deformTimeline.frameCount - 1]); + } + } + } + + var drawOrderValues:Array = map["drawOrder"]; + if (!drawOrderValues) drawOrderValues = map["draworder"]; + if (drawOrderValues) { + var drawOrderTimeline:DrawOrderTimeline = new DrawOrderTimeline(drawOrderValues.length); + var slotCount:int = skeletonData.slots.length; + frameIndex = 0; + for each (var drawOrderMap:Object in drawOrderValues) { + var drawOrder:Vector. = null; + if (drawOrderMap["offsets"]) { + drawOrder = new Vector.(slotCount); + for (i = slotCount - 1; i >= 0; i--) + drawOrder[i] = -1; + var offsets:Array = drawOrderMap["offsets"]; + var unchanged:Vector. = new Vector.(slotCount - offsets.length); + var originalIndex:int = 0, unchangedIndex:int = 0; + for each (var offsetMap:Object in offsets) { + slotIndex = skeletonData.findSlotIndex(offsetMap["slot"]); + if (slotIndex == -1) throw new Error("Slot not found: " + offsetMap["slot"]); + // Collect unchanged items. + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + // Set changed items. + drawOrder[originalIndex + offsetMap["offset"]] = originalIndex++; + } + // Collect remaining unchanged items. + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + // Fill in unchanged items. + for (i = slotCount - 1; i >= 0; i--) + if (drawOrder[i] == -1) drawOrder[i] = unchanged[--unchangedIndex]; + } + drawOrderTimeline.setFrame(frameIndex++, drawOrderMap["time"], drawOrder); + } + timelines[timelines.length] = drawOrderTimeline; + duration = Math.max(duration, drawOrderTimeline.frames[drawOrderTimeline.frameCount - 1]); + } + + var eventsMap:Array = map["events"]; + if (eventsMap) { + var eventTimeline:EventTimeline = new EventTimeline(eventsMap.length); + frameIndex = 0; + for each (var eventMap:Object in eventsMap) { + var eventData:EventData = skeletonData.findEvent(eventMap["name"]); + if (!eventData) throw new Error("Event not found: " + eventMap["name"]); + var event:Event = new Event(eventMap["time"], eventData); + event.intValue = eventMap.hasOwnProperty("int") ? eventMap["int"] : eventData.intValue; + event.floatValue = eventMap.hasOwnProperty("float") ? eventMap["float"] : eventData.floatValue; + event.stringValue = eventMap.hasOwnProperty("string") ? eventMap["string"] : eventData.stringValue; + eventTimeline.setFrame(frameIndex++, event); + } + timelines[timelines.length] = eventTimeline; + duration = Math.max(duration, eventTimeline.frames[eventTimeline.frameCount - 1]); + } + + skeletonData.animations[skeletonData.animations.length] = new Animation(name, timelines, duration); + } + + static private function readCurve (map:Object, timeline:CurveTimeline, frameIndex:int) : void { + var curve:Object = map["curve"]; + if (!curve) return; + if (curve == "stepped") + timeline.setStepped(frameIndex); + else if (curve is Array) + timeline.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]); + } + + static private function toColor (hexString:String, colorIndex:int) : Number { + if (hexString.length != 8) throw new ArgumentError("Color hexidecimal length must be 8, recieved: " + hexString); + return parseInt(hexString.substring(colorIndex * 2, colorIndex * 2 + 2), 16) / 255; + } + + static private function getFloatArray (map:Object, name:String, scale:Number) : Vector. { + var list:Array = map[name]; + var values:Vector. = new Vector.(list.length, true); + var i:int = 0, n:int = list.length; + if (scale == 1) { + for (; i < n; i++) + values[i] = list[i]; + } else { + for (; i < n; i++) + values[i] = list[i] * scale; + } + return values; + } + + static private function getIntArray (map:Object, name:String) : Vector. { + var list:Array = map[name]; + var values:Vector. = new Vector.(list.length, true); + for (var i:int = 0, n:int = list.length; i < n; i++) + values[i] = int(list[i]); + return values; + } + + static private function getUintArray (map:Object, name:String) : Vector. { + var list:Array = map[name]; + var values:Vector. = new Vector.(list.length, true); + for (var i:int = 0, n:int = list.length; i < n; i++) + values[i] = int(list[i]); + return values; + } +} + +} + +import spine.attachments.MeshAttachment; + +internal class LinkedMesh { + internal var parent:String, skin:String; + internal var slotIndex:int; + internal var mesh:MeshAttachment; + + public function LinkedMesh (mesh:MeshAttachment, skin:String, slotIndex:int, parent:String) { + this.mesh = mesh; + this.skin = skin; + this.slotIndex = slotIndex; + this.parent = parent; + } } diff --git a/spine-as3/spine-as3/src/spine/Skin.as b/spine-as3/spine-as3/src/spine/Skin.as index 020b607607..603806a8b6 100644 --- a/spine-as3/spine-as3/src/spine/Skin.as +++ b/spine-as3/spine-as3/src/spine/Skin.as @@ -1,94 +1,93 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { -import flash.utils.Dictionary; - -import spine.attachments.Attachment; - -/** Stores attachments by slot index and attachment name. */ -public class Skin { - internal var _name:String; - private var _attachments:Vector. = new Vector.(); - - public function Skin (name:String) { - if (name == null) throw new ArgumentError("name cannot be null."); - _name = name; - } - - public function addAttachment (slotIndex:int, name:String, attachment:Attachment) : void { - if (attachment == null) throw new ArgumentError("attachment cannot be null."); - if (slotIndex >= attachments.length) attachments.length = slotIndex + 1; - if (!attachments[slotIndex]) attachments[slotIndex] = new Dictionary(); - attachments[slotIndex][name] = attachment; - } - - /** @return May be null. */ - public function getAttachment (slotIndex:int, name:String) : Attachment { - if (slotIndex >= attachments.length) return null; - var dictionary:Dictionary = attachments[slotIndex]; - return dictionary ? dictionary[name] : null; - } - - public function get attachments () : Vector. { - return _attachments; - } - - public function get name () : String { - return _name; - } - - public function toString () : String { - return _name; - } - - /** Attach each attachment in this skin if the corresponding attachment in the old skin is currently attached. */ - public function attachAll (skeleton:Skeleton, oldSkin:Skin) : void { - var slotIndex:int = 0; - for each (var slot:Slot in skeleton.slots) { - var slotAttachment:Attachment = slot.attachment; - if (slotAttachment && slotIndex < oldSkin.attachments.length) { - var dictionary:Dictionary = oldSkin.attachments[slotIndex]; - for (var name:String in dictionary) { - var skinAttachment:Attachment = dictionary[name]; - if (slotAttachment == skinAttachment) { - var attachment:Attachment = getAttachment(slotIndex, name); - if (attachment != null) slot.attachment = attachment; - break; - } - } - } - slotIndex++; - } - } -} - +package spine { +import flash.utils.Dictionary; + +import spine.attachments.Attachment; + +/** Stores attachments by slot index and attachment name. */ +public class Skin { + internal var _name:String; + private var _attachments:Vector. = new Vector.(); + + public function Skin (name:String) { + if (name == null) throw new ArgumentError("name cannot be null."); + _name = name; + } + + public function addAttachment (slotIndex:int, name:String, attachment:Attachment) : void { + if (attachment == null) throw new ArgumentError("attachment cannot be null."); + if (slotIndex >= attachments.length) attachments.length = slotIndex + 1; + if (!attachments[slotIndex]) attachments[slotIndex] = new Dictionary(); + attachments[slotIndex][name] = attachment; + } + + /** @return May be null. */ + public function getAttachment (slotIndex:int, name:String) : Attachment { + if (slotIndex >= attachments.length) return null; + var dictionary:Dictionary = attachments[slotIndex]; + return dictionary ? dictionary[name] : null; + } + + public function get attachments () : Vector. { + return _attachments; + } + + public function get name () : String { + return _name; + } + + public function toString () : String { + return _name; + } + + /** Attach each attachment in this skin if the corresponding attachment in the old skin is currently attached. */ + public function attachAll (skeleton:Skeleton, oldSkin:Skin) : void { + var slotIndex:int = 0; + for each (var slot:Slot in skeleton.slots) { + var slotAttachment:Attachment = slot.attachment; + if (slotAttachment && slotIndex < oldSkin.attachments.length) { + var dictionary:Dictionary = oldSkin.attachments[slotIndex]; + for (var name:String in dictionary) { + var skinAttachment:Attachment = dictionary[name]; + if (slotAttachment == skinAttachment) { + var attachment:Attachment = getAttachment(slotIndex, name); + if (attachment != null) slot.attachment = attachment; + break; + } + } + } + slotIndex++; + } + } +} + } diff --git a/spine-as3/spine-as3/src/spine/Slot.as b/spine-as3/spine-as3/src/spine/Slot.as index d178cb7200..0c90609e90 100644 --- a/spine-as3/spine-as3/src/spine/Slot.as +++ b/spine-as3/spine-as3/src/spine/Slot.as @@ -1,107 +1,106 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { -import spine.attachments.Attachment; - -public class Slot { - internal var _data:SlotData; - internal var _bone:Bone; - public var r:Number; - public var g:Number; - public var b:Number; - public var a:Number; - internal var _attachment:Attachment; - private var _attachmentTime:Number; - public var attachmentVertices:Vector. = new Vector.(); - - public function Slot (data:SlotData, bone:Bone) { - if (data == null) throw new ArgumentError("data cannot be null."); - if (bone == null) throw new ArgumentError("bone cannot be null."); - _data = data; - _bone = bone; - setToSetupPose(); - } - - public function get data () : SlotData { - return _data; - } - - public function get bone () : Bone { - return _bone; - } - - public function get skeleton () : Skeleton { - return _bone._skeleton; - } - - /** @return May be null. */ - public function get attachment () : Attachment { - return _attachment; - } - - /** Sets the attachment and resets {@link #getAttachmentTime()}. - * @param attachment May be null. */ - public function set attachment (attachment:Attachment) : void { - if (_attachment == attachment) return; - _attachment = attachment; - _attachmentTime = _bone._skeleton.time; - attachmentVertices.length = 0; - } - - public function set attachmentTime (time:Number) : void { - _attachmentTime = _bone._skeleton.time - time; - } - - /** Returns the time since the attachment was set. */ - public function get attachmentTime () : Number { - return _bone._skeleton.time - _attachmentTime; - } - - public function setToSetupPose () : void { - r = _data.r; - g = _data.g; - b = _data.b; - a = _data.a; - if (_data.attachmentName == null) - attachment = null; - else { - _attachment = null; - attachment = _bone._skeleton.getAttachmentForSlotIndex(data.index, data.attachmentName); - } - } - - public function toString () : String { - return _data.name; - } -} - +package spine { +import spine.attachments.Attachment; + +public class Slot { + internal var _data:SlotData; + internal var _bone:Bone; + public var r:Number; + public var g:Number; + public var b:Number; + public var a:Number; + internal var _attachment:Attachment; + private var _attachmentTime:Number; + public var attachmentVertices:Vector. = new Vector.(); + + public function Slot (data:SlotData, bone:Bone) { + if (data == null) throw new ArgumentError("data cannot be null."); + if (bone == null) throw new ArgumentError("bone cannot be null."); + _data = data; + _bone = bone; + setToSetupPose(); + } + + public function get data () : SlotData { + return _data; + } + + public function get bone () : Bone { + return _bone; + } + + public function get skeleton () : Skeleton { + return _bone._skeleton; + } + + /** @return May be null. */ + public function get attachment () : Attachment { + return _attachment; + } + + /** Sets the attachment and resets {@link #getAttachmentTime()}. + * @param attachment May be null. */ + public function set attachment (attachment:Attachment) : void { + if (_attachment == attachment) return; + _attachment = attachment; + _attachmentTime = _bone._skeleton.time; + attachmentVertices.length = 0; + } + + public function set attachmentTime (time:Number) : void { + _attachmentTime = _bone._skeleton.time - time; + } + + /** Returns the time since the attachment was set. */ + public function get attachmentTime () : Number { + return _bone._skeleton.time - _attachmentTime; + } + + public function setToSetupPose () : void { + r = _data.r; + g = _data.g; + b = _data.b; + a = _data.a; + if (_data.attachmentName == null) + attachment = null; + else { + _attachment = null; + attachment = _bone._skeleton.getAttachmentForSlotIndex(data.index, data.attachmentName); + } + } + + public function toString () : String { + return _data.name; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/SlotData.as b/spine-as3/spine-as3/src/spine/SlotData.as index e81f59173d..cd0c7c01a5 100644 --- a/spine-as3/spine-as3/src/spine/SlotData.as +++ b/spine-as3/spine-as3/src/spine/SlotData.as @@ -1,71 +1,70 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { - -public class SlotData { - internal var _index:int; - internal var _name:String; - internal var _boneData:BoneData; - public var r:Number = 1; - public var g:Number = 1; - public var b:Number = 1; - public var a:Number = 1; - public var attachmentName:String; - public var blendMode:BlendMode; - - public function SlotData (index:int, name:String, boneData:BoneData) { - if (index < 0) throw new ArgumentError("index must be >= 0."); - if (name == null) throw new ArgumentError("name cannot be null."); - if (boneData == null) throw new ArgumentError("boneData cannot be null."); - _index = index; - _name = name; - _boneData = boneData; - } - - public function get index () : int { - return _index; - } - - public function get name () : String { - return _name; - } - - public function get boneData () : BoneData { - return _boneData; - } - - public function toString () : String { - return _name; - } -} - +package spine { + +public class SlotData { + internal var _index:int; + internal var _name:String; + internal var _boneData:BoneData; + public var r:Number = 1; + public var g:Number = 1; + public var b:Number = 1; + public var a:Number = 1; + public var attachmentName:String; + public var blendMode:BlendMode; + + public function SlotData (index:int, name:String, boneData:BoneData) { + if (index < 0) throw new ArgumentError("index must be >= 0."); + if (name == null) throw new ArgumentError("name cannot be null."); + if (boneData == null) throw new ArgumentError("boneData cannot be null."); + _index = index; + _name = name; + _boneData = boneData; + } + + public function get index () : int { + return _index; + } + + public function get name () : String { + return _name; + } + + public function get boneData () : BoneData { + return _boneData; + } + + public function toString () : String { + return _name; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/SpacingMode.as b/spine-as3/spine-as3/src/spine/SpacingMode.as index df9317e6f1..9d6e90ffab 100644 --- a/spine-as3/spine-as3/src/spine/SpacingMode.as +++ b/spine-as3/spine-as3/src/spine/SpacingMode.as @@ -1,40 +1,39 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { - -public class SpacingMode { - public static const length:SpacingMode = new SpacingMode(); - public static const fixed:SpacingMode = new SpacingMode(); - public static const percent:SpacingMode = new SpacingMode(); +package spine { + +public class SpacingMode { + public static const length:SpacingMode = new SpacingMode(); + public static const fixed:SpacingMode = new SpacingMode(); + public static const percent:SpacingMode = new SpacingMode(); +} + } - -} \ No newline at end of file diff --git a/spine-as3/spine-as3/src/spine/TransformConstraint.as b/spine-as3/spine-as3/src/spine/TransformConstraint.as index b9c16f8a06..4fc4e1fd96 100644 --- a/spine-as3/spine-as3/src/spine/TransformConstraint.as +++ b/spine-as3/spine-as3/src/spine/TransformConstraint.as @@ -1,133 +1,132 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { - -public class TransformConstraint implements Updatable { - internal var _data:TransformConstraintData; - internal var _bones:Vector.; - public var target:Bone; - public var rotateMix:Number; - public var translateMix:Number; - public var scaleMix:Number; - public var shearMix:Number; - internal var _temp:Vector. = new Vector.(2); - - public function TransformConstraint (data:TransformConstraintData, skeleton:Skeleton) { - if (data == null) throw new ArgumentError("data cannot be null."); - if (skeleton == null) throw new ArgumentError("skeleton cannot be null."); - _data = data; - rotateMix = data.rotateMix; - translateMix = data.translateMix; - scaleMix = data.scaleMix; - shearMix = data.shearMix; - _bones = new Vector.(); - for each (var boneData:BoneData in data.bones) - _bones.push(skeleton.findBone(boneData.name)); - target = skeleton.findBone(data.target._name); - } - - public function apply () : void { - update(); - } - - public function update () : void { - var rotateMix:Number = this.rotateMix, translateMix:Number = this.translateMix, scaleMix:Number = this.scaleMix, shearMix:Number = this.shearMix; - var target:Bone = this.target; - var ta:Number = target.a, tb:Number = target.b, tc:Number = target.c, td:Number = target.d; - var bones:Vector. = this._bones; - for (var i:int = 0, n:int = bones.length; i < n; i++) { - var bone:Bone = bones[i]; - - if (rotateMix > 0) { - var a:Number = bone.a, b:Number = bone.b, c:Number = bone.c, d:Number = bone.d; - var r:Number = Math.atan2(tc, ta) - Math.atan2(c, a) + data.offsetRotation * MathUtils.degRad; - if (r > Math.PI) - r -= Math.PI * 2; - else if (r < -Math.PI) r += Math.PI * 2; - r *= rotateMix; - var cos:Number = Math.cos(r), sin:Number = Math.sin(r); - bone._a = cos * a - sin * c; - bone._b = cos * b - sin * d; - bone._c = sin * a + cos * c; - bone._d = sin * b + cos * d; - } - - if (translateMix > 0) { - _temp[0] = data.offsetX; - _temp[1] = data.offsetY; - target.localToWorld(_temp); - bone._worldX += (_temp[0] - bone.worldX) * translateMix; - bone._worldY += (_temp[1] - bone.worldY) * translateMix; - } - - if (scaleMix > 0) { - var bs:Number = Math.sqrt(bone.a * bone.a + bone.c * bone.c); - var ts:Number = Math.sqrt(ta * ta + tc * tc); - var s:Number = bs > 0.00001 ? (bs + (ts - bs + data.offsetScaleX) * scaleMix) / bs : 0; - bone._a *= s; - bone._c *= s; - bs = Math.sqrt(bone.b * bone.b + bone.d * bone.d); - ts = Math.sqrt(tb * tb + td * td); - s = bs > 0.00001 ? (bs + (ts - bs + data.offsetScaleY) * scaleMix) / bs : 0; - bone._b *= s; - bone._d *= s; - } - - if (shearMix > 0) { - b = bone.b, d = bone.d; - var by:Number = Math.atan2(d, b); - r = Math.atan2(td, tb) - Math.atan2(tc, ta) - (by - Math.atan2(bone.c, bone.a)); - if (r > Math.PI) - r -= Math.PI * 2; - else if (r < -Math.PI) r += Math.PI * 2; - r = by + (r + data.offsetShearY * MathUtils.degRad) * shearMix; - s = Math.sqrt(b * b + d * d); - bone._b = Math.cos(r) * s; - bone._d = Math.sin(r) * s; - } - } - } - - public function get data () : TransformConstraintData { - return _data; - } - - public function get bones () : Vector. { - return _bones; - } - - public function toString () : String { - return _data._name; - } -} - +package spine { + +public class TransformConstraint implements Updatable { + internal var _data:TransformConstraintData; + internal var _bones:Vector.; + public var target:Bone; + public var rotateMix:Number; + public var translateMix:Number; + public var scaleMix:Number; + public var shearMix:Number; + internal var _temp:Vector. = new Vector.(2); + + public function TransformConstraint (data:TransformConstraintData, skeleton:Skeleton) { + if (data == null) throw new ArgumentError("data cannot be null."); + if (skeleton == null) throw new ArgumentError("skeleton cannot be null."); + _data = data; + rotateMix = data.rotateMix; + translateMix = data.translateMix; + scaleMix = data.scaleMix; + shearMix = data.shearMix; + _bones = new Vector.(); + for each (var boneData:BoneData in data.bones) + _bones.push(skeleton.findBone(boneData.name)); + target = skeleton.findBone(data.target._name); + } + + public function apply () : void { + update(); + } + + public function update () : void { + var rotateMix:Number = this.rotateMix, translateMix:Number = this.translateMix, scaleMix:Number = this.scaleMix, shearMix:Number = this.shearMix; + var target:Bone = this.target; + var ta:Number = target.a, tb:Number = target.b, tc:Number = target.c, td:Number = target.d; + var bones:Vector. = this._bones; + for (var i:int = 0, n:int = bones.length; i < n; i++) { + var bone:Bone = bones[i]; + + if (rotateMix > 0) { + var a:Number = bone.a, b:Number = bone.b, c:Number = bone.c, d:Number = bone.d; + var r:Number = Math.atan2(tc, ta) - Math.atan2(c, a) + data.offsetRotation * MathUtils.degRad; + if (r > Math.PI) + r -= Math.PI * 2; + else if (r < -Math.PI) r += Math.PI * 2; + r *= rotateMix; + var cos:Number = Math.cos(r), sin:Number = Math.sin(r); + bone._a = cos * a - sin * c; + bone._b = cos * b - sin * d; + bone._c = sin * a + cos * c; + bone._d = sin * b + cos * d; + } + + if (translateMix > 0) { + _temp[0] = data.offsetX; + _temp[1] = data.offsetY; + target.localToWorld(_temp); + bone._worldX += (_temp[0] - bone.worldX) * translateMix; + bone._worldY += (_temp[1] - bone.worldY) * translateMix; + } + + if (scaleMix > 0) { + var bs:Number = Math.sqrt(bone.a * bone.a + bone.c * bone.c); + var ts:Number = Math.sqrt(ta * ta + tc * tc); + var s:Number = bs > 0.00001 ? (bs + (ts - bs + data.offsetScaleX) * scaleMix) / bs : 0; + bone._a *= s; + bone._c *= s; + bs = Math.sqrt(bone.b * bone.b + bone.d * bone.d); + ts = Math.sqrt(tb * tb + td * td); + s = bs > 0.00001 ? (bs + (ts - bs + data.offsetScaleY) * scaleMix) / bs : 0; + bone._b *= s; + bone._d *= s; + } + + if (shearMix > 0) { + b = bone.b, d = bone.d; + var by:Number = Math.atan2(d, b); + r = Math.atan2(td, tb) - Math.atan2(tc, ta) - (by - Math.atan2(bone.c, bone.a)); + if (r > Math.PI) + r -= Math.PI * 2; + else if (r < -Math.PI) r += Math.PI * 2; + r = by + (r + data.offsetShearY * MathUtils.degRad) * shearMix; + s = Math.sqrt(b * b + d * d); + bone._b = Math.cos(r) * s; + bone._d = Math.sin(r) * s; + } + } + } + + public function get data () : TransformConstraintData { + return _data; + } + + public function get bones () : Vector. { + return _bones; + } + + public function toString () : String { + return _data._name; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/TransformConstraintData.as b/spine-as3/spine-as3/src/spine/TransformConstraintData.as index 4fd3b8fa64..3e44e7131f 100644 --- a/spine-as3/spine-as3/src/spine/TransformConstraintData.as +++ b/spine-as3/spine-as3/src/spine/TransformConstraintData.as @@ -1,67 +1,66 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { - -public class TransformConstraintData { - internal var _name:String; - internal var _bones:Vector. = new Vector.(); - public var target:BoneData; - public var rotateMix:Number; - public var translateMix:Number; - public var scaleMix:Number; - public var shearMix:Number; - public var offsetRotation:Number; - public var offsetX:Number; - public var offsetY:Number; - public var offsetScaleX:Number; - public var offsetScaleY:Number; - public var offsetShearY:Number; - - public function TransformConstraintData (name:String) { - if (name == null) throw new ArgumentError("name cannot be null."); - _name = name; - } - - public function get bones () : Vector. {; - return _bones; - } - - public function get name () : String { - return _name; - } - - public function toString () : String { - return _name; - } -} - +package spine { + +public class TransformConstraintData { + internal var _name:String; + internal var _bones:Vector. = new Vector.(); + public var target:BoneData; + public var rotateMix:Number; + public var translateMix:Number; + public var scaleMix:Number; + public var shearMix:Number; + public var offsetRotation:Number; + public var offsetX:Number; + public var offsetY:Number; + public var offsetScaleX:Number; + public var offsetScaleY:Number; + public var offsetShearY:Number; + + public function TransformConstraintData (name:String) { + if (name == null) throw new ArgumentError("name cannot be null."); + _name = name; + } + + public function get bones () : Vector. {; + return _bones; + } + + public function get name () : String { + return _name; + } + + public function toString () : String { + return _name; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/Updatable.as b/spine-as3/spine-as3/src/spine/Updatable.as index f5d49dbe21..30bb195f40 100644 --- a/spine-as3/spine-as3/src/spine/Updatable.as +++ b/spine-as3/spine-as3/src/spine/Updatable.as @@ -1,38 +1,37 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine { - -public interface Updatable { - function update () : void; -} - +package spine { + +public interface Updatable { + function update () : void; +} + } diff --git a/spine-as3/spine-as3/src/spine/animation/Animation.as b/spine-as3/spine-as3/src/spine/animation/Animation.as index 0dcf026f32..f8d70b269a 100644 --- a/spine-as3/spine-as3/src/spine/animation/Animation.as +++ b/spine-as3/spine-as3/src/spine/animation/Animation.as @@ -1,134 +1,133 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { -import spine.Event; -import spine.Skeleton; - -public class Animation { - internal var _name:String; - private var _timelines:Vector.; - public var duration:Number; - - public function Animation (name:String, timelines:Vector., duration:Number) { - if (name == null) throw new ArgumentError("name cannot be null."); - if (timelines == null) throw new ArgumentError("timelines cannot be null."); - _name = name; - _timelines = timelines; - this.duration = duration; - } - - public function get timelines () : Vector. { - return _timelines; - } - - /** Poses the skeleton at the specified time for this animation. */ - public function apply (skeleton:Skeleton, lastTime:Number, time:Number, loop:Boolean, events:Vector.) : void { - if (skeleton == null) throw new ArgumentError("skeleton cannot be null."); - - if (loop && duration != 0) { - time %= duration; - if (lastTime > 0) lastTime %= duration; - } - - for (var i:int = 0, n:int = timelines.length; i < n; i++) - timelines[i].apply(skeleton, lastTime, time, events, 1); - } - - /** Poses the skeleton at the specified time for this animation mixed with the current pose. - * @param alpha The amount of this animation that affects the current pose. */ - public function mix (skeleton:Skeleton, lastTime:Number, time:Number, loop:Boolean, events:Vector., alpha:Number) : void { - if (skeleton == null) throw new ArgumentError("skeleton cannot be null."); - - if (loop && duration != 0) { - time %= duration; - if (lastTime > 0) lastTime %= duration; - } - - for (var i:int = 0, n:int = timelines.length; i < n; i++) - timelines[i].apply(skeleton, lastTime, time, events, alpha); - } - - public function get name () : String { - return _name; - } - - public function toString () : String { - return _name; - } - - /** @param target After the first and before the last entry. */ - static public function binarySearch (values:Vector., target:Number, step:int) : int { - var low:int = 0; - var high:int = values.length / step - 2; - if (high == 0) - return step; - var current:int = high >>> 1; - while (true) { - if (values[int((current + 1) * step)] <= target) - low = current + 1; - else - high = current; - if (low == high) - return (low + 1) * step; - current = (low + high) >>> 1; - } - return 0; // Can't happen. - } - - /** @param target After the first and before the last entry. */ - static public function binarySearch1 (values:Vector., target:Number) : int { - var low:int = 0; - var high:int = values.length - 2; - if (high == 0) - return 1; - var current:int = high >>> 1; - while (true) { - if (values[int(current + 1)] <= target) - low = current + 1; - else - high = current; - if (low == high) - return low + 1; - current = (low + high) >>> 1; - } - return 0; // Can't happen. - } - - static public function linearSearch (values:Vector., target:Number, step:int) : int { - for (var i:int = 0, last:int = values.length - step; i <= last; i += step) - if (values[i] > target) - return i; - return -1; - } -} - +package spine.animation { +import spine.Event; +import spine.Skeleton; + +public class Animation { + internal var _name:String; + private var _timelines:Vector.; + public var duration:Number; + + public function Animation (name:String, timelines:Vector., duration:Number) { + if (name == null) throw new ArgumentError("name cannot be null."); + if (timelines == null) throw new ArgumentError("timelines cannot be null."); + _name = name; + _timelines = timelines; + this.duration = duration; + } + + public function get timelines () : Vector. { + return _timelines; + } + + /** Poses the skeleton at the specified time for this animation. */ + public function apply (skeleton:Skeleton, lastTime:Number, time:Number, loop:Boolean, events:Vector.) : void { + if (skeleton == null) throw new ArgumentError("skeleton cannot be null."); + + if (loop && duration != 0) { + time %= duration; + if (lastTime > 0) lastTime %= duration; + } + + for (var i:int = 0, n:int = timelines.length; i < n; i++) + timelines[i].apply(skeleton, lastTime, time, events, 1); + } + + /** Poses the skeleton at the specified time for this animation mixed with the current pose. + * @param alpha The amount of this animation that affects the current pose. */ + public function mix (skeleton:Skeleton, lastTime:Number, time:Number, loop:Boolean, events:Vector., alpha:Number) : void { + if (skeleton == null) throw new ArgumentError("skeleton cannot be null."); + + if (loop && duration != 0) { + time %= duration; + if (lastTime > 0) lastTime %= duration; + } + + for (var i:int = 0, n:int = timelines.length; i < n; i++) + timelines[i].apply(skeleton, lastTime, time, events, alpha); + } + + public function get name () : String { + return _name; + } + + public function toString () : String { + return _name; + } + + /** @param target After the first and before the last entry. */ + static public function binarySearch (values:Vector., target:Number, step:int) : int { + var low:int = 0; + var high:int = values.length / step - 2; + if (high == 0) + return step; + var current:int = high >>> 1; + while (true) { + if (values[int((current + 1) * step)] <= target) + low = current + 1; + else + high = current; + if (low == high) + return (low + 1) * step; + current = (low + high) >>> 1; + } + return 0; // Can't happen. + } + + /** @param target After the first and before the last entry. */ + static public function binarySearch1 (values:Vector., target:Number) : int { + var low:int = 0; + var high:int = values.length - 2; + if (high == 0) + return 1; + var current:int = high >>> 1; + while (true) { + if (values[int(current + 1)] <= target) + low = current + 1; + else + high = current; + if (low == high) + return low + 1; + current = (low + high) >>> 1; + } + return 0; // Can't happen. + } + + static public function linearSearch (values:Vector., target:Number, step:int) : int { + for (var i:int = 0, last:int = values.length - step; i <= last; i += step) + if (values[i] > target) + return i; + return -1; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/animation/AnimationState.as b/spine-as3/spine-as3/src/spine/animation/AnimationState.as index 420663a182..086f9faa6c 100644 --- a/spine-as3/spine-as3/src/spine/animation/AnimationState.as +++ b/spine-as3/spine-as3/src/spine/animation/AnimationState.as @@ -1,242 +1,241 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { - -import spine.Event; -import spine.Skeleton; - -public class AnimationState { - private var _data:AnimationStateData; - private var _tracks:Vector. = new Vector.(); - private var _events:Vector. = new Vector.(); - public var onStart:Listeners = new Listeners(); - public var onEnd:Listeners = new Listeners(); - public var onComplete:Listeners = new Listeners(); - public var onEvent:Listeners = new Listeners(); - public var timeScale:Number = 1; - - public function AnimationState (data:AnimationStateData) { - if (!data) throw new ArgumentError("data cannot be null."); - _data = data; - } - - public function update (delta:Number) : void { - delta *= timeScale; - for (var i:int = 0; i < _tracks.length; i++) { - var current:TrackEntry = _tracks[i]; - if (!current) continue; - - current.time += delta * current.timeScale; - if (current.previous) { - var previousDelta:Number = delta * current.previous.timeScale; - current.previous.time += previousDelta; - current.mixTime += previousDelta; - } - - var next:TrackEntry = current.next; - if (next) { - next.time = current.lastTime - next.delay; - if (next.time >= 0) setCurrent(i, next); - } else { - // End non-looping animation when it reaches its end time and there is no next entry. - if (!current.loop && current.lastTime >= current.endTime) clearTrack(i); - } - } - } - - public function apply (skeleton:Skeleton) : void { - for (var i:int = 0; i < _tracks.length; i++) { - var current:TrackEntry = _tracks[i]; - if (!current) continue; - - _events.length = 0; - - var time:Number = current.time; - var lastTime:Number = current.lastTime; - var endTime:Number = current.endTime; - var loop:Boolean = current.loop; - if (!loop && time > endTime) time = endTime; - - var previous:TrackEntry = current.previous; - if (!previous) { - if (current.mix == 1) - current.animation.apply(skeleton, current.lastTime, time, loop, _events); - else - current.animation.mix(skeleton, current.lastTime, time, loop, _events, current.mix); - } else { - var previousTime:Number = previous.time; - if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; - previous.animation.apply(skeleton, previousTime, previousTime, previous.loop, null); - - var alpha:Number = current.mixTime / current.mixDuration * current.mix; - if (alpha >= 1) { - alpha = 1; - current.previous = null; - } - current.animation.mix(skeleton, current.lastTime, time, loop, _events, alpha); - } - - for each (var event:Event in _events) { - if (current.onEvent != null) current.onEvent(i, event); - onEvent.invoke(i, event); - } - - // Check if completed the animation or a loop iteration. - if (loop ? (lastTime % endTime > time % endTime) : (lastTime < endTime && time >= endTime)) { - var count:int = (int)(time / endTime); - if (current.onComplete != null) current.onComplete(i, count); - onComplete.invoke(i, count); - } - - current.lastTime = current.time; - } - } - - public function clearTracks () : void { - for (var i:int = 0, n:int = _tracks.length; i < n; i++) - clearTrack(i); - _tracks.length = 0; - } - - public function clearTrack (trackIndex:int) : void { - if (trackIndex >= _tracks.length) return; - var current:TrackEntry = _tracks[trackIndex]; - if (!current) return; - - if (current.onEnd != null) current.onEnd(trackIndex); - onEnd.invoke(trackIndex); - - _tracks[trackIndex] = null; - } - - private function expandToIndex (index:int) : TrackEntry { - if (index < _tracks.length) return _tracks[index]; - while (index >= _tracks.length) - _tracks[_tracks.length] = null; - return null; - } - - private function setCurrent (index:int, entry:TrackEntry) : void { - var current:TrackEntry = expandToIndex(index); - if (current) { - var previous:TrackEntry = current.previous; - current.previous = null; - - if (current.onEnd != null) current.onEnd(index); - onEnd.invoke(index); - - entry.mixDuration = _data.getMix(current.animation, entry.animation); - if (entry.mixDuration > 0) { - entry.mixTime = 0; - // If a mix is in progress, mix from the closest animation. - if (previous != null && current.mixTime / current.mixDuration < 0.5) { - entry.previous = previous; - previous = current; - } else - entry.previous = current; - } - } - - _tracks[index] = entry; - - if (entry.onStart != null) entry.onStart(index); - onStart.invoke(index); - } - - public function setAnimationByName (trackIndex:int, animationName:String, loop:Boolean) : TrackEntry { - var animation:Animation = _data._skeletonData.findAnimation(animationName); - if (!animation) throw new ArgumentError("Animation not found: " + animationName); - return setAnimation(trackIndex, animation, loop); - } - - /** Set the current animation. Any queued animations are cleared. */ - public function setAnimation (trackIndex:int, animation:Animation, loop:Boolean) : TrackEntry { - var entry:TrackEntry = new TrackEntry(); - entry.animation = animation; - entry.loop = loop; - entry.endTime = animation.duration; - setCurrent(trackIndex, entry); - return entry; - } - - public function addAnimationByName (trackIndex:int, animationName:String, loop:Boolean, delay:Number) : TrackEntry { - var animation:Animation = _data._skeletonData.findAnimation(animationName); - if (!animation) throw new ArgumentError("Animation not found: " + animationName); - return addAnimation(trackIndex, animation, loop, delay); - } - - /** Adds an animation to be played delay seconds after the current or last queued animation. - * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */ - public function addAnimation (trackIndex:int, animation:Animation, loop:Boolean, delay:Number) : TrackEntry { - var entry:TrackEntry = new TrackEntry(); - entry.animation = animation; - entry.loop = loop; - entry.endTime = animation.duration; - - var last:TrackEntry = expandToIndex(trackIndex); - if (last) { - while (last.next) - last = last.next; - last.next = entry; - } else - _tracks[trackIndex] = entry; - - if (delay <= 0) { - if (last) - delay += last.endTime - _data.getMix(last.animation, animation); - else - delay = 0; - } - entry.delay = delay; - - return entry; - } - - /** May be null. */ - public function getCurrent (trackIndex:int) : TrackEntry { - if (trackIndex >= _tracks.length) return null; - return _tracks[trackIndex]; - } - - public function toString () : String { - var buffer:String = ""; - for each (var entry:TrackEntry in _tracks) { - if (!entry) continue; - if (buffer.length > 0) buffer += ", "; - buffer += entry.toString(); - } - if (buffer.length == 0) return ""; - return buffer; - } -} - +package spine.animation { + +import spine.Event; +import spine.Skeleton; + +public class AnimationState { + private var _data:AnimationStateData; + private var _tracks:Vector. = new Vector.(); + private var _events:Vector. = new Vector.(); + public var onStart:Listeners = new Listeners(); + public var onEnd:Listeners = new Listeners(); + public var onComplete:Listeners = new Listeners(); + public var onEvent:Listeners = new Listeners(); + public var timeScale:Number = 1; + + public function AnimationState (data:AnimationStateData) { + if (!data) throw new ArgumentError("data cannot be null."); + _data = data; + } + + public function update (delta:Number) : void { + delta *= timeScale; + for (var i:int = 0; i < _tracks.length; i++) { + var current:TrackEntry = _tracks[i]; + if (!current) continue; + + current.time += delta * current.timeScale; + if (current.previous) { + var previousDelta:Number = delta * current.previous.timeScale; + current.previous.time += previousDelta; + current.mixTime += previousDelta; + } + + var next:TrackEntry = current.next; + if (next) { + next.time = current.lastTime - next.delay; + if (next.time >= 0) setCurrent(i, next); + } else { + // End non-looping animation when it reaches its end time and there is no next entry. + if (!current.loop && current.lastTime >= current.endTime) clearTrack(i); + } + } + } + + public function apply (skeleton:Skeleton) : void { + for (var i:int = 0; i < _tracks.length; i++) { + var current:TrackEntry = _tracks[i]; + if (!current) continue; + + _events.length = 0; + + var time:Number = current.time; + var lastTime:Number = current.lastTime; + var endTime:Number = current.endTime; + var loop:Boolean = current.loop; + if (!loop && time > endTime) time = endTime; + + var previous:TrackEntry = current.previous; + if (!previous) { + if (current.mix == 1) + current.animation.apply(skeleton, current.lastTime, time, loop, _events); + else + current.animation.mix(skeleton, current.lastTime, time, loop, _events, current.mix); + } else { + var previousTime:Number = previous.time; + if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; + previous.animation.apply(skeleton, previousTime, previousTime, previous.loop, null); + + var alpha:Number = current.mixTime / current.mixDuration * current.mix; + if (alpha >= 1) { + alpha = 1; + current.previous = null; + } + current.animation.mix(skeleton, current.lastTime, time, loop, _events, alpha); + } + + for each (var event:Event in _events) { + if (current.onEvent != null) current.onEvent(i, event); + onEvent.invoke(i, event); + } + + // Check if completed the animation or a loop iteration. + if (loop ? (lastTime % endTime > time % endTime) : (lastTime < endTime && time >= endTime)) { + var count:int = (int)(time / endTime); + if (current.onComplete != null) current.onComplete(i, count); + onComplete.invoke(i, count); + } + + current.lastTime = current.time; + } + } + + public function clearTracks () : void { + for (var i:int = 0, n:int = _tracks.length; i < n; i++) + clearTrack(i); + _tracks.length = 0; + } + + public function clearTrack (trackIndex:int) : void { + if (trackIndex >= _tracks.length) return; + var current:TrackEntry = _tracks[trackIndex]; + if (!current) return; + + if (current.onEnd != null) current.onEnd(trackIndex); + onEnd.invoke(trackIndex); + + _tracks[trackIndex] = null; + } + + private function expandToIndex (index:int) : TrackEntry { + if (index < _tracks.length) return _tracks[index]; + while (index >= _tracks.length) + _tracks[_tracks.length] = null; + return null; + } + + private function setCurrent (index:int, entry:TrackEntry) : void { + var current:TrackEntry = expandToIndex(index); + if (current) { + var previous:TrackEntry = current.previous; + current.previous = null; + + if (current.onEnd != null) current.onEnd(index); + onEnd.invoke(index); + + entry.mixDuration = _data.getMix(current.animation, entry.animation); + if (entry.mixDuration > 0) { + entry.mixTime = 0; + // If a mix is in progress, mix from the closest animation. + if (previous != null && current.mixTime / current.mixDuration < 0.5) { + entry.previous = previous; + previous = current; + } else + entry.previous = current; + } + } + + _tracks[index] = entry; + + if (entry.onStart != null) entry.onStart(index); + onStart.invoke(index); + } + + public function setAnimationByName (trackIndex:int, animationName:String, loop:Boolean) : TrackEntry { + var animation:Animation = _data._skeletonData.findAnimation(animationName); + if (!animation) throw new ArgumentError("Animation not found: " + animationName); + return setAnimation(trackIndex, animation, loop); + } + + /** Set the current animation. Any queued animations are cleared. */ + public function setAnimation (trackIndex:int, animation:Animation, loop:Boolean) : TrackEntry { + var entry:TrackEntry = new TrackEntry(); + entry.animation = animation; + entry.loop = loop; + entry.endTime = animation.duration; + setCurrent(trackIndex, entry); + return entry; + } + + public function addAnimationByName (trackIndex:int, animationName:String, loop:Boolean, delay:Number) : TrackEntry { + var animation:Animation = _data._skeletonData.findAnimation(animationName); + if (!animation) throw new ArgumentError("Animation not found: " + animationName); + return addAnimation(trackIndex, animation, loop, delay); + } + + /** Adds an animation to be played delay seconds after the current or last queued animation. + * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */ + public function addAnimation (trackIndex:int, animation:Animation, loop:Boolean, delay:Number) : TrackEntry { + var entry:TrackEntry = new TrackEntry(); + entry.animation = animation; + entry.loop = loop; + entry.endTime = animation.duration; + + var last:TrackEntry = expandToIndex(trackIndex); + if (last) { + while (last.next) + last = last.next; + last.next = entry; + } else + _tracks[trackIndex] = entry; + + if (delay <= 0) { + if (last) + delay += last.endTime - _data.getMix(last.animation, animation); + else + delay = 0; + } + entry.delay = delay; + + return entry; + } + + /** May be null. */ + public function getCurrent (trackIndex:int) : TrackEntry { + if (trackIndex >= _tracks.length) return null; + return _tracks[trackIndex]; + } + + public function toString () : String { + var buffer:String = ""; + for each (var entry:TrackEntry in _tracks) { + if (!entry) continue; + if (buffer.length > 0) buffer += ", "; + buffer += entry.toString(); + } + if (buffer.length == 0) return ""; + return buffer; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/animation/AnimationStateData.as b/spine-as3/spine-as3/src/spine/animation/AnimationStateData.as index b304fe4615..0e49f93fb4 100644 --- a/spine-as3/spine-as3/src/spine/animation/AnimationStateData.as +++ b/spine-as3/spine-as3/src/spine/animation/AnimationStateData.as @@ -1,69 +1,68 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { -import spine.SkeletonData; - -public class AnimationStateData { - internal var _skeletonData:SkeletonData; - private var animationToMixTime:Object = new Object(); - public var defaultMix:Number = 0; - - public function AnimationStateData (skeletonData:SkeletonData) { - _skeletonData = skeletonData; - } - - public function get skeletonData () : SkeletonData { - return _skeletonData; - } - - public function setMixByName (fromName:String, toName:String, duration:Number) : void { - var from:Animation = _skeletonData.findAnimation(fromName); - if (from == null) throw new ArgumentError("Animation not found: " + fromName); - var to:Animation = _skeletonData.findAnimation(toName); - if (to == null) throw new ArgumentError("Animation not found: " + toName); - setMix(from, to, duration); - } - - public function setMix (from:Animation, to:Animation, duration:Number) : void { - if (from == null) throw new ArgumentError("from cannot be null."); - if (to == null) throw new ArgumentError("to cannot be null."); - animationToMixTime[from.name + ":" + to.name] = duration; - } - - public function getMix (from:Animation, to:Animation) : Number { - var time:Object = animationToMixTime[from.name + ":" + to.name]; - if (time == null) return defaultMix; - return time as Number; - } -} - +package spine.animation { +import spine.SkeletonData; + +public class AnimationStateData { + internal var _skeletonData:SkeletonData; + private var animationToMixTime:Object = new Object(); + public var defaultMix:Number = 0; + + public function AnimationStateData (skeletonData:SkeletonData) { + _skeletonData = skeletonData; + } + + public function get skeletonData () : SkeletonData { + return _skeletonData; + } + + public function setMixByName (fromName:String, toName:String, duration:Number) : void { + var from:Animation = _skeletonData.findAnimation(fromName); + if (from == null) throw new ArgumentError("Animation not found: " + fromName); + var to:Animation = _skeletonData.findAnimation(toName); + if (to == null) throw new ArgumentError("Animation not found: " + toName); + setMix(from, to, duration); + } + + public function setMix (from:Animation, to:Animation, duration:Number) : void { + if (from == null) throw new ArgumentError("from cannot be null."); + if (to == null) throw new ArgumentError("to cannot be null."); + animationToMixTime[from.name + ":" + to.name] = duration; + } + + public function getMix (from:Animation, to:Animation) : Number { + var time:Object = animationToMixTime[from.name + ":" + to.name]; + if (time == null) return defaultMix; + return time as Number; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/animation/AttachmentTimeline.as b/spine-as3/spine-as3/src/spine/animation/AttachmentTimeline.as index 6b1491d2e3..492534ed67 100644 --- a/spine-as3/spine-as3/src/spine/animation/AttachmentTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/AttachmentTimeline.as @@ -1,71 +1,70 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { -import spine.Event; -import spine.Skeleton; - -public class AttachmentTimeline implements Timeline { - public var slotIndex:int; - public var frames:Vector.; // time, ... - public var attachmentNames:Vector.; - - public function AttachmentTimeline (frameCount:int) { - frames = new Vector.(frameCount, true); - attachmentNames = new Vector.(frameCount, true); - } - - public function get frameCount () : int { - return frames.length; - } - - /** Sets the time and value of the specified keyframe. */ - public function setFrame (frameIndex:int, time:Number, attachmentName:String) : void { - frames[frameIndex] = time; - attachmentNames[frameIndex] = attachmentName; - } - - public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { - var frames:Vector. = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var frameIndex:int; - if (time >= frames[frames.length - 1]) // Time is after last frame. - frameIndex = frames.length - 1; - else - frameIndex = Animation.binarySearch(frames, time, 1) - 1; - - var attachmentName:String = attachmentNames[frameIndex]; - skeleton.slots[slotIndex].attachment = attachmentName == null ? null : skeleton.getAttachmentForSlotIndex(slotIndex, attachmentName); - } -} - +package spine.animation { +import spine.Event; +import spine.Skeleton; + +public class AttachmentTimeline implements Timeline { + public var slotIndex:int; + public var frames:Vector.; // time, ... + public var attachmentNames:Vector.; + + public function AttachmentTimeline (frameCount:int) { + frames = new Vector.(frameCount, true); + attachmentNames = new Vector.(frameCount, true); + } + + public function get frameCount () : int { + return frames.length; + } + + /** Sets the time and value of the specified keyframe. */ + public function setFrame (frameIndex:int, time:Number, attachmentName:String) : void { + frames[frameIndex] = time; + attachmentNames[frameIndex] = attachmentName; + } + + public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { + var frames:Vector. = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var frameIndex:int; + if (time >= frames[frames.length - 1]) // Time is after last frame. + frameIndex = frames.length - 1; + else + frameIndex = Animation.binarySearch(frames, time, 1) - 1; + + var attachmentName:String = attachmentNames[frameIndex]; + skeleton.slots[slotIndex].attachment = attachmentName == null ? null : skeleton.getAttachmentForSlotIndex(slotIndex, attachmentName); + } +} + } diff --git a/spine-as3/spine-as3/src/spine/animation/ColorTimeline.as b/spine-as3/spine-as3/src/spine/animation/ColorTimeline.as index bcc182917b..1a89142e48 100644 --- a/spine-as3/spine-as3/src/spine/animation/ColorTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/ColorTimeline.as @@ -1,103 +1,102 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { -import spine.Event; -import spine.Skeleton; -import spine.Slot; - -public class ColorTimeline extends CurveTimeline { - static public const ENTRIES:int = 5; - static internal const PREV_TIME:int = -5, PREV_R:int = -4, PREV_G:int = -3, PREV_B:int = -2, PREV_A:int = -1; - static internal const R:int = 1, G:int = 2, B:int = 3, A:int = 4; - - public var slotIndex:int; - public var frames:Vector.; // time, r, g, b, a, ... - - public function ColorTimeline (frameCount:int) { - super(frameCount); - frames = new Vector.(frameCount * 5, true); - } - - /** Sets the time and value of the specified keyframe. */ - public function setFrame (frameIndex:int, time:Number, r:Number, g:Number, b:Number, a:Number) : void { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[int(frameIndex + R)] = r; - frames[int(frameIndex + G)] = g; - frames[int(frameIndex + B)] = b; - frames[int(frameIndex + A)] = a; - } - - override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { - if (time < frames[0]) - return; // Time is before first frame. - - var r:Number, g:Number, b:Number, a:Number; - if (time >= frames[int(frames.length - ENTRIES)]) { - // Time is after last frame. - var i:int = frames.length; - r = frames[int(i + PREV_R)]; - g = frames[int(i + PREV_G)]; - b = frames[int(i + PREV_B)]; - a = frames[int(i + PREV_A)]; - } else { - // Interpolate between the previous frame and the current frame. - var frame:int = Animation.binarySearch(frames, time, ENTRIES); - r = frames[int(frame + PREV_R)]; - g = frames[int(frame + PREV_G)]; - b = frames[int(frame + PREV_B)]; - a = frames[int(frame + PREV_A)]; - var frameTime:Number = frames[frame]; - var percent:Number = getCurvePercent(frame / ENTRIES - 1, - 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - r += (frames[frame + R] - r) * percent; - g += (frames[frame + G] - g) * percent; - b += (frames[frame + B] - b) * percent; - a += (frames[frame + A] - a) * percent; - } - var slot:Slot = skeleton.slots[slotIndex]; - if (alpha < 1) { - slot.r += (r - slot.r) * alpha; - slot.g += (g - slot.g) * alpha; - slot.b += (b - slot.b) * alpha; - slot.a += (a - slot.a) * alpha; - } else { - slot.r = r; - slot.g = g; - slot.b = b; - slot.a = a; - } - } -} - +package spine.animation { +import spine.Event; +import spine.Skeleton; +import spine.Slot; + +public class ColorTimeline extends CurveTimeline { + static public const ENTRIES:int = 5; + static internal const PREV_TIME:int = -5, PREV_R:int = -4, PREV_G:int = -3, PREV_B:int = -2, PREV_A:int = -1; + static internal const R:int = 1, G:int = 2, B:int = 3, A:int = 4; + + public var slotIndex:int; + public var frames:Vector.; // time, r, g, b, a, ... + + public function ColorTimeline (frameCount:int) { + super(frameCount); + frames = new Vector.(frameCount * 5, true); + } + + /** Sets the time and value of the specified keyframe. */ + public function setFrame (frameIndex:int, time:Number, r:Number, g:Number, b:Number, a:Number) : void { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[int(frameIndex + R)] = r; + frames[int(frameIndex + G)] = g; + frames[int(frameIndex + B)] = b; + frames[int(frameIndex + A)] = a; + } + + override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { + if (time < frames[0]) + return; // Time is before first frame. + + var r:Number, g:Number, b:Number, a:Number; + if (time >= frames[int(frames.length - ENTRIES)]) { + // Time is after last frame. + var i:int = frames.length; + r = frames[int(i + PREV_R)]; + g = frames[int(i + PREV_G)]; + b = frames[int(i + PREV_B)]; + a = frames[int(i + PREV_A)]; + } else { + // Interpolate between the previous frame and the current frame. + var frame:int = Animation.binarySearch(frames, time, ENTRIES); + r = frames[int(frame + PREV_R)]; + g = frames[int(frame + PREV_G)]; + b = frames[int(frame + PREV_B)]; + a = frames[int(frame + PREV_A)]; + var frameTime:Number = frames[frame]; + var percent:Number = getCurvePercent(frame / ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + r += (frames[frame + R] - r) * percent; + g += (frames[frame + G] - g) * percent; + b += (frames[frame + B] - b) * percent; + a += (frames[frame + A] - a) * percent; + } + var slot:Slot = skeleton.slots[slotIndex]; + if (alpha < 1) { + slot.r += (r - slot.r) * alpha; + slot.g += (g - slot.g) * alpha; + slot.b += (b - slot.b) * alpha; + slot.a += (a - slot.a) * alpha; + } else { + slot.r = r; + slot.g = g; + slot.b = b; + slot.a = a; + } + } +} + } diff --git a/spine-as3/spine-as3/src/spine/animation/CurveTimeline.as b/spine-as3/spine-as3/src/spine/animation/CurveTimeline.as index 9a213997fa..2aa10ebbda 100644 --- a/spine-as3/spine-as3/src/spine/animation/CurveTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/CurveTimeline.as @@ -1,119 +1,118 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { - import spine.MathUtils; -import spine.Event; -import spine.Skeleton; - -/** Base class for frames that use an interpolation bezier curve. */ -public class CurveTimeline implements Timeline { - static private const LINEAR:Number = 0; - static private const STEPPED:Number = 1; - static private const BEZIER:Number = 2; - static private const BEZIER_SIZE:int = 10 * 2 - 1; - - private var curves:Vector.; // type, x, y, ... - - public function CurveTimeline (frameCount:int) { - curves = new Vector.((frameCount - 1) * BEZIER_SIZE, true); - } - - public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { - } - - public function get frameCount () : int { - return curves.length / BEZIER_SIZE + 1; - } - - public function setLinear (frameIndex:int) : void { - curves[int(frameIndex * BEZIER_SIZE)] = LINEAR; - } - - public function setStepped (frameIndex:int) : void { - curves[int(frameIndex * BEZIER_SIZE)] = STEPPED; - } - - /** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. - * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of - * the difference between the keyframe's values. */ - public function setCurve (frameIndex:int, cx1:Number, cy1:Number, cx2:Number, cy2:Number) : void { - var tmpx:Number = (-cx1 * 2 + cx2) * 0.03, tmpy:Number = (-cy1 * 2 + cy2) * 0.03; - var dddfx:Number = ((cx1 - cx2) * 3 + 1) * 0.006, dddfy:Number = ((cy1 - cy2) * 3 + 1) * 0.006; - var ddfx:Number = tmpx * 2 + dddfx, ddfy:Number = tmpy * 2 + dddfy; - var dfx:Number = cx1 * 0.3 + tmpx + dddfx * 0.16666667, dfy:Number = cy1 * 0.3 + tmpy + dddfy * 0.16666667; - - var i:int = frameIndex * BEZIER_SIZE; - var curves:Vector. = this.curves; - curves[int(i++)] = BEZIER; - - var x:Number = dfx, y:Number = dfy; - for (var n:int = i + BEZIER_SIZE - 1; i < n; i += 2) { - curves[i] = x; - curves[int(i + 1)] = y; - dfx += ddfx; - dfy += ddfy; - ddfx += dddfx; - ddfy += dddfy; - x += dfx; - y += dfy; - } - } - - public function getCurvePercent (frameIndex:int, percent:Number) : Number { - percent = MathUtils.clamp(percent, 0, 1); - var curves:Vector. = this.curves; - var i:int = frameIndex * BEZIER_SIZE; - var type:Number = curves[i]; - if (type == LINEAR) return percent; - if (type == STEPPED) return 0; - i++; - var x:Number = 0; - for (var start:int = i, n:int = i + BEZIER_SIZE - 1; i < n; i += 2) { - x = curves[i]; - if (x >= percent) { - var prevX:Number, prevY:Number; - if (i == start) { - prevX = 0; - prevY = 0; - } else { - prevX = curves[int(i - 2)]; - prevY = curves[int(i - 1)]; - } - return prevY + (curves[int(i + 1)] - prevY) * (percent - prevX) / (x - prevX); - } - } - var y:Number = curves[int(i - 1)]; - return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. - } -} - +package spine.animation { + import spine.MathUtils; +import spine.Event; +import spine.Skeleton; + +/** Base class for frames that use an interpolation bezier curve. */ +public class CurveTimeline implements Timeline { + static private const LINEAR:Number = 0; + static private const STEPPED:Number = 1; + static private const BEZIER:Number = 2; + static private const BEZIER_SIZE:int = 10 * 2 - 1; + + private var curves:Vector.; // type, x, y, ... + + public function CurveTimeline (frameCount:int) { + curves = new Vector.((frameCount - 1) * BEZIER_SIZE, true); + } + + public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { + } + + public function get frameCount () : int { + return curves.length / BEZIER_SIZE + 1; + } + + public function setLinear (frameIndex:int) : void { + curves[int(frameIndex * BEZIER_SIZE)] = LINEAR; + } + + public function setStepped (frameIndex:int) : void { + curves[int(frameIndex * BEZIER_SIZE)] = STEPPED; + } + + /** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. + * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of + * the difference between the keyframe's values. */ + public function setCurve (frameIndex:int, cx1:Number, cy1:Number, cx2:Number, cy2:Number) : void { + var tmpx:Number = (-cx1 * 2 + cx2) * 0.03, tmpy:Number = (-cy1 * 2 + cy2) * 0.03; + var dddfx:Number = ((cx1 - cx2) * 3 + 1) * 0.006, dddfy:Number = ((cy1 - cy2) * 3 + 1) * 0.006; + var ddfx:Number = tmpx * 2 + dddfx, ddfy:Number = tmpy * 2 + dddfy; + var dfx:Number = cx1 * 0.3 + tmpx + dddfx * 0.16666667, dfy:Number = cy1 * 0.3 + tmpy + dddfy * 0.16666667; + + var i:int = frameIndex * BEZIER_SIZE; + var curves:Vector. = this.curves; + curves[int(i++)] = BEZIER; + + var x:Number = dfx, y:Number = dfy; + for (var n:int = i + BEZIER_SIZE - 1; i < n; i += 2) { + curves[i] = x; + curves[int(i + 1)] = y; + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + x += dfx; + y += dfy; + } + } + + public function getCurvePercent (frameIndex:int, percent:Number) : Number { + percent = MathUtils.clamp(percent, 0, 1); + var curves:Vector. = this.curves; + var i:int = frameIndex * BEZIER_SIZE; + var type:Number = curves[i]; + if (type == LINEAR) return percent; + if (type == STEPPED) return 0; + i++; + var x:Number = 0; + for (var start:int = i, n:int = i + BEZIER_SIZE - 1; i < n; i += 2) { + x = curves[i]; + if (x >= percent) { + var prevX:Number, prevY:Number; + if (i == start) { + prevX = 0; + prevY = 0; + } else { + prevX = curves[int(i - 2)]; + prevY = curves[int(i - 1)]; + } + return prevY + (curves[int(i + 1)] - prevY) * (percent - prevX) / (x - prevX); + } + } + var y:Number = curves[int(i - 1)]; + return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. + } +} + } diff --git a/spine-as3/spine-as3/src/spine/animation/DeformTimeline.as b/spine-as3/spine-as3/src/spine/animation/DeformTimeline.as index f91ec96045..336af315d4 100644 --- a/spine-as3/spine-as3/src/spine/animation/DeformTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/DeformTimeline.as @@ -1,106 +1,105 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { -import spine.attachments.VertexAttachment; -import spine.Event; -import spine.Skeleton; -import spine.Slot; - -public class DeformTimeline extends CurveTimeline { - public var slotIndex:int; - public var frames:Vector.; - public var frameVertices:Vector.>; - public var attachment:VertexAttachment; - - public function DeformTimeline (frameCount:int) { - super(frameCount); - frames = new Vector.(frameCount, true); - frameVertices = new Vector.>(frameCount, true); - } - - /** Sets the time and value of the specified keyframe. */ - public function setFrame (frameIndex:int, time:Number, vertices:Vector.) : void { - frames[frameIndex] = time; - frameVertices[frameIndex] = vertices; - } - - override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { - var slot:Slot = skeleton.slots[slotIndex]; - var slotAttachment:VertexAttachment = slot.attachment as VertexAttachment; - if (!slotAttachment || !slotAttachment.applyDeform(attachment)) return; - - var frames:Vector. = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var frameVertices:Vector.> = this.frameVertices; - var vertexCount:int = frameVertices[0].length; - - var vertices:Vector. = slot.attachmentVertices; - if (vertices.length != vertexCount) alpha = 1; // Don't mix from uninitialized slot vertices. - vertices.length = vertexCount; - - var i:int; - if (time >= frames[frames.length - 1]) { // Time is after last frame. - var lastVertices:Vector. = frameVertices[int(frames.length - 1)]; - if (alpha < 1) { - for (i = 0; i < vertexCount; i++) - vertices[i] += (lastVertices[i] - vertices[i]) * alpha; - } else { - for (i = 0; i < vertexCount; i++) - vertices[i] = lastVertices[i]; - } - return; - } - - // Interpolate between the previous frame and the current frame. - var frame:int = Animation.binarySearch1(frames, time); - var prevVertices:Vector. = frameVertices[int(frame - 1)]; - var nextVertices:Vector. = frameVertices[frame]; - var frameTime:Number = frames[frame]; - var percent:Number = getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime)); - - var prev:Number; - if (alpha < 1) { - for (i = 0; i < vertexCount; i++) { - prev = prevVertices[i]; - vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha; - } - } else { - for (i = 0; i < vertexCount; i++) { - prev = prevVertices[i]; - vertices[i] = prev + (nextVertices[i] - prev) * percent; - } - } - } -} - +package spine.animation { +import spine.attachments.VertexAttachment; +import spine.Event; +import spine.Skeleton; +import spine.Slot; + +public class DeformTimeline extends CurveTimeline { + public var slotIndex:int; + public var frames:Vector.; + public var frameVertices:Vector.>; + public var attachment:VertexAttachment; + + public function DeformTimeline (frameCount:int) { + super(frameCount); + frames = new Vector.(frameCount, true); + frameVertices = new Vector.>(frameCount, true); + } + + /** Sets the time and value of the specified keyframe. */ + public function setFrame (frameIndex:int, time:Number, vertices:Vector.) : void { + frames[frameIndex] = time; + frameVertices[frameIndex] = vertices; + } + + override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { + var slot:Slot = skeleton.slots[slotIndex]; + var slotAttachment:VertexAttachment = slot.attachment as VertexAttachment; + if (!slotAttachment || !slotAttachment.applyDeform(attachment)) return; + + var frames:Vector. = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + var frameVertices:Vector.> = this.frameVertices; + var vertexCount:int = frameVertices[0].length; + + var vertices:Vector. = slot.attachmentVertices; + if (vertices.length != vertexCount) alpha = 1; // Don't mix from uninitialized slot vertices. + vertices.length = vertexCount; + + var i:int; + if (time >= frames[frames.length - 1]) { // Time is after last frame. + var lastVertices:Vector. = frameVertices[int(frames.length - 1)]; + if (alpha < 1) { + for (i = 0; i < vertexCount; i++) + vertices[i] += (lastVertices[i] - vertices[i]) * alpha; + } else { + for (i = 0; i < vertexCount; i++) + vertices[i] = lastVertices[i]; + } + return; + } + + // Interpolate between the previous frame and the current frame. + var frame:int = Animation.binarySearch1(frames, time); + var prevVertices:Vector. = frameVertices[int(frame - 1)]; + var nextVertices:Vector. = frameVertices[frame]; + var frameTime:Number = frames[frame]; + var percent:Number = getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime)); + + var prev:Number; + if (alpha < 1) { + for (i = 0; i < vertexCount; i++) { + prev = prevVertices[i]; + vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha; + } + } else { + for (i = 0; i < vertexCount; i++) { + prev = prevVertices[i]; + vertices[i] = prev + (nextVertices[i] - prev) * percent; + } + } + } +} + } diff --git a/spine-as3/spine-as3/src/spine/animation/DrawOrderTimeline.as b/spine-as3/spine-as3/src/spine/animation/DrawOrderTimeline.as index 5f3fa7305e..29928c2bc4 100644 --- a/spine-as3/spine-as3/src/spine/animation/DrawOrderTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/DrawOrderTimeline.as @@ -1,80 +1,79 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { -import spine.Event; -import spine.Skeleton; -import spine.Slot; - -public class DrawOrderTimeline implements Timeline { - public var frames:Vector.; // time, ... - public var drawOrders:Vector.>; - - public function DrawOrderTimeline (frameCount:int) { - frames = new Vector.(frameCount, true); - drawOrders = new Vector.>(frameCount, true); - } - - public function get frameCount () : int { - return frames.length; - } - - /** Sets the time and value of the specified keyframe. */ - public function setFrame (frameIndex:int, time:Number, drawOrder:Vector.) : void { - frames[frameIndex] = time; - drawOrders[frameIndex] = drawOrder; - } - - public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { - if (time < frames[0]) - return; // Time is before first frame. - - var frameIndex:int; - if (time >= frames[int(frames.length - 1)]) // Time is after last frame. - frameIndex = frames.length - 1; - else - frameIndex = Animation.binarySearch1(frames, time) - 1; - - var drawOrder:Vector. = skeleton.drawOrder; - var slots:Vector. = skeleton.slots; - var drawOrderToSetupIndex:Vector. = drawOrders[frameIndex]; - var i:int = 0; - if (!drawOrderToSetupIndex) { - for each (var slot:Slot in slots) - drawOrder[i++] = slot; - } else { - for each (var setupIndex:int in drawOrderToSetupIndex) - drawOrder[i++] = slots[setupIndex]; - } - } -} - +package spine.animation { +import spine.Event; +import spine.Skeleton; +import spine.Slot; + +public class DrawOrderTimeline implements Timeline { + public var frames:Vector.; // time, ... + public var drawOrders:Vector.>; + + public function DrawOrderTimeline (frameCount:int) { + frames = new Vector.(frameCount, true); + drawOrders = new Vector.>(frameCount, true); + } + + public function get frameCount () : int { + return frames.length; + } + + /** Sets the time and value of the specified keyframe. */ + public function setFrame (frameIndex:int, time:Number, drawOrder:Vector.) : void { + frames[frameIndex] = time; + drawOrders[frameIndex] = drawOrder; + } + + public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { + if (time < frames[0]) + return; // Time is before first frame. + + var frameIndex:int; + if (time >= frames[int(frames.length - 1)]) // Time is after last frame. + frameIndex = frames.length - 1; + else + frameIndex = Animation.binarySearch1(frames, time) - 1; + + var drawOrder:Vector. = skeleton.drawOrder; + var slots:Vector. = skeleton.slots; + var drawOrderToSetupIndex:Vector. = drawOrders[frameIndex]; + var i:int = 0; + if (!drawOrderToSetupIndex) { + for each (var slot:Slot in slots) + drawOrder[i++] = slot; + } else { + for each (var setupIndex:int in drawOrderToSetupIndex) + drawOrder[i++] = slots[setupIndex]; + } + } +} + } diff --git a/spine-as3/spine-as3/src/spine/animation/EventTimeline.as b/spine-as3/spine-as3/src/spine/animation/EventTimeline.as index 01e8615f72..61a6a303f9 100644 --- a/spine-as3/spine-as3/src/spine/animation/EventTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/EventTimeline.as @@ -1,82 +1,81 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { -import spine.Event; -import spine.Skeleton; - -public class EventTimeline implements Timeline { - public var frames:Vector.; // time, ... - public var events:Vector.; - - public function EventTimeline (frameCount:int) { - frames = new Vector.(frameCount, true); - events = new Vector.(frameCount, true); - } - - public function get frameCount () : int { - return frames.length; - } - - /** Sets the time and value of the specified keyframe. */ - public function setFrame (frameIndex:int, event:Event) : void { - frames[frameIndex] = event.time; - events[frameIndex] = event; - } - - /** Fires events for frames > lastTime and <= time. */ - public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { - if (!firedEvents) return; - - if (lastTime > time) { // Fire events after last time for looped animations. - apply(skeleton, lastTime, int.MAX_VALUE, firedEvents, alpha); - lastTime = -1; - } else if (lastTime >= frames[int(frameCount - 1)]) // Last time is after last frame. - return; - if (time < frames[0]) return; // Time is before first frame. - - var frame:int; - if (lastTime < frames[0]) - frame = 0; - else { - frame = Animation.binarySearch1(frames, lastTime); - var frameTime:Number = frames[frame]; - while (frame > 0) { // Fire multiple events with the same frame. - if (frames[int(frame - 1)] != frameTime) break; - frame--; - } - } - for (; frame < frameCount && time >= frames[frame]; frame++) - firedEvents[firedEvents.length] = events[frame]; - } -} - +package spine.animation { +import spine.Event; +import spine.Skeleton; + +public class EventTimeline implements Timeline { + public var frames:Vector.; // time, ... + public var events:Vector.; + + public function EventTimeline (frameCount:int) { + frames = new Vector.(frameCount, true); + events = new Vector.(frameCount, true); + } + + public function get frameCount () : int { + return frames.length; + } + + /** Sets the time and value of the specified keyframe. */ + public function setFrame (frameIndex:int, event:Event) : void { + frames[frameIndex] = event.time; + events[frameIndex] = event; + } + + /** Fires events for frames > lastTime and <= time. */ + public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { + if (!firedEvents) return; + + if (lastTime > time) { // Fire events after last time for looped animations. + apply(skeleton, lastTime, int.MAX_VALUE, firedEvents, alpha); + lastTime = -1; + } else if (lastTime >= frames[int(frameCount - 1)]) // Last time is after last frame. + return; + if (time < frames[0]) return; // Time is before first frame. + + var frame:int; + if (lastTime < frames[0]) + frame = 0; + else { + frame = Animation.binarySearch1(frames, lastTime); + var frameTime:Number = frames[frame]; + while (frame > 0) { // Fire multiple events with the same frame. + if (frames[int(frame - 1)] != frameTime) break; + frame--; + } + } + for (; frame < frameCount && time >= frames[frame]; frame++) + firedEvents[firedEvents.length] = events[frame]; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/animation/IkConstraintTimeline.as b/spine-as3/spine-as3/src/spine/animation/IkConstraintTimeline.as index 444163d7bf..831aa8a752 100644 --- a/spine-as3/spine-as3/src/spine/animation/IkConstraintTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/IkConstraintTimeline.as @@ -1,80 +1,79 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { -import spine.Event; -import spine.IkConstraint; -import spine.Skeleton; - -public class IkConstraintTimeline extends CurveTimeline { - static public const ENTRIES:int = 3; - static internal const PREV_TIME:int = -3, PREV_MIX:int = -2, PREV_BEND_DIRECTION:int = -1; - static internal const MIX:int = 1, BEND_DIRECTION:int = 2; - - public var ikConstraintIndex:int; - public var frames:Vector.; // time, mix, bendDirection, ... - - public function IkConstraintTimeline (frameCount:int) { - super(frameCount); - frames = new Vector.(frameCount * ENTRIES, true); - } - - /** Sets the time, mix and bend direction of the specified keyframe. */ - public function setFrame (frameIndex:int, time:Number, mix:Number, bendDirection:int) : void { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[int(frameIndex + MIX)] = mix; - frames[int(frameIndex + BEND_DIRECTION)] = bendDirection; - } - - override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { - if (time < frames[0]) return; // Time is before first frame. - - var constraint:IkConstraint = skeleton.ikConstraints[ikConstraintIndex]; - - if (time >= frames[int(frames.length - ENTRIES)]) { // Time is after last frame. - constraint.mix += (frames[int(frames.length + PREV_MIX)] - constraint.mix) * alpha; - constraint.bendDirection = int(frames[int(frames.length + PREV_BEND_DIRECTION)]); - return; - } - - // Interpolate between the previous frame and the current frame. - var frame:int = Animation.binarySearch(frames, time, ENTRIES); - var mix:Number = frames[int(frame + PREV_MIX)]; - var frameTime:Number = frames[frame]; - var percent:Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - constraint.mix += (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha; - constraint.bendDirection = int(frames[frame + PREV_BEND_DIRECTION]); - } -} - +package spine.animation { +import spine.Event; +import spine.IkConstraint; +import spine.Skeleton; + +public class IkConstraintTimeline extends CurveTimeline { + static public const ENTRIES:int = 3; + static internal const PREV_TIME:int = -3, PREV_MIX:int = -2, PREV_BEND_DIRECTION:int = -1; + static internal const MIX:int = 1, BEND_DIRECTION:int = 2; + + public var ikConstraintIndex:int; + public var frames:Vector.; // time, mix, bendDirection, ... + + public function IkConstraintTimeline (frameCount:int) { + super(frameCount); + frames = new Vector.(frameCount * ENTRIES, true); + } + + /** Sets the time, mix and bend direction of the specified keyframe. */ + public function setFrame (frameIndex:int, time:Number, mix:Number, bendDirection:int) : void { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[int(frameIndex + MIX)] = mix; + frames[int(frameIndex + BEND_DIRECTION)] = bendDirection; + } + + override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { + if (time < frames[0]) return; // Time is before first frame. + + var constraint:IkConstraint = skeleton.ikConstraints[ikConstraintIndex]; + + if (time >= frames[int(frames.length - ENTRIES)]) { // Time is after last frame. + constraint.mix += (frames[int(frames.length + PREV_MIX)] - constraint.mix) * alpha; + constraint.bendDirection = int(frames[int(frames.length + PREV_BEND_DIRECTION)]); + return; + } + + // Interpolate between the previous frame and the current frame. + var frame:int = Animation.binarySearch(frames, time, ENTRIES); + var mix:Number = frames[int(frame + PREV_MIX)]; + var frameTime:Number = frames[frame]; + var percent:Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + constraint.mix += (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha; + constraint.bendDirection = int(frames[frame + PREV_BEND_DIRECTION]); + } +} + } diff --git a/spine-as3/spine-as3/src/spine/animation/Listeners.as b/spine-as3/spine-as3/src/spine/animation/Listeners.as index f0a246ac27..0aa32d4a8d 100644 --- a/spine-as3/spine-as3/src/spine/animation/Listeners.as +++ b/spine-as3/spine-as3/src/spine/animation/Listeners.as @@ -1,64 +1,63 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { - public class Listeners { - private var _listeners:Vector. = new Vector.(); - - public function Listeners () { - } - - public function get listeners () : Vector. { - return _listeners; - } - - public function add (listener:Function) : void { - if (listener == null) - throw new ArgumentError("listener cannot be null."); - var indexOf:int = _listeners.indexOf(listener); - if (indexOf == -1) - _listeners[_listeners.length] = listener; - } - - public function remove (listener:Function) : void { - if (listener == null) - throw new ArgumentError("listener cannot be null."); - var indexOf:int = _listeners.indexOf(listener); - if (indexOf != -1) - _listeners.splice(_listeners.indexOf(listener), 1); - } - - public function invoke (... args:*) : void { - for each (var listener:Function in _listeners) - listener.apply(null, args); - } - } +package spine.animation { + public class Listeners { + private var _listeners:Vector. = new Vector.(); + + public function Listeners () { + } + + public function get listeners () : Vector. { + return _listeners; + } + + public function add (listener:Function) : void { + if (listener == null) + throw new ArgumentError("listener cannot be null."); + var indexOf:int = _listeners.indexOf(listener); + if (indexOf == -1) + _listeners[_listeners.length] = listener; + } + + public function remove (listener:Function) : void { + if (listener == null) + throw new ArgumentError("listener cannot be null."); + var indexOf:int = _listeners.indexOf(listener); + if (indexOf != -1) + _listeners.splice(_listeners.indexOf(listener), 1); + } + + public function invoke (... args:*) : void { + for each (var listener:Function in _listeners) + listener.apply(null, args); + } + } } diff --git a/spine-as3/spine-as3/src/spine/animation/PathConstraintMixTimeline.as b/spine-as3/spine-as3/src/spine/animation/PathConstraintMixTimeline.as index 1fb9c03151..11d594f693 100644 --- a/spine-as3/spine-as3/src/spine/animation/PathConstraintMixTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/PathConstraintMixTimeline.as @@ -1,83 +1,82 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { -import spine.Event; -import spine.Skeleton; -import spine.PathConstraint; - -public class PathConstraintMixTimeline extends CurveTimeline { - static public const ENTRIES:int = 3; - static internal const PREV_TIME:int = -3, PREV_ROTATE:int = -2, PREV_TRANSLATE:int = -1; - static internal const ROTATE:int = 1, TRANSLATE:int = 2; - - public var pathConstraintIndex:int; - - public var frames:Vector.; // time, rotate mix, translate mix, ... - - public function PathConstraintMixTimeline (frameCount:int) { - super(frameCount); - frames = new Vector.(frameCount * ENTRIES, true); - } - - /** Sets the time and mixes of the specified keyframe. */ - public function setFrame (frameIndex:int, time:Number, rotateMix:Number, translateMix:Number) : void { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[frameIndex + ROTATE] = rotateMix; - frames[frameIndex + TRANSLATE] = translateMix; - } - - override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { - if (time < frames[0]) return; // Time is before first frame. - - var constraint:PathConstraint = skeleton.pathConstraints[pathConstraintIndex]; - - if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. - var i:int = frames.length; - constraint.rotateMix += (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha; - constraint.translateMix += (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - var frame:int = Animation.binarySearch(frames, time, ENTRIES); - var rotate:Number = frames[frame + PREV_ROTATE]; - var translate:Number = frames[frame + PREV_TRANSLATE]; - var frameTime:Number = frames[frame]; - var percent:Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - constraint.rotateMix += (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha; - constraint.translateMix += (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix) - * alpha; - } +package spine.animation { +import spine.Event; +import spine.Skeleton; +import spine.PathConstraint; + +public class PathConstraintMixTimeline extends CurveTimeline { + static public const ENTRIES:int = 3; + static internal const PREV_TIME:int = -3, PREV_ROTATE:int = -2, PREV_TRANSLATE:int = -1; + static internal const ROTATE:int = 1, TRANSLATE:int = 2; + + public var pathConstraintIndex:int; + + public var frames:Vector.; // time, rotate mix, translate mix, ... + + public function PathConstraintMixTimeline (frameCount:int) { + super(frameCount); + frames = new Vector.(frameCount * ENTRIES, true); + } + + /** Sets the time and mixes of the specified keyframe. */ + public function setFrame (frameIndex:int, time:Number, rotateMix:Number, translateMix:Number) : void { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[frameIndex + ROTATE] = rotateMix; + frames[frameIndex + TRANSLATE] = translateMix; + } + + override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { + if (time < frames[0]) return; // Time is before first frame. + + var constraint:PathConstraint = skeleton.pathConstraints[pathConstraintIndex]; + + if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. + var i:int = frames.length; + constraint.rotateMix += (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha; + constraint.translateMix += (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + var frame:int = Animation.binarySearch(frames, time, ENTRIES); + var rotate:Number = frames[frame + PREV_ROTATE]; + var translate:Number = frames[frame + PREV_TRANSLATE]; + var frameTime:Number = frames[frame]; + var percent:Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + constraint.rotateMix += (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha; + constraint.translateMix += (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix) + * alpha; + } +} } -} \ No newline at end of file diff --git a/spine-as3/spine-as3/src/spine/animation/PathConstraintPositionTimeline.as b/spine-as3/spine-as3/src/spine/animation/PathConstraintPositionTimeline.as index ba013f3e64..7bbbe6a04c 100644 --- a/spine-as3/spine-as3/src/spine/animation/PathConstraintPositionTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/PathConstraintPositionTimeline.as @@ -1,78 +1,77 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { -import spine.PathConstraint; -import spine.Event; -import spine.Skeleton; - -public class PathConstraintPositionTimeline extends CurveTimeline { - static public const ENTRIES:int = 2; - static internal const PREV_TIME:int = -2, PREV_VALUE:int = -1; - static internal const VALUE:int = 1; - - public var pathConstraintIndex:int; - - public var frames:Vector.; // time, position, ... - - public function PathConstraintPositionTimeline (frameCount:int) { - super(frameCount); - frames = new Vector.(frameCount * ENTRIES, true); - } - - /** Sets the time and value of the specified keyframe. */ - public function setFrame (frameIndex:int, time:Number, value:Number) : void { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[frameIndex + VALUE] = value; - } - - override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { - if (time < frames[0]) return; // Time is before first frame. - - var constraint:PathConstraint = skeleton.pathConstraints[pathConstraintIndex]; - - if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. - var i:int = frames.length; - constraint.position += (frames[i + PREV_VALUE] - constraint.position) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - var frame:int = Animation.binarySearch(frames, time, ENTRIES); - var position:Number = frames[frame + PREV_VALUE]; - var frameTime:Number = frames[frame]; - var percent:Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - constraint.position += (position + (frames[frame + VALUE] - position) * percent - constraint.position) * alpha; - } +package spine.animation { +import spine.PathConstraint; +import spine.Event; +import spine.Skeleton; + +public class PathConstraintPositionTimeline extends CurveTimeline { + static public const ENTRIES:int = 2; + static internal const PREV_TIME:int = -2, PREV_VALUE:int = -1; + static internal const VALUE:int = 1; + + public var pathConstraintIndex:int; + + public var frames:Vector.; // time, position, ... + + public function PathConstraintPositionTimeline (frameCount:int) { + super(frameCount); + frames = new Vector.(frameCount * ENTRIES, true); + } + + /** Sets the time and value of the specified keyframe. */ + public function setFrame (frameIndex:int, time:Number, value:Number) : void { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[frameIndex + VALUE] = value; + } + + override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { + if (time < frames[0]) return; // Time is before first frame. + + var constraint:PathConstraint = skeleton.pathConstraints[pathConstraintIndex]; + + if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. + var i:int = frames.length; + constraint.position += (frames[i + PREV_VALUE] - constraint.position) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + var frame:int = Animation.binarySearch(frames, time, ENTRIES); + var position:Number = frames[frame + PREV_VALUE]; + var frameTime:Number = frames[frame]; + var percent:Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + constraint.position += (position + (frames[frame + VALUE] - position) * percent - constraint.position) * alpha; + } +} } -} \ No newline at end of file diff --git a/spine-as3/spine-as3/src/spine/animation/PathConstraintSpacingTimeline.as b/spine-as3/spine-as3/src/spine/animation/PathConstraintSpacingTimeline.as index 8a2a39e9e3..aa5af6a5cc 100644 --- a/spine-as3/spine-as3/src/spine/animation/PathConstraintSpacingTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/PathConstraintSpacingTimeline.as @@ -1,62 +1,61 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { -import spine.Skeleton; -import spine.Event; -import spine.PathConstraint; - -public class PathConstraintSpacingTimeline extends PathConstraintPositionTimeline { - public function PathConstraintSpacingTimeline (frameCount:int) { - super(frameCount); - } - - override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { - if (time < frames[0]) return; // Time is before first frame. - - var constraint:PathConstraint = skeleton.pathConstraints[pathConstraintIndex]; - - if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. - var i:int = frames.length; - constraint.spacing += (frames[i + PREV_VALUE] - constraint.spacing) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - var frame:int = Animation.binarySearch(frames, time, ENTRIES); - var spacing:Number = frames[frame + PREV_VALUE]; - var frameTime:Number = frames[frame]; - var percent:Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - constraint.spacing += (spacing + (frames[frame + VALUE] - spacing) * percent - constraint.spacing) * alpha; - } +package spine.animation { +import spine.Skeleton; +import spine.Event; +import spine.PathConstraint; + +public class PathConstraintSpacingTimeline extends PathConstraintPositionTimeline { + public function PathConstraintSpacingTimeline (frameCount:int) { + super(frameCount); + } + + override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { + if (time < frames[0]) return; // Time is before first frame. + + var constraint:PathConstraint = skeleton.pathConstraints[pathConstraintIndex]; + + if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. + var i:int = frames.length; + constraint.spacing += (frames[i + PREV_VALUE] - constraint.spacing) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + var frame:int = Animation.binarySearch(frames, time, ENTRIES); + var spacing:Number = frames[frame + PREV_VALUE]; + var frameTime:Number = frames[frame]; + var percent:Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + constraint.spacing += (spacing + (frames[frame + VALUE] - spacing) * percent - constraint.spacing) * alpha; + } +} } -} \ No newline at end of file diff --git a/spine-as3/spine-as3/src/spine/animation/RotateTimeline.as b/spine-as3/spine-as3/src/spine/animation/RotateTimeline.as index 524ad946ef..4b584035a7 100644 --- a/spine-as3/spine-as3/src/spine/animation/RotateTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/RotateTimeline.as @@ -1,93 +1,92 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { -import spine.Bone; -import spine.Event; -import spine.Skeleton; - -public class RotateTimeline extends CurveTimeline { - static public const ENTRIES:int = 2; - static private const PREV_TIME:int = -2, PREV_ROTATION:int = -1; - static private const ROTATION:int = 1; - - public var boneIndex:int; - public var frames:Vector.; // time, value, ... - - public function RotateTimeline (frameCount:int) { - super(frameCount); - frames = new Vector.(frameCount * 2, true); - } - - /** Sets the time and angle of the specified keyframe. */ - public function setFrame (frameIndex:int, time:Number, degrees:Number) : void { - frameIndex <<= 1; - frames[frameIndex] = time; - frames[int(frameIndex + ROTATION)] = degrees; - } - - override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { - if (time < frames[0]) - return; // Time is before first frame. - - var bone:Bone = skeleton.bones[boneIndex]; - - if (time >= frames[int(frames.length - 2)]) { // Time is after last frame. - var amount:Number = bone.data.rotation + frames[int(frames.length + PREV_ROTATION)] - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - var frame:int = Animation.binarySearch(frames, time, ENTRIES); - var prevRotation:Number = frames[int(frame + PREV_ROTATION)]; - var frameTime:Number = frames[frame]; - var percent:Number = getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - amount = frames[int(frame + ROTATION)] - prevRotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - amount = bone.data.rotation + (prevRotation + amount * percent) - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - } -} - +package spine.animation { +import spine.Bone; +import spine.Event; +import spine.Skeleton; + +public class RotateTimeline extends CurveTimeline { + static public const ENTRIES:int = 2; + static private const PREV_TIME:int = -2, PREV_ROTATION:int = -1; + static private const ROTATION:int = 1; + + public var boneIndex:int; + public var frames:Vector.; // time, value, ... + + public function RotateTimeline (frameCount:int) { + super(frameCount); + frames = new Vector.(frameCount * 2, true); + } + + /** Sets the time and angle of the specified keyframe. */ + public function setFrame (frameIndex:int, time:Number, degrees:Number) : void { + frameIndex <<= 1; + frames[frameIndex] = time; + frames[int(frameIndex + ROTATION)] = degrees; + } + + override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { + if (time < frames[0]) + return; // Time is before first frame. + + var bone:Bone = skeleton.bones[boneIndex]; + + if (time >= frames[int(frames.length - 2)]) { // Time is after last frame. + var amount:Number = bone.data.rotation + frames[int(frames.length + PREV_ROTATION)] - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + var frame:int = Animation.binarySearch(frames, time, ENTRIES); + var prevRotation:Number = frames[int(frame + PREV_ROTATION)]; + var frameTime:Number = frames[frame]; + var percent:Number = getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + amount = frames[int(frame + ROTATION)] - prevRotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + amount = bone.data.rotation + (prevRotation + amount * percent) - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/animation/ScaleTimeline.as b/spine-as3/spine-as3/src/spine/animation/ScaleTimeline.as index ec5dd47f16..ab7e7da995 100644 --- a/spine-as3/spine-as3/src/spine/animation/ScaleTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/ScaleTimeline.as @@ -1,65 +1,64 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { -import spine.Bone; -import spine.Event; -import spine.Skeleton; - -public class ScaleTimeline extends TranslateTimeline { - public function ScaleTimeline (frameCount:int) { - super(frameCount); - } - - override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { - if (time < frames[0]) - return; // Time is before first frame. - - var bone:Bone = skeleton.bones[boneIndex]; - if (time >= frames[int(frames.length - ENTRIES)]) { // Time is after last frame. - bone.scaleX += (bone.data.scaleX * frames[int(frames.length + PREV_X)] - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY * frames[int(frames.length + PREV_Y)] - bone.scaleY) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - var frame:int = Animation.binarySearch(frames, time, ENTRIES); - var prevX:Number = frames[frame + PREV_X]; - var prevY:Number = frames[frame + PREV_Y]; - var frameTime:Number = frames[frame]; - var percent:Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - bone.scaleX += (bone.data.scaleX * (prevX + (frames[frame + X] - prevX) * percent) - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY * (prevY + (frames[frame + Y] - prevY) * percent) - bone.scaleY) * alpha; - } -} - +package spine.animation { +import spine.Bone; +import spine.Event; +import spine.Skeleton; + +public class ScaleTimeline extends TranslateTimeline { + public function ScaleTimeline (frameCount:int) { + super(frameCount); + } + + override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { + if (time < frames[0]) + return; // Time is before first frame. + + var bone:Bone = skeleton.bones[boneIndex]; + if (time >= frames[int(frames.length - ENTRIES)]) { // Time is after last frame. + bone.scaleX += (bone.data.scaleX * frames[int(frames.length + PREV_X)] - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY * frames[int(frames.length + PREV_Y)] - bone.scaleY) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + var frame:int = Animation.binarySearch(frames, time, ENTRIES); + var prevX:Number = frames[frame + PREV_X]; + var prevY:Number = frames[frame + PREV_Y]; + var frameTime:Number = frames[frame]; + var percent:Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + bone.scaleX += (bone.data.scaleX * (prevX + (frames[frame + X] - prevX) * percent) - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY * (prevY + (frames[frame + Y] - prevY) * percent) - bone.scaleY) * alpha; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/animation/ShearTimeline.as b/spine-as3/spine-as3/src/spine/animation/ShearTimeline.as index 3ea018421b..e5b24bf78d 100644 --- a/spine-as3/spine-as3/src/spine/animation/ShearTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/ShearTimeline.as @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ package spine.animation { diff --git a/spine-as3/spine-as3/src/spine/animation/Timeline.as b/spine-as3/spine-as3/src/spine/animation/Timeline.as index f871c46a7c..4f972cc562 100644 --- a/spine-as3/spine-as3/src/spine/animation/Timeline.as +++ b/spine-as3/spine-as3/src/spine/animation/Timeline.as @@ -1,41 +1,40 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { -import spine.Event; -import spine.Skeleton; - -public interface Timeline { - /** Sets the value(s) for the specified time. */ - function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void; -} - +package spine.animation { +import spine.Event; +import spine.Skeleton; + +public interface Timeline { + /** Sets the value(s) for the specified time. */ + function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void; +} + } diff --git a/spine-as3/spine-as3/src/spine/animation/TrackEntry.as b/spine-as3/spine-as3/src/spine/animation/TrackEntry.as index 8112bba58f..2ec83ef491 100644 --- a/spine-as3/spine-as3/src/spine/animation/TrackEntry.as +++ b/spine-as3/spine-as3/src/spine/animation/TrackEntry.as @@ -1,51 +1,50 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { - -public class TrackEntry { - public var next:TrackEntry; - internal var previous:TrackEntry; - public var animation:Animation; - public var loop:Boolean; - public var delay:Number, time:Number = 0, lastTime:Number = -1, endTime:Number, timeScale:Number = 1; - internal var mixTime:Number, mixDuration:Number, mix:Number = 1; - public var onStart:Function, onEnd:Function, onComplete:Function, onEvent:Function; - - public function TrackEntry () { - } - - public function toString () : String { - return animation == null ? "" : animation.name; - } -} - +package spine.animation { + +public class TrackEntry { + public var next:TrackEntry; + internal var previous:TrackEntry; + public var animation:Animation; + public var loop:Boolean; + public var delay:Number, time:Number = 0, lastTime:Number = -1, endTime:Number, timeScale:Number = 1; + internal var mixTime:Number, mixDuration:Number, mix:Number = 1; + public var onStart:Function, onEnd:Function, onComplete:Function, onEvent:Function; + + public function TrackEntry () { + } + + public function toString () : String { + return animation == null ? "" : animation.name; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/animation/TransformConstraintTimeline.as b/spine-as3/spine-as3/src/spine/animation/TransformConstraintTimeline.as index 72de9dff19..3f649c8569 100644 --- a/spine-as3/spine-as3/src/spine/animation/TransformConstraintTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/TransformConstraintTimeline.as @@ -1,90 +1,89 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { -import spine.Event; -import spine.Skeleton; -import spine.TransformConstraint; - -public class TransformConstraintTimeline extends CurveTimeline { - static public const ENTRIES:int = 5; - static internal const PREV_TIME:int = -5, PREV_ROTATE:int = -4, PREV_TRANSLATE:int = -3, PREV_SCALE:int = -2, PREV_SHEAR:int = -1; - static internal const ROTATE:int = 1, TRANSLATE:int = 2, SCALE:int = 3, SHEAR:int = 4; - - public var transformConstraintIndex:int; - public var frames:Vector.; // time, rotate mix, translate mix, scale mix, shear mix, ... - - public function TransformConstraintTimeline (frameCount:int) { - super(frameCount); - frames = new Vector.(frameCount * ENTRIES, true); - } - - /** Sets the time and mixes of the specified keyframe. */ - public function setFrame (frameIndex:int, time:Number, rotateMix:Number, translateMix:Number, scaleMix:Number, shearMix:Number) : void { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[frameIndex + ROTATE] = rotateMix; - frames[frameIndex + TRANSLATE] = translateMix; - frames[frameIndex + SCALE] = scaleMix; - frames[frameIndex + SHEAR] = shearMix; - } - - override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { - if (time < frames[0]) return; // Time is before first frame. - - var constraint:TransformConstraint = skeleton.transformConstraints[transformConstraintIndex]; - - if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. - var i:int = frames.length; - constraint.rotateMix += (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha; - constraint.translateMix += (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha; - constraint.scaleMix += (frames[i + PREV_SCALE] - constraint.scaleMix) * alpha; - constraint.shearMix += (frames[i + PREV_SHEAR] - constraint.shearMix) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - var frame:int = Animation.binarySearch(frames, time, ENTRIES); - var frameTime:Number = frames[frame]; - var percent:Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - var rotate:Number = frames[frame + PREV_ROTATE]; - var translate:Number = frames[frame + PREV_TRANSLATE]; - var scale:Number = frames[frame + PREV_SCALE]; - var shear:Number = frames[frame + PREV_SHEAR]; - constraint.rotateMix += (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha; - constraint.translateMix += (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix) - * alpha; - constraint.scaleMix += (scale + (frames[frame + SCALE] - scale) * percent - constraint.scaleMix) * alpha; - constraint.shearMix += (shear + (frames[frame + SHEAR] - shear) * percent - constraint.shearMix) * alpha; - } +package spine.animation { +import spine.Event; +import spine.Skeleton; +import spine.TransformConstraint; + +public class TransformConstraintTimeline extends CurveTimeline { + static public const ENTRIES:int = 5; + static internal const PREV_TIME:int = -5, PREV_ROTATE:int = -4, PREV_TRANSLATE:int = -3, PREV_SCALE:int = -2, PREV_SHEAR:int = -1; + static internal const ROTATE:int = 1, TRANSLATE:int = 2, SCALE:int = 3, SHEAR:int = 4; + + public var transformConstraintIndex:int; + public var frames:Vector.; // time, rotate mix, translate mix, scale mix, shear mix, ... + + public function TransformConstraintTimeline (frameCount:int) { + super(frameCount); + frames = new Vector.(frameCount * ENTRIES, true); + } + + /** Sets the time and mixes of the specified keyframe. */ + public function setFrame (frameIndex:int, time:Number, rotateMix:Number, translateMix:Number, scaleMix:Number, shearMix:Number) : void { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[frameIndex + ROTATE] = rotateMix; + frames[frameIndex + TRANSLATE] = translateMix; + frames[frameIndex + SCALE] = scaleMix; + frames[frameIndex + SHEAR] = shearMix; + } + + override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { + if (time < frames[0]) return; // Time is before first frame. + + var constraint:TransformConstraint = skeleton.transformConstraints[transformConstraintIndex]; + + if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. + var i:int = frames.length; + constraint.rotateMix += (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha; + constraint.translateMix += (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha; + constraint.scaleMix += (frames[i + PREV_SCALE] - constraint.scaleMix) * alpha; + constraint.shearMix += (frames[i + PREV_SHEAR] - constraint.shearMix) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + var frame:int = Animation.binarySearch(frames, time, ENTRIES); + var frameTime:Number = frames[frame]; + var percent:Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + var rotate:Number = frames[frame + PREV_ROTATE]; + var translate:Number = frames[frame + PREV_TRANSLATE]; + var scale:Number = frames[frame + PREV_SCALE]; + var shear:Number = frames[frame + PREV_SHEAR]; + constraint.rotateMix += (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha; + constraint.translateMix += (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix) + * alpha; + constraint.scaleMix += (scale + (frames[frame + SCALE] - scale) * percent - constraint.scaleMix) * alpha; + constraint.shearMix += (shear + (frames[frame + SHEAR] - shear) * percent - constraint.shearMix) * alpha; + } +} } -} \ No newline at end of file diff --git a/spine-as3/spine-as3/src/spine/animation/TranslateTimeline.as b/spine-as3/spine-as3/src/spine/animation/TranslateTimeline.as index d9c7dc5378..eebd54e2bc 100644 --- a/spine-as3/spine-as3/src/spine/animation/TranslateTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/TranslateTimeline.as @@ -1,82 +1,81 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.animation { -import spine.Bone; -import spine.Event; -import spine.Skeleton; - -public class TranslateTimeline extends CurveTimeline { - static public const ENTRIES:int = 3; - static internal const PREV_TIME:int = -3, PREV_X:int = -2, PREV_Y:int = -1; - static internal const X:int = 1, Y:int = 2; - - public var boneIndex:int; - public var frames:Vector.; // time, value, value, ... - - public function TranslateTimeline (frameCount:int) { - super(frameCount); - frames = new Vector.(frameCount * ENTRIES, true); - } - - /** Sets the time and value of the specified keyframe. */ - public function setFrame (frameIndex:int, time:Number, x:Number, y:Number) : void { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[int(frameIndex + X)] = x; - frames[int(frameIndex + Y)] = y; - } - - override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { - if (time < frames[0]) - return; // Time is before first frame. - - var bone:Bone = skeleton.bones[boneIndex]; - - if (time >= frames[int(frames.length - ENTRIES)]) { // Time is after last frame. - bone.x += (bone.data.x + frames[int(frames.length + PREV_X)] - bone.x) * alpha; - bone.y += (bone.data.y + frames[int(frames.length + PREV_Y)] - bone.y) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - var frame:int = Animation.binarySearch(frames, time, ENTRIES); - var prevX:Number = frames[frame + PREV_X]; - var prevY:Number = frames[frame + PREV_Y]; - var frameTime:Number = frames[frame]; - var percent:Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - bone.x += (bone.data.x + prevX + (frames[frame + X] - prevX) * percent - bone.x) * alpha; - bone.y += (bone.data.y + prevY + (frames[frame + Y] - prevY) * percent - bone.y) * alpha; - } -} - +package spine.animation { +import spine.Bone; +import spine.Event; +import spine.Skeleton; + +public class TranslateTimeline extends CurveTimeline { + static public const ENTRIES:int = 3; + static internal const PREV_TIME:int = -3, PREV_X:int = -2, PREV_Y:int = -1; + static internal const X:int = 1, Y:int = 2; + + public var boneIndex:int; + public var frames:Vector.; // time, value, value, ... + + public function TranslateTimeline (frameCount:int) { + super(frameCount); + frames = new Vector.(frameCount * ENTRIES, true); + } + + /** Sets the time and value of the specified keyframe. */ + public function setFrame (frameIndex:int, time:Number, x:Number, y:Number) : void { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[int(frameIndex + X)] = x; + frames[int(frameIndex + Y)] = y; + } + + override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { + if (time < frames[0]) + return; // Time is before first frame. + + var bone:Bone = skeleton.bones[boneIndex]; + + if (time >= frames[int(frames.length - ENTRIES)]) { // Time is after last frame. + bone.x += (bone.data.x + frames[int(frames.length + PREV_X)] - bone.x) * alpha; + bone.y += (bone.data.y + frames[int(frames.length + PREV_Y)] - bone.y) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + var frame:int = Animation.binarySearch(frames, time, ENTRIES); + var prevX:Number = frames[frame + PREV_X]; + var prevY:Number = frames[frame + PREV_Y]; + var frameTime:Number = frames[frame]; + var percent:Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + bone.x += (bone.data.x + prevX + (frames[frame + X] - prevX) * percent - bone.x) * alpha; + bone.y += (bone.data.y + prevY + (frames[frame + Y] - prevY) * percent - bone.y) * alpha; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/atlas/Atlas.as b/spine-as3/spine-as3/src/spine/atlas/Atlas.as index 0797c783e7..796a171e9e 100644 --- a/spine-as3/spine-as3/src/spine/atlas/Atlas.as +++ b/spine-as3/spine-as3/src/spine/atlas/Atlas.as @@ -1,211 +1,210 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.atlas { -import flash.utils.ByteArray; - -public class Atlas { - private var pages:Vector. = new Vector.(); - private var regions:Vector. = new Vector.(); - private var textureLoader:TextureLoader; - - /** @param object A String or ByteArray. */ - public function Atlas (object:*, textureLoader:TextureLoader) { - if (!object) - return; - if (object is String) - load(String(object), textureLoader); - else if (object is ByteArray) - load(ByteArray(object).readUTFBytes(ByteArray(object).length), textureLoader); - else - throw new ArgumentError("object must be a TextureAtlas or AttachmentLoader."); - } - - protected function load (atlasText:String, textureLoader:TextureLoader) : void { - if (textureLoader == null) - throw new ArgumentError("textureLoader cannot be null."); - this.textureLoader = textureLoader; - - var reader:Reader = new Reader(atlasText); - var tuple:Array = new Array(); - tuple.length = 4; - var page:AtlasPage = null; - while (true) { - var line:String = reader.readLine(); - if (line == null) - break; - line = reader.trim(line); - if (line.length == 0) - page = null; - else if (!page) { - page = new AtlasPage(); - page.name = line; - - if (reader.readTuple(tuple) == 2) { // size is only optional for an atlas packed with an old TexturePacker. - page.width = parseInt(tuple[0]); - page.height = parseInt(tuple[1]); - reader.readTuple(tuple); - } - page.format = Format[tuple[0]]; - - reader.readTuple(tuple); - page.minFilter = TextureFilter[tuple[0]]; - page.magFilter = TextureFilter[tuple[1]]; - - var direction:String = reader.readValue(); - page.uWrap = TextureWrap.clampToEdge; - page.vWrap = TextureWrap.clampToEdge; - if (direction == "x") - page.uWrap = TextureWrap.repeat; - else if (direction == "y") - page.vWrap = TextureWrap.repeat; - else if (direction == "xy") - page.uWrap = page.vWrap = TextureWrap.repeat; - - textureLoader.loadPage(page, line); - - pages[pages.length] = page; - - } else { - var region:AtlasRegion = new AtlasRegion(); - region.name = line; - region.page = page; - - region.rotate = reader.readValue() == "true"; - - reader.readTuple(tuple); - var x:int = parseInt(tuple[0]); - var y:int = parseInt(tuple[1]); - - reader.readTuple(tuple); - var width:int = parseInt(tuple[0]); - var height:int = parseInt(tuple[1]); - - region.u = x / page.width; - region.v = y / page.height; - if (region.rotate) { - region.u2 = (x + height) / page.width; - region.v2 = (y + width) / page.height; - } else { - region.u2 = (x + width) / page.width; - region.v2 = (y + height) / page.height; - } - region.x = x; - region.y = y; - region.width = Math.abs(width); - region.height = Math.abs(height); - - if (reader.readTuple(tuple) == 4) { // split is optional - region.splits = new Vector.(parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])); - - if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits - region.pads = Vector.(parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])); - - reader.readTuple(tuple); - } - } - - region.originalWidth = parseInt(tuple[0]); - region.originalHeight = parseInt(tuple[1]); - - reader.readTuple(tuple); - region.offsetX = parseInt(tuple[0]); - region.offsetY = parseInt(tuple[1]); - - region.index = parseInt(reader.readValue()); - - textureLoader.loadRegion(region); - regions[regions.length] = region; - } - } - } - - /** Returns the first region found with the specified name. This method uses string comparison to find the region, so the result - * should be cached rather than calling this method multiple times. - * @return The region, or null. */ - public function findRegion (name:String) : AtlasRegion { - for (var i:int = 0, n:int = regions.length; i < n; i++) - if (regions[i].name == name) - return regions[i]; - return null; - } - - public function dispose () : void { - for (var i:int = 0, n:int = pages.length; i < n; i++) - textureLoader.unloadPage(pages[i]); - } -} - -} - -class Reader { - private var lines:Array; - private var index:int; - - public function Reader (text:String) { - lines = text.split(/\r\n|\r|\n/); - } - - public function trim (value:String) : String { - return value.replace(/^\s+|\s+$/gs, ""); - } - - public function readLine () : String { - if (index >= lines.length) - return null; - return lines[index++]; - } - - public function readValue () : String { - var line:String = readLine(); - var colon:int = line.indexOf(":"); - if (colon == -1) - throw new Error("Invalid line: " + line); - return trim(line.substring(colon + 1)); - } - - /** Returns the number of tuple values read (1, 2 or 4). */ - public function readTuple (tuple:Array) : int { - var line:String = readLine(); - var colon:int = line.indexOf(":"); - if (colon == -1) - throw new Error("Invalid line: " + line); - var i:int = 0, lastMatch:int = colon + 1; - for (; i < 3; i++) { - var comma:int = line.indexOf(",", lastMatch); - if (comma == -1) break; - tuple[i] = trim(line.substr(lastMatch, comma - lastMatch)); - lastMatch = comma + 1; - } - tuple[i] = trim(line.substring(lastMatch)); - return i + 1; - } +package spine.atlas { +import flash.utils.ByteArray; + +public class Atlas { + private var pages:Vector. = new Vector.(); + private var regions:Vector. = new Vector.(); + private var textureLoader:TextureLoader; + + /** @param object A String or ByteArray. */ + public function Atlas (object:*, textureLoader:TextureLoader) { + if (!object) + return; + if (object is String) + load(String(object), textureLoader); + else if (object is ByteArray) + load(ByteArray(object).readUTFBytes(ByteArray(object).length), textureLoader); + else + throw new ArgumentError("object must be a TextureAtlas or AttachmentLoader."); + } + + protected function load (atlasText:String, textureLoader:TextureLoader) : void { + if (textureLoader == null) + throw new ArgumentError("textureLoader cannot be null."); + this.textureLoader = textureLoader; + + var reader:Reader = new Reader(atlasText); + var tuple:Array = new Array(); + tuple.length = 4; + var page:AtlasPage = null; + while (true) { + var line:String = reader.readLine(); + if (line == null) + break; + line = reader.trim(line); + if (line.length == 0) + page = null; + else if (!page) { + page = new AtlasPage(); + page.name = line; + + if (reader.readTuple(tuple) == 2) { // size is only optional for an atlas packed with an old TexturePacker. + page.width = parseInt(tuple[0]); + page.height = parseInt(tuple[1]); + reader.readTuple(tuple); + } + page.format = Format[tuple[0]]; + + reader.readTuple(tuple); + page.minFilter = TextureFilter[tuple[0]]; + page.magFilter = TextureFilter[tuple[1]]; + + var direction:String = reader.readValue(); + page.uWrap = TextureWrap.clampToEdge; + page.vWrap = TextureWrap.clampToEdge; + if (direction == "x") + page.uWrap = TextureWrap.repeat; + else if (direction == "y") + page.vWrap = TextureWrap.repeat; + else if (direction == "xy") + page.uWrap = page.vWrap = TextureWrap.repeat; + + textureLoader.loadPage(page, line); + + pages[pages.length] = page; + + } else { + var region:AtlasRegion = new AtlasRegion(); + region.name = line; + region.page = page; + + region.rotate = reader.readValue() == "true"; + + reader.readTuple(tuple); + var x:int = parseInt(tuple[0]); + var y:int = parseInt(tuple[1]); + + reader.readTuple(tuple); + var width:int = parseInt(tuple[0]); + var height:int = parseInt(tuple[1]); + + region.u = x / page.width; + region.v = y / page.height; + if (region.rotate) { + region.u2 = (x + height) / page.width; + region.v2 = (y + width) / page.height; + } else { + region.u2 = (x + width) / page.width; + region.v2 = (y + height) / page.height; + } + region.x = x; + region.y = y; + region.width = Math.abs(width); + region.height = Math.abs(height); + + if (reader.readTuple(tuple) == 4) { // split is optional + region.splits = new Vector.(parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])); + + if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits + region.pads = Vector.(parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])); + + reader.readTuple(tuple); + } + } + + region.originalWidth = parseInt(tuple[0]); + region.originalHeight = parseInt(tuple[1]); + + reader.readTuple(tuple); + region.offsetX = parseInt(tuple[0]); + region.offsetY = parseInt(tuple[1]); + + region.index = parseInt(reader.readValue()); + + textureLoader.loadRegion(region); + regions[regions.length] = region; + } + } + } + + /** Returns the first region found with the specified name. This method uses string comparison to find the region, so the result + * should be cached rather than calling this method multiple times. + * @return The region, or null. */ + public function findRegion (name:String) : AtlasRegion { + for (var i:int = 0, n:int = regions.length; i < n; i++) + if (regions[i].name == name) + return regions[i]; + return null; + } + + public function dispose () : void { + for (var i:int = 0, n:int = pages.length; i < n; i++) + textureLoader.unloadPage(pages[i]); + } +} + +} + +class Reader { + private var lines:Array; + private var index:int; + + public function Reader (text:String) { + lines = text.split(/\r\n|\r|\n/); + } + + public function trim (value:String) : String { + return value.replace(/^\s+|\s+$/gs, ""); + } + + public function readLine () : String { + if (index >= lines.length) + return null; + return lines[index++]; + } + + public function readValue () : String { + var line:String = readLine(); + var colon:int = line.indexOf(":"); + if (colon == -1) + throw new Error("Invalid line: " + line); + return trim(line.substring(colon + 1)); + } + + /** Returns the number of tuple values read (1, 2 or 4). */ + public function readTuple (tuple:Array) : int { + var line:String = readLine(); + var colon:int = line.indexOf(":"); + if (colon == -1) + throw new Error("Invalid line: " + line); + var i:int = 0, lastMatch:int = colon + 1; + for (; i < 3; i++) { + var comma:int = line.indexOf(",", lastMatch); + if (comma == -1) break; + tuple[i] = trim(line.substr(lastMatch, comma - lastMatch)); + lastMatch = comma + 1; + } + tuple[i] = trim(line.substring(lastMatch)); + return i + 1; + } } diff --git a/spine-as3/spine-as3/src/spine/atlas/AtlasPage.as b/spine-as3/spine-as3/src/spine/atlas/AtlasPage.as index cc0bf3dbb1..c40ab38790 100644 --- a/spine-as3/spine-as3/src/spine/atlas/AtlasPage.as +++ b/spine-as3/spine-as3/src/spine/atlas/AtlasPage.as @@ -1,49 +1,48 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.atlas { - -public class AtlasPage { - public var name:String; - public var format:Format; - public var minFilter:TextureFilter; - public var magFilter:TextureFilter; - public var uWrap:TextureWrap; - public var vWrap:TextureWrap; - public var rendererObject:Object; - public var width:int; - public var height:int; - - public function AtlasPage () { - } -} - +package spine.atlas { + +public class AtlasPage { + public var name:String; + public var format:Format; + public var minFilter:TextureFilter; + public var magFilter:TextureFilter; + public var uWrap:TextureWrap; + public var vWrap:TextureWrap; + public var rendererObject:Object; + public var width:int; + public var height:int; + + public function AtlasPage () { + } +} + } diff --git a/spine-as3/spine-as3/src/spine/atlas/AtlasRegion.as b/spine-as3/spine-as3/src/spine/atlas/AtlasRegion.as index 7e3e9488ea..ef8bc956a6 100644 --- a/spine-as3/spine-as3/src/spine/atlas/AtlasRegion.as +++ b/spine-as3/spine-as3/src/spine/atlas/AtlasRegion.as @@ -1,59 +1,58 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.atlas { - -public class AtlasRegion { - public var page:AtlasPage; - public var name:String; - public var x:int; - public var y:int; - public var width:int; - public var height:int; - public var u:Number; - public var v:Number; - public var u2:Number; - public var v2:Number; - public var offsetX:Number; - public var offsetY:Number; - public var originalWidth:int; - public var originalHeight:int; - public var index:int; - public var rotate:Boolean; - public var splits:Vector.; - public var pads:Vector.; - public var rendererObject:Object; - - public function AtlasRegion () { - } -} - +package spine.atlas { + +public class AtlasRegion { + public var page:AtlasPage; + public var name:String; + public var x:int; + public var y:int; + public var width:int; + public var height:int; + public var u:Number; + public var v:Number; + public var u2:Number; + public var v2:Number; + public var offsetX:Number; + public var offsetY:Number; + public var originalWidth:int; + public var originalHeight:int; + public var index:int; + public var rotate:Boolean; + public var splits:Vector.; + public var pads:Vector.; + public var rendererObject:Object; + + public function AtlasRegion () { + } +} + } diff --git a/spine-as3/spine-as3/src/spine/atlas/Format.as b/spine-as3/spine-as3/src/spine/atlas/Format.as index 11828e92aa..b54b890cb4 100644 --- a/spine-as3/spine-as3/src/spine/atlas/Format.as +++ b/spine-as3/spine-as3/src/spine/atlas/Format.as @@ -1,52 +1,51 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.atlas { - -public class Format { - public static const alpha:Format = new Format(0, "alpha"); - public static const intensity:Format = new Format(1, "intensity"); - public static const luminanceAlpha:Format = new Format(2, "luminanceAlpha"); - public static const rgb565:Format = new Format(3, "rgb565"); - public static const rgba4444:Format = new Format(4, "rgba4444"); - public static const rgb888:Format = new Format(5, "rgb888"); - public static const rgba8888:Format = new Format(6, "rgba8888"); - - public var ordinal:int; - public var name:String; - - public function Format (ordinal:int, name:String) { - this.ordinal = ordinal; - this.name = name; - } -} - +package spine.atlas { + +public class Format { + public static const alpha:Format = new Format(0, "alpha"); + public static const intensity:Format = new Format(1, "intensity"); + public static const luminanceAlpha:Format = new Format(2, "luminanceAlpha"); + public static const rgb565:Format = new Format(3, "rgb565"); + public static const rgba4444:Format = new Format(4, "rgba4444"); + public static const rgb888:Format = new Format(5, "rgb888"); + public static const rgba8888:Format = new Format(6, "rgba8888"); + + public var ordinal:int; + public var name:String; + + public function Format (ordinal:int, name:String) { + this.ordinal = ordinal; + this.name = name; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/atlas/TextureFilter.as b/spine-as3/spine-as3/src/spine/atlas/TextureFilter.as index 9d64dde210..4f64e92b04 100644 --- a/spine-as3/spine-as3/src/spine/atlas/TextureFilter.as +++ b/spine-as3/spine-as3/src/spine/atlas/TextureFilter.as @@ -1,52 +1,51 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.atlas { - -public class TextureFilter { - public static const nearest:TextureFilter = new TextureFilter(0, "nearest"); - public static const linear:TextureFilter = new TextureFilter(1, "linear"); - public static const mipMap:TextureFilter = new TextureFilter(2, "mipMap"); - public static const mipMapNearestNearest:TextureFilter = new TextureFilter(3, "mipMapNearestNearest"); - public static const mipMapLinearNearest:TextureFilter = new TextureFilter(4, "mipMapLinearNearest"); - public static const mipMapNearestLinear:TextureFilter = new TextureFilter(5, "mipMapNearestLinear"); - public static const mipMapLinearLinear:TextureFilter = new TextureFilter(6, "mipMapLinearLinear"); - - public var ordinal:int; - public var name:String; - - public function TextureFilter (ordinal:int, name:String) { - this.ordinal = ordinal; - this.name = name; - } -} - +package spine.atlas { + +public class TextureFilter { + public static const nearest:TextureFilter = new TextureFilter(0, "nearest"); + public static const linear:TextureFilter = new TextureFilter(1, "linear"); + public static const mipMap:TextureFilter = new TextureFilter(2, "mipMap"); + public static const mipMapNearestNearest:TextureFilter = new TextureFilter(3, "mipMapNearestNearest"); + public static const mipMapLinearNearest:TextureFilter = new TextureFilter(4, "mipMapLinearNearest"); + public static const mipMapNearestLinear:TextureFilter = new TextureFilter(5, "mipMapNearestLinear"); + public static const mipMapLinearLinear:TextureFilter = new TextureFilter(6, "mipMapLinearLinear"); + + public var ordinal:int; + public var name:String; + + public function TextureFilter (ordinal:int, name:String) { + this.ordinal = ordinal; + this.name = name; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/atlas/TextureLoader.as b/spine-as3/spine-as3/src/spine/atlas/TextureLoader.as index 36a4131954..ea0c879358 100644 --- a/spine-as3/spine-as3/src/spine/atlas/TextureLoader.as +++ b/spine-as3/spine-as3/src/spine/atlas/TextureLoader.as @@ -1,40 +1,39 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.atlas { - -public interface TextureLoader { - function loadPage (page:AtlasPage, path:String) : void; - function loadRegion (region:AtlasRegion) : void; - function unloadPage (page:AtlasPage) : void; -} - +package spine.atlas { + +public interface TextureLoader { + function loadPage (page:AtlasPage, path:String) : void; + function loadRegion (region:AtlasRegion) : void; + function unloadPage (page:AtlasPage) : void; +} + } diff --git a/spine-as3/spine-as3/src/spine/atlas/TextureWrap.as b/spine-as3/spine-as3/src/spine/atlas/TextureWrap.as index 744e3b08cf..1b5c07775e 100644 --- a/spine-as3/spine-as3/src/spine/atlas/TextureWrap.as +++ b/spine-as3/spine-as3/src/spine/atlas/TextureWrap.as @@ -1,48 +1,47 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.atlas { - -public class TextureWrap { - public static const mirroredRepeat:TextureWrap = new TextureWrap(0, "mirroredRepeat"); - public static const clampToEdge:TextureWrap = new TextureWrap(1, "clampToEdge"); - public static const repeat:TextureWrap = new TextureWrap(2, "repeat"); - - public var ordinal:int; - public var name:String; - - public function TextureWrap (ordinal:int, name:String) { - this.ordinal = ordinal; - this.name = name; - } -} - +package spine.atlas { + +public class TextureWrap { + public static const mirroredRepeat:TextureWrap = new TextureWrap(0, "mirroredRepeat"); + public static const clampToEdge:TextureWrap = new TextureWrap(1, "clampToEdge"); + public static const repeat:TextureWrap = new TextureWrap(2, "repeat"); + + public var ordinal:int; + public var name:String; + + public function TextureWrap (ordinal:int, name:String) { + this.ordinal = ordinal; + this.name = name; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/attachments/AtlasAttachmentLoader.as b/spine-as3/spine-as3/src/spine/attachments/AtlasAttachmentLoader.as index 31e1f225b9..fca49c1de2 100644 --- a/spine-as3/spine-as3/src/spine/attachments/AtlasAttachmentLoader.as +++ b/spine-as3/spine-as3/src/spine/attachments/AtlasAttachmentLoader.as @@ -1,105 +1,104 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.attachments { -import spine.Skin; -import spine.atlas.Atlas; -import spine.atlas.AtlasRegion; - -public class AtlasAttachmentLoader implements AttachmentLoader { - private var atlas:Atlas; - - public function AtlasAttachmentLoader (atlas:Atlas) { - if (atlas == null) - throw new ArgumentError("atlas cannot be null."); - this.atlas = atlas; - } - - public function newRegionAttachment (skin:Skin, name:String, path:String) : RegionAttachment { - var region:AtlasRegion = atlas.findRegion(path); - if (region == null) - throw new Error("Region not found in atlas: " + path + " (region attachment: " + name + ")"); - var attachment:RegionAttachment = new RegionAttachment(name); - attachment.rendererObject = region; - var scaleX:Number = region.page.width / nextPOT(region.page.width); - var scaleY:Number = region.page.height / nextPOT(region.page.height); - attachment.setUVs(region.u * scaleX, region.v * scaleY, region.u2 * scaleX, region.v2 * scaleY, region.rotate); - attachment.regionOffsetX = region.offsetX; - attachment.regionOffsetY = region.offsetY; - attachment.regionWidth = region.width; - attachment.regionHeight = region.height; - attachment.regionOriginalWidth = region.originalWidth; - attachment.regionOriginalHeight = region.originalHeight; - return attachment; - } - - public function newMeshAttachment (skin:Skin, name:String, path:String) : MeshAttachment { - var region:AtlasRegion = atlas.findRegion(path); - if (region == null) - throw new Error("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); - var attachment:MeshAttachment = new MeshAttachment(name); - attachment.rendererObject = region; - var scaleX:Number = region.page.width / nextPOT(region.page.width); - var scaleY:Number = region.page.height / nextPOT(region.page.height); - attachment.regionU = region.u * scaleX; - attachment.regionV = region.v * scaleY; - attachment.regionU2 = region.u2 * scaleX; - attachment.regionV2 = region.v2 * scaleY; - attachment.regionRotate = region.rotate; - attachment.regionOffsetX = region.offsetX; - attachment.regionOffsetY = region.offsetY; - attachment.regionWidth = region.width; - attachment.regionHeight = region.height; - attachment.regionOriginalWidth = region.originalWidth; - attachment.regionOriginalHeight = region.originalHeight; - return attachment; - } - - public function newBoundingBoxAttachment (skin:Skin, name:String) : BoundingBoxAttachment { - return new BoundingBoxAttachment(name); - } - - public function newPathAttachment(skin:Skin, name:String) : PathAttachment { - return new PathAttachment(name); - } - - static public function nextPOT (value:int) : int { - value--; - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; - return value + 1; - } -} - +package spine.attachments { +import spine.Skin; +import spine.atlas.Atlas; +import spine.atlas.AtlasRegion; + +public class AtlasAttachmentLoader implements AttachmentLoader { + private var atlas:Atlas; + + public function AtlasAttachmentLoader (atlas:Atlas) { + if (atlas == null) + throw new ArgumentError("atlas cannot be null."); + this.atlas = atlas; + } + + public function newRegionAttachment (skin:Skin, name:String, path:String) : RegionAttachment { + var region:AtlasRegion = atlas.findRegion(path); + if (region == null) + throw new Error("Region not found in atlas: " + path + " (region attachment: " + name + ")"); + var attachment:RegionAttachment = new RegionAttachment(name); + attachment.rendererObject = region; + var scaleX:Number = region.page.width / nextPOT(region.page.width); + var scaleY:Number = region.page.height / nextPOT(region.page.height); + attachment.setUVs(region.u * scaleX, region.v * scaleY, region.u2 * scaleX, region.v2 * scaleY, region.rotate); + attachment.regionOffsetX = region.offsetX; + attachment.regionOffsetY = region.offsetY; + attachment.regionWidth = region.width; + attachment.regionHeight = region.height; + attachment.regionOriginalWidth = region.originalWidth; + attachment.regionOriginalHeight = region.originalHeight; + return attachment; + } + + public function newMeshAttachment (skin:Skin, name:String, path:String) : MeshAttachment { + var region:AtlasRegion = atlas.findRegion(path); + if (region == null) + throw new Error("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); + var attachment:MeshAttachment = new MeshAttachment(name); + attachment.rendererObject = region; + var scaleX:Number = region.page.width / nextPOT(region.page.width); + var scaleY:Number = region.page.height / nextPOT(region.page.height); + attachment.regionU = region.u * scaleX; + attachment.regionV = region.v * scaleY; + attachment.regionU2 = region.u2 * scaleX; + attachment.regionV2 = region.v2 * scaleY; + attachment.regionRotate = region.rotate; + attachment.regionOffsetX = region.offsetX; + attachment.regionOffsetY = region.offsetY; + attachment.regionWidth = region.width; + attachment.regionHeight = region.height; + attachment.regionOriginalWidth = region.originalWidth; + attachment.regionOriginalHeight = region.originalHeight; + return attachment; + } + + public function newBoundingBoxAttachment (skin:Skin, name:String) : BoundingBoxAttachment { + return new BoundingBoxAttachment(name); + } + + public function newPathAttachment(skin:Skin, name:String) : PathAttachment { + return new PathAttachment(name); + } + + static public function nextPOT (value:int) : int { + value--; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; + return value + 1; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/attachments/Attachment.as b/spine-as3/spine-as3/src/spine/attachments/Attachment.as index ac8898524a..a1a74a7dcb 100644 --- a/spine-as3/spine-as3/src/spine/attachments/Attachment.as +++ b/spine-as3/spine-as3/src/spine/attachments/Attachment.as @@ -1,52 +1,51 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.attachments { - -public class Attachment { - internal var _name:String; - - public function Attachment (name:String) { - if (name == null) - throw new ArgumentError("name cannot be null."); - _name = name; - } - - public function get name () : String { - return _name; - } - - public function toString () : String { - return name; - } -} - +package spine.attachments { + +public class Attachment { + internal var _name:String; + + public function Attachment (name:String) { + if (name == null) + throw new ArgumentError("name cannot be null."); + _name = name; + } + + public function get name () : String { + return _name; + } + + public function toString () : String { + return name; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/attachments/AttachmentLoader.as b/spine-as3/spine-as3/src/spine/attachments/AttachmentLoader.as index 002952f674..0694cb5f64 100644 --- a/spine-as3/spine-as3/src/spine/attachments/AttachmentLoader.as +++ b/spine-as3/spine-as3/src/spine/attachments/AttachmentLoader.as @@ -1,49 +1,48 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.attachments { -import spine.Skin; - -public interface AttachmentLoader { - /** @return May be null to not load an attachment. */ - function newRegionAttachment (skin:Skin, name:String, path:String) : RegionAttachment; - - /** @return May be null to not load an attachment. */ - function newMeshAttachment (skin:Skin, name:String, path:String) : MeshAttachment; - - /** @return May be null to not load an attachment. */ - function newBoundingBoxAttachment (skin:Skin, name:String) : BoundingBoxAttachment; - - /** @return May be null to not load an attachment */ - function newPathAttachment(skin:Skin, name:String): PathAttachment; -} - +package spine.attachments { +import spine.Skin; + +public interface AttachmentLoader { + /** @return May be null to not load an attachment. */ + function newRegionAttachment (skin:Skin, name:String, path:String) : RegionAttachment; + + /** @return May be null to not load an attachment. */ + function newMeshAttachment (skin:Skin, name:String, path:String) : MeshAttachment; + + /** @return May be null to not load an attachment. */ + function newBoundingBoxAttachment (skin:Skin, name:String) : BoundingBoxAttachment; + + /** @return May be null to not load an attachment */ + function newPathAttachment(skin:Skin, name:String): PathAttachment; +} + } diff --git a/spine-as3/spine-as3/src/spine/attachments/AttachmentType.as b/spine-as3/spine-as3/src/spine/attachments/AttachmentType.as index 68a3014448..c9f253fe64 100644 --- a/spine-as3/spine-as3/src/spine/attachments/AttachmentType.as +++ b/spine-as3/spine-as3/src/spine/attachments/AttachmentType.as @@ -1,51 +1,50 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.attachments { - -public class AttachmentType { - public static const region:AttachmentType = new AttachmentType(0, "region"); - public static const regionsequence:AttachmentType = new AttachmentType(1, "regionsequence"); - public static const boundingbox:AttachmentType = new AttachmentType(2, "boundingbox"); - public static const mesh:AttachmentType = new AttachmentType(3, "mesh"); - public static const linkedmesh:AttachmentType = new AttachmentType(3, "linkedmesh"); - public static const path:AttachmentType = new AttachmentType(4, "path"); - - public var ordinal:int; - public var name:String; - - public function AttachmentType (ordinal:int, name:String) { - this.ordinal = ordinal; - this.name = name; - } -} - +package spine.attachments { + +public class AttachmentType { + public static const region:AttachmentType = new AttachmentType(0, "region"); + public static const regionsequence:AttachmentType = new AttachmentType(1, "regionsequence"); + public static const boundingbox:AttachmentType = new AttachmentType(2, "boundingbox"); + public static const mesh:AttachmentType = new AttachmentType(3, "mesh"); + public static const linkedmesh:AttachmentType = new AttachmentType(3, "linkedmesh"); + public static const path:AttachmentType = new AttachmentType(4, "path"); + + public var ordinal:int; + public var name:String; + + public function AttachmentType (ordinal:int, name:String) { + this.ordinal = ordinal; + this.name = name; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/attachments/BoundingBoxAttachment.as b/spine-as3/spine-as3/src/spine/attachments/BoundingBoxAttachment.as index a27590c8f7..76385960a4 100644 --- a/spine-as3/spine-as3/src/spine/attachments/BoundingBoxAttachment.as +++ b/spine-as3/spine-as3/src/spine/attachments/BoundingBoxAttachment.as @@ -1,39 +1,38 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.attachments { - -public dynamic class BoundingBoxAttachment extends VertexAttachment { - public function BoundingBoxAttachment (name:String) { - super(name); - } -} +package spine.attachments { + +public dynamic class BoundingBoxAttachment extends VertexAttachment { + public function BoundingBoxAttachment (name:String) { + super(name); + } +} } diff --git a/spine-as3/spine-as3/src/spine/attachments/MeshAttachment.as b/spine-as3/spine-as3/src/spine/attachments/MeshAttachment.as index 3f71472658..9a02bb91b7 100644 --- a/spine-as3/spine-as3/src/spine/attachments/MeshAttachment.as +++ b/spine-as3/spine-as3/src/spine/attachments/MeshAttachment.as @@ -1,111 +1,110 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.attachments { - -public dynamic class MeshAttachment extends VertexAttachment { - public var worldVertices:Vector.; - public var uvs:Vector.; - public var regionUVs:Vector.; - public var triangles:Vector.; - public var r:Number = 1; - public var g:Number = 1; - public var b:Number = 1; - public var a:Number = 1; - public var hullLength:int; - private var _parentMesh:MeshAttachment; - public var inheritDeform:Boolean; - - public var path:String; - public var rendererObject:Object; - public var regionU:Number; - public var regionV:Number; - public var regionU2:Number; - public var regionV2:Number; - public var regionRotate:Boolean; - public var regionOffsetX:Number; // Pixels stripped from the bottom left, unrotated. - public var regionOffsetY:Number; - public var regionWidth:Number; // Unrotated, stripped size. - public var regionHeight:Number; - public var regionOriginalWidth:Number; // Unrotated, unstripped size. - public var regionOriginalHeight:Number; - - // Nonessential. - public var edges:Vector.; - public var width:Number; - public var height:Number; - - public function MeshAttachment (name:String) { - super(name); - } - - public function updateUVs () : void { - var width:Number = regionU2 - regionU, height:Number = regionV2 - regionV; - var i:int, n:int = regionUVs.length; - if (!uvs || uvs.length != n) uvs = new Vector.(n, true); - if (regionRotate) { - for (i = 0; i < n; i += 2) { - uvs[i] = regionU + regionUVs[int(i + 1)] * width; - uvs[int(i + 1)] = regionV + height - regionUVs[i] * height; - } - } else { - for (i = 0; i < n; i += 2) { - uvs[i] = regionU + regionUVs[i] * width; - uvs[int(i + 1)] = regionV + regionUVs[int(i + 1)] * height; - } - } - } - - public function applyFFD (sourceAttachment:Attachment) : Boolean { - return this == sourceAttachment || (inheritDeform && _parentMesh == sourceAttachment); - } - - public function get parentMesh () : MeshAttachment { - return _parentMesh; - } - - public function set parentMesh (parentMesh:MeshAttachment) : void { - _parentMesh = parentMesh; - if (parentMesh != null) { - bones = parentMesh.bones; - vertices = parentMesh.vertices; - worldVerticesLength = parentMesh.worldVerticesLength; - regionUVs = parentMesh.regionUVs; - triangles = parentMesh.triangles; - hullLength = parentMesh.hullLength; - edges = parentMesh.edges; - width = parentMesh.width; - height = parentMesh.height; - } - } -} - +package spine.attachments { + +public dynamic class MeshAttachment extends VertexAttachment { + public var worldVertices:Vector.; + public var uvs:Vector.; + public var regionUVs:Vector.; + public var triangles:Vector.; + public var r:Number = 1; + public var g:Number = 1; + public var b:Number = 1; + public var a:Number = 1; + public var hullLength:int; + private var _parentMesh:MeshAttachment; + public var inheritDeform:Boolean; + + public var path:String; + public var rendererObject:Object; + public var regionU:Number; + public var regionV:Number; + public var regionU2:Number; + public var regionV2:Number; + public var regionRotate:Boolean; + public var regionOffsetX:Number; // Pixels stripped from the bottom left, unrotated. + public var regionOffsetY:Number; + public var regionWidth:Number; // Unrotated, stripped size. + public var regionHeight:Number; + public var regionOriginalWidth:Number; // Unrotated, unstripped size. + public var regionOriginalHeight:Number; + + // Nonessential. + public var edges:Vector.; + public var width:Number; + public var height:Number; + + public function MeshAttachment (name:String) { + super(name); + } + + public function updateUVs () : void { + var width:Number = regionU2 - regionU, height:Number = regionV2 - regionV; + var i:int, n:int = regionUVs.length; + if (!uvs || uvs.length != n) uvs = new Vector.(n, true); + if (regionRotate) { + for (i = 0; i < n; i += 2) { + uvs[i] = regionU + regionUVs[int(i + 1)] * width; + uvs[int(i + 1)] = regionV + height - regionUVs[i] * height; + } + } else { + for (i = 0; i < n; i += 2) { + uvs[i] = regionU + regionUVs[i] * width; + uvs[int(i + 1)] = regionV + regionUVs[int(i + 1)] * height; + } + } + } + + public function applyFFD (sourceAttachment:Attachment) : Boolean { + return this == sourceAttachment || (inheritDeform && _parentMesh == sourceAttachment); + } + + public function get parentMesh () : MeshAttachment { + return _parentMesh; + } + + public function set parentMesh (parentMesh:MeshAttachment) : void { + _parentMesh = parentMesh; + if (parentMesh != null) { + bones = parentMesh.bones; + vertices = parentMesh.vertices; + worldVerticesLength = parentMesh.worldVerticesLength; + regionUVs = parentMesh.regionUVs; + triangles = parentMesh.triangles; + hullLength = parentMesh.hullLength; + edges = parentMesh.edges; + width = parentMesh.width; + height = parentMesh.height; + } + } +} + } diff --git a/spine-as3/spine-as3/src/spine/attachments/PathAttachment.as b/spine-as3/spine-as3/src/spine/attachments/PathAttachment.as index 96a0cd8170..ad79a6f807 100644 --- a/spine-as3/spine-as3/src/spine/attachments/PathAttachment.as +++ b/spine-as3/spine-as3/src/spine/attachments/PathAttachment.as @@ -1,43 +1,42 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.attachments { - -public dynamic class PathAttachment extends VertexAttachment { - public var lengths:Vector.; - public var closed:Boolean, constantSpeed:Boolean; - - public function PathAttachment (name:String) { - super(name); - } -} - +package spine.attachments { + +public dynamic class PathAttachment extends VertexAttachment { + public var lengths:Vector.; + public var closed:Boolean, constantSpeed:Boolean; + + public function PathAttachment (name:String) { + super(name); + } +} + } diff --git a/spine-as3/spine-as3/src/spine/attachments/RegionAttachment.as b/spine-as3/spine-as3/src/spine/attachments/RegionAttachment.as index 971e349c18..955a366158 100644 --- a/spine-as3/spine-as3/src/spine/attachments/RegionAttachment.as +++ b/spine-as3/spine-as3/src/spine/attachments/RegionAttachment.as @@ -1,151 +1,150 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.attachments { -import spine.Bone; - -public dynamic class RegionAttachment extends Attachment { - public const X1:int = 0; - public const Y1:int = 1; - public const X2:int = 2; - public const Y2:int = 3; - public const X3:int = 4; - public const Y3:int = 5; - public const X4:int = 6; - public const Y4:int = 7; - - public var x:Number; - public var y:Number; - public var scaleX:Number = 1; - public var scaleY:Number = 1; - public var rotation:Number; - public var width:Number; - public var height:Number; - public var r:Number = 1; - public var g:Number = 1; - public var b:Number = 1; - public var a:Number = 1; - - public var path:String; - public var rendererObject:Object; - public var regionOffsetX:Number; // Pixels stripped from the bottom left, unrotated. - public var regionOffsetY:Number; - public var regionWidth:Number; // Unrotated, stripped size. - public var regionHeight:Number; - public var regionOriginalWidth:Number; // Unrotated, unstripped size. - public var regionOriginalHeight:Number; - - public var offset:Vector. = new Vector.(); - public var uvs:Vector. = new Vector.(); - - public function RegionAttachment (name:String) { - super(name); - offset.length = 8; - uvs.length = 8; - } - - public function setUVs (u:Number, v:Number, u2:Number, v2:Number, rotate:Boolean) : void { - if (rotate) { - uvs[X2] = u; - uvs[Y2] = v2; - uvs[X3] = u; - uvs[Y3] = v; - uvs[X4] = u2; - uvs[Y4] = v; - uvs[X1] = u2; - uvs[Y1] = v2; - } else { - uvs[X1] = u; - uvs[Y1] = v2; - uvs[X2] = u; - uvs[Y2] = v; - uvs[X3] = u2; - uvs[Y3] = v; - uvs[X4] = u2; - uvs[Y4] = v2; - } - } - - public function updateOffset () : void { - var regionScaleX:Number = width / regionOriginalWidth * scaleX; - var regionScaleY:Number = height / regionOriginalHeight * scaleY; - var localX:Number = -width / 2 * scaleX + regionOffsetX * regionScaleX; - var localY:Number = -height / 2 * scaleY + regionOffsetY * regionScaleY; - var localX2:Number = localX + regionWidth * regionScaleX; - var localY2:Number = localY + regionHeight * regionScaleY; - var radians:Number = rotation * Math.PI / 180; - var cos:Number = Math.cos(radians); - var sin:Number = Math.sin(radians); - var localXCos:Number = localX * cos + x; - var localXSin:Number = localX * sin; - var localYCos:Number = localY * cos + y; - var localYSin:Number = localY * sin; - var localX2Cos:Number = localX2 * cos + x; - var localX2Sin:Number = localX2 * sin; - var localY2Cos:Number = localY2 * cos + y; - var localY2Sin:Number = localY2 * sin; - offset[X1] = localXCos - localYSin; - offset[Y1] = localYCos + localXSin; - offset[X2] = localXCos - localY2Sin; - offset[Y2] = localY2Cos + localXSin; - offset[X3] = localX2Cos - localY2Sin; - offset[Y3] = localY2Cos + localX2Sin; - offset[X4] = localX2Cos - localYSin; - offset[Y4] = localYCos + localX2Sin; - } - - public function computeWorldVertices (x:Number, y:Number, bone:Bone, worldVertices:Vector.) : void { - x += bone.worldX; - y += bone.worldY; - var m00:Number = bone.a; - var m01:Number = bone.b; - var m10:Number = bone.c; - var m11:Number = bone.d; - var x1:Number = offset[X1]; - var y1:Number = offset[Y1]; - var x2:Number = offset[X2]; - var y2:Number = offset[Y2]; - var x3:Number = offset[X3]; - var y3:Number = offset[Y3]; - var x4:Number = offset[X4]; - var y4:Number = offset[Y4]; - worldVertices[X1] = x1 * m00 + y1 * m01 + x; - worldVertices[Y1] = x1 * m10 + y1 * m11 + y; - worldVertices[X2] = x2 * m00 + y2 * m01 + x; - worldVertices[Y2] = x2 * m10 + y2 * m11 + y; - worldVertices[X3] = x3 * m00 + y3 * m01 + x; - worldVertices[Y3] = x3 * m10 + y3 * m11 + y; - worldVertices[X4] = x4 * m00 + y4 * m01 + x; - worldVertices[Y4] = x4 * m10 + y4 * m11 + y; - } -} - +package spine.attachments { +import spine.Bone; + +public dynamic class RegionAttachment extends Attachment { + public const X1:int = 0; + public const Y1:int = 1; + public const X2:int = 2; + public const Y2:int = 3; + public const X3:int = 4; + public const Y3:int = 5; + public const X4:int = 6; + public const Y4:int = 7; + + public var x:Number; + public var y:Number; + public var scaleX:Number = 1; + public var scaleY:Number = 1; + public var rotation:Number; + public var width:Number; + public var height:Number; + public var r:Number = 1; + public var g:Number = 1; + public var b:Number = 1; + public var a:Number = 1; + + public var path:String; + public var rendererObject:Object; + public var regionOffsetX:Number; // Pixels stripped from the bottom left, unrotated. + public var regionOffsetY:Number; + public var regionWidth:Number; // Unrotated, stripped size. + public var regionHeight:Number; + public var regionOriginalWidth:Number; // Unrotated, unstripped size. + public var regionOriginalHeight:Number; + + public var offset:Vector. = new Vector.(); + public var uvs:Vector. = new Vector.(); + + public function RegionAttachment (name:String) { + super(name); + offset.length = 8; + uvs.length = 8; + } + + public function setUVs (u:Number, v:Number, u2:Number, v2:Number, rotate:Boolean) : void { + if (rotate) { + uvs[X2] = u; + uvs[Y2] = v2; + uvs[X3] = u; + uvs[Y3] = v; + uvs[X4] = u2; + uvs[Y4] = v; + uvs[X1] = u2; + uvs[Y1] = v2; + } else { + uvs[X1] = u; + uvs[Y1] = v2; + uvs[X2] = u; + uvs[Y2] = v; + uvs[X3] = u2; + uvs[Y3] = v; + uvs[X4] = u2; + uvs[Y4] = v2; + } + } + + public function updateOffset () : void { + var regionScaleX:Number = width / regionOriginalWidth * scaleX; + var regionScaleY:Number = height / regionOriginalHeight * scaleY; + var localX:Number = -width / 2 * scaleX + regionOffsetX * regionScaleX; + var localY:Number = -height / 2 * scaleY + regionOffsetY * regionScaleY; + var localX2:Number = localX + regionWidth * regionScaleX; + var localY2:Number = localY + regionHeight * regionScaleY; + var radians:Number = rotation * Math.PI / 180; + var cos:Number = Math.cos(radians); + var sin:Number = Math.sin(radians); + var localXCos:Number = localX * cos + x; + var localXSin:Number = localX * sin; + var localYCos:Number = localY * cos + y; + var localYSin:Number = localY * sin; + var localX2Cos:Number = localX2 * cos + x; + var localX2Sin:Number = localX2 * sin; + var localY2Cos:Number = localY2 * cos + y; + var localY2Sin:Number = localY2 * sin; + offset[X1] = localXCos - localYSin; + offset[Y1] = localYCos + localXSin; + offset[X2] = localXCos - localY2Sin; + offset[Y2] = localY2Cos + localXSin; + offset[X3] = localX2Cos - localY2Sin; + offset[Y3] = localY2Cos + localX2Sin; + offset[X4] = localX2Cos - localYSin; + offset[Y4] = localYCos + localX2Sin; + } + + public function computeWorldVertices (x:Number, y:Number, bone:Bone, worldVertices:Vector.) : void { + x += bone.worldX; + y += bone.worldY; + var m00:Number = bone.a; + var m01:Number = bone.b; + var m10:Number = bone.c; + var m11:Number = bone.d; + var x1:Number = offset[X1]; + var y1:Number = offset[Y1]; + var x2:Number = offset[X2]; + var y2:Number = offset[Y2]; + var x3:Number = offset[X3]; + var y3:Number = offset[Y3]; + var x4:Number = offset[X4]; + var y4:Number = offset[Y4]; + worldVertices[X1] = x1 * m00 + y1 * m01 + x; + worldVertices[Y1] = x1 * m10 + y1 * m11 + y; + worldVertices[X2] = x2 * m00 + y2 * m01 + x; + worldVertices[Y2] = x2 * m10 + y2 * m11 + y; + worldVertices[X3] = x3 * m00 + y3 * m01 + x; + worldVertices[Y3] = x3 * m10 + y3 * m11 + y; + worldVertices[X4] = x4 * m00 + y4 * m01 + x; + worldVertices[Y4] = x4 * m10 + y4 * m11 + y; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/attachments/VertexAttachment.as b/spine-as3/spine-as3/src/spine/attachments/VertexAttachment.as index 936657ffc6..2b4614eb10 100644 --- a/spine-as3/spine-as3/src/spine/attachments/VertexAttachment.as +++ b/spine-as3/spine-as3/src/spine/attachments/VertexAttachment.as @@ -1,127 +1,126 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.attachments { - import spine.Bone; - import spine.Skeleton; - import spine.Slot; - -public dynamic class VertexAttachment extends Attachment { - public var bones:Vector.; - public var vertices:Vector.; - public var worldVerticesLength:int; - - public function VertexAttachment (name:String) { - super(name); - } - - public function computeWorldVertices (slot:Slot, worldVertices:Vector.): void { - computeWorldVertices2(slot, 0, worldVerticesLength, worldVertices, 0); - } - - /** Transforms local vertices to world coordinates. - * @param start The index of the first local vertex value to transform. Each vertex has 2 values, x and y. - * @param count The number of world vertex values to output. Must be <= {@link #getWorldVerticesLength()} - start. - * @param worldVertices The output world vertices. Must have a length >= offset + count. - * @param offset The worldVertices index to begin writing values. */ - public function computeWorldVertices2 (slot:Slot, start:int, count:int, worldVertices:Vector., offset:int): void { - count += offset; - var skeleton:Skeleton = slot.skeleton; - var x:Number = skeleton.x, y:Number = skeleton.y; - var deformArray:Vector. = slot.attachmentVertices; - var vertices:Vector. = this.vertices; - var bones:Vector. = this.bones; - var deform:Vector.; - - var v:int, w:int, n:int, i:int, skip:int, b:int, f:int; - var vx:Number, vy:Number; - var wx:Number, wy:Number; - var bone:Bone; - - if (bones == null) { - if (deformArray.length > 0) vertices = deformArray; - bone = slot.bone; - x += bone.worldX; - y += bone.worldY; - var a:Number = bone.a, bb:Number = bone.b, c:Number = bone.c, d:Number = bone.d; - for (v = start, w = offset; w < count; v += 2, w += 2) { - vx = vertices[v], vy = vertices[v + 1]; - worldVertices[w] = vx * a + vy * bb + x; - worldVertices[w + 1] = vx * c + vy * d + y; - } - return; - } - v = 0, skip = 0; - for (i = 0; i < start; i += 2) { - n = bones[v]; - v += n + 1; - skip += n; - } - var skeletonBones:Vector. = skeleton.bones; - if (deformArray.length == 0) { - for (w = offset, b = skip * 3; w < count; w += 2) { - wx = x, wy = y; - n = bones[v++]; - n += v; - for (; v < n; v++, b += 3) { - bone = skeletonBones[bones[v]]; - vx = vertices[b]; vy = vertices[b + 1]; var weight:Number = vertices[b + 2]; - wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; - wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; - } - worldVertices[w] = wx; - worldVertices[w + 1] = wy; - } - } else { - deform = deformArray; - for (w = offset, b = skip * 3, f = skip << 1; w < count; w += 2) { - wx = x; wy = y; - n = bones[v++]; - n += v; - for (; v < n; v++, b += 3, f += 2) { - bone = skeletonBones[bones[v]]; - vx = vertices[b] + deform[f]; vy = vertices[b + 1] + deform[f + 1]; weight = vertices[b + 2]; - wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; - wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; - } - worldVertices[w] = wx; - worldVertices[w + 1] = wy; - } - } - } - - /** Returns true if a deform originally applied to the specified attachment should be applied to this attachment. */ - public function applyDeform (sourceAttachment:VertexAttachment): Boolean { - return this == sourceAttachment; - } -} - +package spine.attachments { + import spine.Bone; + import spine.Skeleton; + import spine.Slot; + +public dynamic class VertexAttachment extends Attachment { + public var bones:Vector.; + public var vertices:Vector.; + public var worldVerticesLength:int; + + public function VertexAttachment (name:String) { + super(name); + } + + public function computeWorldVertices (slot:Slot, worldVertices:Vector.): void { + computeWorldVertices2(slot, 0, worldVerticesLength, worldVertices, 0); + } + + /** Transforms local vertices to world coordinates. + * @param start The index of the first local vertex value to transform. Each vertex has 2 values, x and y. + * @param count The number of world vertex values to output. Must be <= {@link #getWorldVerticesLength()} - start. + * @param worldVertices The output world vertices. Must have a length >= offset + count. + * @param offset The worldVertices index to begin writing values. */ + public function computeWorldVertices2 (slot:Slot, start:int, count:int, worldVertices:Vector., offset:int): void { + count += offset; + var skeleton:Skeleton = slot.skeleton; + var x:Number = skeleton.x, y:Number = skeleton.y; + var deformArray:Vector. = slot.attachmentVertices; + var vertices:Vector. = this.vertices; + var bones:Vector. = this.bones; + var deform:Vector.; + + var v:int, w:int, n:int, i:int, skip:int, b:int, f:int; + var vx:Number, vy:Number; + var wx:Number, wy:Number; + var bone:Bone; + + if (bones == null) { + if (deformArray.length > 0) vertices = deformArray; + bone = slot.bone; + x += bone.worldX; + y += bone.worldY; + var a:Number = bone.a, bb:Number = bone.b, c:Number = bone.c, d:Number = bone.d; + for (v = start, w = offset; w < count; v += 2, w += 2) { + vx = vertices[v], vy = vertices[v + 1]; + worldVertices[w] = vx * a + vy * bb + x; + worldVertices[w + 1] = vx * c + vy * d + y; + } + return; + } + v = 0, skip = 0; + for (i = 0; i < start; i += 2) { + n = bones[v]; + v += n + 1; + skip += n; + } + var skeletonBones:Vector. = skeleton.bones; + if (deformArray.length == 0) { + for (w = offset, b = skip * 3; w < count; w += 2) { + wx = x, wy = y; + n = bones[v++]; + n += v; + for (; v < n; v++, b += 3) { + bone = skeletonBones[bones[v]]; + vx = vertices[b]; vy = vertices[b + 1]; var weight:Number = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } else { + deform = deformArray; + for (w = offset, b = skip * 3, f = skip << 1; w < count; w += 2) { + wx = x; wy = y; + n = bones[v++]; + n += v; + for (; v < n; v++, b += 3, f += 2) { + bone = skeletonBones[bones[v]]; + vx = vertices[b] + deform[f]; vy = vertices[b + 1] + deform[f + 1]; weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } + } + + /** Returns true if a deform originally applied to the specified attachment should be applied to this attachment. */ + public function applyDeform (sourceAttachment:VertexAttachment): Boolean { + return this == sourceAttachment; + } +} + } diff --git a/spine-as3/spine-as3/src/spine/flash/FlashTextureLoader.as b/spine-as3/spine-as3/src/spine/flash/FlashTextureLoader.as index ff1926dafb..6501a383de 100644 --- a/spine-as3/spine-as3/src/spine/flash/FlashTextureLoader.as +++ b/spine-as3/spine-as3/src/spine/flash/FlashTextureLoader.as @@ -1,86 +1,85 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.flash { -import flash.display.Bitmap; -import flash.display.BitmapData; - -import spine.atlas.AtlasPage; -import spine.atlas.AtlasRegion; -import spine.atlas.TextureLoader; - -public class FlashTextureLoader implements TextureLoader { - public var bitmapDatas:Object = {}; - public var singleBitmapData:BitmapData; - - /** @param bitmaps A Bitmap or BitmapData for an atlas that has only one page, or for a multi page atlas an object where the - * key is the image path and the value is the Bitmap or BitmapData. */ - public function FlashTextureLoader (bitmaps:Object) { - if (bitmaps is BitmapData) { - singleBitmapData = BitmapData(bitmaps); - return; - } - if (bitmaps is Bitmap) { - singleBitmapData = Bitmap(bitmaps).bitmapData; - return; - } - - for (var path:* in bitmaps) { - var object:* = bitmaps[path]; - var bitmapData:BitmapData; - if (object is BitmapData) - bitmapData = BitmapData(object); - else if (object is Bitmap) - bitmapData = Bitmap(object).bitmapData; - else - throw new ArgumentError("Object for path \"" + path + "\" must be a Bitmap or BitmapData: " + object); - bitmapDatas[path] = bitmapData; - } - } - - public function loadPage (page:AtlasPage, path:String) : void { - var bitmapData:BitmapData = singleBitmapData || bitmapDatas[path]; - if (!bitmapData) - throw new ArgumentError("BitmapData not found with name: " + path); - page.rendererObject = bitmapData; - page.width = bitmapData.width; - page.height = bitmapData.height; - } - - public function loadRegion (region:AtlasRegion) : void { - } - - public function unloadPage (page:AtlasPage) : void { - BitmapData(page.rendererObject).dispose(); - } -} - +package spine.flash { +import flash.display.Bitmap; +import flash.display.BitmapData; + +import spine.atlas.AtlasPage; +import spine.atlas.AtlasRegion; +import spine.atlas.TextureLoader; + +public class FlashTextureLoader implements TextureLoader { + public var bitmapDatas:Object = {}; + public var singleBitmapData:BitmapData; + + /** @param bitmaps A Bitmap or BitmapData for an atlas that has only one page, or for a multi page atlas an object where the + * key is the image path and the value is the Bitmap or BitmapData. */ + public function FlashTextureLoader (bitmaps:Object) { + if (bitmaps is BitmapData) { + singleBitmapData = BitmapData(bitmaps); + return; + } + if (bitmaps is Bitmap) { + singleBitmapData = Bitmap(bitmaps).bitmapData; + return; + } + + for (var path:* in bitmaps) { + var object:* = bitmaps[path]; + var bitmapData:BitmapData; + if (object is BitmapData) + bitmapData = BitmapData(object); + else if (object is Bitmap) + bitmapData = Bitmap(object).bitmapData; + else + throw new ArgumentError("Object for path \"" + path + "\" must be a Bitmap or BitmapData: " + object); + bitmapDatas[path] = bitmapData; + } + } + + public function loadPage (page:AtlasPage, path:String) : void { + var bitmapData:BitmapData = singleBitmapData || bitmapDatas[path]; + if (!bitmapData) + throw new ArgumentError("BitmapData not found with name: " + path); + page.rendererObject = bitmapData; + page.width = bitmapData.width; + page.height = bitmapData.height; + } + + public function loadRegion (region:AtlasRegion) : void { + } + + public function unloadPage (page:AtlasPage) : void { + BitmapData(page.rendererObject).dispose(); + } +} + } diff --git a/spine-as3/spine-as3/src/spine/flash/SkeletonAnimation.as b/spine-as3/spine-as3/src/spine/flash/SkeletonAnimation.as index 5860ccfeaf..c8f836f380 100644 --- a/spine-as3/spine-as3/src/spine/flash/SkeletonAnimation.as +++ b/spine-as3/spine-as3/src/spine/flash/SkeletonAnimation.as @@ -1,53 +1,52 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.flash { -import spine.SkeletonData; -import spine.animation.AnimationState; -import spine.animation.AnimationStateData; - -public class SkeletonAnimation extends SkeletonSprite { - public var state:AnimationState; - - public function SkeletonAnimation (skeletonData:SkeletonData, stateData:AnimationStateData = null) { - super(skeletonData); - state = new AnimationState(stateData ? stateData : new AnimationStateData(skeletonData)); - } - - override public function advanceTime (time:Number) : void { - state.update(time * timeScale); - state.apply(skeleton); - skeleton.updateWorldTransform(); - super.advanceTime(time); - } -} - +package spine.flash { +import spine.SkeletonData; +import spine.animation.AnimationState; +import spine.animation.AnimationStateData; + +public class SkeletonAnimation extends SkeletonSprite { + public var state:AnimationState; + + public function SkeletonAnimation (skeletonData:SkeletonData, stateData:AnimationStateData = null) { + super(skeletonData); + state = new AnimationState(stateData ? stateData : new AnimationStateData(skeletonData)); + } + + override public function advanceTime (time:Number) : void { + state.update(time * timeScale); + state.apply(skeleton); + skeleton.updateWorldTransform(); + super.advanceTime(time); + } +} + } diff --git a/spine-as3/spine-as3/src/spine/flash/SkeletonSprite.as b/spine-as3/spine-as3/src/spine/flash/SkeletonSprite.as index e0ae300cbd..15c8e54c32 100644 --- a/spine-as3/spine-as3/src/spine/flash/SkeletonSprite.as +++ b/spine-as3/spine-as3/src/spine/flash/SkeletonSprite.as @@ -1,153 +1,152 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.flash { -import flash.utils.Dictionary; -import flash.display.Bitmap; -import flash.display.BitmapData; -import flash.display.BlendMode; -import flash.display.Sprite; -import flash.events.Event; -import flash.geom.ColorTransform; -import flash.geom.Point; -import flash.geom.Rectangle; -import flash.utils.getTimer; - -import spine.Bone; -import spine.Skeleton; -import spine.SkeletonData; -import spine.Slot; -import spine.atlas.AtlasRegion; -import spine.attachments.RegionAttachment; - -public class SkeletonSprite extends Sprite { - static private var blendModes:Vector. = new [ - BlendMode.NORMAL, BlendMode.ADD, BlendMode.MULTIPLY, BlendMode.SCREEN]; - - private var _skeleton:Skeleton; - public var timeScale:Number = 1; - private var lastTime:int; - private var wrappers:Dictionary = new Dictionary(true); - - public function SkeletonSprite (skeletonData:SkeletonData) { - Bone.yDown = true; - - _skeleton = new Skeleton(skeletonData); - _skeleton.updateWorldTransform(); - - addEventListener(Event.ENTER_FRAME, enterFrame); - } - - private function enterFrame (event:Event) : void { - var time:int = getTimer(); - advanceTime((time - lastTime) / 1000); - lastTime = time; - } - - public function advanceTime (delta:Number) : void { - _skeleton.update(delta * timeScale); - - removeChildren(); - var drawOrder:Vector. = skeleton.drawOrder; - for (var i:int = 0, n:int = drawOrder.length; i < n; i++) { - var slot:Slot = drawOrder[i]; - var regionAttachment:RegionAttachment = slot.attachment as RegionAttachment; - if (!regionAttachment) continue; - - var wrapper:Sprite = wrappers[regionAttachment]; - if (!wrapper) { - var region:AtlasRegion = AtlasRegion(regionAttachment.rendererObject); - var regionHeight:Number = region.rotate ? region.width : region.height; - var regionData:BitmapData = region.rendererObject as BitmapData; - if (!regionData) { - var bitmapData:BitmapData = region.page.rendererObject as BitmapData; - var regionWidth:Number = region.rotate ? region.height : region.width; - regionData = new BitmapData(regionWidth, regionHeight); - regionData.copyPixels(bitmapData, new Rectangle(region.x, region.y, regionWidth, regionHeight), new Point()); - region.rendererObject = regionData; - } - - var bitmap:Bitmap = new Bitmap(regionData); - bitmap.smoothing = true; - - // Rotate and scale using default registration point (top left corner, y-down, CW) instead of image center. - bitmap.rotation = -regionAttachment.rotation; - bitmap.scaleX = regionAttachment.scaleX * (regionAttachment.width / region.width); - bitmap.scaleY = regionAttachment.scaleY * (regionAttachment.height / region.height); - - // Position using attachment translation, shifted as if scale and rotation were at image center. - var radians:Number = -regionAttachment.rotation * Math.PI / 180; - var cos:Number = Math.cos(radians); - var sin:Number = Math.sin(radians); - var shiftX:Number = -regionAttachment.width / 2 * regionAttachment.scaleX; - var shiftY:Number = -regionAttachment.height / 2 * regionAttachment.scaleY; - if (region.rotate) { - bitmap.rotation += 90; - shiftX += regionHeight * (regionAttachment.width / region.width); - } - bitmap.x = regionAttachment.x + shiftX * cos - shiftY * sin; - bitmap.y = -regionAttachment.y + shiftX * sin + shiftY * cos; - - // Use bone as registration point. - wrapper = new Sprite(); - wrapper.transform.colorTransform = new ColorTransform(); - wrapper.addChild(bitmap); - wrappers[regionAttachment] = wrapper; - } - - wrapper.blendMode = blendModes[slot.data.blendMode.ordinal]; - - var colorTransform:ColorTransform = wrapper.transform.colorTransform; - colorTransform.redMultiplier = skeleton.r * slot.r * regionAttachment.r; - colorTransform.greenMultiplier = skeleton.g * slot.g * regionAttachment.g; - colorTransform.blueMultiplier = skeleton.b * slot.b * regionAttachment.b; - colorTransform.alphaMultiplier = skeleton.a * slot.a * regionAttachment.a; - wrapper.transform.colorTransform = colorTransform; - - var bone:Bone = slot.bone; - var flipX:int = skeleton.flipX ? -1 : 1; - var flipY:int = skeleton.flipY ? -1 : 1; - - wrapper.x = bone.worldX; - wrapper.y = bone.worldY; - wrapper.rotation = bone.worldRotationX * flipX * flipY; - wrapper.scaleX = bone.worldScaleX * flipX; - wrapper.scaleY = bone.worldScaleY * flipY; - addChild(wrapper); - } - } - - public function get skeleton () : Skeleton { - return _skeleton; - } -} - +package spine.flash { +import flash.utils.Dictionary; +import flash.display.Bitmap; +import flash.display.BitmapData; +import flash.display.BlendMode; +import flash.display.Sprite; +import flash.events.Event; +import flash.geom.ColorTransform; +import flash.geom.Point; +import flash.geom.Rectangle; +import flash.utils.getTimer; + +import spine.Bone; +import spine.Skeleton; +import spine.SkeletonData; +import spine.Slot; +import spine.atlas.AtlasRegion; +import spine.attachments.RegionAttachment; + +public class SkeletonSprite extends Sprite { + static private var blendModes:Vector. = new [ + BlendMode.NORMAL, BlendMode.ADD, BlendMode.MULTIPLY, BlendMode.SCREEN]; + + private var _skeleton:Skeleton; + public var timeScale:Number = 1; + private var lastTime:int; + private var wrappers:Dictionary = new Dictionary(true); + + public function SkeletonSprite (skeletonData:SkeletonData) { + Bone.yDown = true; + + _skeleton = new Skeleton(skeletonData); + _skeleton.updateWorldTransform(); + + addEventListener(Event.ENTER_FRAME, enterFrame); + } + + private function enterFrame (event:Event) : void { + var time:int = getTimer(); + advanceTime((time - lastTime) / 1000); + lastTime = time; + } + + public function advanceTime (delta:Number) : void { + _skeleton.update(delta * timeScale); + + removeChildren(); + var drawOrder:Vector. = skeleton.drawOrder; + for (var i:int = 0, n:int = drawOrder.length; i < n; i++) { + var slot:Slot = drawOrder[i]; + var regionAttachment:RegionAttachment = slot.attachment as RegionAttachment; + if (!regionAttachment) continue; + + var wrapper:Sprite = wrappers[regionAttachment]; + if (!wrapper) { + var region:AtlasRegion = AtlasRegion(regionAttachment.rendererObject); + var regionHeight:Number = region.rotate ? region.width : region.height; + var regionData:BitmapData = region.rendererObject as BitmapData; + if (!regionData) { + var bitmapData:BitmapData = region.page.rendererObject as BitmapData; + var regionWidth:Number = region.rotate ? region.height : region.width; + regionData = new BitmapData(regionWidth, regionHeight); + regionData.copyPixels(bitmapData, new Rectangle(region.x, region.y, regionWidth, regionHeight), new Point()); + region.rendererObject = regionData; + } + + var bitmap:Bitmap = new Bitmap(regionData); + bitmap.smoothing = true; + + // Rotate and scale using default registration point (top left corner, y-down, CW) instead of image center. + bitmap.rotation = -regionAttachment.rotation; + bitmap.scaleX = regionAttachment.scaleX * (regionAttachment.width / region.width); + bitmap.scaleY = regionAttachment.scaleY * (regionAttachment.height / region.height); + + // Position using attachment translation, shifted as if scale and rotation were at image center. + var radians:Number = -regionAttachment.rotation * Math.PI / 180; + var cos:Number = Math.cos(radians); + var sin:Number = Math.sin(radians); + var shiftX:Number = -regionAttachment.width / 2 * regionAttachment.scaleX; + var shiftY:Number = -regionAttachment.height / 2 * regionAttachment.scaleY; + if (region.rotate) { + bitmap.rotation += 90; + shiftX += regionHeight * (regionAttachment.width / region.width); + } + bitmap.x = regionAttachment.x + shiftX * cos - shiftY * sin; + bitmap.y = -regionAttachment.y + shiftX * sin + shiftY * cos; + + // Use bone as registration point. + wrapper = new Sprite(); + wrapper.transform.colorTransform = new ColorTransform(); + wrapper.addChild(bitmap); + wrappers[regionAttachment] = wrapper; + } + + wrapper.blendMode = blendModes[slot.data.blendMode.ordinal]; + + var colorTransform:ColorTransform = wrapper.transform.colorTransform; + colorTransform.redMultiplier = skeleton.r * slot.r * regionAttachment.r; + colorTransform.greenMultiplier = skeleton.g * slot.g * regionAttachment.g; + colorTransform.blueMultiplier = skeleton.b * slot.b * regionAttachment.b; + colorTransform.alphaMultiplier = skeleton.a * slot.a * regionAttachment.a; + wrapper.transform.colorTransform = colorTransform; + + var bone:Bone = slot.bone; + var flipX:int = skeleton.flipX ? -1 : 1; + var flipY:int = skeleton.flipY ? -1 : 1; + + wrapper.x = bone.worldX; + wrapper.y = bone.worldY; + wrapper.rotation = bone.worldRotationX * flipX * flipY; + wrapper.scaleX = bone.worldScaleX * flipX; + wrapper.scaleY = bone.worldScaleY * flipY; + addChild(wrapper); + } + } + + public function get skeleton () : Skeleton { + return _skeleton; + } +} + } diff --git a/spine-c/include/spine/Animation.h b/spine-c/include/spine/Animation.h index 03304728ee..c30b510ad4 100644 --- a/spine-c/include/spine/Animation.h +++ b/spine-c/include/spine/Animation.h @@ -1,551 +1,550 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_ANIMATION_H_ -#define SPINE_ANIMATION_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spTimeline spTimeline; -struct spSkeleton; - -typedef struct spAnimation { - const char* const name; - float duration; - - int timelinesCount; - spTimeline** timelines; - -#ifdef __cplusplus - spAnimation() : - name(0), - duration(0), - timelinesCount(0), - timelines(0) { - } -#endif -} spAnimation; - -spAnimation* spAnimation_create (const char* name, int timelinesCount); -void spAnimation_dispose (spAnimation* self); - -/** Poses the skeleton at the specified time for this animation. - * @param lastTime The last time the animation was applied. - * @param events Any triggered events are added. May be null.*/ -void spAnimation_apply (const spAnimation* self, struct spSkeleton* skeleton, float lastTime, float time, int loop, - spEvent** events, int* eventsCount); - -/** Poses the skeleton at the specified time for this animation mixed with the current pose. - * @param lastTime The last time the animation was applied. - * @param events Any triggered events are added. May be null. - * @param alpha The amount of this animation that affects the current pose. */ -void spAnimation_mix (const spAnimation* self, struct spSkeleton* skeleton, float lastTime, float time, int loop, - spEvent** events, int* eventsCount, float alpha); - -#ifdef SPINE_SHORT_NAMES -typedef spAnimation Animation; -#define Animation_create(...) spAnimation_create(__VA_ARGS__) -#define Animation_dispose(...) spAnimation_dispose(__VA_ARGS__) -#define Animation_apply(...) spAnimation_apply(__VA_ARGS__) -#define Animation_mix(...) spAnimation_mix(__VA_ARGS__) -#endif - -/**/ - -typedef enum { - SP_TIMELINE_SCALE, - SP_TIMELINE_ROTATE, - SP_TIMELINE_TRANSLATE, - SP_TIMELINE_SHEAR, - SP_TIMELINE_COLOR, - SP_TIMELINE_ATTACHMENT, - SP_TIMELINE_EVENT, - SP_TIMELINE_DRAWORDER, - SP_TIMELINE_DEFORM, - SP_TIMELINE_IKCONSTRAINT, - SP_TIMELINE_TRANSFORMCONSTRAINT, - SP_TIMELINE_PATHCONSTRAINTPOSITION, - SP_TIMELINE_PATHCONSTRAINTSPACING, - SP_TIMELINE_PATHCONSTRAINTMIX -} spTimelineType; - -struct spTimeline { - const spTimelineType type; - const void* const vtable; - -#ifdef __cplusplus - spTimeline() : - type(SP_TIMELINE_SCALE), - vtable(0) { - } -#endif -}; - -void spTimeline_dispose (spTimeline* self); -void spTimeline_apply (const spTimeline* self, struct spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha); - -#ifdef SPINE_SHORT_NAMES -typedef spTimeline Timeline; -#define TIMELINE_SCALE SP_TIMELINE_SCALE -#define TIMELINE_ROTATE SP_TIMELINE_ROTATE -#define TIMELINE_TRANSLATE SP_TIMELINE_TRANSLATE -#define TIMELINE_COLOR SP_TIMELINE_COLOR -#define TIMELINE_ATTACHMENT SP_TIMELINE_ATTACHMENT -#define TIMELINE_EVENT SP_TIMELINE_EVENT -#define TIMELINE_DRAWORDER SP_TIMELINE_DRAWORDER -#define Timeline_dispose(...) spTimeline_dispose(__VA_ARGS__) -#define Timeline_apply(...) spTimeline_apply(__VA_ARGS__) -#endif - -/**/ - -typedef struct spCurveTimeline { - spTimeline super; - float* curves; /* type, x, y, ... */ - -#ifdef __cplusplus - spCurveTimeline() : - super(), - curves(0) { - } -#endif -} spCurveTimeline; - -void spCurveTimeline_setLinear (spCurveTimeline* self, int frameIndex); -void spCurveTimeline_setStepped (spCurveTimeline* self, int frameIndex); - -/* Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. - * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of - * the difference between the keyframe's values. */ -void spCurveTimeline_setCurve (spCurveTimeline* self, int frameIndex, float cx1, float cy1, float cx2, float cy2); -float spCurveTimeline_getCurvePercent (const spCurveTimeline* self, int frameIndex, float percent); - -#ifdef SPINE_SHORT_NAMES -typedef spCurveTimeline CurveTimeline; -#define CurveTimeline_setLinear(...) spCurveTimeline_setLinear(__VA_ARGS__) -#define CurveTimeline_setStepped(...) spCurveTimeline_setStepped(__VA_ARGS__) -#define CurveTimeline_setCurve(...) spCurveTimeline_setCurve(__VA_ARGS__) -#define CurveTimeline_getCurvePercent(...) spCurveTimeline_getCurvePercent(__VA_ARGS__) -#endif - -/**/ - -typedef struct spBaseTimeline { - spCurveTimeline super; - int const framesCount; - float* const frames; /* time, angle, ... for rotate. time, x, y, ... for translate and scale. */ - int boneIndex; - -#ifdef __cplusplus - spBaseTimeline() : - super(), - framesCount(0), - frames(0), - boneIndex(0) { - } -#endif -} spBaseTimeline; - -/**/ - -static const int ROTATE_ENTRIES = 2; - -typedef struct spBaseTimeline spRotateTimeline; - -spRotateTimeline* spRotateTimeline_create (int framesCount); - -void spRotateTimeline_setFrame (spRotateTimeline* self, int frameIndex, float time, float angle); - -#ifdef SPINE_SHORT_NAMES -typedef spRotateTimeline RotateTimeline; -#define RotateTimeline_create(...) spRotateTimeline_create(__VA_ARGS__) -#define RotateTimeline_setFrame(...) spRotateTimeline_setFrame(__VA_ARGS__) -#endif - -/**/ - -static const int TRANSLATE_ENTRIES = 3; - -typedef struct spBaseTimeline spTranslateTimeline; - -spTranslateTimeline* spTranslateTimeline_create (int framesCount); - -void spTranslateTimeline_setFrame (spTranslateTimeline* self, int frameIndex, float time, float x, float y); - -#ifdef SPINE_SHORT_NAMES -typedef spTranslateTimeline TranslateTimeline; -#define TranslateTimeline_create(...) spTranslateTimeline_create(__VA_ARGS__) -#define TranslateTimeline_setFrame(...) spTranslateTimeline_setFrame(__VA_ARGS__) -#endif - -/**/ - -typedef struct spBaseTimeline spScaleTimeline; - -spScaleTimeline* spScaleTimeline_create (int framesCount); - -void spScaleTimeline_setFrame (spScaleTimeline* self, int frameIndex, float time, float x, float y); - -#ifdef SPINE_SHORT_NAMES -typedef spScaleTimeline ScaleTimeline; -#define ScaleTimeline_create(...) spScaleTimeline_create(__VA_ARGS__) -#define ScaleTimeline_setFrame(...) spScaleTimeline_setFrame(__VA_ARGS__) -#endif - -/**/ - -typedef struct spBaseTimeline spShearTimeline; - -spShearTimeline* spShearTimeline_create (int framesCount); - -void spShearTimeline_setFrame (spShearTimeline* self, int frameIndex, float time, float x, float y); - -#ifdef SPINE_SHORT_NAMES -typedef spShearTimeline ShearTimeline; -#define ShearTimeline_create(...) spShearTimeline_create(__VA_ARGS__) -#define ShearTimeline_setFrame(...) spShearTimeline_setFrame(__VA_ARGS__) -#endif - -/**/ - -static const int COLOR_ENTRIES = 5; - -typedef struct spColorTimeline { - spCurveTimeline super; - int const framesCount; - float* const frames; /* time, r, g, b, a, ... */ - int slotIndex; - -#ifdef __cplusplus - spColorTimeline() : - super(), - framesCount(0), - frames(0), - slotIndex(0) { - } -#endif -} spColorTimeline; - -spColorTimeline* spColorTimeline_create (int framesCount); - -void spColorTimeline_setFrame (spColorTimeline* self, int frameIndex, float time, float r, float g, float b, float a); - -#ifdef SPINE_SHORT_NAMES -typedef spColorTimeline ColorTimeline; -#define ColorTimeline_create(...) spColorTimeline_create(__VA_ARGS__) -#define ColorTimeline_setFrame(...) spColorTimeline_setFrame(__VA_ARGS__) -#endif - -/**/ - -typedef struct spAttachmentTimeline { - spTimeline super; - int const framesCount; - float* const frames; /* time, ... */ - int slotIndex; - const char** const attachmentNames; - -#ifdef __cplusplus - spAttachmentTimeline() : - super(), - framesCount(0), - frames(0), - slotIndex(0), - attachmentNames(0) { - } -#endif -} spAttachmentTimeline; - -spAttachmentTimeline* spAttachmentTimeline_create (int framesCount); - -/* @param attachmentName May be 0. */ -void spAttachmentTimeline_setFrame (spAttachmentTimeline* self, int frameIndex, float time, const char* attachmentName); - -#ifdef SPINE_SHORT_NAMES -typedef spAttachmentTimeline AttachmentTimeline; -#define AttachmentTimeline_create(...) spAttachmentTimeline_create(__VA_ARGS__) -#define AttachmentTimeline_setFrame(...) spAttachmentTimeline_setFrame(__VA_ARGS__) -#endif - -/**/ - -typedef struct spEventTimeline { - spTimeline super; - int const framesCount; - float* const frames; /* time, ... */ - spEvent** const events; - -#ifdef __cplusplus - spEventTimeline() : - super(), - framesCount(0), - frames(0), - events(0) { - } -#endif -} spEventTimeline; - -spEventTimeline* spEventTimeline_create (int framesCount); - -void spEventTimeline_setFrame (spEventTimeline* self, int frameIndex, spEvent* event); - -#ifdef SPINE_SHORT_NAMES -typedef spEventTimeline EventTimeline; -#define EventTimeline_create(...) spEventTimeline_create(__VA_ARGS__) -#define EventTimeline_setFrame(...) spEventTimeline_setFrame(__VA_ARGS__) -#endif - -/**/ - -typedef struct spDrawOrderTimeline { - spTimeline super; - int const framesCount; - float* const frames; /* time, ... */ - const int** const drawOrders; - int const slotsCount; - -#ifdef __cplusplus - spDrawOrderTimeline() : - super(), - framesCount(0), - frames(0), - drawOrders(0), - slotsCount(0) { - } -#endif -} spDrawOrderTimeline; - -spDrawOrderTimeline* spDrawOrderTimeline_create (int framesCount, int slotsCount); - -void spDrawOrderTimeline_setFrame (spDrawOrderTimeline* self, int frameIndex, float time, const int* drawOrder); - -#ifdef SPINE_SHORT_NAMES -typedef spDrawOrderTimeline DrawOrderTimeline; -#define DrawOrderTimeline_create(...) spDrawOrderTimeline_create(__VA_ARGS__) -#define DrawOrderTimeline_setFrame(...) spDrawOrderTimeline_setFrame(__VA_ARGS__) -#endif - -/**/ - -typedef struct spDeformTimeline { - spCurveTimeline super; - int const framesCount; - float* const frames; /* time, ... */ - int const frameVerticesCount; - const float** const frameVertices; - int slotIndex; - spAttachment* attachment; - -#ifdef __cplusplus - spDeformTimeline() : - super(), - framesCount(0), - frames(0), - frameVerticesCount(0), - frameVertices(0), - slotIndex(0) { - } -#endif -} spDeformTimeline; - -spDeformTimeline* spDeformTimeline_create (int framesCount, int frameVerticesCount); - -void spDeformTimeline_setFrame (spDeformTimeline* self, int frameIndex, float time, float* vertices); - -#ifdef SPINE_SHORT_NAMES -typedef spDeformTimeline DeformTimeline; -#define DeformTimeline_create(...) spDeformTimeline_create(__VA_ARGS__) -#define DeformTimeline_setFrame(...) spDeformTimeline_setFrame(__VA_ARGS__) -#endif - -/**/ - -static const int IKCONSTRAINT_ENTRIES = 3; - -typedef struct spIkConstraintTimeline { - spCurveTimeline super; - int const framesCount; - float* const frames; /* time, mix, bendDirection, ... */ - int ikConstraintIndex; - -#ifdef __cplusplus - spIkConstraintTimeline() : - super(), - framesCount(0), - frames(0), - ikConstraintIndex(0) { - } -#endif -} spIkConstraintTimeline; - -spIkConstraintTimeline* spIkConstraintTimeline_create (int framesCount); - -void spIkConstraintTimeline_setFrame (spIkConstraintTimeline* self, int frameIndex, float time, float mix, int bendDirection); - -#ifdef SPINE_SHORT_NAMES -typedef spIkConstraintTimeline IkConstraintTimeline; -#define IkConstraintTimeline_create(...) spIkConstraintTimeline_create(__VA_ARGS__) -#define IkConstraintTimeline_setFrame(...) spIkConstraintTimeline_setFrame(__VA_ARGS__) -#endif - -/**/ - -static const int TRANSFORMCONSTRAINT_ENTRIES = 5; - -typedef struct spTransformConstraintTimeline { - spCurveTimeline super; - int const framesCount; - float* const frames; /* time, rotate mix, translate mix, scale mix, shear mix, ... */ - int transformConstraintIndex; - -#ifdef __cplusplus - spTransformConstraintTimeline() : - super(), - framesCount(0), - frames(0), - transformConstraintIndex(0) { - } -#endif -} spTransformConstraintTimeline; - -spTransformConstraintTimeline* spTransformConstraintTimeline_create (int framesCount); - -void spTransformConstraintTimeline_setFrame (spTransformConstraintTimeline* self, int frameIndex, float time, float rotateMix, float translateMix, float scaleMix, float shearMix); - -#ifdef SPINE_SHORT_NAMES -typedef spTransformConstraintTimeline TransformConstraintTimeline; -#define TransformConstraintTimeline_create(...) spTransformConstraintTimeline_create(__VA_ARGS__) -#define TransformConstraintTimeline_setFrame(...) spTransformConstraintTimeline_setFrame(__VA_ARGS__) -#endif - -/**/ - -static const int PATHCONSTRAINTPOSITION_ENTRIES = 2; - -typedef struct spPathConstraintPositionTimeline { - spCurveTimeline super; - int const framesCount; - float* const frames; /* time, rotate mix, translate mix, scale mix, shear mix, ... */ - int pathConstraintIndex; - -#ifdef __cplusplus - spPathConstraintPositionTimeline() : - super(), - framesCount(0), - frames(0), - pathConstraintIndex(0) { - } -#endif -} spPathConstraintPositionTimeline; - -spPathConstraintPositionTimeline* spPathConstraintPositionTimeline_create (int framesCount); - -void spPathConstraintPositionTimeline_setFrame (spPathConstraintPositionTimeline* self, int frameIndex, float time, float value); - -#ifdef SPINE_SHORT_NAMES -typedef spPathConstraintPositionTimeline PathConstraintPositionTimeline; -#define PathConstraintPositionTimeline_create(...) spPathConstraintPositionTimeline_create(__VA_ARGS__) -#define PathConstraintPositionTimeline_setFrame(...) spPathConstraintPositionTimeline_setFrame(__VA_ARGS__) -#endif - -/**/ - -static const int PATHCONSTRAINTSPACING_ENTRIES = 2; - -typedef struct spPathConstraintSpacingTimeline { - spCurveTimeline super; - int const framesCount; - float* const frames; /* time, rotate mix, translate mix, scale mix, shear mix, ... */ - int pathConstraintIndex; - -#ifdef __cplusplus - spPathConstraintSpacingTimeline() : - super(), - framesCount(0), - frames(0), - pathConstraintIndex(0) { - } -#endif -} spPathConstraintSpacingTimeline; - -spPathConstraintSpacingTimeline* spPathConstraintSpacingTimeline_create (int framesCount); - -void spPathConstraintSpacingTimeline_setFrame (spPathConstraintSpacingTimeline* self, int frameIndex, float time, float value); - -#ifdef SPINE_SHORT_NAMES -typedef spPathConstraintSpacingTimeline PathConstraintSpacingTimeline; -#define PathConstraintSpacingTimeline_create(...) spPathConstraintSpacingTimeline_create(__VA_ARGS__) -#define PathConstraintSpacingTimeline_setFrame(...) spPathConstraintSpacingTimeline_setFrame(__VA_ARGS__) -#endif - -/**/ - -static const int PATHCONSTRAINTMIX_ENTRIES = 3; - -typedef struct spPathConstraintMixTimeline { - spCurveTimeline super; - int const framesCount; - float* const frames; /* time, rotate mix, translate mix, scale mix, shear mix, ... */ - int pathConstraintIndex; - -#ifdef __cplusplus - spPathConstraintMixTimeline() : - super(), - framesCount(0), - frames(0), - pathConstraintIndex(0) { - } -#endif -} spPathConstraintMixTimeline; - -spPathConstraintMixTimeline* spPathConstraintMixTimeline_create (int framesCount); - -void spPathConstraintMixTimeline_setFrame (spPathConstraintMixTimeline* self, int frameIndex, float time, float rotateMix, float translateMix); - -#ifdef SPINE_SHORT_NAMES -typedef spPathConstraintMixTimeline PathConstraintMixTimeline; -#define PathConstraintMixTimeline_create(...) spPathConstraintMixTimeline_create(__VA_ARGS__) -#define PathConstraintMixTimeline_setFrame(...) spPathConstraintMixTimeline_setFrame(__VA_ARGS__) -#endif - -/**/ - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_ANIMATION_H_ +#define SPINE_ANIMATION_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spTimeline spTimeline; +struct spSkeleton; + +typedef struct spAnimation { + const char* const name; + float duration; + + int timelinesCount; + spTimeline** timelines; + +#ifdef __cplusplus + spAnimation() : + name(0), + duration(0), + timelinesCount(0), + timelines(0) { + } +#endif +} spAnimation; + +spAnimation* spAnimation_create (const char* name, int timelinesCount); +void spAnimation_dispose (spAnimation* self); + +/** Poses the skeleton at the specified time for this animation. + * @param lastTime The last time the animation was applied. + * @param events Any triggered events are added. May be null.*/ +void spAnimation_apply (const spAnimation* self, struct spSkeleton* skeleton, float lastTime, float time, int loop, + spEvent** events, int* eventsCount); + +/** Poses the skeleton at the specified time for this animation mixed with the current pose. + * @param lastTime The last time the animation was applied. + * @param events Any triggered events are added. May be null. + * @param alpha The amount of this animation that affects the current pose. */ +void spAnimation_mix (const spAnimation* self, struct spSkeleton* skeleton, float lastTime, float time, int loop, + spEvent** events, int* eventsCount, float alpha); + +#ifdef SPINE_SHORT_NAMES +typedef spAnimation Animation; +#define Animation_create(...) spAnimation_create(__VA_ARGS__) +#define Animation_dispose(...) spAnimation_dispose(__VA_ARGS__) +#define Animation_apply(...) spAnimation_apply(__VA_ARGS__) +#define Animation_mix(...) spAnimation_mix(__VA_ARGS__) +#endif + +/**/ + +typedef enum { + SP_TIMELINE_SCALE, + SP_TIMELINE_ROTATE, + SP_TIMELINE_TRANSLATE, + SP_TIMELINE_SHEAR, + SP_TIMELINE_COLOR, + SP_TIMELINE_ATTACHMENT, + SP_TIMELINE_EVENT, + SP_TIMELINE_DRAWORDER, + SP_TIMELINE_DEFORM, + SP_TIMELINE_IKCONSTRAINT, + SP_TIMELINE_TRANSFORMCONSTRAINT, + SP_TIMELINE_PATHCONSTRAINTPOSITION, + SP_TIMELINE_PATHCONSTRAINTSPACING, + SP_TIMELINE_PATHCONSTRAINTMIX +} spTimelineType; + +struct spTimeline { + const spTimelineType type; + const void* const vtable; + +#ifdef __cplusplus + spTimeline() : + type(SP_TIMELINE_SCALE), + vtable(0) { + } +#endif +}; + +void spTimeline_dispose (spTimeline* self); +void spTimeline_apply (const spTimeline* self, struct spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, + int* eventsCount, float alpha); + +#ifdef SPINE_SHORT_NAMES +typedef spTimeline Timeline; +#define TIMELINE_SCALE SP_TIMELINE_SCALE +#define TIMELINE_ROTATE SP_TIMELINE_ROTATE +#define TIMELINE_TRANSLATE SP_TIMELINE_TRANSLATE +#define TIMELINE_COLOR SP_TIMELINE_COLOR +#define TIMELINE_ATTACHMENT SP_TIMELINE_ATTACHMENT +#define TIMELINE_EVENT SP_TIMELINE_EVENT +#define TIMELINE_DRAWORDER SP_TIMELINE_DRAWORDER +#define Timeline_dispose(...) spTimeline_dispose(__VA_ARGS__) +#define Timeline_apply(...) spTimeline_apply(__VA_ARGS__) +#endif + +/**/ + +typedef struct spCurveTimeline { + spTimeline super; + float* curves; /* type, x, y, ... */ + +#ifdef __cplusplus + spCurveTimeline() : + super(), + curves(0) { + } +#endif +} spCurveTimeline; + +void spCurveTimeline_setLinear (spCurveTimeline* self, int frameIndex); +void spCurveTimeline_setStepped (spCurveTimeline* self, int frameIndex); + +/* Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. + * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of + * the difference between the keyframe's values. */ +void spCurveTimeline_setCurve (spCurveTimeline* self, int frameIndex, float cx1, float cy1, float cx2, float cy2); +float spCurveTimeline_getCurvePercent (const spCurveTimeline* self, int frameIndex, float percent); + +#ifdef SPINE_SHORT_NAMES +typedef spCurveTimeline CurveTimeline; +#define CurveTimeline_setLinear(...) spCurveTimeline_setLinear(__VA_ARGS__) +#define CurveTimeline_setStepped(...) spCurveTimeline_setStepped(__VA_ARGS__) +#define CurveTimeline_setCurve(...) spCurveTimeline_setCurve(__VA_ARGS__) +#define CurveTimeline_getCurvePercent(...) spCurveTimeline_getCurvePercent(__VA_ARGS__) +#endif + +/**/ + +typedef struct spBaseTimeline { + spCurveTimeline super; + int const framesCount; + float* const frames; /* time, angle, ... for rotate. time, x, y, ... for translate and scale. */ + int boneIndex; + +#ifdef __cplusplus + spBaseTimeline() : + super(), + framesCount(0), + frames(0), + boneIndex(0) { + } +#endif +} spBaseTimeline; + +/**/ + +static const int ROTATE_ENTRIES = 2; + +typedef struct spBaseTimeline spRotateTimeline; + +spRotateTimeline* spRotateTimeline_create (int framesCount); + +void spRotateTimeline_setFrame (spRotateTimeline* self, int frameIndex, float time, float angle); + +#ifdef SPINE_SHORT_NAMES +typedef spRotateTimeline RotateTimeline; +#define RotateTimeline_create(...) spRotateTimeline_create(__VA_ARGS__) +#define RotateTimeline_setFrame(...) spRotateTimeline_setFrame(__VA_ARGS__) +#endif + +/**/ + +static const int TRANSLATE_ENTRIES = 3; + +typedef struct spBaseTimeline spTranslateTimeline; + +spTranslateTimeline* spTranslateTimeline_create (int framesCount); + +void spTranslateTimeline_setFrame (spTranslateTimeline* self, int frameIndex, float time, float x, float y); + +#ifdef SPINE_SHORT_NAMES +typedef spTranslateTimeline TranslateTimeline; +#define TranslateTimeline_create(...) spTranslateTimeline_create(__VA_ARGS__) +#define TranslateTimeline_setFrame(...) spTranslateTimeline_setFrame(__VA_ARGS__) +#endif + +/**/ + +typedef struct spBaseTimeline spScaleTimeline; + +spScaleTimeline* spScaleTimeline_create (int framesCount); + +void spScaleTimeline_setFrame (spScaleTimeline* self, int frameIndex, float time, float x, float y); + +#ifdef SPINE_SHORT_NAMES +typedef spScaleTimeline ScaleTimeline; +#define ScaleTimeline_create(...) spScaleTimeline_create(__VA_ARGS__) +#define ScaleTimeline_setFrame(...) spScaleTimeline_setFrame(__VA_ARGS__) +#endif + +/**/ + +typedef struct spBaseTimeline spShearTimeline; + +spShearTimeline* spShearTimeline_create (int framesCount); + +void spShearTimeline_setFrame (spShearTimeline* self, int frameIndex, float time, float x, float y); + +#ifdef SPINE_SHORT_NAMES +typedef spShearTimeline ShearTimeline; +#define ShearTimeline_create(...) spShearTimeline_create(__VA_ARGS__) +#define ShearTimeline_setFrame(...) spShearTimeline_setFrame(__VA_ARGS__) +#endif + +/**/ + +static const int COLOR_ENTRIES = 5; + +typedef struct spColorTimeline { + spCurveTimeline super; + int const framesCount; + float* const frames; /* time, r, g, b, a, ... */ + int slotIndex; + +#ifdef __cplusplus + spColorTimeline() : + super(), + framesCount(0), + frames(0), + slotIndex(0) { + } +#endif +} spColorTimeline; + +spColorTimeline* spColorTimeline_create (int framesCount); + +void spColorTimeline_setFrame (spColorTimeline* self, int frameIndex, float time, float r, float g, float b, float a); + +#ifdef SPINE_SHORT_NAMES +typedef spColorTimeline ColorTimeline; +#define ColorTimeline_create(...) spColorTimeline_create(__VA_ARGS__) +#define ColorTimeline_setFrame(...) spColorTimeline_setFrame(__VA_ARGS__) +#endif + +/**/ + +typedef struct spAttachmentTimeline { + spTimeline super; + int const framesCount; + float* const frames; /* time, ... */ + int slotIndex; + const char** const attachmentNames; + +#ifdef __cplusplus + spAttachmentTimeline() : + super(), + framesCount(0), + frames(0), + slotIndex(0), + attachmentNames(0) { + } +#endif +} spAttachmentTimeline; + +spAttachmentTimeline* spAttachmentTimeline_create (int framesCount); + +/* @param attachmentName May be 0. */ +void spAttachmentTimeline_setFrame (spAttachmentTimeline* self, int frameIndex, float time, const char* attachmentName); + +#ifdef SPINE_SHORT_NAMES +typedef spAttachmentTimeline AttachmentTimeline; +#define AttachmentTimeline_create(...) spAttachmentTimeline_create(__VA_ARGS__) +#define AttachmentTimeline_setFrame(...) spAttachmentTimeline_setFrame(__VA_ARGS__) +#endif + +/**/ + +typedef struct spEventTimeline { + spTimeline super; + int const framesCount; + float* const frames; /* time, ... */ + spEvent** const events; + +#ifdef __cplusplus + spEventTimeline() : + super(), + framesCount(0), + frames(0), + events(0) { + } +#endif +} spEventTimeline; + +spEventTimeline* spEventTimeline_create (int framesCount); + +void spEventTimeline_setFrame (spEventTimeline* self, int frameIndex, spEvent* event); + +#ifdef SPINE_SHORT_NAMES +typedef spEventTimeline EventTimeline; +#define EventTimeline_create(...) spEventTimeline_create(__VA_ARGS__) +#define EventTimeline_setFrame(...) spEventTimeline_setFrame(__VA_ARGS__) +#endif + +/**/ + +typedef struct spDrawOrderTimeline { + spTimeline super; + int const framesCount; + float* const frames; /* time, ... */ + const int** const drawOrders; + int const slotsCount; + +#ifdef __cplusplus + spDrawOrderTimeline() : + super(), + framesCount(0), + frames(0), + drawOrders(0), + slotsCount(0) { + } +#endif +} spDrawOrderTimeline; + +spDrawOrderTimeline* spDrawOrderTimeline_create (int framesCount, int slotsCount); + +void spDrawOrderTimeline_setFrame (spDrawOrderTimeline* self, int frameIndex, float time, const int* drawOrder); + +#ifdef SPINE_SHORT_NAMES +typedef spDrawOrderTimeline DrawOrderTimeline; +#define DrawOrderTimeline_create(...) spDrawOrderTimeline_create(__VA_ARGS__) +#define DrawOrderTimeline_setFrame(...) spDrawOrderTimeline_setFrame(__VA_ARGS__) +#endif + +/**/ + +typedef struct spDeformTimeline { + spCurveTimeline super; + int const framesCount; + float* const frames; /* time, ... */ + int const frameVerticesCount; + const float** const frameVertices; + int slotIndex; + spAttachment* attachment; + +#ifdef __cplusplus + spDeformTimeline() : + super(), + framesCount(0), + frames(0), + frameVerticesCount(0), + frameVertices(0), + slotIndex(0) { + } +#endif +} spDeformTimeline; + +spDeformTimeline* spDeformTimeline_create (int framesCount, int frameVerticesCount); + +void spDeformTimeline_setFrame (spDeformTimeline* self, int frameIndex, float time, float* vertices); + +#ifdef SPINE_SHORT_NAMES +typedef spDeformTimeline DeformTimeline; +#define DeformTimeline_create(...) spDeformTimeline_create(__VA_ARGS__) +#define DeformTimeline_setFrame(...) spDeformTimeline_setFrame(__VA_ARGS__) +#endif + +/**/ + +static const int IKCONSTRAINT_ENTRIES = 3; + +typedef struct spIkConstraintTimeline { + spCurveTimeline super; + int const framesCount; + float* const frames; /* time, mix, bendDirection, ... */ + int ikConstraintIndex; + +#ifdef __cplusplus + spIkConstraintTimeline() : + super(), + framesCount(0), + frames(0), + ikConstraintIndex(0) { + } +#endif +} spIkConstraintTimeline; + +spIkConstraintTimeline* spIkConstraintTimeline_create (int framesCount); + +void spIkConstraintTimeline_setFrame (spIkConstraintTimeline* self, int frameIndex, float time, float mix, int bendDirection); + +#ifdef SPINE_SHORT_NAMES +typedef spIkConstraintTimeline IkConstraintTimeline; +#define IkConstraintTimeline_create(...) spIkConstraintTimeline_create(__VA_ARGS__) +#define IkConstraintTimeline_setFrame(...) spIkConstraintTimeline_setFrame(__VA_ARGS__) +#endif + +/**/ + +static const int TRANSFORMCONSTRAINT_ENTRIES = 5; + +typedef struct spTransformConstraintTimeline { + spCurveTimeline super; + int const framesCount; + float* const frames; /* time, rotate mix, translate mix, scale mix, shear mix, ... */ + int transformConstraintIndex; + +#ifdef __cplusplus + spTransformConstraintTimeline() : + super(), + framesCount(0), + frames(0), + transformConstraintIndex(0) { + } +#endif +} spTransformConstraintTimeline; + +spTransformConstraintTimeline* spTransformConstraintTimeline_create (int framesCount); + +void spTransformConstraintTimeline_setFrame (spTransformConstraintTimeline* self, int frameIndex, float time, float rotateMix, float translateMix, float scaleMix, float shearMix); + +#ifdef SPINE_SHORT_NAMES +typedef spTransformConstraintTimeline TransformConstraintTimeline; +#define TransformConstraintTimeline_create(...) spTransformConstraintTimeline_create(__VA_ARGS__) +#define TransformConstraintTimeline_setFrame(...) spTransformConstraintTimeline_setFrame(__VA_ARGS__) +#endif + +/**/ + +static const int PATHCONSTRAINTPOSITION_ENTRIES = 2; + +typedef struct spPathConstraintPositionTimeline { + spCurveTimeline super; + int const framesCount; + float* const frames; /* time, rotate mix, translate mix, scale mix, shear mix, ... */ + int pathConstraintIndex; + +#ifdef __cplusplus + spPathConstraintPositionTimeline() : + super(), + framesCount(0), + frames(0), + pathConstraintIndex(0) { + } +#endif +} spPathConstraintPositionTimeline; + +spPathConstraintPositionTimeline* spPathConstraintPositionTimeline_create (int framesCount); + +void spPathConstraintPositionTimeline_setFrame (spPathConstraintPositionTimeline* self, int frameIndex, float time, float value); + +#ifdef SPINE_SHORT_NAMES +typedef spPathConstraintPositionTimeline PathConstraintPositionTimeline; +#define PathConstraintPositionTimeline_create(...) spPathConstraintPositionTimeline_create(__VA_ARGS__) +#define PathConstraintPositionTimeline_setFrame(...) spPathConstraintPositionTimeline_setFrame(__VA_ARGS__) +#endif + +/**/ + +static const int PATHCONSTRAINTSPACING_ENTRIES = 2; + +typedef struct spPathConstraintSpacingTimeline { + spCurveTimeline super; + int const framesCount; + float* const frames; /* time, rotate mix, translate mix, scale mix, shear mix, ... */ + int pathConstraintIndex; + +#ifdef __cplusplus + spPathConstraintSpacingTimeline() : + super(), + framesCount(0), + frames(0), + pathConstraintIndex(0) { + } +#endif +} spPathConstraintSpacingTimeline; + +spPathConstraintSpacingTimeline* spPathConstraintSpacingTimeline_create (int framesCount); + +void spPathConstraintSpacingTimeline_setFrame (spPathConstraintSpacingTimeline* self, int frameIndex, float time, float value); + +#ifdef SPINE_SHORT_NAMES +typedef spPathConstraintSpacingTimeline PathConstraintSpacingTimeline; +#define PathConstraintSpacingTimeline_create(...) spPathConstraintSpacingTimeline_create(__VA_ARGS__) +#define PathConstraintSpacingTimeline_setFrame(...) spPathConstraintSpacingTimeline_setFrame(__VA_ARGS__) +#endif + +/**/ + +static const int PATHCONSTRAINTMIX_ENTRIES = 3; + +typedef struct spPathConstraintMixTimeline { + spCurveTimeline super; + int const framesCount; + float* const frames; /* time, rotate mix, translate mix, scale mix, shear mix, ... */ + int pathConstraintIndex; + +#ifdef __cplusplus + spPathConstraintMixTimeline() : + super(), + framesCount(0), + frames(0), + pathConstraintIndex(0) { + } +#endif +} spPathConstraintMixTimeline; + +spPathConstraintMixTimeline* spPathConstraintMixTimeline_create (int framesCount); + +void spPathConstraintMixTimeline_setFrame (spPathConstraintMixTimeline* self, int frameIndex, float time, float rotateMix, float translateMix); + +#ifdef SPINE_SHORT_NAMES +typedef spPathConstraintMixTimeline PathConstraintMixTimeline; +#define PathConstraintMixTimeline_create(...) spPathConstraintMixTimeline_create(__VA_ARGS__) +#define PathConstraintMixTimeline_setFrame(...) spPathConstraintMixTimeline_setFrame(__VA_ARGS__) +#endif + +/**/ + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_ANIMATION_H_ */ diff --git a/spine-c/include/spine/AnimationState.h b/spine-c/include/spine/AnimationState.h index 5bc17929a1..ca504ab919 100644 --- a/spine-c/include/spine/AnimationState.h +++ b/spine-c/include/spine/AnimationState.h @@ -1,152 +1,151 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_ANIMATIONSTATE_H_ -#define SPINE_ANIMATIONSTATE_H_ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - SP_ANIMATION_START, SP_ANIMATION_END, SP_ANIMATION_COMPLETE, SP_ANIMATION_EVENT -} spEventType; - -typedef struct spAnimationState spAnimationState; - -typedef void (*spAnimationStateListener) (spAnimationState* state, int trackIndex, spEventType type, spEvent* event, - int loopCount); - -typedef struct spTrackEntry spTrackEntry; -struct spTrackEntry { - spAnimationState* const state; - spTrackEntry* next; - spTrackEntry* previous; - spAnimation* animation; - int/*bool*/loop; - float delay, time, lastTime, endTime, timeScale; - spAnimationStateListener listener; - float mixTime, mixDuration, mix; - - void* rendererObject; - -#ifdef __cplusplus - spTrackEntry() : - state(0), - next(0), - previous(0), - animation(0), - loop(0), - delay(0), time(0), lastTime(0), endTime(0), timeScale(0), - listener(0), - mixTime(0), mixDuration(0), mix(0), - rendererObject(0) { - } -#endif -}; - -struct spAnimationState { - spAnimationStateData* const data; - float timeScale; - spAnimationStateListener listener; - - int tracksCount; - spTrackEntry** tracks; - - void* rendererObject; - -#ifdef __cplusplus - spAnimationState() : - data(0), - timeScale(0), - listener(0), - tracksCount(0), - tracks(0), - rendererObject(0) { - } -#endif -}; - -/* @param data May be 0 for no mixing. */ -spAnimationState* spAnimationState_create (spAnimationStateData* data); -void spAnimationState_dispose (spAnimationState* self); - -void spAnimationState_update (spAnimationState* self, float delta); -void spAnimationState_apply (spAnimationState* self, struct spSkeleton* skeleton); - -void spAnimationState_clearTracks (spAnimationState* self); -void spAnimationState_clearTrack (spAnimationState* self, int trackIndex); - -/** Set the current animation. Any queued animations are cleared. */ -spTrackEntry* spAnimationState_setAnimationByName (spAnimationState* self, int trackIndex, const char* animationName, - int/*bool*/loop); -spTrackEntry* spAnimationState_setAnimation (spAnimationState* self, int trackIndex, spAnimation* animation, int/*bool*/loop); - -/** Adds an animation to be played delay seconds after the current or last queued animation, taking into account any mix - * duration. */ -spTrackEntry* spAnimationState_addAnimationByName (spAnimationState* self, int trackIndex, const char* animationName, - int/*bool*/loop, float delay); -spTrackEntry* spAnimationState_addAnimation (spAnimationState* self, int trackIndex, spAnimation* animation, int/*bool*/loop, - float delay); - -spTrackEntry* spAnimationState_getCurrent (spAnimationState* self, int trackIndex); - -#ifdef SPINE_SHORT_NAMES -typedef spEventType EventType; -#define ANIMATION_START SP_ANIMATION_START -#define ANIMATION_END SP_ANIMATION_END -#define ANIMATION_COMPLETE SP_ANIMATION_COMPLETE -#define ANIMATION_EVENT SP_ANIMATION_EVENT -typedef spAnimationStateListener AnimationStateListener; -typedef spTrackEntry TrackEntry; -typedef spAnimationState AnimationState; -#define AnimationState_create(...) spAnimationState_create(__VA_ARGS__) -#define AnimationState_dispose(...) spAnimationState_dispose(__VA_ARGS__) -#define AnimationState_update(...) spAnimationState_update(__VA_ARGS__) -#define AnimationState_apply(...) spAnimationState_apply(__VA_ARGS__) -#define AnimationState_clearTracks(...) spAnimationState_clearTracks(__VA_ARGS__) -#define AnimationState_clearTrack(...) spAnimationState_clearTrack(__VA_ARGS__) -#define AnimationState_setAnimationByName(...) spAnimationState_setAnimationByName(__VA_ARGS__) -#define AnimationState_setAnimation(...) spAnimationState_setAnimation(__VA_ARGS__) -#define AnimationState_addAnimationByName(...) spAnimationState_addAnimationByName(__VA_ARGS__) -#define AnimationState_addAnimation(...) spAnimationState_addAnimation(__VA_ARGS__) -#define AnimationState_getCurrent(...) spAnimationState_getCurrent(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_ANIMATIONSTATE_H_ +#define SPINE_ANIMATIONSTATE_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + SP_ANIMATION_START, SP_ANIMATION_END, SP_ANIMATION_COMPLETE, SP_ANIMATION_EVENT +} spEventType; + +typedef struct spAnimationState spAnimationState; + +typedef void (*spAnimationStateListener) (spAnimationState* state, int trackIndex, spEventType type, spEvent* event, + int loopCount); + +typedef struct spTrackEntry spTrackEntry; +struct spTrackEntry { + spAnimationState* const state; + spTrackEntry* next; + spTrackEntry* previous; + spAnimation* animation; + int/*bool*/loop; + float delay, time, lastTime, endTime, timeScale; + spAnimationStateListener listener; + float mixTime, mixDuration, mix; + + void* rendererObject; + +#ifdef __cplusplus + spTrackEntry() : + state(0), + next(0), + previous(0), + animation(0), + loop(0), + delay(0), time(0), lastTime(0), endTime(0), timeScale(0), + listener(0), + mixTime(0), mixDuration(0), mix(0), + rendererObject(0) { + } +#endif +}; + +struct spAnimationState { + spAnimationStateData* const data; + float timeScale; + spAnimationStateListener listener; + + int tracksCount; + spTrackEntry** tracks; + + void* rendererObject; + +#ifdef __cplusplus + spAnimationState() : + data(0), + timeScale(0), + listener(0), + tracksCount(0), + tracks(0), + rendererObject(0) { + } +#endif +}; + +/* @param data May be 0 for no mixing. */ +spAnimationState* spAnimationState_create (spAnimationStateData* data); +void spAnimationState_dispose (spAnimationState* self); + +void spAnimationState_update (spAnimationState* self, float delta); +void spAnimationState_apply (spAnimationState* self, struct spSkeleton* skeleton); + +void spAnimationState_clearTracks (spAnimationState* self); +void spAnimationState_clearTrack (spAnimationState* self, int trackIndex); + +/** Set the current animation. Any queued animations are cleared. */ +spTrackEntry* spAnimationState_setAnimationByName (spAnimationState* self, int trackIndex, const char* animationName, + int/*bool*/loop); +spTrackEntry* spAnimationState_setAnimation (spAnimationState* self, int trackIndex, spAnimation* animation, int/*bool*/loop); + +/** Adds an animation to be played delay seconds after the current or last queued animation, taking into account any mix + * duration. */ +spTrackEntry* spAnimationState_addAnimationByName (spAnimationState* self, int trackIndex, const char* animationName, + int/*bool*/loop, float delay); +spTrackEntry* spAnimationState_addAnimation (spAnimationState* self, int trackIndex, spAnimation* animation, int/*bool*/loop, + float delay); + +spTrackEntry* spAnimationState_getCurrent (spAnimationState* self, int trackIndex); + +#ifdef SPINE_SHORT_NAMES +typedef spEventType EventType; +#define ANIMATION_START SP_ANIMATION_START +#define ANIMATION_END SP_ANIMATION_END +#define ANIMATION_COMPLETE SP_ANIMATION_COMPLETE +#define ANIMATION_EVENT SP_ANIMATION_EVENT +typedef spAnimationStateListener AnimationStateListener; +typedef spTrackEntry TrackEntry; +typedef spAnimationState AnimationState; +#define AnimationState_create(...) spAnimationState_create(__VA_ARGS__) +#define AnimationState_dispose(...) spAnimationState_dispose(__VA_ARGS__) +#define AnimationState_update(...) spAnimationState_update(__VA_ARGS__) +#define AnimationState_apply(...) spAnimationState_apply(__VA_ARGS__) +#define AnimationState_clearTracks(...) spAnimationState_clearTracks(__VA_ARGS__) +#define AnimationState_clearTrack(...) spAnimationState_clearTrack(__VA_ARGS__) +#define AnimationState_setAnimationByName(...) spAnimationState_setAnimationByName(__VA_ARGS__) +#define AnimationState_setAnimation(...) spAnimationState_setAnimation(__VA_ARGS__) +#define AnimationState_addAnimationByName(...) spAnimationState_addAnimationByName(__VA_ARGS__) +#define AnimationState_addAnimation(...) spAnimationState_addAnimation(__VA_ARGS__) +#define AnimationState_getCurrent(...) spAnimationState_getCurrent(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_ANIMATIONSTATE_H_ */ diff --git a/spine-c/include/spine/AnimationStateData.h b/spine-c/include/spine/AnimationStateData.h index 1345384e72..45d4ebe22f 100644 --- a/spine-c/include/spine/AnimationStateData.h +++ b/spine-c/include/spine/AnimationStateData.h @@ -1,77 +1,76 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_ANIMATIONSTATEDATA_H_ -#define SPINE_ANIMATIONSTATEDATA_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spAnimationStateData { - spSkeletonData* const skeletonData; - float defaultMix; - const void* const entries; - -#ifdef __cplusplus - spAnimationStateData() : - skeletonData(0), - defaultMix(0), - entries(0) { - } -#endif -} spAnimationStateData; - -spAnimationStateData* spAnimationStateData_create (spSkeletonData* skeletonData); -void spAnimationStateData_dispose (spAnimationStateData* self); - -void spAnimationStateData_setMixByName (spAnimationStateData* self, const char* fromName, const char* toName, float duration); -void spAnimationStateData_setMix (spAnimationStateData* self, spAnimation* from, spAnimation* to, float duration); -/* Returns 0 if there is no mixing between the animations. */ -float spAnimationStateData_getMix (spAnimationStateData* self, spAnimation* from, spAnimation* to); - -#ifdef SPINE_SHORT_NAMES -typedef spAnimationStateData AnimationStateData; -#define AnimationStateData_create(...) spAnimationStateData_create(__VA_ARGS__) -#define AnimationStateData_dispose(...) spAnimationStateData_dispose(__VA_ARGS__) -#define AnimationStateData_setMixByName(...) spAnimationStateData_setMixByName(__VA_ARGS__) -#define AnimationStateData_setMix(...) spAnimationStateData_setMix(__VA_ARGS__) -#define AnimationStateData_getMix(...) spAnimationStateData_getMix(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_ANIMATIONSTATEDATA_H_ +#define SPINE_ANIMATIONSTATEDATA_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spAnimationStateData { + spSkeletonData* const skeletonData; + float defaultMix; + const void* const entries; + +#ifdef __cplusplus + spAnimationStateData() : + skeletonData(0), + defaultMix(0), + entries(0) { + } +#endif +} spAnimationStateData; + +spAnimationStateData* spAnimationStateData_create (spSkeletonData* skeletonData); +void spAnimationStateData_dispose (spAnimationStateData* self); + +void spAnimationStateData_setMixByName (spAnimationStateData* self, const char* fromName, const char* toName, float duration); +void spAnimationStateData_setMix (spAnimationStateData* self, spAnimation* from, spAnimation* to, float duration); +/* Returns 0 if there is no mixing between the animations. */ +float spAnimationStateData_getMix (spAnimationStateData* self, spAnimation* from, spAnimation* to); + +#ifdef SPINE_SHORT_NAMES +typedef spAnimationStateData AnimationStateData; +#define AnimationStateData_create(...) spAnimationStateData_create(__VA_ARGS__) +#define AnimationStateData_dispose(...) spAnimationStateData_dispose(__VA_ARGS__) +#define AnimationStateData_setMixByName(...) spAnimationStateData_setMixByName(__VA_ARGS__) +#define AnimationStateData_setMix(...) spAnimationStateData_setMix(__VA_ARGS__) +#define AnimationStateData_getMix(...) spAnimationStateData_getMix(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_ANIMATIONSTATEDATA_H_ */ diff --git a/spine-c/include/spine/Atlas.h b/spine-c/include/spine/Atlas.h index ffb47322a2..563173b7c5 100644 --- a/spine-c/include/spine/Atlas.h +++ b/spine-c/include/spine/Atlas.h @@ -1,173 +1,172 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_ATLAS_H_ -#define SPINE_ATLAS_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spAtlas spAtlas; - -typedef enum { - SP_ATLAS_UNKNOWN_FORMAT, - SP_ATLAS_ALPHA, - SP_ATLAS_INTENSITY, - SP_ATLAS_LUMINANCE_ALPHA, - SP_ATLAS_RGB565, - SP_ATLAS_RGBA4444, - SP_ATLAS_RGB888, - SP_ATLAS_RGBA8888 -} spAtlasFormat; - -typedef enum { - SP_ATLAS_UNKNOWN_FILTER, - SP_ATLAS_NEAREST, - SP_ATLAS_LINEAR, - SP_ATLAS_MIPMAP, - SP_ATLAS_MIPMAP_NEAREST_NEAREST, - SP_ATLAS_MIPMAP_LINEAR_NEAREST, - SP_ATLAS_MIPMAP_NEAREST_LINEAR, - SP_ATLAS_MIPMAP_LINEAR_LINEAR -} spAtlasFilter; - -typedef enum { - SP_ATLAS_MIRROREDREPEAT, - SP_ATLAS_CLAMPTOEDGE, - SP_ATLAS_REPEAT -} spAtlasWrap; - -typedef struct spAtlasPage spAtlasPage; -struct spAtlasPage { - const spAtlas* atlas; - const char* name; - spAtlasFormat format; - spAtlasFilter minFilter, magFilter; - spAtlasWrap uWrap, vWrap; - - void* rendererObject; - int width, height; - - spAtlasPage* next; -}; - -spAtlasPage* spAtlasPage_create (spAtlas* atlas, const char* name); -void spAtlasPage_dispose (spAtlasPage* self); - -#ifdef SPINE_SHORT_NAMES -typedef spAtlasFormat AtlasFormat; -#define ATLAS_UNKNOWN_FORMAT SP_ATLAS_UNKNOWN_FORMAT -#define ATLAS_ALPHA SP_ATLAS_ALPHA -#define ATLAS_INTENSITY SP_ATLAS_INTENSITY -#define ATLAS_LUMINANCE_ALPHA SP_ATLAS_LUMINANCE_ALPHA -#define ATLAS_RGB565 SP_ATLAS_RGB565 -#define ATLAS_RGBA4444 SP_ATLAS_RGBA4444 -#define ATLAS_RGB888 SP_ATLAS_RGB888 -#define ATLAS_RGBA8888 SP_ATLAS_RGBA8888 -typedef spAtlasFilter AtlasFilter; -#define ATLAS_UNKNOWN_FILTER SP_ATLAS_UNKNOWN_FILTER -#define ATLAS_NEAREST SP_ATLAS_NEAREST -#define ATLAS_LINEAR SP_ATLAS_LINEAR -#define ATLAS_MIPMAP SP_ATLAS_MIPMAP -#define ATLAS_MIPMAP_NEAREST_NEAREST SP_ATLAS_MIPMAP_NEAREST_NEAREST -#define ATLAS_MIPMAP_LINEAR_NEAREST SP_ATLAS_MIPMAP_LINEAR_NEAREST -#define ATLAS_MIPMAP_NEAREST_LINEAR SP_ATLAS_MIPMAP_NEAREST_LINEAR -#define ATLAS_MIPMAP_LINEAR_LINEAR SP_ATLAS_MIPMAP_LINEAR_LINEAR -typedef spAtlasWrap AtlasWrap; -#define ATLAS_MIRROREDREPEAT SP_ATLAS_MIRROREDREPEAT -#define ATLAS_CLAMPTOEDGE SP_ATLAS_CLAMPTOEDGE -#define ATLAS_REPEAT SP_ATLAS_REPEAT -typedef spAtlasPage AtlasPage; -#define AtlasPage_create(...) spAtlasPage_create(__VA_ARGS__) -#define AtlasPage_dispose(...) spAtlasPage_dispose(__VA_ARGS__) -#endif - -/**/ - -typedef struct spAtlasRegion spAtlasRegion; -struct spAtlasRegion { - const char* name; - int x, y, width, height; - float u, v, u2, v2; - int offsetX, offsetY; - int originalWidth, originalHeight; - int index; - int/*bool*/rotate; - int/*bool*/flip; - int* splits; - int* pads; - - spAtlasPage* page; - - spAtlasRegion* next; -}; - -spAtlasRegion* spAtlasRegion_create (); -void spAtlasRegion_dispose (spAtlasRegion* self); - -#ifdef SPINE_SHORT_NAMES -typedef spAtlasRegion AtlasRegion; -#define AtlasRegion_create(...) spAtlasRegion_create(__VA_ARGS__) -#define AtlasRegion_dispose(...) spAtlasRegion_dispose(__VA_ARGS__) -#endif - -/**/ - -struct spAtlas { - spAtlasPage* pages; - spAtlasRegion* regions; - - void* rendererObject; -}; - -/* Image files referenced in the atlas file will be prefixed with dir. */ -spAtlas* spAtlas_create (const char* data, int length, const char* dir, void* rendererObject); -/* Image files referenced in the atlas file will be prefixed with the directory containing the atlas file. */ -spAtlas* spAtlas_createFromFile (const char* path, void* rendererObject); -void spAtlas_dispose (spAtlas* atlas); - -/* Returns 0 if the region was not found. */ -spAtlasRegion* spAtlas_findRegion (const spAtlas* self, const char* name); - -#ifdef SPINE_SHORT_NAMES -typedef spAtlas Atlas; -#define Atlas_create(...) spAtlas_create(__VA_ARGS__) -#define Atlas_createFromFile(...) spAtlas_createFromFile(__VA_ARGS__) -#define Atlas_dispose(...) spAtlas_dispose(__VA_ARGS__) -#define Atlas_findRegion(...) spAtlas_findRegion(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_ATLAS_H_ +#define SPINE_ATLAS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spAtlas spAtlas; + +typedef enum { + SP_ATLAS_UNKNOWN_FORMAT, + SP_ATLAS_ALPHA, + SP_ATLAS_INTENSITY, + SP_ATLAS_LUMINANCE_ALPHA, + SP_ATLAS_RGB565, + SP_ATLAS_RGBA4444, + SP_ATLAS_RGB888, + SP_ATLAS_RGBA8888 +} spAtlasFormat; + +typedef enum { + SP_ATLAS_UNKNOWN_FILTER, + SP_ATLAS_NEAREST, + SP_ATLAS_LINEAR, + SP_ATLAS_MIPMAP, + SP_ATLAS_MIPMAP_NEAREST_NEAREST, + SP_ATLAS_MIPMAP_LINEAR_NEAREST, + SP_ATLAS_MIPMAP_NEAREST_LINEAR, + SP_ATLAS_MIPMAP_LINEAR_LINEAR +} spAtlasFilter; + +typedef enum { + SP_ATLAS_MIRROREDREPEAT, + SP_ATLAS_CLAMPTOEDGE, + SP_ATLAS_REPEAT +} spAtlasWrap; + +typedef struct spAtlasPage spAtlasPage; +struct spAtlasPage { + const spAtlas* atlas; + const char* name; + spAtlasFormat format; + spAtlasFilter minFilter, magFilter; + spAtlasWrap uWrap, vWrap; + + void* rendererObject; + int width, height; + + spAtlasPage* next; +}; + +spAtlasPage* spAtlasPage_create (spAtlas* atlas, const char* name); +void spAtlasPage_dispose (spAtlasPage* self); + +#ifdef SPINE_SHORT_NAMES +typedef spAtlasFormat AtlasFormat; +#define ATLAS_UNKNOWN_FORMAT SP_ATLAS_UNKNOWN_FORMAT +#define ATLAS_ALPHA SP_ATLAS_ALPHA +#define ATLAS_INTENSITY SP_ATLAS_INTENSITY +#define ATLAS_LUMINANCE_ALPHA SP_ATLAS_LUMINANCE_ALPHA +#define ATLAS_RGB565 SP_ATLAS_RGB565 +#define ATLAS_RGBA4444 SP_ATLAS_RGBA4444 +#define ATLAS_RGB888 SP_ATLAS_RGB888 +#define ATLAS_RGBA8888 SP_ATLAS_RGBA8888 +typedef spAtlasFilter AtlasFilter; +#define ATLAS_UNKNOWN_FILTER SP_ATLAS_UNKNOWN_FILTER +#define ATLAS_NEAREST SP_ATLAS_NEAREST +#define ATLAS_LINEAR SP_ATLAS_LINEAR +#define ATLAS_MIPMAP SP_ATLAS_MIPMAP +#define ATLAS_MIPMAP_NEAREST_NEAREST SP_ATLAS_MIPMAP_NEAREST_NEAREST +#define ATLAS_MIPMAP_LINEAR_NEAREST SP_ATLAS_MIPMAP_LINEAR_NEAREST +#define ATLAS_MIPMAP_NEAREST_LINEAR SP_ATLAS_MIPMAP_NEAREST_LINEAR +#define ATLAS_MIPMAP_LINEAR_LINEAR SP_ATLAS_MIPMAP_LINEAR_LINEAR +typedef spAtlasWrap AtlasWrap; +#define ATLAS_MIRROREDREPEAT SP_ATLAS_MIRROREDREPEAT +#define ATLAS_CLAMPTOEDGE SP_ATLAS_CLAMPTOEDGE +#define ATLAS_REPEAT SP_ATLAS_REPEAT +typedef spAtlasPage AtlasPage; +#define AtlasPage_create(...) spAtlasPage_create(__VA_ARGS__) +#define AtlasPage_dispose(...) spAtlasPage_dispose(__VA_ARGS__) +#endif + +/**/ + +typedef struct spAtlasRegion spAtlasRegion; +struct spAtlasRegion { + const char* name; + int x, y, width, height; + float u, v, u2, v2; + int offsetX, offsetY; + int originalWidth, originalHeight; + int index; + int/*bool*/rotate; + int/*bool*/flip; + int* splits; + int* pads; + + spAtlasPage* page; + + spAtlasRegion* next; +}; + +spAtlasRegion* spAtlasRegion_create (); +void spAtlasRegion_dispose (spAtlasRegion* self); + +#ifdef SPINE_SHORT_NAMES +typedef spAtlasRegion AtlasRegion; +#define AtlasRegion_create(...) spAtlasRegion_create(__VA_ARGS__) +#define AtlasRegion_dispose(...) spAtlasRegion_dispose(__VA_ARGS__) +#endif + +/**/ + +struct spAtlas { + spAtlasPage* pages; + spAtlasRegion* regions; + + void* rendererObject; +}; + +/* Image files referenced in the atlas file will be prefixed with dir. */ +spAtlas* spAtlas_create (const char* data, int length, const char* dir, void* rendererObject); +/* Image files referenced in the atlas file will be prefixed with the directory containing the atlas file. */ +spAtlas* spAtlas_createFromFile (const char* path, void* rendererObject); +void spAtlas_dispose (spAtlas* atlas); + +/* Returns 0 if the region was not found. */ +spAtlasRegion* spAtlas_findRegion (const spAtlas* self, const char* name); + +#ifdef SPINE_SHORT_NAMES +typedef spAtlas Atlas; +#define Atlas_create(...) spAtlas_create(__VA_ARGS__) +#define Atlas_createFromFile(...) spAtlas_createFromFile(__VA_ARGS__) +#define Atlas_dispose(...) spAtlas_dispose(__VA_ARGS__) +#define Atlas_findRegion(...) spAtlas_findRegion(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_ATLAS_H_ */ diff --git a/spine-c/include/spine/AtlasAttachmentLoader.h b/spine-c/include/spine/AtlasAttachmentLoader.h index 1205c95170..324efe5a2e 100644 --- a/spine-c/include/spine/AtlasAttachmentLoader.h +++ b/spine-c/include/spine/AtlasAttachmentLoader.h @@ -1,58 +1,57 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_ATLASATTACHMENTLOADER_H_ -#define SPINE_ATLASATTACHMENTLOADER_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spAtlasAttachmentLoader { - spAttachmentLoader super; - spAtlas* atlas; -} spAtlasAttachmentLoader; - -spAtlasAttachmentLoader* spAtlasAttachmentLoader_create (spAtlas* atlas); - -#ifdef SPINE_SHORT_NAMES -typedef spAtlasAttachmentLoader AtlasAttachmentLoader; -#define AtlasAttachmentLoader_create(...) spAtlasAttachmentLoader_create(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_ATLASATTACHMENTLOADER_H_ +#define SPINE_ATLASATTACHMENTLOADER_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spAtlasAttachmentLoader { + spAttachmentLoader super; + spAtlas* atlas; +} spAtlasAttachmentLoader; + +spAtlasAttachmentLoader* spAtlasAttachmentLoader_create (spAtlas* atlas); + +#ifdef SPINE_SHORT_NAMES +typedef spAtlasAttachmentLoader AtlasAttachmentLoader; +#define AtlasAttachmentLoader_create(...) spAtlasAttachmentLoader_create(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_ATLASATTACHMENTLOADER_H_ */ diff --git a/spine-c/include/spine/Attachment.h b/spine-c/include/spine/Attachment.h index 84e9dc0fb2..3add5d7f64 100644 --- a/spine-c/include/spine/Attachment.h +++ b/spine-c/include/spine/Attachment.h @@ -1,80 +1,79 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_ATTACHMENT_H_ -#define SPINE_ATTACHMENT_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -struct spAttachmentLoader; - -typedef enum { - SP_ATTACHMENT_REGION, - SP_ATTACHMENT_BOUNDING_BOX, - SP_ATTACHMENT_MESH, - SP_ATTACHMENT_LINKED_MESH, - SP_ATTACHMENT_PATH -} spAttachmentType; - -typedef struct spAttachment { - const char* const name; - const spAttachmentType type; - const void* const vtable; - struct spAttachmentLoader* attachmentLoader; - -#ifdef __cplusplus - spAttachment() : - name(0), - type(SP_ATTACHMENT_REGION), - vtable(0) { - } -#endif -} spAttachment; - -void spAttachment_dispose (spAttachment* self); - -#ifdef SPINE_SHORT_NAMES -typedef spAttachmentType AttachmentType; -#define ATTACHMENT_REGION SP_ATTACHMENT_REGION -#define ATTACHMENT_BOUNDING_BOX SP_ATTACHMENT_BOUNDING_BOX -#define ATTACHMENT_MESH SP_ATTACHMENT_MESH -#define ATTACHMENT_LINKED_MESH SP_ATTACHMENT_LINKED_MESH -typedef spAttachment Attachment; -#define Attachment_dispose(...) spAttachment_dispose(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_ATTACHMENT_H_ +#define SPINE_ATTACHMENT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct spAttachmentLoader; + +typedef enum { + SP_ATTACHMENT_REGION, + SP_ATTACHMENT_BOUNDING_BOX, + SP_ATTACHMENT_MESH, + SP_ATTACHMENT_LINKED_MESH, + SP_ATTACHMENT_PATH +} spAttachmentType; + +typedef struct spAttachment { + const char* const name; + const spAttachmentType type; + const void* const vtable; + struct spAttachmentLoader* attachmentLoader; + +#ifdef __cplusplus + spAttachment() : + name(0), + type(SP_ATTACHMENT_REGION), + vtable(0) { + } +#endif +} spAttachment; + +void spAttachment_dispose (spAttachment* self); + +#ifdef SPINE_SHORT_NAMES +typedef spAttachmentType AttachmentType; +#define ATTACHMENT_REGION SP_ATTACHMENT_REGION +#define ATTACHMENT_BOUNDING_BOX SP_ATTACHMENT_BOUNDING_BOX +#define ATTACHMENT_MESH SP_ATTACHMENT_MESH +#define ATTACHMENT_LINKED_MESH SP_ATTACHMENT_LINKED_MESH +typedef spAttachment Attachment; +#define Attachment_dispose(...) spAttachment_dispose(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_ATTACHMENT_H_ */ diff --git a/spine-c/include/spine/AttachmentLoader.h b/spine-c/include/spine/AttachmentLoader.h index c1179ae8c2..31b7575c2c 100644 --- a/spine-c/include/spine/AttachmentLoader.h +++ b/spine-c/include/spine/AttachmentLoader.h @@ -1,79 +1,78 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_ATTACHMENTLOADER_H_ -#define SPINE_ATTACHMENTLOADER_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spAttachmentLoader { - const char* error1; - const char* error2; - - const void* const vtable; -#ifdef __cplusplus - spAttachmentLoader () : - error1(0), - error2(0), - vtable(0) { - } -#endif -} spAttachmentLoader; - -void spAttachmentLoader_dispose (spAttachmentLoader* self); - -/* Called to create each attachment. Returns 0 to not load an attachment. If 0 is returned and _spAttachmentLoader_setError was - * called, an error occurred. */ -spAttachment* spAttachmentLoader_createAttachment (spAttachmentLoader* self, spSkin* skin, spAttachmentType type, const char* name, - const char* path); -/* Called after the attachment has been fully configured. */ -void spAttachmentLoader_configureAttachment (spAttachmentLoader* self, spAttachment* attachment); -/* Called just before the attachment is disposed. This can release allocations made in spAttachmentLoader_configureAttachment. */ -void spAttachmentLoader_disposeAttachment (spAttachmentLoader* self, spAttachment* attachment); - -#ifdef SPINE_SHORT_NAMES -typedef spAttachmentLoader AttachmentLoader; -#define AttachmentLoader_dispose(...) spAttachmentLoader_dispose(__VA_ARGS__) -#define AttachmentLoader_createAttachment(...) spAttachmentLoader_createAttachment(__VA_ARGS__) -#define AttachmentLoader_configureAttachment(...) spAttachmentLoader_configureAttachment(__VA_ARGS__) -#define AttachmentLoader_disposeAttachment(...) spAttachmentLoader_disposeAttachment(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_ATTACHMENTLOADER_H_ +#define SPINE_ATTACHMENTLOADER_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spAttachmentLoader { + const char* error1; + const char* error2; + + const void* const vtable; +#ifdef __cplusplus + spAttachmentLoader () : + error1(0), + error2(0), + vtable(0) { + } +#endif +} spAttachmentLoader; + +void spAttachmentLoader_dispose (spAttachmentLoader* self); + +/* Called to create each attachment. Returns 0 to not load an attachment. If 0 is returned and _spAttachmentLoader_setError was + * called, an error occurred. */ +spAttachment* spAttachmentLoader_createAttachment (spAttachmentLoader* self, spSkin* skin, spAttachmentType type, const char* name, + const char* path); +/* Called after the attachment has been fully configured. */ +void spAttachmentLoader_configureAttachment (spAttachmentLoader* self, spAttachment* attachment); +/* Called just before the attachment is disposed. This can release allocations made in spAttachmentLoader_configureAttachment. */ +void spAttachmentLoader_disposeAttachment (spAttachmentLoader* self, spAttachment* attachment); + +#ifdef SPINE_SHORT_NAMES +typedef spAttachmentLoader AttachmentLoader; +#define AttachmentLoader_dispose(...) spAttachmentLoader_dispose(__VA_ARGS__) +#define AttachmentLoader_createAttachment(...) spAttachmentLoader_createAttachment(__VA_ARGS__) +#define AttachmentLoader_configureAttachment(...) spAttachmentLoader_configureAttachment(__VA_ARGS__) +#define AttachmentLoader_disposeAttachment(...) spAttachmentLoader_disposeAttachment(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_ATTACHMENTLOADER_H_ */ diff --git a/spine-c/include/spine/Bone.h b/spine-c/include/spine/Bone.h index 5ab5ffcfcf..2af95b2bee 100644 --- a/spine-c/include/spine/Bone.h +++ b/spine-c/include/spine/Bone.h @@ -1,127 +1,126 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_BONE_H_ -#define SPINE_BONE_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct spSkeleton; - -typedef struct spBone spBone; -struct spBone { - spBoneData* const data; - struct spSkeleton* const skeleton; - spBone* const parent; - int childrenCount; - spBone** const children; - float x, y, rotation, scaleX, scaleY, shearX, shearY; - float appliedRotation; - - float const a, b, worldX; - float const c, d, worldY; - float const worldSignX, worldSignY; - - int/*bool*/ sorted; - -#ifdef __cplusplus - spBone() : - data(0), - skeleton(0), - parent(0), - childrenCount(0), children(0), - x(0), y(0), rotation(0), scaleX(0), scaleY(0), - appliedRotation(0), - - a(0), b(0), worldX(0), - c(0), d(0), worldY(0), - worldSignX(0), worldSignY(0), - - sorted(0) { - } -#endif -}; - -void spBone_setYDown (int/*bool*/yDown); -int/*bool*/spBone_isYDown (); - -/* @param parent May be 0. */ -spBone* spBone_create (spBoneData* data, struct spSkeleton* skeleton, spBone* parent); -void spBone_dispose (spBone* self); - -void spBone_setToSetupPose (spBone* self); - -void spBone_updateWorldTransform (spBone* self); -void spBone_updateWorldTransformWith (spBone* self, float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY); - -float spBone_getWorldRotationX (spBone* self); -float spBone_getWorldRotationY (spBone* self); -float spBone_getWorldScaleX (spBone* self); -float spBone_getWorldScaleY (spBone* self); - -float spBone_worldToLocalRotationX (spBone* self); -float spBone_worldToLocalRotationY (spBone* self); -void spBone_rotateWorld (spBone* self, float degrees); -void spBone_updateLocalTransform (spBone* self); - -void spBone_worldToLocal (spBone* self, float worldX, float worldY, float* localX, float* localY); -void spBone_localToWorld (spBone* self, float localX, float localY, float* worldX, float* worldY); - -#ifdef SPINE_SHORT_NAMES -typedef spBone Bone; -#define Bone_setYDown(...) spBone_setYDown(__VA_ARGS__) -#define Bone_isYDown() spBone_isYDown() -#define Bone_create(...) spBone_create(__VA_ARGS__) -#define Bone_dispose(...) spBone_dispose(__VA_ARGS__) -#define Bone_setToSetupPose(...) spBone_setToSetupPose(__VA_ARGS__) -#define Bone_updateWorldTransform(...) spBone_updateWorldTransform(__VA_ARGS__) -#define Bone_updateWorldTransformWith(...) spBone_updateWorldTransformWith(__VA_ARGS__) -#define Bone_getWorldRotationX(...) spBone_getWorldRotationX(__VA_ARGS__) -#define Bone_getWorldRotationY(...) spBone_getWorldRotationY(__VA_ARGS__) -#define Bone_getWorldScaleX(...) spBone_getWorldScaleX(__VA_ARGS__) -#define Bone_getWorldScaleY(...) spBone_getWorldScaleY(__VA_ARGS__) -#define Bone_worldToLocalRotationX(...) spBone_worldToLocalRotationX(__VA_ARGS__) -#define Bone_worldToLocalRotationY(...) spBone_worldToLocalRotationY(__VA_ARGS__) -#define Bone_rotateWorld(...) spBone_rotateWorld(__VA_ARGS__) -#define Bone_updateLocalTransform(...) spBone_updateLocalTransform(__VA_ARGS__) -#define Bone_worldToLocal(...) spBone_worldToLocal(__VA_ARGS__) -#define Bone_localToWorld(...) spBone_localToWorld(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_BONE_H_ +#define SPINE_BONE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct spSkeleton; + +typedef struct spBone spBone; +struct spBone { + spBoneData* const data; + struct spSkeleton* const skeleton; + spBone* const parent; + int childrenCount; + spBone** const children; + float x, y, rotation, scaleX, scaleY, shearX, shearY; + float appliedRotation; + + float const a, b, worldX; + float const c, d, worldY; + float const worldSignX, worldSignY; + + int/*bool*/ sorted; + +#ifdef __cplusplus + spBone() : + data(0), + skeleton(0), + parent(0), + childrenCount(0), children(0), + x(0), y(0), rotation(0), scaleX(0), scaleY(0), + appliedRotation(0), + + a(0), b(0), worldX(0), + c(0), d(0), worldY(0), + worldSignX(0), worldSignY(0), + + sorted(0) { + } +#endif +}; + +void spBone_setYDown (int/*bool*/yDown); +int/*bool*/spBone_isYDown (); + +/* @param parent May be 0. */ +spBone* spBone_create (spBoneData* data, struct spSkeleton* skeleton, spBone* parent); +void spBone_dispose (spBone* self); + +void spBone_setToSetupPose (spBone* self); + +void spBone_updateWorldTransform (spBone* self); +void spBone_updateWorldTransformWith (spBone* self, float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY); + +float spBone_getWorldRotationX (spBone* self); +float spBone_getWorldRotationY (spBone* self); +float spBone_getWorldScaleX (spBone* self); +float spBone_getWorldScaleY (spBone* self); + +float spBone_worldToLocalRotationX (spBone* self); +float spBone_worldToLocalRotationY (spBone* self); +void spBone_rotateWorld (spBone* self, float degrees); +void spBone_updateLocalTransform (spBone* self); + +void spBone_worldToLocal (spBone* self, float worldX, float worldY, float* localX, float* localY); +void spBone_localToWorld (spBone* self, float localX, float localY, float* worldX, float* worldY); + +#ifdef SPINE_SHORT_NAMES +typedef spBone Bone; +#define Bone_setYDown(...) spBone_setYDown(__VA_ARGS__) +#define Bone_isYDown() spBone_isYDown() +#define Bone_create(...) spBone_create(__VA_ARGS__) +#define Bone_dispose(...) spBone_dispose(__VA_ARGS__) +#define Bone_setToSetupPose(...) spBone_setToSetupPose(__VA_ARGS__) +#define Bone_updateWorldTransform(...) spBone_updateWorldTransform(__VA_ARGS__) +#define Bone_updateWorldTransformWith(...) spBone_updateWorldTransformWith(__VA_ARGS__) +#define Bone_getWorldRotationX(...) spBone_getWorldRotationX(__VA_ARGS__) +#define Bone_getWorldRotationY(...) spBone_getWorldRotationY(__VA_ARGS__) +#define Bone_getWorldScaleX(...) spBone_getWorldScaleX(__VA_ARGS__) +#define Bone_getWorldScaleY(...) spBone_getWorldScaleY(__VA_ARGS__) +#define Bone_worldToLocalRotationX(...) spBone_worldToLocalRotationX(__VA_ARGS__) +#define Bone_worldToLocalRotationY(...) spBone_worldToLocalRotationY(__VA_ARGS__) +#define Bone_rotateWorld(...) spBone_rotateWorld(__VA_ARGS__) +#define Bone_updateLocalTransform(...) spBone_updateLocalTransform(__VA_ARGS__) +#define Bone_worldToLocal(...) spBone_worldToLocal(__VA_ARGS__) +#define Bone_localToWorld(...) spBone_localToWorld(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_BONE_H_ */ diff --git a/spine-c/include/spine/BoneData.h b/spine-c/include/spine/BoneData.h index 9a2451853c..aaef09e467 100644 --- a/spine-c/include/spine/BoneData.h +++ b/spine-c/include/spine/BoneData.h @@ -1,76 +1,75 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_BONEDATA_H_ -#define SPINE_BONEDATA_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spBoneData spBoneData; -struct spBoneData { - const int index; - const char* const name; - spBoneData* const parent; - float length; - float x, y, rotation, scaleX, scaleY, shearX, shearY; - int/*bool*/inheritRotation, inheritScale; - -#ifdef __cplusplus - spBoneData() : - index(0), - name(0), - parent(0), - length(0), - x(0), y(0), - rotation(0), - scaleX(0), scaleY(0), - shearX(0), shearY(0), - inheritRotation(0), inheritScale(0) { - } -#endif -}; - -spBoneData* spBoneData_create (int index, const char* name, spBoneData* parent); -void spBoneData_dispose (spBoneData* self); - -#ifdef SPINE_SHORT_NAMES -typedef spBoneData BoneData; -#define BoneData_create(...) spBoneData_create(__VA_ARGS__) -#define BoneData_dispose(...) spBoneData_dispose(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_BONEDATA_H_ +#define SPINE_BONEDATA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spBoneData spBoneData; +struct spBoneData { + const int index; + const char* const name; + spBoneData* const parent; + float length; + float x, y, rotation, scaleX, scaleY, shearX, shearY; + int/*bool*/inheritRotation, inheritScale; + +#ifdef __cplusplus + spBoneData() : + index(0), + name(0), + parent(0), + length(0), + x(0), y(0), + rotation(0), + scaleX(0), scaleY(0), + shearX(0), shearY(0), + inheritRotation(0), inheritScale(0) { + } +#endif +}; + +spBoneData* spBoneData_create (int index, const char* name, spBoneData* parent); +void spBoneData_dispose (spBoneData* self); + +#ifdef SPINE_SHORT_NAMES +typedef spBoneData BoneData; +#define BoneData_create(...) spBoneData_create(__VA_ARGS__) +#define BoneData_dispose(...) spBoneData_dispose(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_BONEDATA_H_ */ diff --git a/spine-c/include/spine/BoundingBoxAttachment.h b/spine-c/include/spine/BoundingBoxAttachment.h index 785d96770d..33b6278ccb 100644 --- a/spine-c/include/spine/BoundingBoxAttachment.h +++ b/spine-c/include/spine/BoundingBoxAttachment.h @@ -1,61 +1,60 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_BOUNDINGBOXATTACHMENT_H_ -#define SPINE_BOUNDINGBOXATTACHMENT_H_ - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spBoundingBoxAttachment { - spVertexAttachment super; -} spBoundingBoxAttachment; - -spBoundingBoxAttachment* spBoundingBoxAttachment_create (const char* name); -void spBoundingBoxAttachment_computeWorldVertices (spBoundingBoxAttachment* self, spSlot* slot, float* worldVertices); - -#ifdef SPINE_SHORT_NAMES -typedef spBoundingBoxAttachment BoundingBoxAttachment; -#define BoundingBoxAttachment_create(...) spBoundingBoxAttachment_create(__VA_ARGS__) -#define BoundingBoxAttachment_computeWorldVertices(...) spBoundingBoxAttachment_computeWorldVertices(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_BOUNDINGBOXATTACHMENT_H_ +#define SPINE_BOUNDINGBOXATTACHMENT_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spBoundingBoxAttachment { + spVertexAttachment super; +} spBoundingBoxAttachment; + +spBoundingBoxAttachment* spBoundingBoxAttachment_create (const char* name); +void spBoundingBoxAttachment_computeWorldVertices (spBoundingBoxAttachment* self, spSlot* slot, float* worldVertices); + +#ifdef SPINE_SHORT_NAMES +typedef spBoundingBoxAttachment BoundingBoxAttachment; +#define BoundingBoxAttachment_create(...) spBoundingBoxAttachment_create(__VA_ARGS__) +#define BoundingBoxAttachment_computeWorldVertices(...) spBoundingBoxAttachment_computeWorldVertices(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_BOUNDINGBOXATTACHMENT_H_ */ diff --git a/spine-c/include/spine/Event.h b/spine-c/include/spine/Event.h index 31aebadcaa..44b9581f95 100644 --- a/spine-c/include/spine/Event.h +++ b/spine-c/include/spine/Event.h @@ -1,72 +1,71 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_EVENT_H_ -#define SPINE_EVENT_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spEvent { - spEventData* const data; - float const time; - int intValue; - float floatValue; - const char* stringValue; - -#ifdef __cplusplus - spEvent() : - data(0), - time(0), - intValue(0), - floatValue(0), - stringValue(0) { - } -#endif -} spEvent; - -spEvent* spEvent_create (float time, spEventData* data); -void spEvent_dispose (spEvent* self); - -#ifdef SPINE_SHORT_NAMES -typedef spEvent Event; -#define Event_create(...) spEvent_create(__VA_ARGS__) -#define Event_dispose(...) spEvent_dispose(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_EVENT_H_ +#define SPINE_EVENT_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spEvent { + spEventData* const data; + float const time; + int intValue; + float floatValue; + const char* stringValue; + +#ifdef __cplusplus + spEvent() : + data(0), + time(0), + intValue(0), + floatValue(0), + stringValue(0) { + } +#endif +} spEvent; + +spEvent* spEvent_create (float time, spEventData* data); +void spEvent_dispose (spEvent* self); + +#ifdef SPINE_SHORT_NAMES +typedef spEvent Event; +#define Event_create(...) spEvent_create(__VA_ARGS__) +#define Event_dispose(...) spEvent_dispose(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_EVENT_H_ */ diff --git a/spine-c/include/spine/EventData.h b/spine-c/include/spine/EventData.h index 4e0ff20785..0956d22cbb 100644 --- a/spine-c/include/spine/EventData.h +++ b/spine-c/include/spine/EventData.h @@ -1,68 +1,67 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_EVENTDATA_H_ -#define SPINE_EVENTDATA_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spEventData { - const char* const name; - int intValue; - float floatValue; - const char* stringValue; - -#ifdef __cplusplus - spEventData() : - name(0), - intValue(0), - floatValue(0), - stringValue(0) { - } -#endif -} spEventData; - -spEventData* spEventData_create (const char* name); -void spEventData_dispose (spEventData* self); - -#ifdef SPINE_SHORT_NAMES -typedef spEventData EventData; -#define EventData_create(...) spEventData_create(__VA_ARGS__) -#define EventData_dispose(...) spEventData_dispose(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_EVENTDATA_H_ +#define SPINE_EVENTDATA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spEventData { + const char* const name; + int intValue; + float floatValue; + const char* stringValue; + +#ifdef __cplusplus + spEventData() : + name(0), + intValue(0), + floatValue(0), + stringValue(0) { + } +#endif +} spEventData; + +spEventData* spEventData_create (const char* name); +void spEventData_dispose (spEventData* self); + +#ifdef SPINE_SHORT_NAMES +typedef spEventData EventData; +#define EventData_create(...) spEventData_create(__VA_ARGS__) +#define EventData_dispose(...) spEventData_dispose(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_EVENTDATA_H_ */ diff --git a/spine-c/include/spine/IkConstraint.h b/spine-c/include/spine/IkConstraint.h index 2ca3b951d3..d6025ab3bb 100644 --- a/spine-c/include/spine/IkConstraint.h +++ b/spine-c/include/spine/IkConstraint.h @@ -1,90 +1,89 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_IKCONSTRAINT_H_ -#define SPINE_IKCONSTRAINT_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct spSkeleton; - -typedef struct spIkConstraint { - spIkConstraintData* const data; - - int bonesCount; - spBone** bones; - - spBone* target; - int bendDirection; - float mix; - - int level; - -#ifdef __cplusplus - spIkConstraint() : - data(0), - bonesCount(0), - bones(0), - target(0), - bendDirection(0), - mix(0), - level(0) { - } -#endif -} spIkConstraint; - -spIkConstraint* spIkConstraint_create (spIkConstraintData* data, const struct spSkeleton* skeleton); -void spIkConstraint_dispose (spIkConstraint* self); - -void spIkConstraint_apply (spIkConstraint* self); - -void spIkConstraint_apply1 (spBone* bone, float targetX, float targetY, float alpha); -void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDirection, float alpha); - -#ifdef SPINE_SHORT_NAMES -typedef spIkConstraint IkConstraint; -#define IkConstraint_create(...) spIkConstraint_create(__VA_ARGS__) -#define IkConstraint_dispose(...) spIkConstraint_dispose(__VA_ARGS__) -#define IkConstraint_apply(...) spIkConstraint_apply(__VA_ARGS__) -#define IkConstraint_apply1(...) spIkConstraint_apply1(__VA_ARGS__) -#define IkConstraint_apply2(...) spIkConstraint_apply2(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_IKCONSTRAINT_H_ +#define SPINE_IKCONSTRAINT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct spSkeleton; + +typedef struct spIkConstraint { + spIkConstraintData* const data; + + int bonesCount; + spBone** bones; + + spBone* target; + int bendDirection; + float mix; + + int level; + +#ifdef __cplusplus + spIkConstraint() : + data(0), + bonesCount(0), + bones(0), + target(0), + bendDirection(0), + mix(0), + level(0) { + } +#endif +} spIkConstraint; + +spIkConstraint* spIkConstraint_create (spIkConstraintData* data, const struct spSkeleton* skeleton); +void spIkConstraint_dispose (spIkConstraint* self); + +void spIkConstraint_apply (spIkConstraint* self); + +void spIkConstraint_apply1 (spBone* bone, float targetX, float targetY, float alpha); +void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDirection, float alpha); + +#ifdef SPINE_SHORT_NAMES +typedef spIkConstraint IkConstraint; +#define IkConstraint_create(...) spIkConstraint_create(__VA_ARGS__) +#define IkConstraint_dispose(...) spIkConstraint_dispose(__VA_ARGS__) +#define IkConstraint_apply(...) spIkConstraint_apply(__VA_ARGS__) +#define IkConstraint_apply1(...) spIkConstraint_apply1(__VA_ARGS__) +#define IkConstraint_apply2(...) spIkConstraint_apply2(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_IKCONSTRAINT_H_ */ diff --git a/spine-c/include/spine/IkConstraintData.h b/spine-c/include/spine/IkConstraintData.h index 6f35352a94..e6d6399246 100644 --- a/spine-c/include/spine/IkConstraintData.h +++ b/spine-c/include/spine/IkConstraintData.h @@ -1,76 +1,75 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_IKCONSTRAINTDATA_H_ -#define SPINE_IKCONSTRAINTDATA_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spIkConstraintData { - const char* const name; - - int bonesCount; - spBoneData** bones; - - spBoneData* target; - int bendDirection; - float mix; - -#ifdef __cplusplus - spIkConstraintData() : - name(0), - bonesCount(0), - bones(0), - target(0), - bendDirection(0), - mix(0) { - } -#endif -} spIkConstraintData; - -spIkConstraintData* spIkConstraintData_create (const char* name); -void spIkConstraintData_dispose (spIkConstraintData* self); - -#ifdef SPINE_SHORT_NAMES -typedef spIkConstraintData IkConstraintData; -#define IkConstraintData_create(...) spIkConstraintData_create(__VA_ARGS__) -#define IkConstraintData_dispose(...) spIkConstraintData_dispose(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_IKCONSTRAINTDATA_H_ +#define SPINE_IKCONSTRAINTDATA_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spIkConstraintData { + const char* const name; + + int bonesCount; + spBoneData** bones; + + spBoneData* target; + int bendDirection; + float mix; + +#ifdef __cplusplus + spIkConstraintData() : + name(0), + bonesCount(0), + bones(0), + target(0), + bendDirection(0), + mix(0) { + } +#endif +} spIkConstraintData; + +spIkConstraintData* spIkConstraintData_create (const char* name); +void spIkConstraintData_dispose (spIkConstraintData* self); + +#ifdef SPINE_SHORT_NAMES +typedef spIkConstraintData IkConstraintData; +#define IkConstraintData_create(...) spIkConstraintData_create(__VA_ARGS__) +#define IkConstraintData_dispose(...) spIkConstraintData_dispose(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_IKCONSTRAINTDATA_H_ */ diff --git a/spine-c/include/spine/MeshAttachment.h b/spine-c/include/spine/MeshAttachment.h index d232a96805..a9ee83a371 100644 --- a/spine-c/include/spine/MeshAttachment.h +++ b/spine-c/include/spine/MeshAttachment.h @@ -1,93 +1,92 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_MESHATTACHMENT_H_ -#define SPINE_MESHATTACHMENT_H_ - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spMeshAttachment spMeshAttachment; -struct spMeshAttachment { - spVertexAttachment super; - - void* rendererObject; - int regionOffsetX, regionOffsetY; /* Pixels stripped from the bottom left, unrotated. */ - int regionWidth, regionHeight; /* Unrotated, stripped pixel size. */ - int regionOriginalWidth, regionOriginalHeight; /* Unrotated, unstripped pixel size. */ - float regionU, regionV, regionU2, regionV2; - int/*bool*/regionRotate; - - const char* path; - - float* regionUVs; - float* uvs; - - int trianglesCount; - unsigned short* triangles; - - float r, g, b, a; - - int hullLength; - - spMeshAttachment* const parentMesh; - int/*bool*/inheritDeform; - - /* Nonessential. */ - int edgesCount; - int* edges; - float width, height; -}; - -spMeshAttachment* spMeshAttachment_create (const char* name); -void spMeshAttachment_updateUVs (spMeshAttachment* self); -void spMeshAttachment_computeWorldVertices (spMeshAttachment* self, spSlot* slot, float* worldVertices); -void spMeshAttachment_setParentMesh (spMeshAttachment* self, spMeshAttachment* parentMesh); - -#ifdef SPINE_SHORT_NAMES -typedef spMeshAttachment MeshAttachment; -#define MeshAttachment_create(...) spMeshAttachment_create(__VA_ARGS__) -#define MeshAttachment_updateUVs(...) spMeshAttachment_updateUVs(__VA_ARGS__) -#define MeshAttachment_computeWorldVertices(...) spMeshAttachment_computeWorldVertices(__VA_ARGS__) -#define MeshAttachment_setParentMesh(...) spMeshAttachment_setParentMesh(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_MESHATTACHMENT_H_ +#define SPINE_MESHATTACHMENT_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spMeshAttachment spMeshAttachment; +struct spMeshAttachment { + spVertexAttachment super; + + void* rendererObject; + int regionOffsetX, regionOffsetY; /* Pixels stripped from the bottom left, unrotated. */ + int regionWidth, regionHeight; /* Unrotated, stripped pixel size. */ + int regionOriginalWidth, regionOriginalHeight; /* Unrotated, unstripped pixel size. */ + float regionU, regionV, regionU2, regionV2; + int/*bool*/regionRotate; + + const char* path; + + float* regionUVs; + float* uvs; + + int trianglesCount; + unsigned short* triangles; + + float r, g, b, a; + + int hullLength; + + spMeshAttachment* const parentMesh; + int/*bool*/inheritDeform; + + /* Nonessential. */ + int edgesCount; + int* edges; + float width, height; +}; + +spMeshAttachment* spMeshAttachment_create (const char* name); +void spMeshAttachment_updateUVs (spMeshAttachment* self); +void spMeshAttachment_computeWorldVertices (spMeshAttachment* self, spSlot* slot, float* worldVertices); +void spMeshAttachment_setParentMesh (spMeshAttachment* self, spMeshAttachment* parentMesh); + +#ifdef SPINE_SHORT_NAMES +typedef spMeshAttachment MeshAttachment; +#define MeshAttachment_create(...) spMeshAttachment_create(__VA_ARGS__) +#define MeshAttachment_updateUVs(...) spMeshAttachment_updateUVs(__VA_ARGS__) +#define MeshAttachment_computeWorldVertices(...) spMeshAttachment_computeWorldVertices(__VA_ARGS__) +#define MeshAttachment_setParentMesh(...) spMeshAttachment_setParentMesh(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_MESHATTACHMENT_H_ */ diff --git a/spine-c/include/spine/PathAttachment.h b/spine-c/include/spine/PathAttachment.h index ca17f3ad8c..80420cfd87 100644 --- a/spine-c/include/spine/PathAttachment.h +++ b/spine-c/include/spine/PathAttachment.h @@ -1,65 +1,64 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_PATHATTACHMENT_H_ -#define SPINE_PATHATTACHMENT_H_ - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spPathAttachment { - spVertexAttachment super; - int lengthsLength; - float* lengths; - int/*bool*/ closed, constantSpeed; -} spPathAttachment; - -spPathAttachment* spPathAttachment_create (const char* name); -void spPathAttachment_computeWorldVertices (spPathAttachment* self, spSlot* slot, float* worldVertices); -void spPathAttachment_computeWorldVertices1 (spPathAttachment* self, spSlot* slot, int start, int count, float* worldVertices, int offset); - -#ifdef SPINE_SHORT_NAMES -typedef spPathAttachment PathAttachment; -#define PathAttachment_create(...) spPathAttachment_create(__VA_ARGS__) -#define PathAttachment_computeWorldVertices(...) spPathAttachment_computeWorldVertices(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_PATHATTACHMENT_H_ +#define SPINE_PATHATTACHMENT_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spPathAttachment { + spVertexAttachment super; + int lengthsLength; + float* lengths; + int/*bool*/ closed, constantSpeed; +} spPathAttachment; + +spPathAttachment* spPathAttachment_create (const char* name); +void spPathAttachment_computeWorldVertices (spPathAttachment* self, spSlot* slot, float* worldVertices); +void spPathAttachment_computeWorldVertices1 (spPathAttachment* self, spSlot* slot, int start, int count, float* worldVertices, int offset); + +#ifdef SPINE_SHORT_NAMES +typedef spPathAttachment PathAttachment; +#define PathAttachment_create(...) spPathAttachment_create(__VA_ARGS__) +#define PathAttachment_computeWorldVertices(...) spPathAttachment_computeWorldVertices(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_PATHATTACHMENT_H_ */ diff --git a/spine-c/include/spine/PathConstraint.h b/spine-c/include/spine/PathConstraint.h index a956797056..ddbd309617 100644 --- a/spine-c/include/spine/PathConstraint.h +++ b/spine-c/include/spine/PathConstraint.h @@ -1,113 +1,112 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_PATHCONSTRAINT_H_ -#define SPINE_PATHCONSTRAINT_H_ - -#include -#include -#include -#include "PathAttachment.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct spSkeleton; - -typedef struct spPathConstraint { - spPathConstraintData* const data; - int bonesCount; - spBone** const bones; - spSlot* target; - float position, spacing, rotateMix, translateMix; - - int spacesCount; - float* spaces; - - int positionsCount; - float* positions; - - int worldCount; - float* world; - - int curvesCount; - float* curves; - - int lengthsCount; - float* lengths; - - float segments[10]; - -#ifdef __cplusplus - spPathConstraint() : - data(0), - bonesCount(0), - bones(0), - target(0), - position(0), - spacing(0), - rotateMix(0), - translateMix(0), - spacesCount(0), - spaces(0), - positionsCount(0), - positions(0), - worldCount(0), - world(0), - curvesCount(0), - curves(0), - lengthsCount(0), - lengths(0) { - } -#endif -} spPathConstraint; - -#define SP_PATHCONSTRAINT_ - -spPathConstraint* spPathConstraint_create (spPathConstraintData* data, const struct spSkeleton* skeleton); -void spPathConstraint_dispose (spPathConstraint* self); - -void spPathConstraint_apply (spPathConstraint* self); -float* spPathConstraint_computeWorldPositions(spPathConstraint* self, spPathAttachment* path, int spacesCount, int/*bool*/ tangents, int/*bool*/percentPosition, int/**/percentSpacing); - -#ifdef SPINE_SHORT_NAMES -typedef spPathConstraint PathConstraint; -#define PathConstraint_create(...) spPathConstraint_create(__VA_ARGS__) -#define PathConstraint_dispose(...) spPathConstraint_dispose(__VA_ARGS__) -#define PathConstraint_apply(...) spPathConstraint_apply(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_PATHCONSTRAINT_H_ +#define SPINE_PATHCONSTRAINT_H_ + +#include +#include +#include +#include "PathAttachment.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct spSkeleton; + +typedef struct spPathConstraint { + spPathConstraintData* const data; + int bonesCount; + spBone** const bones; + spSlot* target; + float position, spacing, rotateMix, translateMix; + + int spacesCount; + float* spaces; + + int positionsCount; + float* positions; + + int worldCount; + float* world; + + int curvesCount; + float* curves; + + int lengthsCount; + float* lengths; + + float segments[10]; + +#ifdef __cplusplus + spPathConstraint() : + data(0), + bonesCount(0), + bones(0), + target(0), + position(0), + spacing(0), + rotateMix(0), + translateMix(0), + spacesCount(0), + spaces(0), + positionsCount(0), + positions(0), + worldCount(0), + world(0), + curvesCount(0), + curves(0), + lengthsCount(0), + lengths(0) { + } +#endif +} spPathConstraint; + +#define SP_PATHCONSTRAINT_ + +spPathConstraint* spPathConstraint_create (spPathConstraintData* data, const struct spSkeleton* skeleton); +void spPathConstraint_dispose (spPathConstraint* self); + +void spPathConstraint_apply (spPathConstraint* self); +float* spPathConstraint_computeWorldPositions(spPathConstraint* self, spPathAttachment* path, int spacesCount, int/*bool*/ tangents, int/*bool*/percentPosition, int/**/percentSpacing); + +#ifdef SPINE_SHORT_NAMES +typedef spPathConstraint PathConstraint; +#define PathConstraint_create(...) spPathConstraint_create(__VA_ARGS__) +#define PathConstraint_dispose(...) spPathConstraint_dispose(__VA_ARGS__) +#define PathConstraint_apply(...) spPathConstraint_apply(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_PATHCONSTRAINT_H_ */ diff --git a/spine-c/include/spine/PathConstraintData.h b/spine-c/include/spine/PathConstraintData.h index f608193539..1f7621764a 100644 --- a/spine-c/include/spine/PathConstraintData.h +++ b/spine-c/include/spine/PathConstraintData.h @@ -1,96 +1,95 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_PATHCONSTRAINTDATA_H_ -#define SPINE_PATHCONSTRAINTDATA_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - SP_POSITION_MODE_FIXED, SP_POSITION_MODE_PERCENT -} spPositionMode; - -typedef enum { - SP_SPACING_MODE_LENGTH, SP_SPACING_MODE_FIXED, SP_SPACING_MODE_PERCENT -} spSpacingMode; - -typedef enum { - SP_ROTATE_MODE_TANGENT, SP_ROTATE_MODE_CHAIN, SP_ROTATE_MODE_CHAIN_SCALE -} spRotateMode; - -typedef struct spPathConstraintData { - const char* const name; - int bonesCount; - spBoneData** const bones; - spSlotData* target; - spPositionMode positionMode; - spSpacingMode spacingMode; - spRotateMode rotateMode; - float offsetRotation; - float position, spacing, rotateMix, translateMix; - -#ifdef __cplusplus - spPathConstraintData() : - name(0), - bonesCount(0), - bones(0), - target(0), - positionMode(SP_POSITION_MODE_FIXED), - spacingMode(SP_SPACING_MODE_LENGTH), - rotateMode(SP_ROTATE_MODE_TANGENT), - offsetRotation(0), - position(0), - spacing(0), - rotateMix(0), - translateMix(0) { - } -#endif -} spPathConstraintData; - -spPathConstraintData* spPathConstraintData_create (const char* name); -void spPathConstraintData_dispose (spPathConstraintData* self); - -#ifdef SPINE_SHORT_NAMES -typedef spPathConstraintData PathConstraintData; -#define PathConstraintData_create(...) spPathConstraintData_create(__VA_ARGS__) -#define PathConstraintData_dispose(...) spPathConstraintData_dispose(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_PATHCONSTRAINTDATA_H_ +#define SPINE_PATHCONSTRAINTDATA_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + SP_POSITION_MODE_FIXED, SP_POSITION_MODE_PERCENT +} spPositionMode; + +typedef enum { + SP_SPACING_MODE_LENGTH, SP_SPACING_MODE_FIXED, SP_SPACING_MODE_PERCENT +} spSpacingMode; + +typedef enum { + SP_ROTATE_MODE_TANGENT, SP_ROTATE_MODE_CHAIN, SP_ROTATE_MODE_CHAIN_SCALE +} spRotateMode; + +typedef struct spPathConstraintData { + const char* const name; + int bonesCount; + spBoneData** const bones; + spSlotData* target; + spPositionMode positionMode; + spSpacingMode spacingMode; + spRotateMode rotateMode; + float offsetRotation; + float position, spacing, rotateMix, translateMix; + +#ifdef __cplusplus + spPathConstraintData() : + name(0), + bonesCount(0), + bones(0), + target(0), + positionMode(SP_POSITION_MODE_FIXED), + spacingMode(SP_SPACING_MODE_LENGTH), + rotateMode(SP_ROTATE_MODE_TANGENT), + offsetRotation(0), + position(0), + spacing(0), + rotateMix(0), + translateMix(0) { + } +#endif +} spPathConstraintData; + +spPathConstraintData* spPathConstraintData_create (const char* name); +void spPathConstraintData_dispose (spPathConstraintData* self); + +#ifdef SPINE_SHORT_NAMES +typedef spPathConstraintData PathConstraintData; +#define PathConstraintData_create(...) spPathConstraintData_create(__VA_ARGS__) +#define PathConstraintData_dispose(...) spPathConstraintData_dispose(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_PATHCONSTRAINTDATA_H_ */ diff --git a/spine-c/include/spine/RegionAttachment.h b/spine-c/include/spine/RegionAttachment.h index c370dc91be..2e73b75b58 100644 --- a/spine-c/include/spine/RegionAttachment.h +++ b/spine-c/include/spine/RegionAttachment.h @@ -1,88 +1,87 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_REGIONATTACHMENT_H_ -#define SPINE_REGIONATTACHMENT_H_ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - SP_VERTEX_X1 = 0, SP_VERTEX_Y1, SP_VERTEX_X2, SP_VERTEX_Y2, SP_VERTEX_X3, SP_VERTEX_Y3, SP_VERTEX_X4, SP_VERTEX_Y4 -} spVertexIndex; - -typedef struct spRegionAttachment { - spAttachment super; - const char* path; - float x, y, scaleX, scaleY, rotation, width, height; - float r, g, b, a; - - void* rendererObject; - int regionOffsetX, regionOffsetY; /* Pixels stripped from the bottom left, unrotated. */ - int regionWidth, regionHeight; /* Unrotated, stripped pixel size. */ - int regionOriginalWidth, regionOriginalHeight; /* Unrotated, unstripped pixel size. */ - - float offset[8]; - float uvs[8]; -} spRegionAttachment; - -spRegionAttachment* spRegionAttachment_create (const char* name); -void spRegionAttachment_setUVs (spRegionAttachment* self, float u, float v, float u2, float v2, int/*bool*/rotate); -void spRegionAttachment_updateOffset (spRegionAttachment* self); -void spRegionAttachment_computeWorldVertices (spRegionAttachment* self, spBone* bone, float* vertices); - -#ifdef SPINE_SHORT_NAMES -typedef spVertexIndex VertexIndex; -#define VERTEX_X1 SP_VERTEX_X1 -#define VERTEX_Y1 SP_VERTEX_Y1 -#define VERTEX_X2 SP_VERTEX_X2 -#define VERTEX_Y2 SP_VERTEX_Y2 -#define VERTEX_X3 SP_VERTEX_X3 -#define VERTEX_Y3 SP_VERTEX_Y3 -#define VERTEX_X4 SP_VERTEX_X4 -#define VERTEX_Y4 SP_VERTEX_Y4 -typedef spRegionAttachment RegionAttachment; -#define RegionAttachment_create(...) spRegionAttachment_create(__VA_ARGS__) -#define RegionAttachment_setUVs(...) spRegionAttachment_setUVs(__VA_ARGS__) -#define RegionAttachment_updateOffset(...) spRegionAttachment_updateOffset(__VA_ARGS__) -#define RegionAttachment_computeWorldVertices(...) spRegionAttachment_computeWorldVertices(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_REGIONATTACHMENT_H_ +#define SPINE_REGIONATTACHMENT_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + SP_VERTEX_X1 = 0, SP_VERTEX_Y1, SP_VERTEX_X2, SP_VERTEX_Y2, SP_VERTEX_X3, SP_VERTEX_Y3, SP_VERTEX_X4, SP_VERTEX_Y4 +} spVertexIndex; + +typedef struct spRegionAttachment { + spAttachment super; + const char* path; + float x, y, scaleX, scaleY, rotation, width, height; + float r, g, b, a; + + void* rendererObject; + int regionOffsetX, regionOffsetY; /* Pixels stripped from the bottom left, unrotated. */ + int regionWidth, regionHeight; /* Unrotated, stripped pixel size. */ + int regionOriginalWidth, regionOriginalHeight; /* Unrotated, unstripped pixel size. */ + + float offset[8]; + float uvs[8]; +} spRegionAttachment; + +spRegionAttachment* spRegionAttachment_create (const char* name); +void spRegionAttachment_setUVs (spRegionAttachment* self, float u, float v, float u2, float v2, int/*bool*/rotate); +void spRegionAttachment_updateOffset (spRegionAttachment* self); +void spRegionAttachment_computeWorldVertices (spRegionAttachment* self, spBone* bone, float* vertices); + +#ifdef SPINE_SHORT_NAMES +typedef spVertexIndex VertexIndex; +#define VERTEX_X1 SP_VERTEX_X1 +#define VERTEX_Y1 SP_VERTEX_Y1 +#define VERTEX_X2 SP_VERTEX_X2 +#define VERTEX_Y2 SP_VERTEX_Y2 +#define VERTEX_X3 SP_VERTEX_X3 +#define VERTEX_Y3 SP_VERTEX_Y3 +#define VERTEX_X4 SP_VERTEX_X4 +#define VERTEX_Y4 SP_VERTEX_Y4 +typedef spRegionAttachment RegionAttachment; +#define RegionAttachment_create(...) spRegionAttachment_create(__VA_ARGS__) +#define RegionAttachment_setUVs(...) spRegionAttachment_setUVs(__VA_ARGS__) +#define RegionAttachment_updateOffset(...) spRegionAttachment_updateOffset(__VA_ARGS__) +#define RegionAttachment_computeWorldVertices(...) spRegionAttachment_computeWorldVertices(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_REGIONATTACHMENT_H_ */ diff --git a/spine-c/include/spine/Skeleton.h b/spine-c/include/spine/Skeleton.h index db1afdd331..723b32ff81 100644 --- a/spine-c/include/spine/Skeleton.h +++ b/spine-c/include/spine/Skeleton.h @@ -1,176 +1,175 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_SKELETON_H_ -#define SPINE_SKELETON_H_ - -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spSkeleton { - spSkeletonData* const data; - - int bonesCount; - spBone** bones; - spBone* const root; - - int slotsCount; - spSlot** slots; - spSlot** drawOrder; - - int ikConstraintsCount; - spIkConstraint** ikConstraints; - spIkConstraint** ikConstraintsSorted; - - int transformConstraintsCount; - spTransformConstraint** transformConstraints; - - int pathConstraintsCount; - spPathConstraint** pathConstraints; - - spSkin* const skin; - float r, g, b, a; - float time; - int/*bool*/flipX, flipY; - float x, y; - -#ifdef __cplusplus - spSkeleton() : - data(0), - bonesCount(0), - bones(0), - root(0), - slotsCount(0), - slots(0), - drawOrder(0), - - ikConstraintsCount(0), - ikConstraints(0), - ikConstraintsSorted(0), - - transformConstraintsCount(0), - transformConstraints(0), - - skin(0), - r(0), g(0), b(0), a(0), - time(0), - flipX(0), - flipY(0), - x(0), y(0) { - } -#endif -} spSkeleton; - -spSkeleton* spSkeleton_create (spSkeletonData* data); -void spSkeleton_dispose (spSkeleton* self); - -/* Caches information about bones and constraints. Must be called if bones or constraints, or weighted path attachments - * are added or removed. */ -void spSkeleton_updateCache (spSkeleton* self); -void spSkeleton_updateWorldTransform (const spSkeleton* self); - -/* Sets the bones, constraints, and slots to their setup pose values. */ -void spSkeleton_setToSetupPose (const spSkeleton* self); -/* Sets the bones and constraints to their setup pose values. */ -void spSkeleton_setBonesToSetupPose (const spSkeleton* self); -void spSkeleton_setSlotsToSetupPose (const spSkeleton* self); - -/* Returns 0 if the bone was not found. */ -spBone* spSkeleton_findBone (const spSkeleton* self, const char* boneName); -/* Returns -1 if the bone was not found. */ -int spSkeleton_findBoneIndex (const spSkeleton* self, const char* boneName); - -/* Returns 0 if the slot was not found. */ -spSlot* spSkeleton_findSlot (const spSkeleton* self, const char* slotName); -/* Returns -1 if the slot was not found. */ -int spSkeleton_findSlotIndex (const spSkeleton* self, const char* slotName); - -/* Sets the skin used to look up attachments before looking in the SkeletonData defaultSkin. 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 skin May be 0.*/ -void spSkeleton_setSkin (spSkeleton* self, spSkin* skin); -/* Returns 0 if the skin was not found. See spSkeleton_setSkin. - * @param skinName May be 0. */ -int spSkeleton_setSkinByName (spSkeleton* self, const char* skinName); - -/* Returns 0 if the slot or attachment was not found. */ -spAttachment* spSkeleton_getAttachmentForSlotName (const spSkeleton* self, const char* slotName, const char* attachmentName); -/* Returns 0 if the slot or attachment was not found. */ -spAttachment* spSkeleton_getAttachmentForSlotIndex (const spSkeleton* self, int slotIndex, const char* attachmentName); -/* Returns 0 if the slot or attachment was not found. - * @param attachmentName May be 0. */ -int spSkeleton_setAttachment (spSkeleton* self, const char* slotName, const char* attachmentName); - -/* Returns 0 if the IK constraint was not found. */ -spIkConstraint* spSkeleton_findIkConstraint (const spSkeleton* self, const char* constraintName); - -/* Returns 0 if the transform constraint was not found. */ -spTransformConstraint* spSkeleton_findTransformConstraint (const spSkeleton* self, const char* constraintName); - -/* Returns 0 if the path constraint was not found. */ -spPathConstraint* spSkeleton_findPathConstraint (const spSkeleton* self, const char* constraintName); - -void spSkeleton_update (spSkeleton* self, float deltaTime); - -#ifdef SPINE_SHORT_NAMES -typedef spSkeleton Skeleton; -#define Skeleton_create(...) spSkeleton_create(__VA_ARGS__) -#define Skeleton_dispose(...) spSkeleton_dispose(__VA_ARGS__) -#define Skeleton_updateWorldTransform(...) spSkeleton_updateWorldTransform(__VA_ARGS__) -#define Skeleton_setToSetupPose(...) spSkeleton_setToSetupPose(__VA_ARGS__) -#define Skeleton_setBonesToSetupPose(...) spSkeleton_setBonesToSetupPose(__VA_ARGS__) -#define Skeleton_setSlotsToSetupPose(...) spSkeleton_setSlotsToSetupPose(__VA_ARGS__) -#define Skeleton_findBone(...) spSkeleton_findBone(__VA_ARGS__) -#define Skeleton_findBoneIndex(...) spSkeleton_findBoneIndex(__VA_ARGS__) -#define Skeleton_findSlot(...) spSkeleton_findSlot(__VA_ARGS__) -#define Skeleton_findSlotIndex(...) spSkeleton_findSlotIndex(__VA_ARGS__) -#define Skeleton_setSkin(...) spSkeleton_setSkin(__VA_ARGS__) -#define Skeleton_setSkinByName(...) spSkeleton_setSkinByName(__VA_ARGS__) -#define Skeleton_getAttachmentForSlotName(...) spSkeleton_getAttachmentForSlotName(__VA_ARGS__) -#define Skeleton_getAttachmentForSlotIndex(...) spSkeleton_getAttachmentForSlotIndex(__VA_ARGS__) -#define Skeleton_setAttachment(...) spSkeleton_setAttachment(__VA_ARGS__) -#define Skeleton_update(...) spSkeleton_update(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_SKELETON_H_ +#define SPINE_SKELETON_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spSkeleton { + spSkeletonData* const data; + + int bonesCount; + spBone** bones; + spBone* const root; + + int slotsCount; + spSlot** slots; + spSlot** drawOrder; + + int ikConstraintsCount; + spIkConstraint** ikConstraints; + spIkConstraint** ikConstraintsSorted; + + int transformConstraintsCount; + spTransformConstraint** transformConstraints; + + int pathConstraintsCount; + spPathConstraint** pathConstraints; + + spSkin* const skin; + float r, g, b, a; + float time; + int/*bool*/flipX, flipY; + float x, y; + +#ifdef __cplusplus + spSkeleton() : + data(0), + bonesCount(0), + bones(0), + root(0), + slotsCount(0), + slots(0), + drawOrder(0), + + ikConstraintsCount(0), + ikConstraints(0), + ikConstraintsSorted(0), + + transformConstraintsCount(0), + transformConstraints(0), + + skin(0), + r(0), g(0), b(0), a(0), + time(0), + flipX(0), + flipY(0), + x(0), y(0) { + } +#endif +} spSkeleton; + +spSkeleton* spSkeleton_create (spSkeletonData* data); +void spSkeleton_dispose (spSkeleton* self); + +/* Caches information about bones and constraints. Must be called if bones or constraints, or weighted path attachments + * are added or removed. */ +void spSkeleton_updateCache (spSkeleton* self); +void spSkeleton_updateWorldTransform (const spSkeleton* self); + +/* Sets the bones, constraints, and slots to their setup pose values. */ +void spSkeleton_setToSetupPose (const spSkeleton* self); +/* Sets the bones and constraints to their setup pose values. */ +void spSkeleton_setBonesToSetupPose (const spSkeleton* self); +void spSkeleton_setSlotsToSetupPose (const spSkeleton* self); + +/* Returns 0 if the bone was not found. */ +spBone* spSkeleton_findBone (const spSkeleton* self, const char* boneName); +/* Returns -1 if the bone was not found. */ +int spSkeleton_findBoneIndex (const spSkeleton* self, const char* boneName); + +/* Returns 0 if the slot was not found. */ +spSlot* spSkeleton_findSlot (const spSkeleton* self, const char* slotName); +/* Returns -1 if the slot was not found. */ +int spSkeleton_findSlotIndex (const spSkeleton* self, const char* slotName); + +/* Sets the skin used to look up attachments before looking in the SkeletonData defaultSkin. 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 skin May be 0.*/ +void spSkeleton_setSkin (spSkeleton* self, spSkin* skin); +/* Returns 0 if the skin was not found. See spSkeleton_setSkin. + * @param skinName May be 0. */ +int spSkeleton_setSkinByName (spSkeleton* self, const char* skinName); + +/* Returns 0 if the slot or attachment was not found. */ +spAttachment* spSkeleton_getAttachmentForSlotName (const spSkeleton* self, const char* slotName, const char* attachmentName); +/* Returns 0 if the slot or attachment was not found. */ +spAttachment* spSkeleton_getAttachmentForSlotIndex (const spSkeleton* self, int slotIndex, const char* attachmentName); +/* Returns 0 if the slot or attachment was not found. + * @param attachmentName May be 0. */ +int spSkeleton_setAttachment (spSkeleton* self, const char* slotName, const char* attachmentName); + +/* Returns 0 if the IK constraint was not found. */ +spIkConstraint* spSkeleton_findIkConstraint (const spSkeleton* self, const char* constraintName); + +/* Returns 0 if the transform constraint was not found. */ +spTransformConstraint* spSkeleton_findTransformConstraint (const spSkeleton* self, const char* constraintName); + +/* Returns 0 if the path constraint was not found. */ +spPathConstraint* spSkeleton_findPathConstraint (const spSkeleton* self, const char* constraintName); + +void spSkeleton_update (spSkeleton* self, float deltaTime); + +#ifdef SPINE_SHORT_NAMES +typedef spSkeleton Skeleton; +#define Skeleton_create(...) spSkeleton_create(__VA_ARGS__) +#define Skeleton_dispose(...) spSkeleton_dispose(__VA_ARGS__) +#define Skeleton_updateWorldTransform(...) spSkeleton_updateWorldTransform(__VA_ARGS__) +#define Skeleton_setToSetupPose(...) spSkeleton_setToSetupPose(__VA_ARGS__) +#define Skeleton_setBonesToSetupPose(...) spSkeleton_setBonesToSetupPose(__VA_ARGS__) +#define Skeleton_setSlotsToSetupPose(...) spSkeleton_setSlotsToSetupPose(__VA_ARGS__) +#define Skeleton_findBone(...) spSkeleton_findBone(__VA_ARGS__) +#define Skeleton_findBoneIndex(...) spSkeleton_findBoneIndex(__VA_ARGS__) +#define Skeleton_findSlot(...) spSkeleton_findSlot(__VA_ARGS__) +#define Skeleton_findSlotIndex(...) spSkeleton_findSlotIndex(__VA_ARGS__) +#define Skeleton_setSkin(...) spSkeleton_setSkin(__VA_ARGS__) +#define Skeleton_setSkinByName(...) spSkeleton_setSkinByName(__VA_ARGS__) +#define Skeleton_getAttachmentForSlotName(...) spSkeleton_getAttachmentForSlotName(__VA_ARGS__) +#define Skeleton_getAttachmentForSlotIndex(...) spSkeleton_getAttachmentForSlotIndex(__VA_ARGS__) +#define Skeleton_setAttachment(...) spSkeleton_setAttachment(__VA_ARGS__) +#define Skeleton_update(...) spSkeleton_update(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_SKELETON_H_*/ diff --git a/spine-c/include/spine/SkeletonBinary.h b/spine-c/include/spine/SkeletonBinary.h index cbdf1f0f43..8e992bc7f5 100644 --- a/spine-c/include/spine/SkeletonBinary.h +++ b/spine-c/include/spine/SkeletonBinary.h @@ -1,72 +1,71 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_SKELETONBINARY_H_ -#define SPINE_SKELETONBINARY_H_ - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct spAtlasAttachmentLoader; - -typedef struct spSkeletonBinary { - float scale; - spAttachmentLoader* attachmentLoader; - const char* const error; -} spSkeletonBinary; - -spSkeletonBinary* spSkeletonBinary_createWithLoader (spAttachmentLoader* attachmentLoader); -spSkeletonBinary* spSkeletonBinary_create (spAtlas* atlas); -void spSkeletonBinary_dispose (spSkeletonBinary* self); - -spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const unsigned char* binary, const int length); -spSkeletonData* spSkeletonBinary_readSkeletonDataFile (spSkeletonBinary* self, const char* path); - -#ifdef SPINE_SHORT_NAMES -typedef spSkeletonBinary SkeletonBinary; -#define SkeletonBinary_createWithLoader(...) spSkeletonBinary_createWithLoader(__VA_ARGS__) -#define SkeletonBinary_create(...) spSkeletonBinary_create(__VA_ARGS__) -#define SkeletonBinary_dispose(...) spSkeletonBinary_dispose(__VA_ARGS__) -#define SkeletonBinary_readSkeletonData(...) spSkeletonBinary_readSkeletonData(__VA_ARGS__) -#define SkeletonBinary_readSkeletonDataFile(...) spSkeletonBinary_readSkeletonDataFile(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_SKELETONBINARY_H_ +#define SPINE_SKELETONBINARY_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct spAtlasAttachmentLoader; + +typedef struct spSkeletonBinary { + float scale; + spAttachmentLoader* attachmentLoader; + const char* const error; +} spSkeletonBinary; + +spSkeletonBinary* spSkeletonBinary_createWithLoader (spAttachmentLoader* attachmentLoader); +spSkeletonBinary* spSkeletonBinary_create (spAtlas* atlas); +void spSkeletonBinary_dispose (spSkeletonBinary* self); + +spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const unsigned char* binary, const int length); +spSkeletonData* spSkeletonBinary_readSkeletonDataFile (spSkeletonBinary* self, const char* path); + +#ifdef SPINE_SHORT_NAMES +typedef spSkeletonBinary SkeletonBinary; +#define SkeletonBinary_createWithLoader(...) spSkeletonBinary_createWithLoader(__VA_ARGS__) +#define SkeletonBinary_create(...) spSkeletonBinary_create(__VA_ARGS__) +#define SkeletonBinary_dispose(...) spSkeletonBinary_dispose(__VA_ARGS__) +#define SkeletonBinary_readSkeletonData(...) spSkeletonBinary_readSkeletonData(__VA_ARGS__) +#define SkeletonBinary_readSkeletonDataFile(...) spSkeletonBinary_readSkeletonDataFile(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_SKELETONBINARY_H_ */ diff --git a/spine-c/include/spine/SkeletonBounds.h b/spine-c/include/spine/SkeletonBounds.h index d7411b250d..f100850dbd 100644 --- a/spine-c/include/spine/SkeletonBounds.h +++ b/spine-c/include/spine/SkeletonBounds.h @@ -1,113 +1,112 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_SKELETONBOUNDS_H_ -#define SPINE_SKELETONBOUNDS_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spPolygon { - float* const vertices; - int count; - int capacity; -} spPolygon; - -spPolygon* spPolygon_create (int capacity); -void spPolygon_dispose (spPolygon* self); - -int/*bool*/spPolygon_containsPoint (spPolygon* polygon, float x, float y); -int/*bool*/spPolygon_intersectsSegment (spPolygon* polygon, float x1, float y1, float x2, float y2); - -#ifdef SPINE_SHORT_NAMES -typedef spPolygon Polygon; -#define Polygon_create(...) spPolygon_create(__VA_ARGS__) -#define Polygon_dispose(...) spPolygon_dispose(__VA_ARGS__) -#define Polygon_containsPoint(...) spPolygon_containsPoint(__VA_ARGS__) -#define Polygon_intersectsSegment(...) spPolygon_intersectsSegment(__VA_ARGS__) -#endif - -/**/ - -typedef struct spSkeletonBounds { - int count; - spBoundingBoxAttachment** boundingBoxes; - spPolygon** polygons; - - float minX, minY, maxX, maxY; -} spSkeletonBounds; - -spSkeletonBounds* spSkeletonBounds_create (); -void spSkeletonBounds_dispose (spSkeletonBounds* self); -void spSkeletonBounds_update (spSkeletonBounds* self, spSkeleton* skeleton, int/*bool*/updateAabb); - -/** Returns true if the axis aligned bounding box contains the point. */ -int/*bool*/spSkeletonBounds_aabbContainsPoint (spSkeletonBounds* self, float x, float y); - -/** Returns true if the axis aligned bounding box intersects the line segment. */ -int/*bool*/spSkeletonBounds_aabbIntersectsSegment (spSkeletonBounds* self, float x1, float y1, float x2, float y2); - -/** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */ -int/*bool*/spSkeletonBounds_aabbIntersectsSkeleton (spSkeletonBounds* self, spSkeletonBounds* bounds); - -/** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more - * efficient to only call this method if spSkeletonBounds_aabbContainsPoint returns true. */ -spBoundingBoxAttachment* spSkeletonBounds_containsPoint (spSkeletonBounds* self, float x, float y); - -/** Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually - * more efficient to only call this method if spSkeletonBounds_aabbIntersectsSegment returns true. */ -spBoundingBoxAttachment* spSkeletonBounds_intersectsSegment (spSkeletonBounds* self, float x1, float y1, float x2, float y2); - -/** Returns the polygon for the specified bounding box, or null. */ -spPolygon* spSkeletonBounds_getPolygon (spSkeletonBounds* self, spBoundingBoxAttachment* boundingBox); - -#ifdef SPINE_SHORT_NAMES -typedef spSkeletonBounds SkeletonBounds; -#define SkeletonBounds_create(...) spSkeletonBounds_create(__VA_ARGS__) -#define SkeletonBounds_dispose(...) spSkeletonBounds_dispose(__VA_ARGS__) -#define SkeletonBounds_update(...) spSkeletonBounds_update(__VA_ARGS__) -#define SkeletonBounds_aabbContainsPoint(...) spSkeletonBounds_aabbContainsPoint(__VA_ARGS__) -#define SkeletonBounds_aabbIntersectsSegment(...) spSkeletonBounds_aabbIntersectsSegment(__VA_ARGS__) -#define SkeletonBounds_aabbIntersectsSkeleton(...) spSkeletonBounds_aabbIntersectsSkeleton(__VA_ARGS__) -#define SkeletonBounds_containsPoint(...) spSkeletonBounds_containsPoint(__VA_ARGS__) -#define SkeletonBounds_intersectsSegment(...) spSkeletonBounds_intersectsSegment(__VA_ARGS__) -#define SkeletonBounds_getPolygon(...) spSkeletonBounds_getPolygon(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_SKELETONBOUNDS_H_ +#define SPINE_SKELETONBOUNDS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spPolygon { + float* const vertices; + int count; + int capacity; +} spPolygon; + +spPolygon* spPolygon_create (int capacity); +void spPolygon_dispose (spPolygon* self); + +int/*bool*/spPolygon_containsPoint (spPolygon* polygon, float x, float y); +int/*bool*/spPolygon_intersectsSegment (spPolygon* polygon, float x1, float y1, float x2, float y2); + +#ifdef SPINE_SHORT_NAMES +typedef spPolygon Polygon; +#define Polygon_create(...) spPolygon_create(__VA_ARGS__) +#define Polygon_dispose(...) spPolygon_dispose(__VA_ARGS__) +#define Polygon_containsPoint(...) spPolygon_containsPoint(__VA_ARGS__) +#define Polygon_intersectsSegment(...) spPolygon_intersectsSegment(__VA_ARGS__) +#endif + +/**/ + +typedef struct spSkeletonBounds { + int count; + spBoundingBoxAttachment** boundingBoxes; + spPolygon** polygons; + + float minX, minY, maxX, maxY; +} spSkeletonBounds; + +spSkeletonBounds* spSkeletonBounds_create (); +void spSkeletonBounds_dispose (spSkeletonBounds* self); +void spSkeletonBounds_update (spSkeletonBounds* self, spSkeleton* skeleton, int/*bool*/updateAabb); + +/** Returns true if the axis aligned bounding box contains the point. */ +int/*bool*/spSkeletonBounds_aabbContainsPoint (spSkeletonBounds* self, float x, float y); + +/** Returns true if the axis aligned bounding box intersects the line segment. */ +int/*bool*/spSkeletonBounds_aabbIntersectsSegment (spSkeletonBounds* self, float x1, float y1, float x2, float y2); + +/** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */ +int/*bool*/spSkeletonBounds_aabbIntersectsSkeleton (spSkeletonBounds* self, spSkeletonBounds* bounds); + +/** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more + * efficient to only call this method if spSkeletonBounds_aabbContainsPoint returns true. */ +spBoundingBoxAttachment* spSkeletonBounds_containsPoint (spSkeletonBounds* self, float x, float y); + +/** Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually + * more efficient to only call this method if spSkeletonBounds_aabbIntersectsSegment returns true. */ +spBoundingBoxAttachment* spSkeletonBounds_intersectsSegment (spSkeletonBounds* self, float x1, float y1, float x2, float y2); + +/** Returns the polygon for the specified bounding box, or null. */ +spPolygon* spSkeletonBounds_getPolygon (spSkeletonBounds* self, spBoundingBoxAttachment* boundingBox); + +#ifdef SPINE_SHORT_NAMES +typedef spSkeletonBounds SkeletonBounds; +#define SkeletonBounds_create(...) spSkeletonBounds_create(__VA_ARGS__) +#define SkeletonBounds_dispose(...) spSkeletonBounds_dispose(__VA_ARGS__) +#define SkeletonBounds_update(...) spSkeletonBounds_update(__VA_ARGS__) +#define SkeletonBounds_aabbContainsPoint(...) spSkeletonBounds_aabbContainsPoint(__VA_ARGS__) +#define SkeletonBounds_aabbIntersectsSegment(...) spSkeletonBounds_aabbIntersectsSegment(__VA_ARGS__) +#define SkeletonBounds_aabbIntersectsSkeleton(...) spSkeletonBounds_aabbIntersectsSkeleton(__VA_ARGS__) +#define SkeletonBounds_containsPoint(...) spSkeletonBounds_containsPoint(__VA_ARGS__) +#define SkeletonBounds_intersectsSegment(...) spSkeletonBounds_intersectsSegment(__VA_ARGS__) +#define SkeletonBounds_getPolygon(...) spSkeletonBounds_getPolygon(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_SKELETONBOUNDS_H_ */ diff --git a/spine-c/include/spine/SkeletonData.h b/spine-c/include/spine/SkeletonData.h index e9f9361da1..3ccd231d39 100644 --- a/spine-c/include/spine/SkeletonData.h +++ b/spine-c/include/spine/SkeletonData.h @@ -1,117 +1,116 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_SKELETONDATA_H_ -#define SPINE_SKELETONDATA_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spSkeletonData { - const char* version; - const char* hash; - float width, height; - - int bonesCount; - spBoneData** bones; - - int slotsCount; - spSlotData** slots; - - int skinsCount; - spSkin** skins; - spSkin* defaultSkin; - - int eventsCount; - spEventData** events; - - int animationsCount; - spAnimation** animations; - - int ikConstraintsCount; - spIkConstraintData** ikConstraints; - - int transformConstraintsCount; - spTransformConstraintData** transformConstraints; - - int pathConstraintsCount; - spPathConstraintData** pathConstraints; -} spSkeletonData; - -spSkeletonData* spSkeletonData_create (); -void spSkeletonData_dispose (spSkeletonData* self); - -spBoneData* spSkeletonData_findBone (const spSkeletonData* self, const char* boneName); -int spSkeletonData_findBoneIndex (const spSkeletonData* self, const char* boneName); - -spSlotData* spSkeletonData_findSlot (const spSkeletonData* self, const char* slotName); -int spSkeletonData_findSlotIndex (const spSkeletonData* self, const char* slotName); - -spSkin* spSkeletonData_findSkin (const spSkeletonData* self, const char* skinName); - -spEventData* spSkeletonData_findEvent (const spSkeletonData* self, const char* eventName); - -spAnimation* spSkeletonData_findAnimation (const spSkeletonData* self, const char* animationName); - -spIkConstraintData* spSkeletonData_findIkConstraint (const spSkeletonData* self, const char* constraintName); - -spTransformConstraintData* spSkeletonData_findTransformConstraint (const spSkeletonData* self, const char* constraintName); - -spPathConstraintData* spSkeletonData_findPathConstraint (const spSkeletonData* self, const char* constraintName); - -#ifdef SPINE_SHORT_NAMES -typedef spSkeletonData SkeletonData; -#define SkeletonData_create(...) spSkeletonData_create(__VA_ARGS__) -#define SkeletonData_dispose(...) spSkeletonData_dispose(__VA_ARGS__) -#define SkeletonData_findBone(...) spSkeletonData_findBone(__VA_ARGS__) -#define SkeletonData_findBoneIndex(...) spSkeletonData_findBoneIndex(__VA_ARGS__) -#define SkeletonData_findSlot(...) spSkeletonData_findSlot(__VA_ARGS__) -#define SkeletonData_findSlotIndex(...) spSkeletonData_findSlotIndex(__VA_ARGS__) -#define SkeletonData_findSkin(...) spSkeletonData_findSkin(__VA_ARGS__) -#define SkeletonData_findEvent(...) spSkeletonData_findEvent(__VA_ARGS__) -#define SkeletonData_findAnimation(...) spSkeletonData_findAnimation(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_SKELETONDATA_H_ +#define SPINE_SKELETONDATA_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spSkeletonData { + const char* version; + const char* hash; + float width, height; + + int bonesCount; + spBoneData** bones; + + int slotsCount; + spSlotData** slots; + + int skinsCount; + spSkin** skins; + spSkin* defaultSkin; + + int eventsCount; + spEventData** events; + + int animationsCount; + spAnimation** animations; + + int ikConstraintsCount; + spIkConstraintData** ikConstraints; + + int transformConstraintsCount; + spTransformConstraintData** transformConstraints; + + int pathConstraintsCount; + spPathConstraintData** pathConstraints; +} spSkeletonData; + +spSkeletonData* spSkeletonData_create (); +void spSkeletonData_dispose (spSkeletonData* self); + +spBoneData* spSkeletonData_findBone (const spSkeletonData* self, const char* boneName); +int spSkeletonData_findBoneIndex (const spSkeletonData* self, const char* boneName); + +spSlotData* spSkeletonData_findSlot (const spSkeletonData* self, const char* slotName); +int spSkeletonData_findSlotIndex (const spSkeletonData* self, const char* slotName); + +spSkin* spSkeletonData_findSkin (const spSkeletonData* self, const char* skinName); + +spEventData* spSkeletonData_findEvent (const spSkeletonData* self, const char* eventName); + +spAnimation* spSkeletonData_findAnimation (const spSkeletonData* self, const char* animationName); + +spIkConstraintData* spSkeletonData_findIkConstraint (const spSkeletonData* self, const char* constraintName); + +spTransformConstraintData* spSkeletonData_findTransformConstraint (const spSkeletonData* self, const char* constraintName); + +spPathConstraintData* spSkeletonData_findPathConstraint (const spSkeletonData* self, const char* constraintName); + +#ifdef SPINE_SHORT_NAMES +typedef spSkeletonData SkeletonData; +#define SkeletonData_create(...) spSkeletonData_create(__VA_ARGS__) +#define SkeletonData_dispose(...) spSkeletonData_dispose(__VA_ARGS__) +#define SkeletonData_findBone(...) spSkeletonData_findBone(__VA_ARGS__) +#define SkeletonData_findBoneIndex(...) spSkeletonData_findBoneIndex(__VA_ARGS__) +#define SkeletonData_findSlot(...) spSkeletonData_findSlot(__VA_ARGS__) +#define SkeletonData_findSlotIndex(...) spSkeletonData_findSlotIndex(__VA_ARGS__) +#define SkeletonData_findSkin(...) spSkeletonData_findSkin(__VA_ARGS__) +#define SkeletonData_findEvent(...) spSkeletonData_findEvent(__VA_ARGS__) +#define SkeletonData_findAnimation(...) spSkeletonData_findAnimation(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_SKELETONDATA_H_ */ diff --git a/spine-c/include/spine/SkeletonJson.h b/spine-c/include/spine/SkeletonJson.h index ab954ef7f4..e70f90a924 100644 --- a/spine-c/include/spine/SkeletonJson.h +++ b/spine-c/include/spine/SkeletonJson.h @@ -1,73 +1,72 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_SKELETONJSON_H_ -#define SPINE_SKELETONJSON_H_ - -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct spAtlasAttachmentLoader; - -typedef struct spSkeletonJson { - float scale; - spAttachmentLoader* attachmentLoader; - const char* const error; -} spSkeletonJson; - -spSkeletonJson* spSkeletonJson_createWithLoader (spAttachmentLoader* attachmentLoader); -spSkeletonJson* spSkeletonJson_create (spAtlas* atlas); -void spSkeletonJson_dispose (spSkeletonJson* self); - -spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const char* json); -spSkeletonData* spSkeletonJson_readSkeletonDataFile (spSkeletonJson* self, const char* path); - -#ifdef SPINE_SHORT_NAMES -typedef spSkeletonJson SkeletonJson; -#define SkeletonJson_createWithLoader(...) spSkeletonJson_createWithLoader(__VA_ARGS__) -#define SkeletonJson_create(...) spSkeletonJson_create(__VA_ARGS__) -#define SkeletonJson_dispose(...) spSkeletonJson_dispose(__VA_ARGS__) -#define SkeletonJson_readSkeletonData(...) spSkeletonJson_readSkeletonData(__VA_ARGS__) -#define SkeletonJson_readSkeletonDataFile(...) spSkeletonJson_readSkeletonDataFile(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_SKELETONJSON_H_ +#define SPINE_SKELETONJSON_H_ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct spAtlasAttachmentLoader; + +typedef struct spSkeletonJson { + float scale; + spAttachmentLoader* attachmentLoader; + const char* const error; +} spSkeletonJson; + +spSkeletonJson* spSkeletonJson_createWithLoader (spAttachmentLoader* attachmentLoader); +spSkeletonJson* spSkeletonJson_create (spAtlas* atlas); +void spSkeletonJson_dispose (spSkeletonJson* self); + +spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const char* json); +spSkeletonData* spSkeletonJson_readSkeletonDataFile (spSkeletonJson* self, const char* path); + +#ifdef SPINE_SHORT_NAMES +typedef spSkeletonJson SkeletonJson; +#define SkeletonJson_createWithLoader(...) spSkeletonJson_createWithLoader(__VA_ARGS__) +#define SkeletonJson_create(...) spSkeletonJson_create(__VA_ARGS__) +#define SkeletonJson_dispose(...) spSkeletonJson_dispose(__VA_ARGS__) +#define SkeletonJson_readSkeletonData(...) spSkeletonJson_readSkeletonData(__VA_ARGS__) +#define SkeletonJson_readSkeletonDataFile(...) spSkeletonJson_readSkeletonDataFile(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_SKELETONJSON_H_ */ diff --git a/spine-c/include/spine/Skin.h b/spine-c/include/spine/Skin.h index ff9ac2cc05..b5dc063174 100644 --- a/spine-c/include/spine/Skin.h +++ b/spine-c/include/spine/Skin.h @@ -1,95 +1,94 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_SKIN_H_ -#define SPINE_SKIN_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct spSkeleton; - -typedef struct spSkin { - const char* const name; - -#ifdef __cplusplus - spSkin() : - name(0) { - } -#endif -} spSkin; - -/* Private structs, needed by Skeleton */ -typedef struct _Entry _Entry; -struct _Entry { - int slotIndex; - const char* name; - spAttachment* attachment; - _Entry* next; -}; - -typedef struct { - spSkin super; - _Entry* entries; -} _spSkin; - -spSkin* spSkin_create (const char* name); -void spSkin_dispose (spSkin* self); - -/* The Skin owns the attachment. */ -void spSkin_addAttachment (spSkin* self, int slotIndex, const char* name, spAttachment* attachment); -/* Returns 0 if the attachment was not found. */ -spAttachment* spSkin_getAttachment (const spSkin* self, int slotIndex, const char* name); - -/* Returns 0 if the slot or attachment was not found. */ -const char* spSkin_getAttachmentName (const spSkin* self, int slotIndex, int attachmentIndex); - -/** Attach each attachment in this skin if the corresponding attachment in oldSkin is currently attached. */ -void spSkin_attachAll (const spSkin* self, struct spSkeleton* skeleton, const spSkin* oldspSkin); - -#ifdef SPINE_SHORT_NAMES -typedef spSkin Skin; -#define Skin_create(...) spSkin_create(__VA_ARGS__) -#define Skin_dispose(...) spSkin_dispose(__VA_ARGS__) -#define Skin_addAttachment(...) spSkin_addAttachment(__VA_ARGS__) -#define Skin_getAttachment(...) spSkin_getAttachment(__VA_ARGS__) -#define Skin_getAttachmentName(...) spSkin_getAttachmentName(__VA_ARGS__) -#define Skin_attachAll(...) spSkin_attachAll(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_SKIN_H_ +#define SPINE_SKIN_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct spSkeleton; + +typedef struct spSkin { + const char* const name; + +#ifdef __cplusplus + spSkin() : + name(0) { + } +#endif +} spSkin; + +/* Private structs, needed by Skeleton */ +typedef struct _Entry _Entry; +struct _Entry { + int slotIndex; + const char* name; + spAttachment* attachment; + _Entry* next; +}; + +typedef struct { + spSkin super; + _Entry* entries; +} _spSkin; + +spSkin* spSkin_create (const char* name); +void spSkin_dispose (spSkin* self); + +/* The Skin owns the attachment. */ +void spSkin_addAttachment (spSkin* self, int slotIndex, const char* name, spAttachment* attachment); +/* Returns 0 if the attachment was not found. */ +spAttachment* spSkin_getAttachment (const spSkin* self, int slotIndex, const char* name); + +/* Returns 0 if the slot or attachment was not found. */ +const char* spSkin_getAttachmentName (const spSkin* self, int slotIndex, int attachmentIndex); + +/** Attach each attachment in this skin if the corresponding attachment in oldSkin is currently attached. */ +void spSkin_attachAll (const spSkin* self, struct spSkeleton* skeleton, const spSkin* oldspSkin); + +#ifdef SPINE_SHORT_NAMES +typedef spSkin Skin; +#define Skin_create(...) spSkin_create(__VA_ARGS__) +#define Skin_dispose(...) spSkin_dispose(__VA_ARGS__) +#define Skin_addAttachment(...) spSkin_addAttachment(__VA_ARGS__) +#define Skin_getAttachment(...) spSkin_getAttachment(__VA_ARGS__) +#define Skin_getAttachmentName(...) spSkin_getAttachmentName(__VA_ARGS__) +#define Skin_attachAll(...) spSkin_attachAll(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_SKIN_H_ */ diff --git a/spine-c/include/spine/Slot.h b/spine-c/include/spine/Slot.h index f43e103e3a..26548ce558 100644 --- a/spine-c/include/spine/Slot.h +++ b/spine-c/include/spine/Slot.h @@ -1,91 +1,90 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_SLOT_H_ -#define SPINE_SLOT_H_ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spSlot { - spSlotData* const data; - spBone* const bone; - float r, g, b, a; - spAttachment* const attachment; - - int attachmentVerticesCapacity; - int attachmentVerticesCount; - float* attachmentVertices; - -#ifdef __cplusplus - spSlot() : - data(0), - bone(0), - r(0), g(0), b(0), a(0), - attachment(0), - attachmentVerticesCapacity(0), - attachmentVerticesCount(0), - attachmentVertices(0) { - } -#endif -} spSlot; - -spSlot* spSlot_create (spSlotData* data, spBone* bone); -void spSlot_dispose (spSlot* self); - -/* @param attachment May be 0 to clear the attachment for the slot. */ -void spSlot_setAttachment (spSlot* self, spAttachment* attachment); - -void spSlot_setAttachmentTime (spSlot* self, float time); -float spSlot_getAttachmentTime (const spSlot* self); - -void spSlot_setToSetupPose (spSlot* self); - -#ifdef SPINE_SHORT_NAMES -typedef spSlot Slot; -#define Slot_create(...) spSlot_create(__VA_ARGS__) -#define Slot_dispose(...) spSlot_dispose(__VA_ARGS__) -#define Slot_setAttachment(...) spSlot_setAttachment(__VA_ARGS__) -#define Slot_setAttachmentTime(...) spSlot_setAttachmentTime(__VA_ARGS__) -#define Slot_getAttachmentTime(...) spSlot_getAttachmentTime(__VA_ARGS__) -#define Slot_setToSetupPose(...) spSlot_setToSetupPose(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_SLOT_H_ +#define SPINE_SLOT_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spSlot { + spSlotData* const data; + spBone* const bone; + float r, g, b, a; + spAttachment* const attachment; + + int attachmentVerticesCapacity; + int attachmentVerticesCount; + float* attachmentVertices; + +#ifdef __cplusplus + spSlot() : + data(0), + bone(0), + r(0), g(0), b(0), a(0), + attachment(0), + attachmentVerticesCapacity(0), + attachmentVerticesCount(0), + attachmentVertices(0) { + } +#endif +} spSlot; + +spSlot* spSlot_create (spSlotData* data, spBone* bone); +void spSlot_dispose (spSlot* self); + +/* @param attachment May be 0 to clear the attachment for the slot. */ +void spSlot_setAttachment (spSlot* self, spAttachment* attachment); + +void spSlot_setAttachmentTime (spSlot* self, float time); +float spSlot_getAttachmentTime (const spSlot* self); + +void spSlot_setToSetupPose (spSlot* self); + +#ifdef SPINE_SHORT_NAMES +typedef spSlot Slot; +#define Slot_create(...) spSlot_create(__VA_ARGS__) +#define Slot_dispose(...) spSlot_dispose(__VA_ARGS__) +#define Slot_setAttachment(...) spSlot_setAttachment(__VA_ARGS__) +#define Slot_setAttachmentTime(...) spSlot_setAttachmentTime(__VA_ARGS__) +#define Slot_getAttachmentTime(...) spSlot_getAttachmentTime(__VA_ARGS__) +#define Slot_setToSetupPose(...) spSlot_setToSetupPose(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_SLOT_H_ */ diff --git a/spine-c/include/spine/SlotData.h b/spine-c/include/spine/SlotData.h index 2673b9df15..299a952954 100644 --- a/spine-c/include/spine/SlotData.h +++ b/spine-c/include/spine/SlotData.h @@ -1,87 +1,86 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_SLOTDATA_H_ -#define SPINE_SLOTDATA_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - SP_BLEND_MODE_NORMAL, SP_BLEND_MODE_ADDITIVE, SP_BLEND_MODE_MULTIPLY, SP_BLEND_MODE_SCREEN -} spBlendMode; - -typedef struct spSlotData { - const int index; - const char* const name; - const spBoneData* const boneData; - const char* attachmentName; - float r, g, b, a; - spBlendMode blendMode; - -#ifdef __cplusplus - spSlotData() : - index(0), - name(0), - boneData(0), - attachmentName(0), - r(0), g(0), b(0), a(0), - blendMode(SP_BLEND_MODE_NORMAL) { - } -#endif -} spSlotData; - -spSlotData* spSlotData_create (const int index, const char* name, spBoneData* boneData); -void spSlotData_dispose (spSlotData* self); - -/* @param attachmentName May be 0 for no setup pose attachment. */ -void spSlotData_setAttachmentName (spSlotData* self, const char* attachmentName); - -#ifdef SPINE_SHORT_NAMES -typedef spBlendMode BlendMode; -#define BLEND_MODE_NORMAL SP_BLEND_MODE_NORMAL -#define BLEND_MODE_ADDITIVE SP_BLEND_MODE_ADDITIVE -#define BLEND_MODE_MULTIPLY SP_BLEND_MODE_MULTIPLY -#define BLEND_MODE_SCREEN SP_BLEND_MODE_SCREEN -typedef spSlotData SlotData; -#define SlotData_create(...) spSlotData_create(__VA_ARGS__) -#define SlotData_dispose(...) spSlotData_dispose(__VA_ARGS__) -#define SlotData_setAttachmentName(...) spSlotData_setAttachmentName(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_SLOTDATA_H_ +#define SPINE_SLOTDATA_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + SP_BLEND_MODE_NORMAL, SP_BLEND_MODE_ADDITIVE, SP_BLEND_MODE_MULTIPLY, SP_BLEND_MODE_SCREEN +} spBlendMode; + +typedef struct spSlotData { + const int index; + const char* const name; + const spBoneData* const boneData; + const char* attachmentName; + float r, g, b, a; + spBlendMode blendMode; + +#ifdef __cplusplus + spSlotData() : + index(0), + name(0), + boneData(0), + attachmentName(0), + r(0), g(0), b(0), a(0), + blendMode(SP_BLEND_MODE_NORMAL) { + } +#endif +} spSlotData; + +spSlotData* spSlotData_create (const int index, const char* name, spBoneData* boneData); +void spSlotData_dispose (spSlotData* self); + +/* @param attachmentName May be 0 for no setup pose attachment. */ +void spSlotData_setAttachmentName (spSlotData* self, const char* attachmentName); + +#ifdef SPINE_SHORT_NAMES +typedef spBlendMode BlendMode; +#define BLEND_MODE_NORMAL SP_BLEND_MODE_NORMAL +#define BLEND_MODE_ADDITIVE SP_BLEND_MODE_ADDITIVE +#define BLEND_MODE_MULTIPLY SP_BLEND_MODE_MULTIPLY +#define BLEND_MODE_SCREEN SP_BLEND_MODE_SCREEN +typedef spSlotData SlotData; +#define SlotData_create(...) spSlotData_create(__VA_ARGS__) +#define SlotData_dispose(...) spSlotData_dispose(__VA_ARGS__) +#define SlotData_setAttachmentName(...) spSlotData_setAttachmentName(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_SLOTDATA_H_ */ diff --git a/spine-c/include/spine/TransformConstraint.h b/spine-c/include/spine/TransformConstraint.h index b2b01f8d99..6cce5274c7 100644 --- a/spine-c/include/spine/TransformConstraint.h +++ b/spine-c/include/spine/TransformConstraint.h @@ -1,81 +1,80 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_TRANSFORMCONSTRAINT_H_ -#define SPINE_TRANSFORMCONSTRAINT_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct spSkeleton; - -typedef struct spTransformConstraint { - spTransformConstraintData* const data; - int bonesCount; - spBone** const bones; - spBone* target; - float rotateMix, translateMix, scaleMix, shearMix; - -#ifdef __cplusplus - spTransformConstraint() : - data(0), - bonesCount(0), - bones(0), - target(0), - rotateMix(0), - translateMix(0), - scaleMix(0), - shearMix(0) { - } -#endif -} spTransformConstraint; - -spTransformConstraint* spTransformConstraint_create (spTransformConstraintData* data, const struct spSkeleton* skeleton); -void spTransformConstraint_dispose (spTransformConstraint* self); - -void spTransformConstraint_apply (spTransformConstraint* self); - -#ifdef SPINE_SHORT_NAMES -typedef spTransformConstraint TransformConstraint; -#define TransformConstraint_create(...) spTransformConstraint_create(__VA_ARGS__) -#define TransformConstraint_dispose(...) spTransformConstraint_dispose(__VA_ARGS__) -#define TransformConstraint_apply(...) spTransformConstraint_apply(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_TRANSFORMCONSTRAINT_H_ +#define SPINE_TRANSFORMCONSTRAINT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct spSkeleton; + +typedef struct spTransformConstraint { + spTransformConstraintData* const data; + int bonesCount; + spBone** const bones; + spBone* target; + float rotateMix, translateMix, scaleMix, shearMix; + +#ifdef __cplusplus + spTransformConstraint() : + data(0), + bonesCount(0), + bones(0), + target(0), + rotateMix(0), + translateMix(0), + scaleMix(0), + shearMix(0) { + } +#endif +} spTransformConstraint; + +spTransformConstraint* spTransformConstraint_create (spTransformConstraintData* data, const struct spSkeleton* skeleton); +void spTransformConstraint_dispose (spTransformConstraint* self); + +void spTransformConstraint_apply (spTransformConstraint* self); + +#ifdef SPINE_SHORT_NAMES +typedef spTransformConstraint TransformConstraint; +#define TransformConstraint_create(...) spTransformConstraint_create(__VA_ARGS__) +#define TransformConstraint_dispose(...) spTransformConstraint_dispose(__VA_ARGS__) +#define TransformConstraint_apply(...) spTransformConstraint_apply(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_TRANSFORMCONSTRAINT_H_ */ diff --git a/spine-c/include/spine/TransformConstraintData.h b/spine-c/include/spine/TransformConstraintData.h index 1c71d04275..cd107c5633 100644 --- a/spine-c/include/spine/TransformConstraintData.h +++ b/spine-c/include/spine/TransformConstraintData.h @@ -1,82 +1,81 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_TRANSFORMCONSTRAINTDATA_H_ -#define SPINE_TRANSFORMCONSTRAINTDATA_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spTransformConstraintData { - const char* const name; - int bonesCount; - spBoneData** const bones; - spBoneData* target; - float rotateMix, translateMix, scaleMix, shearMix; - float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY; - -#ifdef __cplusplus - spTransformConstraintData() : - name(0), - bonesCount(0), - bones(0), - target(0), - rotateMix(0), - translateMix(0), - scaleMix(0), - shearMix(0), - offsetRotation(0), - offsetX(0), - offsetY(0), - offsetScaleX(0), - offsetScaleY(0), - offsetShearY(0) { - } -#endif -} spTransformConstraintData; - -spTransformConstraintData* spTransformConstraintData_create (const char* name); -void spTransformConstraintData_dispose (spTransformConstraintData* self); - -#ifdef SPINE_SHORT_NAMES -typedef spTransformConstraintData TransformConstraintData; -#define TransformConstraintData_create(...) spTransformConstraintData_create(__VA_ARGS__) -#define TransformConstraintData_dispose(...) spTransformConstraintData_dispose(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_TRANSFORMCONSTRAINTDATA_H_ +#define SPINE_TRANSFORMCONSTRAINTDATA_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spTransformConstraintData { + const char* const name; + int bonesCount; + spBoneData** const bones; + spBoneData* target; + float rotateMix, translateMix, scaleMix, shearMix; + float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY; + +#ifdef __cplusplus + spTransformConstraintData() : + name(0), + bonesCount(0), + bones(0), + target(0), + rotateMix(0), + translateMix(0), + scaleMix(0), + shearMix(0), + offsetRotation(0), + offsetX(0), + offsetY(0), + offsetScaleX(0), + offsetScaleY(0), + offsetShearY(0) { + } +#endif +} spTransformConstraintData; + +spTransformConstraintData* spTransformConstraintData_create (const char* name); +void spTransformConstraintData_dispose (spTransformConstraintData* self); + +#ifdef SPINE_SHORT_NAMES +typedef spTransformConstraintData TransformConstraintData; +#define TransformConstraintData_create(...) spTransformConstraintData_create(__VA_ARGS__) +#define TransformConstraintData_dispose(...) spTransformConstraintData_dispose(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_TRANSFORMCONSTRAINTDATA_H_ */ diff --git a/spine-c/include/spine/VertexAttachment.h b/spine-c/include/spine/VertexAttachment.h index 6c220eb9e7..6b0d1d4555 100644 --- a/spine-c/include/spine/VertexAttachment.h +++ b/spine-c/include/spine/VertexAttachment.h @@ -1,68 +1,67 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_VERTEXATTACHMENT_H_ -#define SPINE_VERTEXATTACHMENT_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct spVertexAttachment spVertexAttachment; -struct spVertexAttachment { - spAttachment super; - - int bonesCount; - int* bones; - - int verticesCount; - float* vertices; - - int worldVerticesLength; -}; - -void spVertexAttachment_computeWorldVertices (spVertexAttachment* self, spSlot* slot, float* worldVertices); -void spVertexAttachment_computeWorldVertices1 (spVertexAttachment* self, int start, int count, spSlot* slot, float* worldVertices, int offset); - -#ifdef SPINE_SHORT_NAMES -typedef spVertexAttachment VertexAttachment; -#define VertexAttachment_computeWorldVertices(...) spVertexAttachment_computeWorldVertices(__VA_ARGS__) -#define VertexAttachment_computeWorldVertices1(...) spVertexAttachment_computeWorldVertices1(__VA_ARGS__) -#endif - -#ifdef __cplusplus -} -#endif - +#ifndef SPINE_VERTEXATTACHMENT_H_ +#define SPINE_VERTEXATTACHMENT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct spVertexAttachment spVertexAttachment; +struct spVertexAttachment { + spAttachment super; + + int bonesCount; + int* bones; + + int verticesCount; + float* vertices; + + int worldVerticesLength; +}; + +void spVertexAttachment_computeWorldVertices (spVertexAttachment* self, spSlot* slot, float* worldVertices); +void spVertexAttachment_computeWorldVertices1 (spVertexAttachment* self, int start, int count, spSlot* slot, float* worldVertices, int offset); + +#ifdef SPINE_SHORT_NAMES +typedef spVertexAttachment VertexAttachment; +#define VertexAttachment_computeWorldVertices(...) spVertexAttachment_computeWorldVertices(__VA_ARGS__) +#define VertexAttachment_computeWorldVertices1(...) spVertexAttachment_computeWorldVertices1(__VA_ARGS__) +#endif + +#ifdef __cplusplus +} +#endif + #endif /* SPINE_VERTEXATTACHMENT_H_ */ diff --git a/spine-c/include/spine/spine.h b/spine-c/include/spine/spine.h index 704e89407c..37dbaadf81 100644 --- a/spine-c/include/spine/spine.h +++ b/spine-c/include/spine/spine.h @@ -1,59 +1,58 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_SPINE_H_ -#define SPINE_SPINE_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - +#ifndef SPINE_SPINE_H_ +#define SPINE_SPINE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #endif /* SPINE_SPINE_H_ */ diff --git a/spine-c/src/spine/Animation.c b/spine-c/src/spine/Animation.c index 8012d408b5..ebe7abe09a 100644 --- a/spine-c/src/spine/Animation.c +++ b/spine-c/src/spine/Animation.c @@ -1,1056 +1,1055 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include -#include - -spAnimation* spAnimation_create (const char* name, int timelinesCount) { - spAnimation* self = NEW(spAnimation); - MALLOC_STR(self->name, name); - self->timelinesCount = timelinesCount; - self->timelines = MALLOC(spTimeline*, timelinesCount); - return self; -} - -void spAnimation_dispose (spAnimation* self) { - int i; - for (i = 0; i < self->timelinesCount; ++i) - spTimeline_dispose(self->timelines[i]); - FREE(self->timelines); - FREE(self->name); - FREE(self); -} - -void spAnimation_apply (const spAnimation* self, spSkeleton* skeleton, float lastTime, float time, int loop, spEvent** events, - int* eventsCount) { - int i, n = self->timelinesCount; - - if (loop && self->duration) { - time = FMOD(time, self->duration); - if (lastTime > 0) lastTime = FMOD(lastTime, self->duration); - } - - for (i = 0; i < n; ++i) - spTimeline_apply(self->timelines[i], skeleton, lastTime, time, events, eventsCount, 1); -} - -void spAnimation_mix (const spAnimation* self, spSkeleton* skeleton, float lastTime, float time, int loop, spEvent** events, - int* eventsCount, float alpha) { - int i, n = self->timelinesCount; - - if (loop && self->duration) { - time = FMOD(time, self->duration); - if (lastTime > 0) lastTime = FMOD(lastTime, self->duration); - } - - for (i = 0; i < n; ++i) - spTimeline_apply(self->timelines[i], skeleton, lastTime, time, events, eventsCount, alpha); -} - -/**/ - -typedef struct _spTimelineVtable { - void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha); - void (*dispose) (spTimeline* self); -} _spTimelineVtable; - -void _spTimeline_init (spTimeline* self, spTimelineType type, /**/ -void (*dispose) (spTimeline* self), /**/ - void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha)) { - CONST_CAST(spTimelineType, self->type) = type; - CONST_CAST(_spTimelineVtable*, self->vtable) = NEW(_spTimelineVtable); - VTABLE(spTimeline, self)->dispose = dispose; - VTABLE(spTimeline, self)->apply = apply; -} - -void _spTimeline_deinit (spTimeline* self) { - FREE(self->vtable); -} - -void spTimeline_dispose (spTimeline* self) { - VTABLE(spTimeline, self)->dispose(self); -} - -void spTimeline_apply (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha) { - VTABLE(spTimeline, self)->apply(self, skeleton, lastTime, time, firedEvents, eventsCount, alpha); -} - -/**/ - -static const float CURVE_LINEAR = 0, CURVE_STEPPED = 1, CURVE_BEZIER = 2; -static const int BEZIER_SIZE = 10 * 2 - 1; - -void _spCurveTimeline_init (spCurveTimeline* self, spTimelineType type, int framesCount, /**/ -void (*dispose) (spTimeline* self), /**/ - void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha)) { - _spTimeline_init(SUPER(self), type, dispose, apply); - self->curves = CALLOC(float, (framesCount - 1) * BEZIER_SIZE); -} - -void _spCurveTimeline_deinit (spCurveTimeline* self) { - _spTimeline_deinit(SUPER(self)); - FREE(self->curves); -} - -void spCurveTimeline_setLinear (spCurveTimeline* self, int frameIndex) { - self->curves[frameIndex * BEZIER_SIZE] = CURVE_LINEAR; -} - -void spCurveTimeline_setStepped (spCurveTimeline* self, int frameIndex) { - self->curves[frameIndex * BEZIER_SIZE] = CURVE_STEPPED; -} - -void spCurveTimeline_setCurve (spCurveTimeline* self, int frameIndex, float cx1, float cy1, float cx2, float cy2) { - float tmpx = (-cx1 * 2 + cx2) * 0.03f, tmpy = (-cy1 * 2 + cy2) * 0.03f; - float dddfx = ((cx1 - cx2) * 3 + 1) * 0.006f, dddfy = ((cy1 - cy2) * 3 + 1) * 0.006f; - float ddfx = tmpx * 2 + dddfx, ddfy = tmpy * 2 + dddfy; - float dfx = cx1 * 0.3f + tmpx + dddfx * 0.16666667f, dfy = cy1 * 0.3f + tmpy + dddfy * 0.16666667f; - float x = dfx, y = dfy; - - int i = frameIndex * BEZIER_SIZE, n = i + BEZIER_SIZE - 1; - self->curves[i++] = CURVE_BEZIER; - - for (; i < n; i += 2) { - self->curves[i] = x; - self->curves[i + 1] = y; - dfx += ddfx; - dfy += ddfy; - ddfx += dddfx; - ddfy += dddfy; - x += dfx; - y += dfy; - } -} - -float spCurveTimeline_getCurvePercent (const spCurveTimeline* self, int frameIndex, float percent) { - float x, y; - int i = frameIndex * BEZIER_SIZE, start, n; - float type = self->curves[i]; - percent = CLAMP(percent, 0, 1); - if (type == CURVE_LINEAR) return percent; - if (type == CURVE_STEPPED) return 0; - i++; - x = 0; - for (start = i, n = i + BEZIER_SIZE - 1; i < n; i += 2) { - x = self->curves[i]; - if (x >= percent) { - float prevX, prevY; - if (i == start) { - prevX = 0; - prevY = 0; - } else { - prevX = self->curves[i - 2]; - prevY = self->curves[i - 1]; - } - return prevY + (self->curves[i + 1] - prevY) * (percent - prevX) / (x - prevX); - } - } - y = self->curves[i - 1]; - return y + (1 - y) * (percent - x) / (1 - x); /* Last point is 1,1. */ -} - -/* @param target After the first and before the last entry. */ -static int binarySearch (float *values, int valuesLength, float target, int step) { - int low = 0, current; - int high = valuesLength / step - 2; - if (high == 0) return step; - current = high >> 1; - while (1) { - if (values[(current + 1) * step] <= target) - low = current + 1; - else - high = current; - if (low == high) return (low + 1) * step; - current = (low + high) >> 1; - } - return 0; -} - -/* @param target After the first and before the last entry. */ -static int binarySearch1 (float *values, int valuesLength, float target) { - int low = 0, current; - int high = valuesLength - 2; - if (high == 0) return 1; - current = high >> 1; - while (1) { - if (values[(current + 1)] <= target) - low = current + 1; - else - high = current; - if (low == high) return low + 1; - current = (low + high) >> 1; - } - return 0; -} - -/**/ - -void _spBaseTimeline_dispose (spTimeline* timeline) { - struct spBaseTimeline* self = SUB_CAST(struct spBaseTimeline, timeline); - _spCurveTimeline_deinit(SUPER(self)); - FREE(self->frames); - FREE(self); -} - -/* Many timelines have structure identical to struct spBaseTimeline and extend spCurveTimeline. **/ -struct spBaseTimeline* _spBaseTimeline_create (int framesCount, spTimelineType type, int frameSize, /**/ - void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha)) { - struct spBaseTimeline* self = NEW(struct spBaseTimeline); - _spCurveTimeline_init(SUPER(self), type, framesCount, _spBaseTimeline_dispose, apply); - - CONST_CAST(int, self->framesCount) = framesCount * frameSize; - CONST_CAST(float*, self->frames) = CALLOC(float, self->framesCount); - - return self; -} - -/**/ - -static const int ROTATE_PREV_TIME = -2, ROTATE_PREV_ROTATION = -1; -static const int ROTATE_ROTATION = 1; - -void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha) { - spBone *bone; - int frame; - float prevRotation, frameTime, percent, amount; - - spRotateTimeline* self = SUB_CAST(spRotateTimeline, timeline); - - if (time < self->frames[0]) return; /* Time is before first frame. */ - - bone = skeleton->bones[self->boneIndex]; - - if (time >= self->frames[self->framesCount - ROTATE_ENTRIES]) { /* Time is after last frame. */ - amount = bone->data->rotation + self->frames[self->framesCount + ROTATE_PREV_ROTATION] - bone->rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone->rotation += amount * alpha; - return; - } - - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch(self->frames, self->framesCount, time, ROTATE_ENTRIES); - prevRotation = self->frames[frame + ROTATE_PREV_ROTATION]; - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), (frame >> 1) - 1, 1 - (time - frameTime) / (self->frames[frame + ROTATE_PREV_TIME] - frameTime)); - - amount = self->frames[frame + ROTATE_ROTATION] - prevRotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - amount = bone->data->rotation + (prevRotation + amount * percent) - bone->rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone->rotation += amount * alpha; - - UNUSED(lastTime); - UNUSED(firedEvents); - UNUSED(eventsCount); -} - -spRotateTimeline* spRotateTimeline_create (int framesCount) { - return _spBaseTimeline_create(framesCount, SP_TIMELINE_ROTATE, ROTATE_ENTRIES, _spRotateTimeline_apply); -} - -void spRotateTimeline_setFrame (spRotateTimeline* self, int frameIndex, float time, float degrees) { - frameIndex <<= 1; - self->frames[frameIndex] = time; - self->frames[frameIndex + ROTATE_ROTATION] = degrees; -} - -/**/ - -static const int TRANSLATE_PREV_TIME = -3, TRANSLATE_PREV_X = -2, TRANSLATE_PREV_Y = -1; -static const int TRANSLATE_X = 1, TRANSLATE_Y = 2; - -void _spTranslateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventsCount, float alpha) { - spBone *bone; - int frame; - float prevX, prevY, frameTime, percent; - - spTranslateTimeline* self = SUB_CAST(spTranslateTimeline, timeline); - - if (time < self->frames[0]) return; /* Time is before first frame. */ - - bone = skeleton->bones[self->boneIndex]; - - if (time >= self->frames[self->framesCount - TRANSLATE_ENTRIES]) { /* Time is after last frame. */ - bone->x += (bone->data->x + self->frames[self->framesCount + TRANSLATE_PREV_X] - bone->x) * alpha; - bone->y += (bone->data->y + self->frames[self->framesCount + TRANSLATE_PREV_Y] - bone->y) * alpha; - return; - } - - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch(self->frames, self->framesCount, time, TRANSLATE_ENTRIES); - prevX = self->frames[frame + TRANSLATE_PREV_X]; - prevY = self->frames[frame + TRANSLATE_PREV_Y]; - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / TRANSLATE_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + TRANSLATE_PREV_TIME] - frameTime)); - - bone->x += (bone->data->x + prevX + (self->frames[frame + TRANSLATE_X] - prevX) * percent - bone->x) * alpha; - bone->y += (bone->data->y + prevY + (self->frames[frame + TRANSLATE_Y] - prevY) * percent - bone->y) * alpha; - - UNUSED(lastTime); - UNUSED(firedEvents); - UNUSED(eventsCount); -} - -spTranslateTimeline* spTranslateTimeline_create (int framesCount) { - return _spBaseTimeline_create(framesCount, SP_TIMELINE_TRANSLATE, TRANSLATE_ENTRIES, _spTranslateTimeline_apply); -} - -void spTranslateTimeline_setFrame (spTranslateTimeline* self, int frameIndex, float time, float x, float y) { - frameIndex *= TRANSLATE_ENTRIES; - self->frames[frameIndex] = time; - self->frames[frameIndex + TRANSLATE_X] = x; - self->frames[frameIndex + TRANSLATE_Y] = y; -} - -/**/ - -void _spScaleTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha) { - spBone *bone; - int frame; - float prevX, prevY, frameTime, percent; - - spScaleTimeline* self = SUB_CAST(spScaleTimeline, timeline); - - if (time < self->frames[0]) return; /* Time is before first frame. */ - - bone = skeleton->bones[self->boneIndex]; - if (time >= self->frames[self->framesCount - TRANSLATE_ENTRIES]) { /* Time is after last frame. */ - bone->scaleX += (bone->data->scaleX * self->frames[self->framesCount + TRANSLATE_PREV_X] - bone->scaleX) * alpha; - bone->scaleY += (bone->data->scaleY * self->frames[self->framesCount + TRANSLATE_PREV_Y] - bone->scaleY) * alpha; - return; - } - - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch(self->frames, self->framesCount, time, TRANSLATE_ENTRIES); - prevX = self->frames[frame + TRANSLATE_PREV_X]; - prevY = self->frames[frame + TRANSLATE_PREV_Y]; - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / TRANSLATE_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + TRANSLATE_PREV_TIME] - frameTime)); - - bone->scaleX += (bone->data->scaleX * (prevX + (self->frames[frame + TRANSLATE_X] - prevX) * percent) - bone->scaleX) * alpha; - bone->scaleY += (bone->data->scaleY * (prevY + (self->frames[frame + TRANSLATE_Y] - prevY) * percent) - bone->scaleY) * alpha; - - UNUSED(lastTime); - UNUSED(firedEvents); - UNUSED(eventsCount); -} - -spScaleTimeline* spScaleTimeline_create (int framesCount) { - return _spBaseTimeline_create(framesCount, SP_TIMELINE_SCALE, TRANSLATE_ENTRIES, _spScaleTimeline_apply); -} - -void spScaleTimeline_setFrame (spScaleTimeline* self, int frameIndex, float time, float x, float y) { - spTranslateTimeline_setFrame(self, frameIndex, time, x, y); -} - -/**/ - -void _spShearTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha) { - spBone *bone; - int frame; - float prevX, prevY, frameTime, percent; - - spShearTimeline* self = SUB_CAST(spShearTimeline, timeline); - - if (time < self->frames[0]) return; /* Time is before first frame. */ - - bone = skeleton->bones[self->boneIndex]; - if (time >= self->frames[self->framesCount - TRANSLATE_ENTRIES]) { /* Time is after last frame. */ - bone->shearX += (bone->data->shearX + self->frames[self->framesCount + TRANSLATE_PREV_X] - bone->shearX) * alpha; - bone->shearY += (bone->data->shearY + self->frames[self->framesCount + TRANSLATE_PREV_Y] - bone->shearY) * alpha; - return; - } - - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch(self->frames, self->framesCount, time, TRANSLATE_ENTRIES); - prevX = self->frames[frame + TRANSLATE_PREV_X]; - prevY = self->frames[frame + TRANSLATE_PREV_Y]; - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / TRANSLATE_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + TRANSLATE_PREV_TIME] - frameTime)); - - bone->shearX += (bone->data->shearX + prevX + (self->frames[frame + TRANSLATE_X] - prevX) * percent - bone->shearX) * alpha; - bone->shearY += (bone->data->shearY + prevY + (self->frames[frame + TRANSLATE_Y] - prevY) * percent - bone->shearY) * alpha; - - UNUSED(lastTime); - UNUSED(firedEvents); - UNUSED(eventsCount); -} - -spShearTimeline* spShearTimeline_create (int framesCount) { - return (spShearTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_SHEAR, 3, _spShearTimeline_apply); -} - -void spShearTimeline_setFrame (spShearTimeline* self, int frameIndex, float time, float x, float y) { - spTranslateTimeline_setFrame(self, frameIndex, time, x, y); -} - -/**/ - -static const int COLOR_PREV_TIME = -5, COLOR_PREV_R = -4, COLOR_PREV_G = -3, COLOR_PREV_B = -2, COLOR_PREV_A = -1; -static const int COLOR_R = 1, COLOR_G = 2, COLOR_B = 3, COLOR_A = 4; - -void _spColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha) { - spSlot *slot; - int frame; - float percent, frameTime; - float r, g, b, a; - spColorTimeline* self = (spColorTimeline*)timeline; - - if (time < self->frames[0]) return; /* Time is before first frame. */ - - if (time >= self->frames[self->framesCount - 5]) { /* Time is after last frame */ - int i = self->framesCount; - r = self->frames[i + COLOR_PREV_R]; - g = self->frames[i + COLOR_PREV_G]; - b = self->frames[i + COLOR_PREV_B]; - a = self->frames[i + COLOR_PREV_A]; - } else { - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch(self->frames, self->framesCount, time, COLOR_ENTRIES); - - r = self->frames[frame + COLOR_PREV_R]; - g = self->frames[frame + COLOR_PREV_G]; - b = self->frames[frame + COLOR_PREV_B]; - a = self->frames[frame + COLOR_PREV_A]; - - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / COLOR_ENTRIES - 1, - 1 - (time - frameTime) / (self->frames[frame + COLOR_PREV_TIME] - frameTime)); - - r += (self->frames[frame + COLOR_R] - r) * percent; - g += (self->frames[frame + COLOR_G] - g) * percent; - b += (self->frames[frame + COLOR_B] - b) * percent; - a += (self->frames[frame + COLOR_A] - a) * percent; - } - slot = skeleton->slots[self->slotIndex]; - if (alpha < 1) { - slot->r += (r - slot->r) * alpha; - slot->g += (g - slot->g) * alpha; - slot->b += (b - slot->b) * alpha; - slot->a += (a - slot->a) * alpha; - } else { - slot->r = r; - slot->g = g; - slot->b = b; - slot->a = a; - } - - UNUSED(lastTime); - UNUSED(firedEvents); - UNUSED(eventsCount); -} - -spColorTimeline* spColorTimeline_create (int framesCount) { - return (spColorTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_COLOR, 5, _spColorTimeline_apply); -} - -void spColorTimeline_setFrame (spColorTimeline* self, int frameIndex, float time, float r, float g, float b, float a) { - frameIndex *= COLOR_ENTRIES; - self->frames[frameIndex] = time; - self->frames[frameIndex + COLOR_R] = r; - self->frames[frameIndex + COLOR_G] = g; - self->frames[frameIndex + COLOR_B] = b; - self->frames[frameIndex + COLOR_A] = a; -} - -/**/ - -void _spAttachmentTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventsCount, float alpha) { - const char* attachmentName; - spAttachmentTimeline* self = (spAttachmentTimeline*)timeline; - int frameIndex; - - if (time < self->frames[0]) return; - - if (time >= self->frames[self->framesCount - 1]) - frameIndex = self->framesCount - 1; - else - frameIndex = binarySearch1(self->frames, self->framesCount, time) - 1; - - attachmentName = self->attachmentNames[frameIndex]; - spSlot_setAttachment(skeleton->slots[self->slotIndex], - attachmentName ? spSkeleton_getAttachmentForSlotIndex(skeleton, self->slotIndex, attachmentName) : 0); - - UNUSED(lastTime); - UNUSED(firedEvents); - UNUSED(eventsCount); - UNUSED(alpha); -} - -void _spAttachmentTimeline_dispose (spTimeline* timeline) { - spAttachmentTimeline* self = SUB_CAST(spAttachmentTimeline, timeline); - int i; - - _spTimeline_deinit(timeline); - - for (i = 0; i < self->framesCount; ++i) - FREE(self->attachmentNames[i]); - FREE(self->attachmentNames); - FREE(self->frames); - FREE(self); -} - -spAttachmentTimeline* spAttachmentTimeline_create (int framesCount) { - spAttachmentTimeline* self = NEW(spAttachmentTimeline); - _spTimeline_init(SUPER(self), SP_TIMELINE_ATTACHMENT, _spAttachmentTimeline_dispose, _spAttachmentTimeline_apply); - - CONST_CAST(int, self->framesCount) = framesCount; - CONST_CAST(float*, self->frames) = CALLOC(float, framesCount); - CONST_CAST(char**, self->attachmentNames) = CALLOC(char*, framesCount); - - return self; -} - -void spAttachmentTimeline_setFrame (spAttachmentTimeline* self, int frameIndex, float time, const char* attachmentName) { - self->frames[frameIndex] = time; - - FREE(self->attachmentNames[frameIndex]); - if (attachmentName) - MALLOC_STR(self->attachmentNames[frameIndex], attachmentName); - else - self->attachmentNames[frameIndex] = 0; -} - -/**/ - -/** Fires events for frames > lastTime and <= time. */ -void _spEventTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha) { - spEventTimeline* self = (spEventTimeline*)timeline; - int frame; - if (!firedEvents) return; - - if (lastTime > time) { /* Fire events after last time for looped animations. */ - _spEventTimeline_apply(timeline, skeleton, lastTime, (float)INT_MAX, firedEvents, eventsCount, alpha); - lastTime = -1; - } else if (lastTime >= self->frames[self->framesCount - 1]) /* Last time is after last frame. */ - return; - if (time < self->frames[0]) return; /* Time is before first frame. */ - - if (lastTime < self->frames[0]) - frame = 0; - else { - float frameTime; - frame = binarySearch1(self->frames, self->framesCount, lastTime); - frameTime = self->frames[frame]; - while (frame > 0) { /* Fire multiple events with the same frame. */ - if (self->frames[frame - 1] != frameTime) break; - frame--; - } - } - for (; frame < self->framesCount && time >= self->frames[frame]; ++frame) { - firedEvents[*eventsCount] = self->events[frame]; - (*eventsCount)++; - } -} - -void _spEventTimeline_dispose (spTimeline* timeline) { - spEventTimeline* self = SUB_CAST(spEventTimeline, timeline); - int i; - - _spTimeline_deinit(timeline); - - for (i = 0; i < self->framesCount; ++i) - spEvent_dispose(self->events[i]); - FREE(self->events); - FREE(self->frames); - FREE(self); -} - -spEventTimeline* spEventTimeline_create (int framesCount) { - spEventTimeline* self = NEW(spEventTimeline); - _spTimeline_init(SUPER(self), SP_TIMELINE_EVENT, _spEventTimeline_dispose, _spEventTimeline_apply); - - CONST_CAST(int, self->framesCount) = framesCount; - CONST_CAST(float*, self->frames) = CALLOC(float, framesCount); - CONST_CAST(spEvent**, self->events) = CALLOC(spEvent*, framesCount); - - return self; -} - -void spEventTimeline_setFrame (spEventTimeline* self, int frameIndex, spEvent* event) { - self->frames[frameIndex] = event->time; - - FREE(self->events[frameIndex]); - self->events[frameIndex] = event; -} - -/**/ - -void _spDrawOrderTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventsCount, float alpha) { - int i; - int frame; - const int* drawOrderToSetupIndex; - spDrawOrderTimeline* self = (spDrawOrderTimeline*)timeline; - - if (time < self->frames[0]) return; /* Time is before first frame. */ - - if (time >= self->frames[self->framesCount - 1]) /* Time is after last frame. */ - frame = self->framesCount - 1; - else - frame = binarySearch1(self->frames, self->framesCount, time) - 1; - - drawOrderToSetupIndex = self->drawOrders[frame]; - if (!drawOrderToSetupIndex) - memcpy(skeleton->drawOrder, skeleton->slots, self->slotsCount * sizeof(spSlot*)); - else { - for (i = 0; i < self->slotsCount; ++i) - skeleton->drawOrder[i] = skeleton->slots[drawOrderToSetupIndex[i]]; - } - - UNUSED(lastTime); - UNUSED(firedEvents); - UNUSED(eventsCount); - UNUSED(alpha); -} - -void _spDrawOrderTimeline_dispose (spTimeline* timeline) { - spDrawOrderTimeline* self = SUB_CAST(spDrawOrderTimeline, timeline); - int i; - - _spTimeline_deinit(timeline); - - for (i = 0; i < self->framesCount; ++i) - FREE(self->drawOrders[i]); - FREE(self->drawOrders); - FREE(self->frames); - FREE(self); -} - -spDrawOrderTimeline* spDrawOrderTimeline_create (int framesCount, int slotsCount) { - spDrawOrderTimeline* self = NEW(spDrawOrderTimeline); - _spTimeline_init(SUPER(self), SP_TIMELINE_DRAWORDER, _spDrawOrderTimeline_dispose, _spDrawOrderTimeline_apply); - - CONST_CAST(int, self->framesCount) = framesCount; - CONST_CAST(float*, self->frames) = CALLOC(float, framesCount); - CONST_CAST(int**, self->drawOrders) = CALLOC(int*, framesCount); - CONST_CAST(int, self->slotsCount) = slotsCount; - - return self; -} - -void spDrawOrderTimeline_setFrame (spDrawOrderTimeline* self, int frameIndex, float time, const int* drawOrder) { - self->frames[frameIndex] = time; - - FREE(self->drawOrders[frameIndex]); - if (!drawOrder) - self->drawOrders[frameIndex] = 0; - else { - self->drawOrders[frameIndex] = MALLOC(int, self->slotsCount); - memcpy(CONST_CAST(int*, self->drawOrders[frameIndex]), drawOrder, self->slotsCount * sizeof(int)); - } -} - -/**/ - -void _spDeformTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha) { - int frame, i, vertexCount; - float percent, frameTime; - const float* prevVertices; - const float* nextVertices; - spDeformTimeline* self = (spDeformTimeline*)timeline; - - spSlot *slot = skeleton->slots[self->slotIndex]; - - if (slot->attachment != self->attachment) { - if (!slot->attachment) return; - switch (slot->attachment->type) { - case SP_ATTACHMENT_MESH: { - spMeshAttachment* mesh = SUB_CAST(spMeshAttachment, slot->attachment); - if (!mesh->inheritDeform || mesh->parentMesh != (void*)self->attachment) return; - break; - } - default: - return; - } - } - - if (time < self->frames[0]) return; /* Time is before first frame. */ - - vertexCount = self->frameVerticesCount; - if (slot->attachmentVerticesCount < vertexCount) { - if (slot->attachmentVerticesCapacity < vertexCount) { - FREE(slot->attachmentVertices); - slot->attachmentVertices = MALLOC(float, vertexCount); - slot->attachmentVerticesCapacity = vertexCount; - } - } - if (slot->attachmentVerticesCount != vertexCount) alpha = 1; /* Don't mix from uninitialized slot vertices. */ - slot->attachmentVerticesCount = vertexCount; - - if (time >= self->frames[self->framesCount - 1]) { - /* Time is after last frame. */ - const float* lastVertices = self->frameVertices[self->framesCount - 1]; - if (alpha < 1) { - for (i = 0; i < vertexCount; ++i) - slot->attachmentVertices[i] += (lastVertices[i] - slot->attachmentVertices[i]) * alpha; - } else - memcpy(slot->attachmentVertices, lastVertices, vertexCount * sizeof(float)); - return; - } - - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch1(self->frames, self->framesCount, time); - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), frame - 1, 1 - (time - frameTime) / (self->frames[frame - 1] - frameTime)); - - prevVertices = self->frameVertices[frame - 1]; - nextVertices = self->frameVertices[frame]; - - if (alpha < 1) { - for (i = 0; i < vertexCount; ++i) { - float prev = prevVertices[i]; - slot->attachmentVertices[i] += (prev + (nextVertices[i] - prev) * percent - slot->attachmentVertices[i]) * alpha; - } - } else { - for (i = 0; i < vertexCount; ++i) { - float prev = prevVertices[i]; - slot->attachmentVertices[i] = prev + (nextVertices[i] - prev) * percent; - } - } - - UNUSED(lastTime); - UNUSED(firedEvents); - UNUSED(eventsCount); -} - -void _spDeformTimeline_dispose (spTimeline* timeline) { - spDeformTimeline* self = SUB_CAST(spDeformTimeline, timeline); - int i; - - _spCurveTimeline_deinit(SUPER(self)); - - for (i = 0; i < self->framesCount; ++i) - FREE(self->frameVertices[i]); - FREE(self->frameVertices); - FREE(self->frames); - FREE(self); -} - -spDeformTimeline* spDeformTimeline_create (int framesCount, int frameVerticesCount) { - spDeformTimeline* self = NEW(spDeformTimeline); - _spCurveTimeline_init(SUPER(self), SP_TIMELINE_DEFORM, framesCount, _spDeformTimeline_dispose, _spDeformTimeline_apply); - CONST_CAST(int, self->framesCount) = framesCount; - CONST_CAST(float*, self->frames) = CALLOC(float, self->framesCount); - CONST_CAST(float**, self->frameVertices) = CALLOC(float*, framesCount); - CONST_CAST(int, self->frameVerticesCount) = frameVerticesCount; - return self; -} - -void spDeformTimeline_setFrame (spDeformTimeline* self, int frameIndex, float time, float* vertices) { - self->frames[frameIndex] = time; - - FREE(self->frameVertices[frameIndex]); - if (!vertices) - self->frameVertices[frameIndex] = 0; - else { - self->frameVertices[frameIndex] = MALLOC(float, self->frameVerticesCount); - memcpy(CONST_CAST(float*, self->frameVertices[frameIndex]), vertices, self->frameVerticesCount * sizeof(float)); - } -} - - -/**/ - -static const int IKCONSTRAINT_PREV_TIME = -3, IKCONSTRAINT_PREV_MIX = -2, IKCONSTRAINT_PREV_BEND_DIRECTION = -1; -static const int IKCONSTRAINT_MIX = 1, IKCONSTRAINT_BEND_DIRECTION = 2; - -void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventsCount, float alpha) { - int frame; - float frameTime, percent, mix; - spIkConstraint* constraint; - spIkConstraintTimeline* self = (spIkConstraintTimeline*)timeline; - - if (time < self->frames[0]) return; /* Time is before first frame. */ - - constraint = skeleton->ikConstraints[self->ikConstraintIndex]; - - if (time >= self->frames[self->framesCount - IKCONSTRAINT_ENTRIES]) { /* Time is after last frame. */ - constraint->mix += (self->frames[self->framesCount + IKCONSTRAINT_PREV_MIX] - constraint->mix) * alpha; - constraint->bendDirection = (int)self->frames[self->framesCount + IKCONSTRAINT_PREV_BEND_DIRECTION]; - return; - } - - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch(self->frames, self->framesCount, time, IKCONSTRAINT_ENTRIES); - mix = self->frames[frame + IKCONSTRAINT_PREV_MIX]; - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / IKCONSTRAINT_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + IKCONSTRAINT_PREV_TIME] - frameTime)); - - constraint->mix += (mix + (self->frames[frame + IKCONSTRAINT_MIX] - mix) * percent - constraint->mix) * alpha; - constraint->bendDirection = (int)self->frames[frame + IKCONSTRAINT_PREV_BEND_DIRECTION]; - - UNUSED(lastTime); - UNUSED(firedEvents); - UNUSED(eventsCount); -} - -spIkConstraintTimeline* spIkConstraintTimeline_create (int framesCount) { - return (spIkConstraintTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_IKCONSTRAINT, IKCONSTRAINT_ENTRIES, _spIkConstraintTimeline_apply); -} - -void spIkConstraintTimeline_setFrame (spIkConstraintTimeline* self, int frameIndex, float time, float mix, int bendDirection) { - frameIndex *= IKCONSTRAINT_ENTRIES; - self->frames[frameIndex] = time; - self->frames[frameIndex + IKCONSTRAINT_MIX] = mix; - self->frames[frameIndex + IKCONSTRAINT_BEND_DIRECTION] = (float)bendDirection; -} - -/**/ -static const int TRANSFORMCONSTRAINT_PREV_TIME = -5; -static const int TRANSFORMCONSTRAINT_PREV_ROTATE = -4; -static const int TRANSFORMCONSTRAINT_PREV_TRANSLATE = -3; -static const int TRANSFORMCONSTRAINT_PREV_SCALE = -2; -static const int TRANSFORMCONSTRAINT_PREV_SHEAR = -1; -static const int TRANSFORMCONSTRAINT_ROTATE = 1; -static const int TRANSFORMCONSTRAINT_TRANSLATE = 2; -static const int TRANSFORMCONSTRAINT_SCALE = 3; -static const int TRANSFORMCONSTRAINT_SHEAR = 4; - -void _spTransformConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventsCount, float alpha) { - int frame; - float frameTime, percent, rotate, translate, scale, shear; - spTransformConstraint* constraint; - spTransformConstraintTimeline* self = (spTransformConstraintTimeline*)timeline; - - if (time < self->frames[0]) return; /* Time is before first frame. */ - - constraint = skeleton->transformConstraints[self->transformConstraintIndex]; - - if (time >= self->frames[self->framesCount - TRANSFORMCONSTRAINT_ENTRIES]) { /* Time is after last frame. */ - int len = self->framesCount; - constraint->rotateMix += (self->frames[len + TRANSFORMCONSTRAINT_PREV_ROTATE] - constraint->rotateMix) * alpha; - constraint->translateMix += (self->frames[len + TRANSFORMCONSTRAINT_PREV_TRANSLATE] - constraint->translateMix) * alpha; - constraint->scaleMix += (self->frames[len + TRANSFORMCONSTRAINT_PREV_SCALE] - constraint->scaleMix) * alpha; - constraint->shearMix += (self->frames[len + TRANSFORMCONSTRAINT_PREV_SHEAR] - constraint->shearMix) * alpha; - return; - } - - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch(self->frames, self->framesCount, time, TRANSFORMCONSTRAINT_ENTRIES); - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / TRANSFORMCONSTRAINT_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + TRANSFORMCONSTRAINT_PREV_TIME] - frameTime)); - - rotate = self->frames[frame + TRANSFORMCONSTRAINT_PREV_ROTATE]; - translate = self->frames[frame + TRANSFORMCONSTRAINT_PREV_TRANSLATE]; - scale = self->frames[frame + TRANSFORMCONSTRAINT_PREV_SCALE]; - shear = self->frames[frame + TRANSFORMCONSTRAINT_PREV_SHEAR]; - constraint->rotateMix += (rotate + (self->frames[frame + TRANSFORMCONSTRAINT_ROTATE] - rotate) * percent - constraint->rotateMix) * alpha; - constraint->translateMix += (translate + (self->frames[frame + TRANSFORMCONSTRAINT_TRANSLATE] - translate) * percent - constraint->translateMix) * alpha; - constraint->scaleMix += (scale + (self->frames[frame + TRANSFORMCONSTRAINT_SCALE] - scale) * percent - constraint->scaleMix) * alpha; - constraint->shearMix += (shear + (self->frames[frame + TRANSFORMCONSTRAINT_SHEAR] - shear) * percent - constraint->shearMix) * alpha; - - UNUSED(lastTime); - UNUSED(firedEvents); - UNUSED(eventsCount); -} - -spTransformConstraintTimeline* spTransformConstraintTimeline_create (int framesCount) { - return (spTransformConstraintTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_TRANSFORMCONSTRAINT, TRANSFORMCONSTRAINT_ENTRIES, _spTransformConstraintTimeline_apply); -} - -void spTransformConstraintTimeline_setFrame (spTransformConstraintTimeline* self, int frameIndex, float time, float rotateMix, float translateMix, float scaleMix, float shearMix) { - frameIndex *= TRANSFORMCONSTRAINT_ENTRIES; - self->frames[frameIndex] = time; - self->frames[frameIndex + TRANSFORMCONSTRAINT_ROTATE] = rotateMix; - self->frames[frameIndex + TRANSFORMCONSTRAINT_TRANSLATE] = translateMix; - self->frames[frameIndex + TRANSFORMCONSTRAINT_SCALE] = scaleMix; - self->frames[frameIndex + TRANSFORMCONSTRAINT_SHEAR] = shearMix; -} - -/**/ - -static const int PATHCONSTRAINTPOSITION_PREV_TIME = -2; -static const int PATHCONSTRAINTPOSITION_PREV_VALUE = -1; -static const int PATHCONSTRAINTPOSITION_VALUE = 1; - -void _spPathConstraintPositionTimeline_apply(const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventsCount, float alpha) { - int frame; - float frameTime, percent, position; - spPathConstraint* constraint; - spPathConstraintPositionTimeline* self = (spPathConstraintPositionTimeline*)timeline; - - if (time < self->frames[0]) return; /* Time is before first frame. */ - - constraint = skeleton->pathConstraints[self->pathConstraintIndex]; - - if (time >= self->frames[self->framesCount - PATHCONSTRAINTPOSITION_ENTRIES]) { /* Time is after last frame. */ - int len = self->framesCount; - constraint->position += (self->frames[len + PATHCONSTRAINTPOSITION_PREV_VALUE] - constraint->position) * alpha; - return; - } - - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch(self->frames, self->framesCount, time, PATHCONSTRAINTPOSITION_ENTRIES); - position = self->frames[frame + PATHCONSTRAINTPOSITION_PREV_VALUE]; - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / PATHCONSTRAINTPOSITION_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + PATHCONSTRAINTPOSITION_PREV_TIME] - frameTime)); - - constraint->position += (position + (self->frames[frame + PATHCONSTRAINTPOSITION_VALUE] - position) * percent - constraint->position) * alpha; - - UNUSED(lastTime); - UNUSED(firedEvents); - UNUSED(eventsCount); -} - -spPathConstraintPositionTimeline* spPathConstraintPositionTimeline_create (int framesCount) { - return (spPathConstraintPositionTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_PATHCONSTRAINTPOSITION, PATHCONSTRAINTPOSITION_ENTRIES, _spPathConstraintPositionTimeline_apply); -} - -void spPathConstraintPositionTimeline_setFrame (spPathConstraintPositionTimeline* self, int frameIndex, float time, float value) { - frameIndex *= PATHCONSTRAINTPOSITION_ENTRIES; - self->frames[frameIndex] = time; - self->frames[frameIndex + PATHCONSTRAINTPOSITION_VALUE] = value; -} - -/**/ -static const int PATHCONSTRAINTSPACING_PREV_TIME = -2; -static const int PATHCONSTRAINTSPACING_PREV_VALUE = -1; -static const int PATHCONSTRAINTSPACING_VALUE = 1; - -void _spPathConstraintSpacingTimeline_apply(const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventsCount, float alpha) { - int frame; - float frameTime, percent, spacing; - spPathConstraint* constraint; - spPathConstraintSpacingTimeline* self = (spPathConstraintSpacingTimeline*)timeline; - - if (time < self->frames[0]) return; /* Time is before first frame. */ - - constraint = skeleton->pathConstraints[self->pathConstraintIndex]; - - if (time >= self->frames[self->framesCount - PATHCONSTRAINTSPACING_ENTRIES]) { /* Time is after last frame. */ - int len = self->framesCount; - constraint->spacing += (self->frames[len + PATHCONSTRAINTSPACING_PREV_VALUE] - constraint->spacing) * alpha; - return; - } - - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch(self->frames, self->framesCount, time, PATHCONSTRAINTSPACING_ENTRIES); - spacing = self->frames[frame + PATHCONSTRAINTSPACING_PREV_VALUE]; - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / PATHCONSTRAINTSPACING_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + PATHCONSTRAINTSPACING_PREV_TIME] - frameTime)); - - constraint->spacing += (spacing + (self->frames[frame + PATHCONSTRAINTSPACING_VALUE] - spacing) * percent - constraint->spacing) * alpha; - - UNUSED(lastTime); - UNUSED(firedEvents); - UNUSED(eventsCount); -} - -spPathConstraintSpacingTimeline* spPathConstraintSpacingTimeline_create (int framesCount) { - return (spPathConstraintSpacingTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_PATHCONSTRAINTSPACING, PATHCONSTRAINTSPACING_ENTRIES, _spPathConstraintSpacingTimeline_apply); -} - -void spPathConstraintSpacingTimeline_setFrame (spPathConstraintSpacingTimeline* self, int frameIndex, float time, float value) { - frameIndex *= PATHCONSTRAINTSPACING_ENTRIES; - self->frames[frameIndex] = time; - self->frames[frameIndex + PATHCONSTRAINTSPACING_VALUE] = value; -} - -/**/ - -static const int PATHCONSTRAINTMIX_PREV_TIME = -3; -static const int PATHCONSTRAINTMIX_PREV_ROTATE = -2; -static const int PATHCONSTRAINTMIX_PREV_TRANSLATE = -1; -static const int PATHCONSTRAINTMIX_ROTATE = 1; -static const int PATHCONSTRAINTMIX_TRANSLATE = 2; - -void _spPathConstraintMixTimeline_apply(const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventsCount, float alpha) { - int frame; - float frameTime, percent, rotate, translate; - spPathConstraint* constraint; - spPathConstraintMixTimeline* self = (spPathConstraintMixTimeline*)timeline; - - if (time < self->frames[0]) return; /* Time is before first frame. */ - - constraint = skeleton->pathConstraints[self->pathConstraintIndex]; - - if (time >= self->frames[self->framesCount - PATHCONSTRAINTMIX_ENTRIES]) { /* Time is after last frame. */ - int len = self->framesCount; - constraint->rotateMix += (self->frames[len + PATHCONSTRAINTMIX_PREV_ROTATE] - constraint->rotateMix) * alpha; - constraint->translateMix += (self->frames[len + PATHCONSTRAINTMIX_PREV_TRANSLATE] - constraint->translateMix) * alpha; - return; - } - - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch(self->frames, self->framesCount, time, PATHCONSTRAINTMIX_ENTRIES); - rotate = self->frames[frame + PATHCONSTRAINTMIX_PREV_ROTATE]; - translate = self->frames[frame + PATHCONSTRAINTMIX_PREV_TRANSLATE]; - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / PATHCONSTRAINTMIX_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + PATHCONSTRAINTMIX_PREV_TIME] - frameTime)); - - constraint->rotateMix += (rotate + (self->frames[frame + PATHCONSTRAINTMIX_ROTATE] - rotate) * percent - constraint->rotateMix) * alpha; - constraint->translateMix += (translate + (self->frames[frame + PATHCONSTRAINTMIX_TRANSLATE] - translate) * percent - constraint->translateMix) * alpha; - - UNUSED(lastTime); - UNUSED(firedEvents); - UNUSED(eventsCount); -} - -spPathConstraintMixTimeline* spPathConstraintMixTimeline_create (int framesCount) { - return (spPathConstraintMixTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_PATHCONSTRAINTMIX, PATHCONSTRAINTMIX_ENTRIES, _spPathConstraintMixTimeline_apply); -} - -void spPathConstraintMixTimeline_setFrame (spPathConstraintMixTimeline* self, int frameIndex, float time, float rotateMix, float translateMix) { - frameIndex *= PATHCONSTRAINTMIX_ENTRIES; - self->frames[frameIndex] = time; - self->frames[frameIndex + PATHCONSTRAINTMIX_ROTATE] = rotateMix; - self->frames[frameIndex + PATHCONSTRAINTMIX_TRANSLATE] = translateMix; +#include +#include +#include +#include + +spAnimation* spAnimation_create (const char* name, int timelinesCount) { + spAnimation* self = NEW(spAnimation); + MALLOC_STR(self->name, name); + self->timelinesCount = timelinesCount; + self->timelines = MALLOC(spTimeline*, timelinesCount); + return self; +} + +void spAnimation_dispose (spAnimation* self) { + int i; + for (i = 0; i < self->timelinesCount; ++i) + spTimeline_dispose(self->timelines[i]); + FREE(self->timelines); + FREE(self->name); + FREE(self); +} + +void spAnimation_apply (const spAnimation* self, spSkeleton* skeleton, float lastTime, float time, int loop, spEvent** events, + int* eventsCount) { + int i, n = self->timelinesCount; + + if (loop && self->duration) { + time = FMOD(time, self->duration); + if (lastTime > 0) lastTime = FMOD(lastTime, self->duration); + } + + for (i = 0; i < n; ++i) + spTimeline_apply(self->timelines[i], skeleton, lastTime, time, events, eventsCount, 1); +} + +void spAnimation_mix (const spAnimation* self, spSkeleton* skeleton, float lastTime, float time, int loop, spEvent** events, + int* eventsCount, float alpha) { + int i, n = self->timelinesCount; + + if (loop && self->duration) { + time = FMOD(time, self->duration); + if (lastTime > 0) lastTime = FMOD(lastTime, self->duration); + } + + for (i = 0; i < n; ++i) + spTimeline_apply(self->timelines[i], skeleton, lastTime, time, events, eventsCount, alpha); +} + +/**/ + +typedef struct _spTimelineVtable { + void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, + int* eventsCount, float alpha); + void (*dispose) (spTimeline* self); +} _spTimelineVtable; + +void _spTimeline_init (spTimeline* self, spTimelineType type, /**/ +void (*dispose) (spTimeline* self), /**/ + void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, + int* eventsCount, float alpha)) { + CONST_CAST(spTimelineType, self->type) = type; + CONST_CAST(_spTimelineVtable*, self->vtable) = NEW(_spTimelineVtable); + VTABLE(spTimeline, self)->dispose = dispose; + VTABLE(spTimeline, self)->apply = apply; +} + +void _spTimeline_deinit (spTimeline* self) { + FREE(self->vtable); +} + +void spTimeline_dispose (spTimeline* self) { + VTABLE(spTimeline, self)->dispose(self); +} + +void spTimeline_apply (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, + int* eventsCount, float alpha) { + VTABLE(spTimeline, self)->apply(self, skeleton, lastTime, time, firedEvents, eventsCount, alpha); +} + +/**/ + +static const float CURVE_LINEAR = 0, CURVE_STEPPED = 1, CURVE_BEZIER = 2; +static const int BEZIER_SIZE = 10 * 2 - 1; + +void _spCurveTimeline_init (spCurveTimeline* self, spTimelineType type, int framesCount, /**/ +void (*dispose) (spTimeline* self), /**/ + void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, + int* eventsCount, float alpha)) { + _spTimeline_init(SUPER(self), type, dispose, apply); + self->curves = CALLOC(float, (framesCount - 1) * BEZIER_SIZE); +} + +void _spCurveTimeline_deinit (spCurveTimeline* self) { + _spTimeline_deinit(SUPER(self)); + FREE(self->curves); +} + +void spCurveTimeline_setLinear (spCurveTimeline* self, int frameIndex) { + self->curves[frameIndex * BEZIER_SIZE] = CURVE_LINEAR; +} + +void spCurveTimeline_setStepped (spCurveTimeline* self, int frameIndex) { + self->curves[frameIndex * BEZIER_SIZE] = CURVE_STEPPED; +} + +void spCurveTimeline_setCurve (spCurveTimeline* self, int frameIndex, float cx1, float cy1, float cx2, float cy2) { + float tmpx = (-cx1 * 2 + cx2) * 0.03f, tmpy = (-cy1 * 2 + cy2) * 0.03f; + float dddfx = ((cx1 - cx2) * 3 + 1) * 0.006f, dddfy = ((cy1 - cy2) * 3 + 1) * 0.006f; + float ddfx = tmpx * 2 + dddfx, ddfy = tmpy * 2 + dddfy; + float dfx = cx1 * 0.3f + tmpx + dddfx * 0.16666667f, dfy = cy1 * 0.3f + tmpy + dddfy * 0.16666667f; + float x = dfx, y = dfy; + + int i = frameIndex * BEZIER_SIZE, n = i + BEZIER_SIZE - 1; + self->curves[i++] = CURVE_BEZIER; + + for (; i < n; i += 2) { + self->curves[i] = x; + self->curves[i + 1] = y; + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + x += dfx; + y += dfy; + } +} + +float spCurveTimeline_getCurvePercent (const spCurveTimeline* self, int frameIndex, float percent) { + float x, y; + int i = frameIndex * BEZIER_SIZE, start, n; + float type = self->curves[i]; + percent = CLAMP(percent, 0, 1); + if (type == CURVE_LINEAR) return percent; + if (type == CURVE_STEPPED) return 0; + i++; + x = 0; + for (start = i, n = i + BEZIER_SIZE - 1; i < n; i += 2) { + x = self->curves[i]; + if (x >= percent) { + float prevX, prevY; + if (i == start) { + prevX = 0; + prevY = 0; + } else { + prevX = self->curves[i - 2]; + prevY = self->curves[i - 1]; + } + return prevY + (self->curves[i + 1] - prevY) * (percent - prevX) / (x - prevX); + } + } + y = self->curves[i - 1]; + return y + (1 - y) * (percent - x) / (1 - x); /* Last point is 1,1. */ +} + +/* @param target After the first and before the last entry. */ +static int binarySearch (float *values, int valuesLength, float target, int step) { + int low = 0, current; + int high = valuesLength / step - 2; + if (high == 0) return step; + current = high >> 1; + while (1) { + if (values[(current + 1) * step] <= target) + low = current + 1; + else + high = current; + if (low == high) return (low + 1) * step; + current = (low + high) >> 1; + } + return 0; +} + +/* @param target After the first and before the last entry. */ +static int binarySearch1 (float *values, int valuesLength, float target) { + int low = 0, current; + int high = valuesLength - 2; + if (high == 0) return 1; + current = high >> 1; + while (1) { + if (values[(current + 1)] <= target) + low = current + 1; + else + high = current; + if (low == high) return low + 1; + current = (low + high) >> 1; + } + return 0; +} + +/**/ + +void _spBaseTimeline_dispose (spTimeline* timeline) { + struct spBaseTimeline* self = SUB_CAST(struct spBaseTimeline, timeline); + _spCurveTimeline_deinit(SUPER(self)); + FREE(self->frames); + FREE(self); +} + +/* Many timelines have structure identical to struct spBaseTimeline and extend spCurveTimeline. **/ +struct spBaseTimeline* _spBaseTimeline_create (int framesCount, spTimelineType type, int frameSize, /**/ + void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, + int* eventsCount, float alpha)) { + struct spBaseTimeline* self = NEW(struct spBaseTimeline); + _spCurveTimeline_init(SUPER(self), type, framesCount, _spBaseTimeline_dispose, apply); + + CONST_CAST(int, self->framesCount) = framesCount * frameSize; + CONST_CAST(float*, self->frames) = CALLOC(float, self->framesCount); + + return self; +} + +/**/ + +static const int ROTATE_PREV_TIME = -2, ROTATE_PREV_ROTATION = -1; +static const int ROTATE_ROTATION = 1; + +void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, + int* eventsCount, float alpha) { + spBone *bone; + int frame; + float prevRotation, frameTime, percent, amount; + + spRotateTimeline* self = SUB_CAST(spRotateTimeline, timeline); + + if (time < self->frames[0]) return; /* Time is before first frame. */ + + bone = skeleton->bones[self->boneIndex]; + + if (time >= self->frames[self->framesCount - ROTATE_ENTRIES]) { /* Time is after last frame. */ + amount = bone->data->rotation + self->frames[self->framesCount + ROTATE_PREV_ROTATION] - bone->rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone->rotation += amount * alpha; + return; + } + + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch(self->frames, self->framesCount, time, ROTATE_ENTRIES); + prevRotation = self->frames[frame + ROTATE_PREV_ROTATION]; + frameTime = self->frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), (frame >> 1) - 1, 1 - (time - frameTime) / (self->frames[frame + ROTATE_PREV_TIME] - frameTime)); + + amount = self->frames[frame + ROTATE_ROTATION] - prevRotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + amount = bone->data->rotation + (prevRotation + amount * percent) - bone->rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone->rotation += amount * alpha; + + UNUSED(lastTime); + UNUSED(firedEvents); + UNUSED(eventsCount); +} + +spRotateTimeline* spRotateTimeline_create (int framesCount) { + return _spBaseTimeline_create(framesCount, SP_TIMELINE_ROTATE, ROTATE_ENTRIES, _spRotateTimeline_apply); +} + +void spRotateTimeline_setFrame (spRotateTimeline* self, int frameIndex, float time, float degrees) { + frameIndex <<= 1; + self->frames[frameIndex] = time; + self->frames[frameIndex + ROTATE_ROTATION] = degrees; +} + +/**/ + +static const int TRANSLATE_PREV_TIME = -3, TRANSLATE_PREV_X = -2, TRANSLATE_PREV_Y = -1; +static const int TRANSLATE_X = 1, TRANSLATE_Y = 2; + +void _spTranslateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, + spEvent** firedEvents, int* eventsCount, float alpha) { + spBone *bone; + int frame; + float prevX, prevY, frameTime, percent; + + spTranslateTimeline* self = SUB_CAST(spTranslateTimeline, timeline); + + if (time < self->frames[0]) return; /* Time is before first frame. */ + + bone = skeleton->bones[self->boneIndex]; + + if (time >= self->frames[self->framesCount - TRANSLATE_ENTRIES]) { /* Time is after last frame. */ + bone->x += (bone->data->x + self->frames[self->framesCount + TRANSLATE_PREV_X] - bone->x) * alpha; + bone->y += (bone->data->y + self->frames[self->framesCount + TRANSLATE_PREV_Y] - bone->y) * alpha; + return; + } + + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch(self->frames, self->framesCount, time, TRANSLATE_ENTRIES); + prevX = self->frames[frame + TRANSLATE_PREV_X]; + prevY = self->frames[frame + TRANSLATE_PREV_Y]; + frameTime = self->frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / TRANSLATE_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + TRANSLATE_PREV_TIME] - frameTime)); + + bone->x += (bone->data->x + prevX + (self->frames[frame + TRANSLATE_X] - prevX) * percent - bone->x) * alpha; + bone->y += (bone->data->y + prevY + (self->frames[frame + TRANSLATE_Y] - prevY) * percent - bone->y) * alpha; + + UNUSED(lastTime); + UNUSED(firedEvents); + UNUSED(eventsCount); +} + +spTranslateTimeline* spTranslateTimeline_create (int framesCount) { + return _spBaseTimeline_create(framesCount, SP_TIMELINE_TRANSLATE, TRANSLATE_ENTRIES, _spTranslateTimeline_apply); +} + +void spTranslateTimeline_setFrame (spTranslateTimeline* self, int frameIndex, float time, float x, float y) { + frameIndex *= TRANSLATE_ENTRIES; + self->frames[frameIndex] = time; + self->frames[frameIndex + TRANSLATE_X] = x; + self->frames[frameIndex + TRANSLATE_Y] = y; +} + +/**/ + +void _spScaleTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, + int* eventsCount, float alpha) { + spBone *bone; + int frame; + float prevX, prevY, frameTime, percent; + + spScaleTimeline* self = SUB_CAST(spScaleTimeline, timeline); + + if (time < self->frames[0]) return; /* Time is before first frame. */ + + bone = skeleton->bones[self->boneIndex]; + if (time >= self->frames[self->framesCount - TRANSLATE_ENTRIES]) { /* Time is after last frame. */ + bone->scaleX += (bone->data->scaleX * self->frames[self->framesCount + TRANSLATE_PREV_X] - bone->scaleX) * alpha; + bone->scaleY += (bone->data->scaleY * self->frames[self->framesCount + TRANSLATE_PREV_Y] - bone->scaleY) * alpha; + return; + } + + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch(self->frames, self->framesCount, time, TRANSLATE_ENTRIES); + prevX = self->frames[frame + TRANSLATE_PREV_X]; + prevY = self->frames[frame + TRANSLATE_PREV_Y]; + frameTime = self->frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / TRANSLATE_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + TRANSLATE_PREV_TIME] - frameTime)); + + bone->scaleX += (bone->data->scaleX * (prevX + (self->frames[frame + TRANSLATE_X] - prevX) * percent) - bone->scaleX) * alpha; + bone->scaleY += (bone->data->scaleY * (prevY + (self->frames[frame + TRANSLATE_Y] - prevY) * percent) - bone->scaleY) * alpha; + + UNUSED(lastTime); + UNUSED(firedEvents); + UNUSED(eventsCount); +} + +spScaleTimeline* spScaleTimeline_create (int framesCount) { + return _spBaseTimeline_create(framesCount, SP_TIMELINE_SCALE, TRANSLATE_ENTRIES, _spScaleTimeline_apply); +} + +void spScaleTimeline_setFrame (spScaleTimeline* self, int frameIndex, float time, float x, float y) { + spTranslateTimeline_setFrame(self, frameIndex, time, x, y); +} + +/**/ + +void _spShearTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, + int* eventsCount, float alpha) { + spBone *bone; + int frame; + float prevX, prevY, frameTime, percent; + + spShearTimeline* self = SUB_CAST(spShearTimeline, timeline); + + if (time < self->frames[0]) return; /* Time is before first frame. */ + + bone = skeleton->bones[self->boneIndex]; + if (time >= self->frames[self->framesCount - TRANSLATE_ENTRIES]) { /* Time is after last frame. */ + bone->shearX += (bone->data->shearX + self->frames[self->framesCount + TRANSLATE_PREV_X] - bone->shearX) * alpha; + bone->shearY += (bone->data->shearY + self->frames[self->framesCount + TRANSLATE_PREV_Y] - bone->shearY) * alpha; + return; + } + + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch(self->frames, self->framesCount, time, TRANSLATE_ENTRIES); + prevX = self->frames[frame + TRANSLATE_PREV_X]; + prevY = self->frames[frame + TRANSLATE_PREV_Y]; + frameTime = self->frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / TRANSLATE_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + TRANSLATE_PREV_TIME] - frameTime)); + + bone->shearX += (bone->data->shearX + prevX + (self->frames[frame + TRANSLATE_X] - prevX) * percent - bone->shearX) * alpha; + bone->shearY += (bone->data->shearY + prevY + (self->frames[frame + TRANSLATE_Y] - prevY) * percent - bone->shearY) * alpha; + + UNUSED(lastTime); + UNUSED(firedEvents); + UNUSED(eventsCount); +} + +spShearTimeline* spShearTimeline_create (int framesCount) { + return (spShearTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_SHEAR, 3, _spShearTimeline_apply); +} + +void spShearTimeline_setFrame (spShearTimeline* self, int frameIndex, float time, float x, float y) { + spTranslateTimeline_setFrame(self, frameIndex, time, x, y); +} + +/**/ + +static const int COLOR_PREV_TIME = -5, COLOR_PREV_R = -4, COLOR_PREV_G = -3, COLOR_PREV_B = -2, COLOR_PREV_A = -1; +static const int COLOR_R = 1, COLOR_G = 2, COLOR_B = 3, COLOR_A = 4; + +void _spColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, + int* eventsCount, float alpha) { + spSlot *slot; + int frame; + float percent, frameTime; + float r, g, b, a; + spColorTimeline* self = (spColorTimeline*)timeline; + + if (time < self->frames[0]) return; /* Time is before first frame. */ + + if (time >= self->frames[self->framesCount - 5]) { /* Time is after last frame */ + int i = self->framesCount; + r = self->frames[i + COLOR_PREV_R]; + g = self->frames[i + COLOR_PREV_G]; + b = self->frames[i + COLOR_PREV_B]; + a = self->frames[i + COLOR_PREV_A]; + } else { + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch(self->frames, self->framesCount, time, COLOR_ENTRIES); + + r = self->frames[frame + COLOR_PREV_R]; + g = self->frames[frame + COLOR_PREV_G]; + b = self->frames[frame + COLOR_PREV_B]; + a = self->frames[frame + COLOR_PREV_A]; + + frameTime = self->frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / COLOR_ENTRIES - 1, + 1 - (time - frameTime) / (self->frames[frame + COLOR_PREV_TIME] - frameTime)); + + r += (self->frames[frame + COLOR_R] - r) * percent; + g += (self->frames[frame + COLOR_G] - g) * percent; + b += (self->frames[frame + COLOR_B] - b) * percent; + a += (self->frames[frame + COLOR_A] - a) * percent; + } + slot = skeleton->slots[self->slotIndex]; + if (alpha < 1) { + slot->r += (r - slot->r) * alpha; + slot->g += (g - slot->g) * alpha; + slot->b += (b - slot->b) * alpha; + slot->a += (a - slot->a) * alpha; + } else { + slot->r = r; + slot->g = g; + slot->b = b; + slot->a = a; + } + + UNUSED(lastTime); + UNUSED(firedEvents); + UNUSED(eventsCount); +} + +spColorTimeline* spColorTimeline_create (int framesCount) { + return (spColorTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_COLOR, 5, _spColorTimeline_apply); +} + +void spColorTimeline_setFrame (spColorTimeline* self, int frameIndex, float time, float r, float g, float b, float a) { + frameIndex *= COLOR_ENTRIES; + self->frames[frameIndex] = time; + self->frames[frameIndex + COLOR_R] = r; + self->frames[frameIndex + COLOR_G] = g; + self->frames[frameIndex + COLOR_B] = b; + self->frames[frameIndex + COLOR_A] = a; +} + +/**/ + +void _spAttachmentTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, + spEvent** firedEvents, int* eventsCount, float alpha) { + const char* attachmentName; + spAttachmentTimeline* self = (spAttachmentTimeline*)timeline; + int frameIndex; + + if (time < self->frames[0]) return; + + if (time >= self->frames[self->framesCount - 1]) + frameIndex = self->framesCount - 1; + else + frameIndex = binarySearch1(self->frames, self->framesCount, time) - 1; + + attachmentName = self->attachmentNames[frameIndex]; + spSlot_setAttachment(skeleton->slots[self->slotIndex], + attachmentName ? spSkeleton_getAttachmentForSlotIndex(skeleton, self->slotIndex, attachmentName) : 0); + + UNUSED(lastTime); + UNUSED(firedEvents); + UNUSED(eventsCount); + UNUSED(alpha); +} + +void _spAttachmentTimeline_dispose (spTimeline* timeline) { + spAttachmentTimeline* self = SUB_CAST(spAttachmentTimeline, timeline); + int i; + + _spTimeline_deinit(timeline); + + for (i = 0; i < self->framesCount; ++i) + FREE(self->attachmentNames[i]); + FREE(self->attachmentNames); + FREE(self->frames); + FREE(self); +} + +spAttachmentTimeline* spAttachmentTimeline_create (int framesCount) { + spAttachmentTimeline* self = NEW(spAttachmentTimeline); + _spTimeline_init(SUPER(self), SP_TIMELINE_ATTACHMENT, _spAttachmentTimeline_dispose, _spAttachmentTimeline_apply); + + CONST_CAST(int, self->framesCount) = framesCount; + CONST_CAST(float*, self->frames) = CALLOC(float, framesCount); + CONST_CAST(char**, self->attachmentNames) = CALLOC(char*, framesCount); + + return self; +} + +void spAttachmentTimeline_setFrame (spAttachmentTimeline* self, int frameIndex, float time, const char* attachmentName) { + self->frames[frameIndex] = time; + + FREE(self->attachmentNames[frameIndex]); + if (attachmentName) + MALLOC_STR(self->attachmentNames[frameIndex], attachmentName); + else + self->attachmentNames[frameIndex] = 0; +} + +/**/ + +/** Fires events for frames > lastTime and <= time. */ +void _spEventTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, + int* eventsCount, float alpha) { + spEventTimeline* self = (spEventTimeline*)timeline; + int frame; + if (!firedEvents) return; + + if (lastTime > time) { /* Fire events after last time for looped animations. */ + _spEventTimeline_apply(timeline, skeleton, lastTime, (float)INT_MAX, firedEvents, eventsCount, alpha); + lastTime = -1; + } else if (lastTime >= self->frames[self->framesCount - 1]) /* Last time is after last frame. */ + return; + if (time < self->frames[0]) return; /* Time is before first frame. */ + + if (lastTime < self->frames[0]) + frame = 0; + else { + float frameTime; + frame = binarySearch1(self->frames, self->framesCount, lastTime); + frameTime = self->frames[frame]; + while (frame > 0) { /* Fire multiple events with the same frame. */ + if (self->frames[frame - 1] != frameTime) break; + frame--; + } + } + for (; frame < self->framesCount && time >= self->frames[frame]; ++frame) { + firedEvents[*eventsCount] = self->events[frame]; + (*eventsCount)++; + } +} + +void _spEventTimeline_dispose (spTimeline* timeline) { + spEventTimeline* self = SUB_CAST(spEventTimeline, timeline); + int i; + + _spTimeline_deinit(timeline); + + for (i = 0; i < self->framesCount; ++i) + spEvent_dispose(self->events[i]); + FREE(self->events); + FREE(self->frames); + FREE(self); +} + +spEventTimeline* spEventTimeline_create (int framesCount) { + spEventTimeline* self = NEW(spEventTimeline); + _spTimeline_init(SUPER(self), SP_TIMELINE_EVENT, _spEventTimeline_dispose, _spEventTimeline_apply); + + CONST_CAST(int, self->framesCount) = framesCount; + CONST_CAST(float*, self->frames) = CALLOC(float, framesCount); + CONST_CAST(spEvent**, self->events) = CALLOC(spEvent*, framesCount); + + return self; +} + +void spEventTimeline_setFrame (spEventTimeline* self, int frameIndex, spEvent* event) { + self->frames[frameIndex] = event->time; + + FREE(self->events[frameIndex]); + self->events[frameIndex] = event; +} + +/**/ + +void _spDrawOrderTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, + spEvent** firedEvents, int* eventsCount, float alpha) { + int i; + int frame; + const int* drawOrderToSetupIndex; + spDrawOrderTimeline* self = (spDrawOrderTimeline*)timeline; + + if (time < self->frames[0]) return; /* Time is before first frame. */ + + if (time >= self->frames[self->framesCount - 1]) /* Time is after last frame. */ + frame = self->framesCount - 1; + else + frame = binarySearch1(self->frames, self->framesCount, time) - 1; + + drawOrderToSetupIndex = self->drawOrders[frame]; + if (!drawOrderToSetupIndex) + memcpy(skeleton->drawOrder, skeleton->slots, self->slotsCount * sizeof(spSlot*)); + else { + for (i = 0; i < self->slotsCount; ++i) + skeleton->drawOrder[i] = skeleton->slots[drawOrderToSetupIndex[i]]; + } + + UNUSED(lastTime); + UNUSED(firedEvents); + UNUSED(eventsCount); + UNUSED(alpha); +} + +void _spDrawOrderTimeline_dispose (spTimeline* timeline) { + spDrawOrderTimeline* self = SUB_CAST(spDrawOrderTimeline, timeline); + int i; + + _spTimeline_deinit(timeline); + + for (i = 0; i < self->framesCount; ++i) + FREE(self->drawOrders[i]); + FREE(self->drawOrders); + FREE(self->frames); + FREE(self); +} + +spDrawOrderTimeline* spDrawOrderTimeline_create (int framesCount, int slotsCount) { + spDrawOrderTimeline* self = NEW(spDrawOrderTimeline); + _spTimeline_init(SUPER(self), SP_TIMELINE_DRAWORDER, _spDrawOrderTimeline_dispose, _spDrawOrderTimeline_apply); + + CONST_CAST(int, self->framesCount) = framesCount; + CONST_CAST(float*, self->frames) = CALLOC(float, framesCount); + CONST_CAST(int**, self->drawOrders) = CALLOC(int*, framesCount); + CONST_CAST(int, self->slotsCount) = slotsCount; + + return self; +} + +void spDrawOrderTimeline_setFrame (spDrawOrderTimeline* self, int frameIndex, float time, const int* drawOrder) { + self->frames[frameIndex] = time; + + FREE(self->drawOrders[frameIndex]); + if (!drawOrder) + self->drawOrders[frameIndex] = 0; + else { + self->drawOrders[frameIndex] = MALLOC(int, self->slotsCount); + memcpy(CONST_CAST(int*, self->drawOrders[frameIndex]), drawOrder, self->slotsCount * sizeof(int)); + } +} + +/**/ + +void _spDeformTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, + int* eventsCount, float alpha) { + int frame, i, vertexCount; + float percent, frameTime; + const float* prevVertices; + const float* nextVertices; + spDeformTimeline* self = (spDeformTimeline*)timeline; + + spSlot *slot = skeleton->slots[self->slotIndex]; + + if (slot->attachment != self->attachment) { + if (!slot->attachment) return; + switch (slot->attachment->type) { + case SP_ATTACHMENT_MESH: { + spMeshAttachment* mesh = SUB_CAST(spMeshAttachment, slot->attachment); + if (!mesh->inheritDeform || mesh->parentMesh != (void*)self->attachment) return; + break; + } + default: + return; + } + } + + if (time < self->frames[0]) return; /* Time is before first frame. */ + + vertexCount = self->frameVerticesCount; + if (slot->attachmentVerticesCount < vertexCount) { + if (slot->attachmentVerticesCapacity < vertexCount) { + FREE(slot->attachmentVertices); + slot->attachmentVertices = MALLOC(float, vertexCount); + slot->attachmentVerticesCapacity = vertexCount; + } + } + if (slot->attachmentVerticesCount != vertexCount) alpha = 1; /* Don't mix from uninitialized slot vertices. */ + slot->attachmentVerticesCount = vertexCount; + + if (time >= self->frames[self->framesCount - 1]) { + /* Time is after last frame. */ + const float* lastVertices = self->frameVertices[self->framesCount - 1]; + if (alpha < 1) { + for (i = 0; i < vertexCount; ++i) + slot->attachmentVertices[i] += (lastVertices[i] - slot->attachmentVertices[i]) * alpha; + } else + memcpy(slot->attachmentVertices, lastVertices, vertexCount * sizeof(float)); + return; + } + + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch1(self->frames, self->framesCount, time); + frameTime = self->frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), frame - 1, 1 - (time - frameTime) / (self->frames[frame - 1] - frameTime)); + + prevVertices = self->frameVertices[frame - 1]; + nextVertices = self->frameVertices[frame]; + + if (alpha < 1) { + for (i = 0; i < vertexCount; ++i) { + float prev = prevVertices[i]; + slot->attachmentVertices[i] += (prev + (nextVertices[i] - prev) * percent - slot->attachmentVertices[i]) * alpha; + } + } else { + for (i = 0; i < vertexCount; ++i) { + float prev = prevVertices[i]; + slot->attachmentVertices[i] = prev + (nextVertices[i] - prev) * percent; + } + } + + UNUSED(lastTime); + UNUSED(firedEvents); + UNUSED(eventsCount); +} + +void _spDeformTimeline_dispose (spTimeline* timeline) { + spDeformTimeline* self = SUB_CAST(spDeformTimeline, timeline); + int i; + + _spCurveTimeline_deinit(SUPER(self)); + + for (i = 0; i < self->framesCount; ++i) + FREE(self->frameVertices[i]); + FREE(self->frameVertices); + FREE(self->frames); + FREE(self); +} + +spDeformTimeline* spDeformTimeline_create (int framesCount, int frameVerticesCount) { + spDeformTimeline* self = NEW(spDeformTimeline); + _spCurveTimeline_init(SUPER(self), SP_TIMELINE_DEFORM, framesCount, _spDeformTimeline_dispose, _spDeformTimeline_apply); + CONST_CAST(int, self->framesCount) = framesCount; + CONST_CAST(float*, self->frames) = CALLOC(float, self->framesCount); + CONST_CAST(float**, self->frameVertices) = CALLOC(float*, framesCount); + CONST_CAST(int, self->frameVerticesCount) = frameVerticesCount; + return self; +} + +void spDeformTimeline_setFrame (spDeformTimeline* self, int frameIndex, float time, float* vertices) { + self->frames[frameIndex] = time; + + FREE(self->frameVertices[frameIndex]); + if (!vertices) + self->frameVertices[frameIndex] = 0; + else { + self->frameVertices[frameIndex] = MALLOC(float, self->frameVerticesCount); + memcpy(CONST_CAST(float*, self->frameVertices[frameIndex]), vertices, self->frameVerticesCount * sizeof(float)); + } +} + + +/**/ + +static const int IKCONSTRAINT_PREV_TIME = -3, IKCONSTRAINT_PREV_MIX = -2, IKCONSTRAINT_PREV_BEND_DIRECTION = -1; +static const int IKCONSTRAINT_MIX = 1, IKCONSTRAINT_BEND_DIRECTION = 2; + +void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, + spEvent** firedEvents, int* eventsCount, float alpha) { + int frame; + float frameTime, percent, mix; + spIkConstraint* constraint; + spIkConstraintTimeline* self = (spIkConstraintTimeline*)timeline; + + if (time < self->frames[0]) return; /* Time is before first frame. */ + + constraint = skeleton->ikConstraints[self->ikConstraintIndex]; + + if (time >= self->frames[self->framesCount - IKCONSTRAINT_ENTRIES]) { /* Time is after last frame. */ + constraint->mix += (self->frames[self->framesCount + IKCONSTRAINT_PREV_MIX] - constraint->mix) * alpha; + constraint->bendDirection = (int)self->frames[self->framesCount + IKCONSTRAINT_PREV_BEND_DIRECTION]; + return; + } + + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch(self->frames, self->framesCount, time, IKCONSTRAINT_ENTRIES); + mix = self->frames[frame + IKCONSTRAINT_PREV_MIX]; + frameTime = self->frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / IKCONSTRAINT_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + IKCONSTRAINT_PREV_TIME] - frameTime)); + + constraint->mix += (mix + (self->frames[frame + IKCONSTRAINT_MIX] - mix) * percent - constraint->mix) * alpha; + constraint->bendDirection = (int)self->frames[frame + IKCONSTRAINT_PREV_BEND_DIRECTION]; + + UNUSED(lastTime); + UNUSED(firedEvents); + UNUSED(eventsCount); +} + +spIkConstraintTimeline* spIkConstraintTimeline_create (int framesCount) { + return (spIkConstraintTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_IKCONSTRAINT, IKCONSTRAINT_ENTRIES, _spIkConstraintTimeline_apply); +} + +void spIkConstraintTimeline_setFrame (spIkConstraintTimeline* self, int frameIndex, float time, float mix, int bendDirection) { + frameIndex *= IKCONSTRAINT_ENTRIES; + self->frames[frameIndex] = time; + self->frames[frameIndex + IKCONSTRAINT_MIX] = mix; + self->frames[frameIndex + IKCONSTRAINT_BEND_DIRECTION] = (float)bendDirection; +} + +/**/ +static const int TRANSFORMCONSTRAINT_PREV_TIME = -5; +static const int TRANSFORMCONSTRAINT_PREV_ROTATE = -4; +static const int TRANSFORMCONSTRAINT_PREV_TRANSLATE = -3; +static const int TRANSFORMCONSTRAINT_PREV_SCALE = -2; +static const int TRANSFORMCONSTRAINT_PREV_SHEAR = -1; +static const int TRANSFORMCONSTRAINT_ROTATE = 1; +static const int TRANSFORMCONSTRAINT_TRANSLATE = 2; +static const int TRANSFORMCONSTRAINT_SCALE = 3; +static const int TRANSFORMCONSTRAINT_SHEAR = 4; + +void _spTransformConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, + spEvent** firedEvents, int* eventsCount, float alpha) { + int frame; + float frameTime, percent, rotate, translate, scale, shear; + spTransformConstraint* constraint; + spTransformConstraintTimeline* self = (spTransformConstraintTimeline*)timeline; + + if (time < self->frames[0]) return; /* Time is before first frame. */ + + constraint = skeleton->transformConstraints[self->transformConstraintIndex]; + + if (time >= self->frames[self->framesCount - TRANSFORMCONSTRAINT_ENTRIES]) { /* Time is after last frame. */ + int len = self->framesCount; + constraint->rotateMix += (self->frames[len + TRANSFORMCONSTRAINT_PREV_ROTATE] - constraint->rotateMix) * alpha; + constraint->translateMix += (self->frames[len + TRANSFORMCONSTRAINT_PREV_TRANSLATE] - constraint->translateMix) * alpha; + constraint->scaleMix += (self->frames[len + TRANSFORMCONSTRAINT_PREV_SCALE] - constraint->scaleMix) * alpha; + constraint->shearMix += (self->frames[len + TRANSFORMCONSTRAINT_PREV_SHEAR] - constraint->shearMix) * alpha; + return; + } + + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch(self->frames, self->framesCount, time, TRANSFORMCONSTRAINT_ENTRIES); + frameTime = self->frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / TRANSFORMCONSTRAINT_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + TRANSFORMCONSTRAINT_PREV_TIME] - frameTime)); + + rotate = self->frames[frame + TRANSFORMCONSTRAINT_PREV_ROTATE]; + translate = self->frames[frame + TRANSFORMCONSTRAINT_PREV_TRANSLATE]; + scale = self->frames[frame + TRANSFORMCONSTRAINT_PREV_SCALE]; + shear = self->frames[frame + TRANSFORMCONSTRAINT_PREV_SHEAR]; + constraint->rotateMix += (rotate + (self->frames[frame + TRANSFORMCONSTRAINT_ROTATE] - rotate) * percent - constraint->rotateMix) * alpha; + constraint->translateMix += (translate + (self->frames[frame + TRANSFORMCONSTRAINT_TRANSLATE] - translate) * percent - constraint->translateMix) * alpha; + constraint->scaleMix += (scale + (self->frames[frame + TRANSFORMCONSTRAINT_SCALE] - scale) * percent - constraint->scaleMix) * alpha; + constraint->shearMix += (shear + (self->frames[frame + TRANSFORMCONSTRAINT_SHEAR] - shear) * percent - constraint->shearMix) * alpha; + + UNUSED(lastTime); + UNUSED(firedEvents); + UNUSED(eventsCount); +} + +spTransformConstraintTimeline* spTransformConstraintTimeline_create (int framesCount) { + return (spTransformConstraintTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_TRANSFORMCONSTRAINT, TRANSFORMCONSTRAINT_ENTRIES, _spTransformConstraintTimeline_apply); +} + +void spTransformConstraintTimeline_setFrame (spTransformConstraintTimeline* self, int frameIndex, float time, float rotateMix, float translateMix, float scaleMix, float shearMix) { + frameIndex *= TRANSFORMCONSTRAINT_ENTRIES; + self->frames[frameIndex] = time; + self->frames[frameIndex + TRANSFORMCONSTRAINT_ROTATE] = rotateMix; + self->frames[frameIndex + TRANSFORMCONSTRAINT_TRANSLATE] = translateMix; + self->frames[frameIndex + TRANSFORMCONSTRAINT_SCALE] = scaleMix; + self->frames[frameIndex + TRANSFORMCONSTRAINT_SHEAR] = shearMix; +} + +/**/ + +static const int PATHCONSTRAINTPOSITION_PREV_TIME = -2; +static const int PATHCONSTRAINTPOSITION_PREV_VALUE = -1; +static const int PATHCONSTRAINTPOSITION_VALUE = 1; + +void _spPathConstraintPositionTimeline_apply(const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, + spEvent** firedEvents, int* eventsCount, float alpha) { + int frame; + float frameTime, percent, position; + spPathConstraint* constraint; + spPathConstraintPositionTimeline* self = (spPathConstraintPositionTimeline*)timeline; + + if (time < self->frames[0]) return; /* Time is before first frame. */ + + constraint = skeleton->pathConstraints[self->pathConstraintIndex]; + + if (time >= self->frames[self->framesCount - PATHCONSTRAINTPOSITION_ENTRIES]) { /* Time is after last frame. */ + int len = self->framesCount; + constraint->position += (self->frames[len + PATHCONSTRAINTPOSITION_PREV_VALUE] - constraint->position) * alpha; + return; + } + + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch(self->frames, self->framesCount, time, PATHCONSTRAINTPOSITION_ENTRIES); + position = self->frames[frame + PATHCONSTRAINTPOSITION_PREV_VALUE]; + frameTime = self->frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / PATHCONSTRAINTPOSITION_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + PATHCONSTRAINTPOSITION_PREV_TIME] - frameTime)); + + constraint->position += (position + (self->frames[frame + PATHCONSTRAINTPOSITION_VALUE] - position) * percent - constraint->position) * alpha; + + UNUSED(lastTime); + UNUSED(firedEvents); + UNUSED(eventsCount); +} + +spPathConstraintPositionTimeline* spPathConstraintPositionTimeline_create (int framesCount) { + return (spPathConstraintPositionTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_PATHCONSTRAINTPOSITION, PATHCONSTRAINTPOSITION_ENTRIES, _spPathConstraintPositionTimeline_apply); +} + +void spPathConstraintPositionTimeline_setFrame (spPathConstraintPositionTimeline* self, int frameIndex, float time, float value) { + frameIndex *= PATHCONSTRAINTPOSITION_ENTRIES; + self->frames[frameIndex] = time; + self->frames[frameIndex + PATHCONSTRAINTPOSITION_VALUE] = value; +} + +/**/ +static const int PATHCONSTRAINTSPACING_PREV_TIME = -2; +static const int PATHCONSTRAINTSPACING_PREV_VALUE = -1; +static const int PATHCONSTRAINTSPACING_VALUE = 1; + +void _spPathConstraintSpacingTimeline_apply(const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, + spEvent** firedEvents, int* eventsCount, float alpha) { + int frame; + float frameTime, percent, spacing; + spPathConstraint* constraint; + spPathConstraintSpacingTimeline* self = (spPathConstraintSpacingTimeline*)timeline; + + if (time < self->frames[0]) return; /* Time is before first frame. */ + + constraint = skeleton->pathConstraints[self->pathConstraintIndex]; + + if (time >= self->frames[self->framesCount - PATHCONSTRAINTSPACING_ENTRIES]) { /* Time is after last frame. */ + int len = self->framesCount; + constraint->spacing += (self->frames[len + PATHCONSTRAINTSPACING_PREV_VALUE] - constraint->spacing) * alpha; + return; + } + + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch(self->frames, self->framesCount, time, PATHCONSTRAINTSPACING_ENTRIES); + spacing = self->frames[frame + PATHCONSTRAINTSPACING_PREV_VALUE]; + frameTime = self->frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / PATHCONSTRAINTSPACING_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + PATHCONSTRAINTSPACING_PREV_TIME] - frameTime)); + + constraint->spacing += (spacing + (self->frames[frame + PATHCONSTRAINTSPACING_VALUE] - spacing) * percent - constraint->spacing) * alpha; + + UNUSED(lastTime); + UNUSED(firedEvents); + UNUSED(eventsCount); +} + +spPathConstraintSpacingTimeline* spPathConstraintSpacingTimeline_create (int framesCount) { + return (spPathConstraintSpacingTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_PATHCONSTRAINTSPACING, PATHCONSTRAINTSPACING_ENTRIES, _spPathConstraintSpacingTimeline_apply); +} + +void spPathConstraintSpacingTimeline_setFrame (spPathConstraintSpacingTimeline* self, int frameIndex, float time, float value) { + frameIndex *= PATHCONSTRAINTSPACING_ENTRIES; + self->frames[frameIndex] = time; + self->frames[frameIndex + PATHCONSTRAINTSPACING_VALUE] = value; +} + +/**/ + +static const int PATHCONSTRAINTMIX_PREV_TIME = -3; +static const int PATHCONSTRAINTMIX_PREV_ROTATE = -2; +static const int PATHCONSTRAINTMIX_PREV_TRANSLATE = -1; +static const int PATHCONSTRAINTMIX_ROTATE = 1; +static const int PATHCONSTRAINTMIX_TRANSLATE = 2; + +void _spPathConstraintMixTimeline_apply(const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, + spEvent** firedEvents, int* eventsCount, float alpha) { + int frame; + float frameTime, percent, rotate, translate; + spPathConstraint* constraint; + spPathConstraintMixTimeline* self = (spPathConstraintMixTimeline*)timeline; + + if (time < self->frames[0]) return; /* Time is before first frame. */ + + constraint = skeleton->pathConstraints[self->pathConstraintIndex]; + + if (time >= self->frames[self->framesCount - PATHCONSTRAINTMIX_ENTRIES]) { /* Time is after last frame. */ + int len = self->framesCount; + constraint->rotateMix += (self->frames[len + PATHCONSTRAINTMIX_PREV_ROTATE] - constraint->rotateMix) * alpha; + constraint->translateMix += (self->frames[len + PATHCONSTRAINTMIX_PREV_TRANSLATE] - constraint->translateMix) * alpha; + return; + } + + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch(self->frames, self->framesCount, time, PATHCONSTRAINTMIX_ENTRIES); + rotate = self->frames[frame + PATHCONSTRAINTMIX_PREV_ROTATE]; + translate = self->frames[frame + PATHCONSTRAINTMIX_PREV_TRANSLATE]; + frameTime = self->frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / PATHCONSTRAINTMIX_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + PATHCONSTRAINTMIX_PREV_TIME] - frameTime)); + + constraint->rotateMix += (rotate + (self->frames[frame + PATHCONSTRAINTMIX_ROTATE] - rotate) * percent - constraint->rotateMix) * alpha; + constraint->translateMix += (translate + (self->frames[frame + PATHCONSTRAINTMIX_TRANSLATE] - translate) * percent - constraint->translateMix) * alpha; + + UNUSED(lastTime); + UNUSED(firedEvents); + UNUSED(eventsCount); +} + +spPathConstraintMixTimeline* spPathConstraintMixTimeline_create (int framesCount) { + return (spPathConstraintMixTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_PATHCONSTRAINTMIX, PATHCONSTRAINTMIX_ENTRIES, _spPathConstraintMixTimeline_apply); +} + +void spPathConstraintMixTimeline_setFrame (spPathConstraintMixTimeline* self, int frameIndex, float time, float rotateMix, float translateMix) { + frameIndex *= PATHCONSTRAINTMIX_ENTRIES; + self->frames[frameIndex] = time; + self->frames[frameIndex + PATHCONSTRAINTMIX_ROTATE] = rotateMix; + self->frames[frameIndex + PATHCONSTRAINTMIX_TRANSLATE] = translateMix; } diff --git a/spine-c/src/spine/AnimationState.c b/spine-c/src/spine/AnimationState.c index 85452419ff..4ad1792176 100644 --- a/spine-c/src/spine/AnimationState.c +++ b/spine-c/src/spine/AnimationState.c @@ -1,323 +1,322 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include - -spTrackEntry* _spTrackEntry_create (spAnimationState* state) { - spTrackEntry* self = NEW(spTrackEntry); - CONST_CAST(spAnimationState*, self->state) = state; - self->timeScale = 1; - self->lastTime = -1; - self->mix = 1; - return self; -} - -void _spTrackEntry_dispose (spTrackEntry* self) { - if (self->previous) SUB_CAST(_spAnimationState, self->state)->disposeTrackEntry(self->previous); - FREE(self); -} - -/**/ - -spTrackEntry* _spAnimationState_createTrackEntry (spAnimationState* self) { - return _spTrackEntry_create(self); -} - -void _spAnimationState_disposeTrackEntry (spTrackEntry* entry) { - _spTrackEntry_dispose(entry); -} - -spAnimationState* spAnimationState_create (spAnimationStateData* data) { - _spAnimationState* internal = NEW(_spAnimationState); - spAnimationState* self = SUPER(internal); - internal->events = MALLOC(spEvent*, 64); - self->timeScale = 1; - CONST_CAST(spAnimationStateData*, self->data) = data; - internal->createTrackEntry = _spAnimationState_createTrackEntry; - internal->disposeTrackEntry = _spAnimationState_disposeTrackEntry; - return self; -} - -void _spAnimationState_disposeAllEntries (spAnimationState* self, spTrackEntry* entry) { - _spAnimationState* internal = SUB_CAST(_spAnimationState, self); - while (entry) { - spTrackEntry* next = entry->next; - internal->disposeTrackEntry(entry); - entry = next; - } -} - -void spAnimationState_dispose (spAnimationState* self) { - int i; - _spAnimationState* internal = SUB_CAST(_spAnimationState, self); - FREE(internal->events); - for (i = 0; i < self->tracksCount; ++i) - _spAnimationState_disposeAllEntries(self, self->tracks[i]); - FREE(self->tracks); - FREE(self); -} - -void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEntry* entry); - -void spAnimationState_update (spAnimationState* self, float delta) { - int i; - float previousDelta; - delta *= self->timeScale; - for (i = 0; i < self->tracksCount; ++i) { - spTrackEntry* current = self->tracks[i]; - if (!current) continue; - - current->time += delta * current->timeScale; - if (current->previous) { - previousDelta = delta * current->previous->timeScale; - current->previous->time += previousDelta; - current->mixTime += previousDelta; - } - - if (current->next) { - current->next->time = current->lastTime - current->next->delay; - if (current->next->time >= 0) _spAnimationState_setCurrent(self, i, current->next); - } else { - /* End non-looping animation when it reaches its end time and there is no next entry. */ - if (!current->loop && current->lastTime >= current->endTime) spAnimationState_clearTrack(self, i); - } - } -} - -void spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) { - _spAnimationState* internal = SUB_CAST(_spAnimationState, self); - - int i, ii; - int eventsCount; - int entryChanged; - float time; - spTrackEntry* previous; - for (i = 0; i < self->tracksCount; ++i) { - spTrackEntry* current = self->tracks[i]; - if (!current) continue; - - eventsCount = 0; - - time = current->time; - if (!current->loop && time > current->endTime) time = current->endTime; - - previous = current->previous; - if (!previous) { - if (current->mix == 1) { - spAnimation_apply(current->animation, skeleton, current->lastTime, time, - current->loop, internal->events, &eventsCount); - } else { - spAnimation_mix(current->animation, skeleton, current->lastTime, time, - current->loop, internal->events, &eventsCount, current->mix); - } - } else { - float alpha = current->mixTime / current->mixDuration * current->mix; - - float previousTime = previous->time; - if (!previous->loop && previousTime > previous->endTime) previousTime = previous->endTime; - spAnimation_apply(previous->animation, skeleton, previousTime, previousTime, previous->loop, 0, 0); - - if (alpha >= 1) { - alpha = 1; - internal->disposeTrackEntry(current->previous); - current->previous = 0; - } - spAnimation_mix(current->animation, skeleton, current->lastTime, time, - current->loop, internal->events, &eventsCount, alpha); - } - - entryChanged = 0; - for (ii = 0; ii < eventsCount; ++ii) { - spEvent* event = internal->events[ii]; - if (current->listener) { - current->listener(self, i, SP_ANIMATION_EVENT, event, 0); - if (self->tracks[i] != current) { - entryChanged = 1; - break; - } - } - if (self->listener) { - self->listener(self, i, SP_ANIMATION_EVENT, event, 0); - if (self->tracks[i] != current) { - entryChanged = 1; - break; - } - } - } - if (entryChanged) continue; - - /* Check if completed the animation or a loop iteration. */ - if (current->loop ? (FMOD(current->lastTime, current->endTime) > FMOD(time, current->endTime)) - : (current->lastTime < current->endTime && time >= current->endTime)) { - int count = (int)(time / current->endTime); - if (current->listener) { - current->listener(self, i, SP_ANIMATION_COMPLETE, 0, count); - if (self->tracks[i] != current) continue; - } - if (self->listener) { - self->listener(self, i, SP_ANIMATION_COMPLETE, 0, count); - if (self->tracks[i] != current) continue; - } - } - - current->lastTime = current->time; - } -} - -void spAnimationState_clearTracks (spAnimationState* self) { - int i; - for (i = 0; i < self->tracksCount; ++i) - spAnimationState_clearTrack(self, i); - self->tracksCount = 0; -} - -void spAnimationState_clearTrack (spAnimationState* self, int trackIndex) { - spTrackEntry* current; - if (trackIndex >= self->tracksCount) return; - current = self->tracks[trackIndex]; - if (!current) return; - - if (current->listener) current->listener(self, trackIndex, SP_ANIMATION_END, 0, 0); - if (self->listener) self->listener(self, trackIndex, SP_ANIMATION_END, 0, 0); - - self->tracks[trackIndex] = 0; - - _spAnimationState_disposeAllEntries(self, current); -} - -spTrackEntry* _spAnimationState_expandToIndex (spAnimationState* self, int index) { - spTrackEntry** newTracks; - if (index < self->tracksCount) return self->tracks[index]; - newTracks = CALLOC(spTrackEntry*, index + 1); - memcpy(newTracks, self->tracks, self->tracksCount * sizeof(spTrackEntry*)); - FREE(self->tracks); - self->tracks = newTracks; - self->tracksCount = index + 1; - return 0; -} - -void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEntry* entry) { - _spAnimationState* internal = SUB_CAST(_spAnimationState, self); - - spTrackEntry* current = _spAnimationState_expandToIndex(self, index); - if (current) { - spTrackEntry* previous = current->previous; - current->previous = 0; - - if (current->listener) current->listener(self, index, SP_ANIMATION_END, 0, 0); - if (self->listener) self->listener(self, index, SP_ANIMATION_END, 0, 0); - - entry->mixDuration = spAnimationStateData_getMix(self->data, current->animation, entry->animation); - if (entry->mixDuration > 0) { - entry->mixTime = 0; - /* If a mix is in progress, mix from the closest animation. */ - if (previous && current->mixTime / current->mixDuration < 0.5f) { - entry->previous = previous; - previous = current; - } else - entry->previous = current; - } else - internal->disposeTrackEntry(current); - - if (previous) internal->disposeTrackEntry(previous); - } - - self->tracks[index] = entry; - - if (entry->listener) { - entry->listener(self, index, SP_ANIMATION_START, 0, 0); - if (self->tracks[index] != entry) return; - } - if (self->listener) self->listener(self, index, SP_ANIMATION_START, 0, 0); -} - -spTrackEntry* spAnimationState_setAnimationByName (spAnimationState* self, int trackIndex, const char* animationName, - int/*bool*/loop) { - spAnimation* animation = spSkeletonData_findAnimation(self->data->skeletonData, animationName); - return spAnimationState_setAnimation(self, trackIndex, animation, loop); -} - -spTrackEntry* spAnimationState_setAnimation (spAnimationState* self, int trackIndex, spAnimation* animation, int/*bool*/loop) { - _spAnimationState* internal = SUB_CAST(_spAnimationState, self); - - spTrackEntry* entry; - spTrackEntry* current = _spAnimationState_expandToIndex(self, trackIndex); - if (current) _spAnimationState_disposeAllEntries(self, current->next); - - entry = internal->createTrackEntry(self); - entry->animation = animation; - entry->loop = loop; - entry->endTime = animation->duration; - _spAnimationState_setCurrent(self, trackIndex, entry); - return entry; -} - -spTrackEntry* spAnimationState_addAnimationByName (spAnimationState* self, int trackIndex, const char* animationName, - int/*bool*/loop, float delay) { - spAnimation* animation = spSkeletonData_findAnimation(self->data->skeletonData, animationName); - return spAnimationState_addAnimation(self, trackIndex, animation, loop, delay); -} - -spTrackEntry* spAnimationState_addAnimation (spAnimationState* self, int trackIndex, spAnimation* animation, int/*bool*/loop, - float delay) { - _spAnimationState* internal = SUB_CAST(_spAnimationState, self); - spTrackEntry* last; - - spTrackEntry* entry = internal->createTrackEntry(self); - entry->animation = animation; - entry->loop = loop; - entry->endTime = animation->duration; - - last = _spAnimationState_expandToIndex(self, trackIndex); - if (last) { - while (last->next) - last = last->next; - last->next = entry; - } else - self->tracks[trackIndex] = entry; - - if (delay <= 0) { - if (last) - delay += last->endTime - spAnimationStateData_getMix(self->data, last->animation, animation); - else - delay = 0; - } - entry->delay = delay; - - return entry; -} - -spTrackEntry* spAnimationState_getCurrent (spAnimationState* self, int trackIndex) { - if (trackIndex >= self->tracksCount) return 0; - return self->tracks[trackIndex]; +#include +#include +#include + +spTrackEntry* _spTrackEntry_create (spAnimationState* state) { + spTrackEntry* self = NEW(spTrackEntry); + CONST_CAST(spAnimationState*, self->state) = state; + self->timeScale = 1; + self->lastTime = -1; + self->mix = 1; + return self; +} + +void _spTrackEntry_dispose (spTrackEntry* self) { + if (self->previous) SUB_CAST(_spAnimationState, self->state)->disposeTrackEntry(self->previous); + FREE(self); +} + +/**/ + +spTrackEntry* _spAnimationState_createTrackEntry (spAnimationState* self) { + return _spTrackEntry_create(self); +} + +void _spAnimationState_disposeTrackEntry (spTrackEntry* entry) { + _spTrackEntry_dispose(entry); +} + +spAnimationState* spAnimationState_create (spAnimationStateData* data) { + _spAnimationState* internal = NEW(_spAnimationState); + spAnimationState* self = SUPER(internal); + internal->events = MALLOC(spEvent*, 64); + self->timeScale = 1; + CONST_CAST(spAnimationStateData*, self->data) = data; + internal->createTrackEntry = _spAnimationState_createTrackEntry; + internal->disposeTrackEntry = _spAnimationState_disposeTrackEntry; + return self; +} + +void _spAnimationState_disposeAllEntries (spAnimationState* self, spTrackEntry* entry) { + _spAnimationState* internal = SUB_CAST(_spAnimationState, self); + while (entry) { + spTrackEntry* next = entry->next; + internal->disposeTrackEntry(entry); + entry = next; + } +} + +void spAnimationState_dispose (spAnimationState* self) { + int i; + _spAnimationState* internal = SUB_CAST(_spAnimationState, self); + FREE(internal->events); + for (i = 0; i < self->tracksCount; ++i) + _spAnimationState_disposeAllEntries(self, self->tracks[i]); + FREE(self->tracks); + FREE(self); +} + +void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEntry* entry); + +void spAnimationState_update (spAnimationState* self, float delta) { + int i; + float previousDelta; + delta *= self->timeScale; + for (i = 0; i < self->tracksCount; ++i) { + spTrackEntry* current = self->tracks[i]; + if (!current) continue; + + current->time += delta * current->timeScale; + if (current->previous) { + previousDelta = delta * current->previous->timeScale; + current->previous->time += previousDelta; + current->mixTime += previousDelta; + } + + if (current->next) { + current->next->time = current->lastTime - current->next->delay; + if (current->next->time >= 0) _spAnimationState_setCurrent(self, i, current->next); + } else { + /* End non-looping animation when it reaches its end time and there is no next entry. */ + if (!current->loop && current->lastTime >= current->endTime) spAnimationState_clearTrack(self, i); + } + } +} + +void spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) { + _spAnimationState* internal = SUB_CAST(_spAnimationState, self); + + int i, ii; + int eventsCount; + int entryChanged; + float time; + spTrackEntry* previous; + for (i = 0; i < self->tracksCount; ++i) { + spTrackEntry* current = self->tracks[i]; + if (!current) continue; + + eventsCount = 0; + + time = current->time; + if (!current->loop && time > current->endTime) time = current->endTime; + + previous = current->previous; + if (!previous) { + if (current->mix == 1) { + spAnimation_apply(current->animation, skeleton, current->lastTime, time, + current->loop, internal->events, &eventsCount); + } else { + spAnimation_mix(current->animation, skeleton, current->lastTime, time, + current->loop, internal->events, &eventsCount, current->mix); + } + } else { + float alpha = current->mixTime / current->mixDuration * current->mix; + + float previousTime = previous->time; + if (!previous->loop && previousTime > previous->endTime) previousTime = previous->endTime; + spAnimation_apply(previous->animation, skeleton, previousTime, previousTime, previous->loop, 0, 0); + + if (alpha >= 1) { + alpha = 1; + internal->disposeTrackEntry(current->previous); + current->previous = 0; + } + spAnimation_mix(current->animation, skeleton, current->lastTime, time, + current->loop, internal->events, &eventsCount, alpha); + } + + entryChanged = 0; + for (ii = 0; ii < eventsCount; ++ii) { + spEvent* event = internal->events[ii]; + if (current->listener) { + current->listener(self, i, SP_ANIMATION_EVENT, event, 0); + if (self->tracks[i] != current) { + entryChanged = 1; + break; + } + } + if (self->listener) { + self->listener(self, i, SP_ANIMATION_EVENT, event, 0); + if (self->tracks[i] != current) { + entryChanged = 1; + break; + } + } + } + if (entryChanged) continue; + + /* Check if completed the animation or a loop iteration. */ + if (current->loop ? (FMOD(current->lastTime, current->endTime) > FMOD(time, current->endTime)) + : (current->lastTime < current->endTime && time >= current->endTime)) { + int count = (int)(time / current->endTime); + if (current->listener) { + current->listener(self, i, SP_ANIMATION_COMPLETE, 0, count); + if (self->tracks[i] != current) continue; + } + if (self->listener) { + self->listener(self, i, SP_ANIMATION_COMPLETE, 0, count); + if (self->tracks[i] != current) continue; + } + } + + current->lastTime = current->time; + } +} + +void spAnimationState_clearTracks (spAnimationState* self) { + int i; + for (i = 0; i < self->tracksCount; ++i) + spAnimationState_clearTrack(self, i); + self->tracksCount = 0; +} + +void spAnimationState_clearTrack (spAnimationState* self, int trackIndex) { + spTrackEntry* current; + if (trackIndex >= self->tracksCount) return; + current = self->tracks[trackIndex]; + if (!current) return; + + if (current->listener) current->listener(self, trackIndex, SP_ANIMATION_END, 0, 0); + if (self->listener) self->listener(self, trackIndex, SP_ANIMATION_END, 0, 0); + + self->tracks[trackIndex] = 0; + + _spAnimationState_disposeAllEntries(self, current); +} + +spTrackEntry* _spAnimationState_expandToIndex (spAnimationState* self, int index) { + spTrackEntry** newTracks; + if (index < self->tracksCount) return self->tracks[index]; + newTracks = CALLOC(spTrackEntry*, index + 1); + memcpy(newTracks, self->tracks, self->tracksCount * sizeof(spTrackEntry*)); + FREE(self->tracks); + self->tracks = newTracks; + self->tracksCount = index + 1; + return 0; +} + +void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEntry* entry) { + _spAnimationState* internal = SUB_CAST(_spAnimationState, self); + + spTrackEntry* current = _spAnimationState_expandToIndex(self, index); + if (current) { + spTrackEntry* previous = current->previous; + current->previous = 0; + + if (current->listener) current->listener(self, index, SP_ANIMATION_END, 0, 0); + if (self->listener) self->listener(self, index, SP_ANIMATION_END, 0, 0); + + entry->mixDuration = spAnimationStateData_getMix(self->data, current->animation, entry->animation); + if (entry->mixDuration > 0) { + entry->mixTime = 0; + /* If a mix is in progress, mix from the closest animation. */ + if (previous && current->mixTime / current->mixDuration < 0.5f) { + entry->previous = previous; + previous = current; + } else + entry->previous = current; + } else + internal->disposeTrackEntry(current); + + if (previous) internal->disposeTrackEntry(previous); + } + + self->tracks[index] = entry; + + if (entry->listener) { + entry->listener(self, index, SP_ANIMATION_START, 0, 0); + if (self->tracks[index] != entry) return; + } + if (self->listener) self->listener(self, index, SP_ANIMATION_START, 0, 0); +} + +spTrackEntry* spAnimationState_setAnimationByName (spAnimationState* self, int trackIndex, const char* animationName, + int/*bool*/loop) { + spAnimation* animation = spSkeletonData_findAnimation(self->data->skeletonData, animationName); + return spAnimationState_setAnimation(self, trackIndex, animation, loop); +} + +spTrackEntry* spAnimationState_setAnimation (spAnimationState* self, int trackIndex, spAnimation* animation, int/*bool*/loop) { + _spAnimationState* internal = SUB_CAST(_spAnimationState, self); + + spTrackEntry* entry; + spTrackEntry* current = _spAnimationState_expandToIndex(self, trackIndex); + if (current) _spAnimationState_disposeAllEntries(self, current->next); + + entry = internal->createTrackEntry(self); + entry->animation = animation; + entry->loop = loop; + entry->endTime = animation->duration; + _spAnimationState_setCurrent(self, trackIndex, entry); + return entry; +} + +spTrackEntry* spAnimationState_addAnimationByName (spAnimationState* self, int trackIndex, const char* animationName, + int/*bool*/loop, float delay) { + spAnimation* animation = spSkeletonData_findAnimation(self->data->skeletonData, animationName); + return spAnimationState_addAnimation(self, trackIndex, animation, loop, delay); +} + +spTrackEntry* spAnimationState_addAnimation (spAnimationState* self, int trackIndex, spAnimation* animation, int/*bool*/loop, + float delay) { + _spAnimationState* internal = SUB_CAST(_spAnimationState, self); + spTrackEntry* last; + + spTrackEntry* entry = internal->createTrackEntry(self); + entry->animation = animation; + entry->loop = loop; + entry->endTime = animation->duration; + + last = _spAnimationState_expandToIndex(self, trackIndex); + if (last) { + while (last->next) + last = last->next; + last->next = entry; + } else + self->tracks[trackIndex] = entry; + + if (delay <= 0) { + if (last) + delay += last->endTime - spAnimationStateData_getMix(self->data, last->animation, animation); + else + delay = 0; + } + entry->delay = delay; + + return entry; +} + +spTrackEntry* spAnimationState_getCurrent (spAnimationState* self, int trackIndex) { + if (trackIndex >= self->tracksCount) return 0; + return self->tracks[trackIndex]; } diff --git a/spine-c/src/spine/AnimationStateData.c b/spine-c/src/spine/AnimationStateData.c index edb31a97fc..1d5dc540be 100644 --- a/spine-c/src/spine/AnimationStateData.c +++ b/spine-c/src/spine/AnimationStateData.c @@ -1,152 +1,151 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -typedef struct _ToEntry _ToEntry; -struct _ToEntry { - spAnimation* animation; - float duration; - _ToEntry* next; -}; - -_ToEntry* _ToEntry_create (spAnimation* to, float duration) { - _ToEntry* self = NEW(_ToEntry); - self->animation = to; - self->duration = duration; - return self; -} - -void _ToEntry_dispose (_ToEntry* self) { - FREE(self); -} - -/**/ - -typedef struct _FromEntry _FromEntry; -struct _FromEntry { - spAnimation* animation; - _ToEntry* toEntries; - _FromEntry* next; -}; - -_FromEntry* _FromEntry_create (spAnimation* from) { - _FromEntry* self = NEW(_FromEntry); - self->animation = from; - return self; -} - -void _FromEntry_dispose (_FromEntry* self) { - FREE(self); -} - -/**/ - -spAnimationStateData* spAnimationStateData_create (spSkeletonData* skeletonData) { - spAnimationStateData* self = NEW(spAnimationStateData); - CONST_CAST(spSkeletonData*, self->skeletonData) = skeletonData; - return self; -} - -void spAnimationStateData_dispose (spAnimationStateData* self) { - _ToEntry* toEntry; - _ToEntry* nextToEntry; - _FromEntry* nextFromEntry; - - _FromEntry* fromEntry = (_FromEntry*)self->entries; - while (fromEntry) { - toEntry = fromEntry->toEntries; - while (toEntry) { - nextToEntry = toEntry->next; - _ToEntry_dispose(toEntry); - toEntry = nextToEntry; - } - nextFromEntry = fromEntry->next; - _FromEntry_dispose(fromEntry); - fromEntry = nextFromEntry; - } - - FREE(self); -} - -void spAnimationStateData_setMixByName (spAnimationStateData* self, const char* fromName, const char* toName, float duration) { - spAnimation* to; - spAnimation* from = spSkeletonData_findAnimation(self->skeletonData, fromName); - if (!from) return; - to = spSkeletonData_findAnimation(self->skeletonData, toName); - if (!to) return; - spAnimationStateData_setMix(self, from, to, duration); -} - -void spAnimationStateData_setMix (spAnimationStateData* self, spAnimation* from, spAnimation* to, float duration) { - /* Find existing FromEntry. */ - _ToEntry* toEntry; - _FromEntry* fromEntry = (_FromEntry*)self->entries; - while (fromEntry) { - if (fromEntry->animation == from) { - /* Find existing ToEntry. */ - toEntry = fromEntry->toEntries; - while (toEntry) { - if (toEntry->animation == to) { - toEntry->duration = duration; - return; - } - toEntry = toEntry->next; - } - break; /* Add new ToEntry to the existing FromEntry. */ - } - fromEntry = fromEntry->next; - } - if (!fromEntry) { - fromEntry = _FromEntry_create(from); - fromEntry->next = (_FromEntry*)self->entries; - CONST_CAST(_FromEntry*, self->entries) = fromEntry; - } - toEntry = _ToEntry_create(to, duration); - toEntry->next = fromEntry->toEntries; - fromEntry->toEntries = toEntry; -} - -float spAnimationStateData_getMix (spAnimationStateData* self, spAnimation* from, spAnimation* to) { - _FromEntry* fromEntry = (_FromEntry*)self->entries; - while (fromEntry) { - if (fromEntry->animation == from) { - _ToEntry* toEntry = fromEntry->toEntries; - while (toEntry) { - if (toEntry->animation == to) return toEntry->duration; - toEntry = toEntry->next; - } - } - fromEntry = fromEntry->next; - } - return self->defaultMix; +#include +#include + +typedef struct _ToEntry _ToEntry; +struct _ToEntry { + spAnimation* animation; + float duration; + _ToEntry* next; +}; + +_ToEntry* _ToEntry_create (spAnimation* to, float duration) { + _ToEntry* self = NEW(_ToEntry); + self->animation = to; + self->duration = duration; + return self; +} + +void _ToEntry_dispose (_ToEntry* self) { + FREE(self); +} + +/**/ + +typedef struct _FromEntry _FromEntry; +struct _FromEntry { + spAnimation* animation; + _ToEntry* toEntries; + _FromEntry* next; +}; + +_FromEntry* _FromEntry_create (spAnimation* from) { + _FromEntry* self = NEW(_FromEntry); + self->animation = from; + return self; +} + +void _FromEntry_dispose (_FromEntry* self) { + FREE(self); +} + +/**/ + +spAnimationStateData* spAnimationStateData_create (spSkeletonData* skeletonData) { + spAnimationStateData* self = NEW(spAnimationStateData); + CONST_CAST(spSkeletonData*, self->skeletonData) = skeletonData; + return self; +} + +void spAnimationStateData_dispose (spAnimationStateData* self) { + _ToEntry* toEntry; + _ToEntry* nextToEntry; + _FromEntry* nextFromEntry; + + _FromEntry* fromEntry = (_FromEntry*)self->entries; + while (fromEntry) { + toEntry = fromEntry->toEntries; + while (toEntry) { + nextToEntry = toEntry->next; + _ToEntry_dispose(toEntry); + toEntry = nextToEntry; + } + nextFromEntry = fromEntry->next; + _FromEntry_dispose(fromEntry); + fromEntry = nextFromEntry; + } + + FREE(self); +} + +void spAnimationStateData_setMixByName (spAnimationStateData* self, const char* fromName, const char* toName, float duration) { + spAnimation* to; + spAnimation* from = spSkeletonData_findAnimation(self->skeletonData, fromName); + if (!from) return; + to = spSkeletonData_findAnimation(self->skeletonData, toName); + if (!to) return; + spAnimationStateData_setMix(self, from, to, duration); +} + +void spAnimationStateData_setMix (spAnimationStateData* self, spAnimation* from, spAnimation* to, float duration) { + /* Find existing FromEntry. */ + _ToEntry* toEntry; + _FromEntry* fromEntry = (_FromEntry*)self->entries; + while (fromEntry) { + if (fromEntry->animation == from) { + /* Find existing ToEntry. */ + toEntry = fromEntry->toEntries; + while (toEntry) { + if (toEntry->animation == to) { + toEntry->duration = duration; + return; + } + toEntry = toEntry->next; + } + break; /* Add new ToEntry to the existing FromEntry. */ + } + fromEntry = fromEntry->next; + } + if (!fromEntry) { + fromEntry = _FromEntry_create(from); + fromEntry->next = (_FromEntry*)self->entries; + CONST_CAST(_FromEntry*, self->entries) = fromEntry; + } + toEntry = _ToEntry_create(to, duration); + toEntry->next = fromEntry->toEntries; + fromEntry->toEntries = toEntry; +} + +float spAnimationStateData_getMix (spAnimationStateData* self, spAnimation* from, spAnimation* to) { + _FromEntry* fromEntry = (_FromEntry*)self->entries; + while (fromEntry) { + if (fromEntry->animation == from) { + _ToEntry* toEntry = fromEntry->toEntries; + while (toEntry) { + if (toEntry->animation == to) return toEntry->duration; + toEntry = toEntry->next; + } + } + fromEntry = fromEntry->next; + } + return self->defaultMix; } diff --git a/spine-c/src/spine/Atlas.c b/spine-c/src/spine/Atlas.c index 7cb1f5fe27..7da01e6d93 100644 --- a/spine-c/src/spine/Atlas.c +++ b/spine-c/src/spine/Atlas.c @@ -1,354 +1,353 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include - -spAtlasPage* spAtlasPage_create (spAtlas* atlas, const char* name) { - spAtlasPage* self = NEW(spAtlasPage); - CONST_CAST(spAtlas*, self->atlas) = atlas; - MALLOC_STR(self->name, name); - return self; -} - -void spAtlasPage_dispose (spAtlasPage* self) { - _spAtlasPage_disposeTexture(self); - FREE(self->name); - FREE(self); -} - -/**/ - -spAtlasRegion* spAtlasRegion_create () { - return NEW(spAtlasRegion); -} - -void spAtlasRegion_dispose (spAtlasRegion* self) { - FREE(self->name); - FREE(self->splits); - FREE(self->pads); - FREE(self); -} - -/**/ - -typedef struct { - const char* begin; - const char* end; -} Str; - -static void trim (Str* str) { - while (isspace(*str->begin) && str->begin < str->end) - (str->begin)++; - if (str->begin == str->end) return; - str->end--; - while (isspace(*str->end) && str->end >= str->begin) - str->end--; - str->end++; -} - -/* Tokenize string without modification. Returns 0 on failure. */ -static int readLine (const char** begin, const char* end, Str* str) { - if (*begin == end) return 0; - str->begin = *begin; - - /* Find next delimiter. */ - while (*begin != end && **begin != '\n') - (*begin)++; - - str->end = *begin; - trim(str); - - if (*begin != end) (*begin)++; - return 1; -} - -/* Moves str->begin past the first occurence of c. Returns 0 on failure. */ -static int beginPast (Str* str, char c) { - const char* begin = str->begin; - while (1) { - char lastSkippedChar = *begin; - if (begin == str->end) return 0; - begin++; - if (lastSkippedChar == c) break; - } - str->begin = begin; - return 1; -} - -/* Returns 0 on failure. */ -static int readValue (const char** begin, const char* end, Str* str) { - readLine(begin, end, str); - if (!beginPast(str, ':')) return 0; - trim(str); - return 1; -} - -/* Returns the number of tuple values read (1, 2, 4, or 0 for failure). */ -static int readTuple (const char** begin, const char* end, Str tuple[]) { - int i; - Str str = {NULL, NULL}; - readLine(begin, end, &str); - if (!beginPast(&str, ':')) return 0; - - for (i = 0; i < 3; ++i) { - tuple[i].begin = str.begin; - if (!beginPast(&str, ',')) break; - tuple[i].end = str.begin - 2; - trim(&tuple[i]); - } - tuple[i].begin = str.begin; - tuple[i].end = str.end; - trim(&tuple[i]); - return i + 1; -} - -static char* mallocString (Str* str) { - int length = (int)(str->end - str->begin); - char* string = MALLOC(char, length + 1); - memcpy(string, str->begin, length); - string[length] = '\0'; - return string; -} - -static int indexOf (const char** array, int count, Str* str) { - int length = (int)(str->end - str->begin); - int i; - for (i = count - 1; i >= 0; i--) - if (strncmp(array[i], str->begin, length) == 0) return i; - return 0; -} - -static int equals (Str* str, const char* other) { - return strncmp(other, str->begin, str->end - str->begin) == 0; -} - -static int toInt (Str* str) { - return (int)strtol(str->begin, (char**)&str->end, 10); -} - -static spAtlas* abortAtlas (spAtlas* self) { - spAtlas_dispose(self); - return 0; -} - -static const char* formatNames[] = {"", "Alpha", "Intensity", "LuminanceAlpha", "RGB565", "RGBA4444", "RGB888", "RGBA8888"}; -static const char* textureFilterNames[] = {"", "Nearest", "Linear", "MipMap", "MipMapNearestNearest", "MipMapLinearNearest", - "MipMapNearestLinear", "MipMapLinearLinear"}; - -spAtlas* spAtlas_create (const char* begin, int length, const char* dir, void* rendererObject) { - spAtlas* self; - - int count; - const char* end = begin + length; - int dirLength = (int)strlen(dir); - int needsSlash = dirLength > 0 && dir[dirLength - 1] != '/' && dir[dirLength - 1] != '\\'; - - spAtlasPage *page = 0; - spAtlasPage *lastPage = 0; - spAtlasRegion *lastRegion = 0; - Str str; - Str tuple[4]; - - self = NEW(spAtlas); - self->rendererObject = rendererObject; - - while (readLine(&begin, end, &str)) { - if (str.end - str.begin == 0) { - page = 0; - } else if (!page) { - char* name = mallocString(&str); - char* path = MALLOC(char, dirLength + needsSlash + strlen(name) + 1); - memcpy(path, dir, dirLength); - if (needsSlash) path[dirLength] = '/'; - strcpy(path + dirLength + needsSlash, name); - - page = spAtlasPage_create(self, name); - FREE(name); - if (lastPage) - lastPage->next = page; - else - self->pages = page; - lastPage = page; - - switch (readTuple(&begin, end, tuple)) { - case 0: - return abortAtlas(self); - case 2: /* size is only optional for an atlas packed with an old TexturePacker. */ - page->width = toInt(tuple); - page->height = toInt(tuple + 1); - if (!readTuple(&begin, end, tuple)) return abortAtlas(self); - } - page->format = (spAtlasFormat)indexOf(formatNames, 8, tuple); - - if (!readTuple(&begin, end, tuple)) return abortAtlas(self); - page->minFilter = (spAtlasFilter)indexOf(textureFilterNames, 8, tuple); - page->magFilter = (spAtlasFilter)indexOf(textureFilterNames, 8, tuple + 1); - - if (!readValue(&begin, end, &str)) return abortAtlas(self); - - page->uWrap = SP_ATLAS_CLAMPTOEDGE; - page->vWrap = SP_ATLAS_CLAMPTOEDGE; - if (!equals(&str, "none")) { - if (str.end - str.begin == 1) { - if (*str.begin == 'x') - page->uWrap = SP_ATLAS_REPEAT; - else if (*str.begin == 'y') - page->vWrap = SP_ATLAS_REPEAT; - } else if (equals(&str, "xy")) { - page->uWrap = SP_ATLAS_REPEAT; - page->vWrap = SP_ATLAS_REPEAT; - } - } - - _spAtlasPage_createTexture(page, path); - FREE(path); - } else { - spAtlasRegion *region = spAtlasRegion_create(); - if (lastRegion) - lastRegion->next = region; - else - self->regions = region; - lastRegion = region; - - region->page = page; - region->name = mallocString(&str); - - if (!readValue(&begin, end, &str)) return abortAtlas(self); - region->rotate = equals(&str, "true"); - - if (readTuple(&begin, end, tuple) != 2) return abortAtlas(self); - region->x = toInt(tuple); - region->y = toInt(tuple + 1); - - if (readTuple(&begin, end, tuple) != 2) return abortAtlas(self); - region->width = toInt(tuple); - region->height = toInt(tuple + 1); - - region->u = region->x / (float)page->width; - region->v = region->y / (float)page->height; - if (region->rotate) { - region->u2 = (region->x + region->height) / (float)page->width; - region->v2 = (region->y + region->width) / (float)page->height; - } else { - region->u2 = (region->x + region->width) / (float)page->width; - region->v2 = (region->y + region->height) / (float)page->height; - } - - if (!(count = readTuple(&begin, end, tuple))) return abortAtlas(self); - if (count == 4) { /* split is optional */ - region->splits = MALLOC(int, 4); - region->splits[0] = toInt(tuple); - region->splits[1] = toInt(tuple + 1); - region->splits[2] = toInt(tuple + 2); - region->splits[3] = toInt(tuple + 3); - - if (!(count = readTuple(&begin, end, tuple))) return abortAtlas(self); - if (count == 4) { /* pad is optional, but only present with splits */ - region->pads = MALLOC(int, 4); - region->pads[0] = toInt(tuple); - region->pads[1] = toInt(tuple + 1); - region->pads[2] = toInt(tuple + 2); - region->pads[3] = toInt(tuple + 3); - - if (!readTuple(&begin, end, tuple)) return abortAtlas(self); - } - } - - region->originalWidth = toInt(tuple); - region->originalHeight = toInt(tuple + 1); - - readTuple(&begin, end, tuple); - region->offsetX = toInt(tuple); - region->offsetY = toInt(tuple + 1); - - if (!readValue(&begin, end, &str)) return abortAtlas(self); - region->index = toInt(&str); - } - } - - return self; -} - -spAtlas* spAtlas_createFromFile (const char* path, void* rendererObject) { - int dirLength; - char *dir; - int length; - const char* data; - - spAtlas* atlas = 0; - - /* Get directory from atlas path. */ - const char* lastForwardSlash = strrchr(path, '/'); - const char* lastBackwardSlash = strrchr(path, '\\'); - const char* lastSlash = lastForwardSlash > lastBackwardSlash ? lastForwardSlash : lastBackwardSlash; - if (lastSlash == path) lastSlash++; /* Never drop starting slash. */ - dirLength = (int)(lastSlash ? lastSlash - path : 0); - dir = MALLOC(char, dirLength + 1); - memcpy(dir, path, dirLength); - dir[dirLength] = '\0'; - - data = _spUtil_readFile(path, &length); - if (data) atlas = spAtlas_create(data, length, dir, rendererObject); - - FREE(data); - FREE(dir); - return atlas; -} - -void spAtlas_dispose (spAtlas* self) { - spAtlasRegion* region, *nextRegion; - spAtlasPage* page = self->pages; - while (page) { - spAtlasPage* nextPage = page->next; - spAtlasPage_dispose(page); - page = nextPage; - } - - region = self->regions; - while (region) { - nextRegion = region->next; - spAtlasRegion_dispose(region); - region = nextRegion; - } - - FREE(self); -} - -spAtlasRegion* spAtlas_findRegion (const spAtlas* self, const char* name) { - spAtlasRegion* region = self->regions; - while (region) { - if (strcmp(region->name, name) == 0) return region; - region = region->next; - } - return 0; +#include +#include +#include + +spAtlasPage* spAtlasPage_create (spAtlas* atlas, const char* name) { + spAtlasPage* self = NEW(spAtlasPage); + CONST_CAST(spAtlas*, self->atlas) = atlas; + MALLOC_STR(self->name, name); + return self; +} + +void spAtlasPage_dispose (spAtlasPage* self) { + _spAtlasPage_disposeTexture(self); + FREE(self->name); + FREE(self); +} + +/**/ + +spAtlasRegion* spAtlasRegion_create () { + return NEW(spAtlasRegion); +} + +void spAtlasRegion_dispose (spAtlasRegion* self) { + FREE(self->name); + FREE(self->splits); + FREE(self->pads); + FREE(self); +} + +/**/ + +typedef struct { + const char* begin; + const char* end; +} Str; + +static void trim (Str* str) { + while (isspace(*str->begin) && str->begin < str->end) + (str->begin)++; + if (str->begin == str->end) return; + str->end--; + while (isspace(*str->end) && str->end >= str->begin) + str->end--; + str->end++; +} + +/* Tokenize string without modification. Returns 0 on failure. */ +static int readLine (const char** begin, const char* end, Str* str) { + if (*begin == end) return 0; + str->begin = *begin; + + /* Find next delimiter. */ + while (*begin != end && **begin != '\n') + (*begin)++; + + str->end = *begin; + trim(str); + + if (*begin != end) (*begin)++; + return 1; +} + +/* Moves str->begin past the first occurence of c. Returns 0 on failure. */ +static int beginPast (Str* str, char c) { + const char* begin = str->begin; + while (1) { + char lastSkippedChar = *begin; + if (begin == str->end) return 0; + begin++; + if (lastSkippedChar == c) break; + } + str->begin = begin; + return 1; +} + +/* Returns 0 on failure. */ +static int readValue (const char** begin, const char* end, Str* str) { + readLine(begin, end, str); + if (!beginPast(str, ':')) return 0; + trim(str); + return 1; +} + +/* Returns the number of tuple values read (1, 2, 4, or 0 for failure). */ +static int readTuple (const char** begin, const char* end, Str tuple[]) { + int i; + Str str = {NULL, NULL}; + readLine(begin, end, &str); + if (!beginPast(&str, ':')) return 0; + + for (i = 0; i < 3; ++i) { + tuple[i].begin = str.begin; + if (!beginPast(&str, ',')) break; + tuple[i].end = str.begin - 2; + trim(&tuple[i]); + } + tuple[i].begin = str.begin; + tuple[i].end = str.end; + trim(&tuple[i]); + return i + 1; +} + +static char* mallocString (Str* str) { + int length = (int)(str->end - str->begin); + char* string = MALLOC(char, length + 1); + memcpy(string, str->begin, length); + string[length] = '\0'; + return string; +} + +static int indexOf (const char** array, int count, Str* str) { + int length = (int)(str->end - str->begin); + int i; + for (i = count - 1; i >= 0; i--) + if (strncmp(array[i], str->begin, length) == 0) return i; + return 0; +} + +static int equals (Str* str, const char* other) { + return strncmp(other, str->begin, str->end - str->begin) == 0; +} + +static int toInt (Str* str) { + return (int)strtol(str->begin, (char**)&str->end, 10); +} + +static spAtlas* abortAtlas (spAtlas* self) { + spAtlas_dispose(self); + return 0; +} + +static const char* formatNames[] = {"", "Alpha", "Intensity", "LuminanceAlpha", "RGB565", "RGBA4444", "RGB888", "RGBA8888"}; +static const char* textureFilterNames[] = {"", "Nearest", "Linear", "MipMap", "MipMapNearestNearest", "MipMapLinearNearest", + "MipMapNearestLinear", "MipMapLinearLinear"}; + +spAtlas* spAtlas_create (const char* begin, int length, const char* dir, void* rendererObject) { + spAtlas* self; + + int count; + const char* end = begin + length; + int dirLength = (int)strlen(dir); + int needsSlash = dirLength > 0 && dir[dirLength - 1] != '/' && dir[dirLength - 1] != '\\'; + + spAtlasPage *page = 0; + spAtlasPage *lastPage = 0; + spAtlasRegion *lastRegion = 0; + Str str; + Str tuple[4]; + + self = NEW(spAtlas); + self->rendererObject = rendererObject; + + while (readLine(&begin, end, &str)) { + if (str.end - str.begin == 0) { + page = 0; + } else if (!page) { + char* name = mallocString(&str); + char* path = MALLOC(char, dirLength + needsSlash + strlen(name) + 1); + memcpy(path, dir, dirLength); + if (needsSlash) path[dirLength] = '/'; + strcpy(path + dirLength + needsSlash, name); + + page = spAtlasPage_create(self, name); + FREE(name); + if (lastPage) + lastPage->next = page; + else + self->pages = page; + lastPage = page; + + switch (readTuple(&begin, end, tuple)) { + case 0: + return abortAtlas(self); + case 2: /* size is only optional for an atlas packed with an old TexturePacker. */ + page->width = toInt(tuple); + page->height = toInt(tuple + 1); + if (!readTuple(&begin, end, tuple)) return abortAtlas(self); + } + page->format = (spAtlasFormat)indexOf(formatNames, 8, tuple); + + if (!readTuple(&begin, end, tuple)) return abortAtlas(self); + page->minFilter = (spAtlasFilter)indexOf(textureFilterNames, 8, tuple); + page->magFilter = (spAtlasFilter)indexOf(textureFilterNames, 8, tuple + 1); + + if (!readValue(&begin, end, &str)) return abortAtlas(self); + + page->uWrap = SP_ATLAS_CLAMPTOEDGE; + page->vWrap = SP_ATLAS_CLAMPTOEDGE; + if (!equals(&str, "none")) { + if (str.end - str.begin == 1) { + if (*str.begin == 'x') + page->uWrap = SP_ATLAS_REPEAT; + else if (*str.begin == 'y') + page->vWrap = SP_ATLAS_REPEAT; + } else if (equals(&str, "xy")) { + page->uWrap = SP_ATLAS_REPEAT; + page->vWrap = SP_ATLAS_REPEAT; + } + } + + _spAtlasPage_createTexture(page, path); + FREE(path); + } else { + spAtlasRegion *region = spAtlasRegion_create(); + if (lastRegion) + lastRegion->next = region; + else + self->regions = region; + lastRegion = region; + + region->page = page; + region->name = mallocString(&str); + + if (!readValue(&begin, end, &str)) return abortAtlas(self); + region->rotate = equals(&str, "true"); + + if (readTuple(&begin, end, tuple) != 2) return abortAtlas(self); + region->x = toInt(tuple); + region->y = toInt(tuple + 1); + + if (readTuple(&begin, end, tuple) != 2) return abortAtlas(self); + region->width = toInt(tuple); + region->height = toInt(tuple + 1); + + region->u = region->x / (float)page->width; + region->v = region->y / (float)page->height; + if (region->rotate) { + region->u2 = (region->x + region->height) / (float)page->width; + region->v2 = (region->y + region->width) / (float)page->height; + } else { + region->u2 = (region->x + region->width) / (float)page->width; + region->v2 = (region->y + region->height) / (float)page->height; + } + + if (!(count = readTuple(&begin, end, tuple))) return abortAtlas(self); + if (count == 4) { /* split is optional */ + region->splits = MALLOC(int, 4); + region->splits[0] = toInt(tuple); + region->splits[1] = toInt(tuple + 1); + region->splits[2] = toInt(tuple + 2); + region->splits[3] = toInt(tuple + 3); + + if (!(count = readTuple(&begin, end, tuple))) return abortAtlas(self); + if (count == 4) { /* pad is optional, but only present with splits */ + region->pads = MALLOC(int, 4); + region->pads[0] = toInt(tuple); + region->pads[1] = toInt(tuple + 1); + region->pads[2] = toInt(tuple + 2); + region->pads[3] = toInt(tuple + 3); + + if (!readTuple(&begin, end, tuple)) return abortAtlas(self); + } + } + + region->originalWidth = toInt(tuple); + region->originalHeight = toInt(tuple + 1); + + readTuple(&begin, end, tuple); + region->offsetX = toInt(tuple); + region->offsetY = toInt(tuple + 1); + + if (!readValue(&begin, end, &str)) return abortAtlas(self); + region->index = toInt(&str); + } + } + + return self; +} + +spAtlas* spAtlas_createFromFile (const char* path, void* rendererObject) { + int dirLength; + char *dir; + int length; + const char* data; + + spAtlas* atlas = 0; + + /* Get directory from atlas path. */ + const char* lastForwardSlash = strrchr(path, '/'); + const char* lastBackwardSlash = strrchr(path, '\\'); + const char* lastSlash = lastForwardSlash > lastBackwardSlash ? lastForwardSlash : lastBackwardSlash; + if (lastSlash == path) lastSlash++; /* Never drop starting slash. */ + dirLength = (int)(lastSlash ? lastSlash - path : 0); + dir = MALLOC(char, dirLength + 1); + memcpy(dir, path, dirLength); + dir[dirLength] = '\0'; + + data = _spUtil_readFile(path, &length); + if (data) atlas = spAtlas_create(data, length, dir, rendererObject); + + FREE(data); + FREE(dir); + return atlas; +} + +void spAtlas_dispose (spAtlas* self) { + spAtlasRegion* region, *nextRegion; + spAtlasPage* page = self->pages; + while (page) { + spAtlasPage* nextPage = page->next; + spAtlasPage_dispose(page); + page = nextPage; + } + + region = self->regions; + while (region) { + nextRegion = region->next; + spAtlasRegion_dispose(region); + region = nextRegion; + } + + FREE(self); +} + +spAtlasRegion* spAtlas_findRegion (const spAtlas* self, const char* name) { + spAtlasRegion* region = self->regions; + while (region) { + if (strcmp(region->name, name) == 0) return region; + region = region->next; + } + return 0; } diff --git a/spine-c/src/spine/AtlasAttachmentLoader.c b/spine-c/src/spine/AtlasAttachmentLoader.c index 3d240035eb..bb8d92e2d7 100644 --- a/spine-c/src/spine/AtlasAttachmentLoader.c +++ b/spine-c/src/spine/AtlasAttachmentLoader.c @@ -1,97 +1,96 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -spAttachment* _spAtlasAttachmentLoader_createAttachment (spAttachmentLoader* loader, spSkin* skin, spAttachmentType type, - const char* name, const char* path) { - spAtlasAttachmentLoader* self = SUB_CAST(spAtlasAttachmentLoader, loader); - switch (type) { - case SP_ATTACHMENT_REGION: { - spRegionAttachment* attachment; - spAtlasRegion* region = spAtlas_findRegion(self->atlas, path); - if (!region) { - _spAttachmentLoader_setError(loader, "Region not found: ", path); - return 0; - } - attachment = spRegionAttachment_create(name); - attachment->rendererObject = region; - spRegionAttachment_setUVs(attachment, region->u, region->v, region->u2, region->v2, region->rotate); - attachment->regionOffsetX = region->offsetX; - attachment->regionOffsetY = region->offsetY; - attachment->regionWidth = region->width; - attachment->regionHeight = region->height; - attachment->regionOriginalWidth = region->originalWidth; - attachment->regionOriginalHeight = region->originalHeight; - return SUPER(attachment); - } - case SP_ATTACHMENT_MESH: - case SP_ATTACHMENT_LINKED_MESH: { - spMeshAttachment* attachment; - spAtlasRegion* region = spAtlas_findRegion(self->atlas, path); - if (!region) { - _spAttachmentLoader_setError(loader, "Region not found: ", path); - return 0; - } - attachment = spMeshAttachment_create(name); - attachment->rendererObject = region; - attachment->regionU = region->u; - attachment->regionV = region->v; - attachment->regionU2 = region->u2; - attachment->regionV2 = region->v2; - attachment->regionRotate = region->rotate; - attachment->regionOffsetX = region->offsetX; - attachment->regionOffsetY = region->offsetY; - attachment->regionWidth = region->width; - attachment->regionHeight = region->height; - attachment->regionOriginalWidth = region->originalWidth; - attachment->regionOriginalHeight = region->originalHeight; - return SUPER(SUPER(attachment)); - } - case SP_ATTACHMENT_BOUNDING_BOX: - return SUPER(SUPER(spBoundingBoxAttachment_create(name))); - case SP_ATTACHMENT_PATH: - return SUPER(SUPER(spPathAttachment_create(name))); - default: - _spAttachmentLoader_setUnknownTypeError(loader, type); - return 0; - } - - UNUSED(skin); -} - -spAtlasAttachmentLoader* spAtlasAttachmentLoader_create (spAtlas* atlas) { - spAtlasAttachmentLoader* self = NEW(spAtlasAttachmentLoader); - _spAttachmentLoader_init(SUPER(self), _spAttachmentLoader_deinit, _spAtlasAttachmentLoader_createAttachment, 0, 0); - self->atlas = atlas; - return self; +#include +#include + +spAttachment* _spAtlasAttachmentLoader_createAttachment (spAttachmentLoader* loader, spSkin* skin, spAttachmentType type, + const char* name, const char* path) { + spAtlasAttachmentLoader* self = SUB_CAST(spAtlasAttachmentLoader, loader); + switch (type) { + case SP_ATTACHMENT_REGION: { + spRegionAttachment* attachment; + spAtlasRegion* region = spAtlas_findRegion(self->atlas, path); + if (!region) { + _spAttachmentLoader_setError(loader, "Region not found: ", path); + return 0; + } + attachment = spRegionAttachment_create(name); + attachment->rendererObject = region; + spRegionAttachment_setUVs(attachment, region->u, region->v, region->u2, region->v2, region->rotate); + attachment->regionOffsetX = region->offsetX; + attachment->regionOffsetY = region->offsetY; + attachment->regionWidth = region->width; + attachment->regionHeight = region->height; + attachment->regionOriginalWidth = region->originalWidth; + attachment->regionOriginalHeight = region->originalHeight; + return SUPER(attachment); + } + case SP_ATTACHMENT_MESH: + case SP_ATTACHMENT_LINKED_MESH: { + spMeshAttachment* attachment; + spAtlasRegion* region = spAtlas_findRegion(self->atlas, path); + if (!region) { + _spAttachmentLoader_setError(loader, "Region not found: ", path); + return 0; + } + attachment = spMeshAttachment_create(name); + attachment->rendererObject = region; + attachment->regionU = region->u; + attachment->regionV = region->v; + attachment->regionU2 = region->u2; + attachment->regionV2 = region->v2; + attachment->regionRotate = region->rotate; + attachment->regionOffsetX = region->offsetX; + attachment->regionOffsetY = region->offsetY; + attachment->regionWidth = region->width; + attachment->regionHeight = region->height; + attachment->regionOriginalWidth = region->originalWidth; + attachment->regionOriginalHeight = region->originalHeight; + return SUPER(SUPER(attachment)); + } + case SP_ATTACHMENT_BOUNDING_BOX: + return SUPER(SUPER(spBoundingBoxAttachment_create(name))); + case SP_ATTACHMENT_PATH: + return SUPER(SUPER(spPathAttachment_create(name))); + default: + _spAttachmentLoader_setUnknownTypeError(loader, type); + return 0; + } + + UNUSED(skin); +} + +spAtlasAttachmentLoader* spAtlasAttachmentLoader_create (spAtlas* atlas) { + spAtlasAttachmentLoader* self = NEW(spAtlasAttachmentLoader); + _spAttachmentLoader_init(SUPER(self), _spAttachmentLoader_deinit, _spAtlasAttachmentLoader_createAttachment, 0, 0); + self->atlas = atlas; + return self; } diff --git a/spine-c/src/spine/Attachment.c b/spine-c/src/spine/Attachment.c index 20a57f0e58..ea0f143f64 100644 --- a/spine-c/src/spine/Attachment.c +++ b/spine-c/src/spine/Attachment.c @@ -1,58 +1,57 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include - -typedef struct _spAttachmentVtable { - void (*dispose) (spAttachment* self); -} _spAttachmentVtable; - -void _spAttachment_init (spAttachment* self, const char* name, spAttachmentType type, /**/ - void (*dispose) (spAttachment* self)) { - - CONST_CAST(_spAttachmentVtable*, self->vtable) = NEW(_spAttachmentVtable); - VTABLE(spAttachment, self) ->dispose = dispose; - - MALLOC_STR(self->name, name); - CONST_CAST(spAttachmentType, self->type) = type; -} - -void _spAttachment_deinit (spAttachment* self) { - if (self->attachmentLoader) spAttachmentLoader_disposeAttachment(self->attachmentLoader, self); - FREE(self->vtable); - FREE(self->name); -} - -void spAttachment_dispose (spAttachment* self) { - VTABLE(spAttachment, self) ->dispose(self); +#include +#include +#include + +typedef struct _spAttachmentVtable { + void (*dispose) (spAttachment* self); +} _spAttachmentVtable; + +void _spAttachment_init (spAttachment* self, const char* name, spAttachmentType type, /**/ + void (*dispose) (spAttachment* self)) { + + CONST_CAST(_spAttachmentVtable*, self->vtable) = NEW(_spAttachmentVtable); + VTABLE(spAttachment, self) ->dispose = dispose; + + MALLOC_STR(self->name, name); + CONST_CAST(spAttachmentType, self->type) = type; +} + +void _spAttachment_deinit (spAttachment* self) { + if (self->attachmentLoader) spAttachmentLoader_disposeAttachment(self->attachmentLoader, self); + FREE(self->vtable); + FREE(self->name); +} + +void spAttachment_dispose (spAttachment* self) { + VTABLE(spAttachment, self) ->dispose(self); } diff --git a/spine-c/src/spine/AttachmentLoader.c b/spine-c/src/spine/AttachmentLoader.c index 9c5f132faa..2971f7a214 100644 --- a/spine-c/src/spine/AttachmentLoader.c +++ b/spine-c/src/spine/AttachmentLoader.c @@ -1,99 +1,98 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include - -typedef struct _spAttachmentLoaderVtable { - spAttachment* (*createAttachment) (spAttachmentLoader* self, spSkin* skin, spAttachmentType type, const char* name, - const char* path); - void (*configureAttachment) (spAttachmentLoader* self, spAttachment*); - void (*disposeAttachment) (spAttachmentLoader* self, spAttachment*); - void (*dispose) (spAttachmentLoader* self); -} _spAttachmentLoaderVtable; - -void _spAttachmentLoader_init (spAttachmentLoader* self, - void (*dispose) (spAttachmentLoader* self), - spAttachment* (*createAttachment) (spAttachmentLoader* self, spSkin* skin, spAttachmentType type, const char* name, - const char* path), - void (*configureAttachment) (spAttachmentLoader* self, spAttachment*), - void (*disposeAttachment) (spAttachmentLoader* self, spAttachment*) -) { - CONST_CAST(_spAttachmentLoaderVtable*, self->vtable) = NEW(_spAttachmentLoaderVtable); - VTABLE(spAttachmentLoader, self)->dispose = dispose; - VTABLE(spAttachmentLoader, self)->createAttachment = createAttachment; - VTABLE(spAttachmentLoader, self)->configureAttachment = configureAttachment; - VTABLE(spAttachmentLoader, self)->disposeAttachment = disposeAttachment; -} - -void _spAttachmentLoader_deinit (spAttachmentLoader* self) { - FREE(self->vtable); - FREE(self->error1); - FREE(self->error2); -} - -void spAttachmentLoader_dispose (spAttachmentLoader* self) { - VTABLE(spAttachmentLoader, self)->dispose(self); - FREE(self); -} - -spAttachment* spAttachmentLoader_createAttachment (spAttachmentLoader* self, spSkin* skin, spAttachmentType type, const char* name, - const char* path) { - FREE(self->error1); - FREE(self->error2); - self->error1 = 0; - self->error2 = 0; - return VTABLE(spAttachmentLoader, self)->createAttachment(self, skin, type, name, path); -} - -void spAttachmentLoader_configureAttachment (spAttachmentLoader* self, spAttachment* attachment) { - if (!VTABLE(spAttachmentLoader, self)->configureAttachment) return; - VTABLE(spAttachmentLoader, self)->configureAttachment(self, attachment); -} - -void spAttachmentLoader_disposeAttachment (spAttachmentLoader* self, spAttachment* attachment) { - if (!VTABLE(spAttachmentLoader, self)->disposeAttachment) return; - VTABLE(spAttachmentLoader, self)->disposeAttachment(self, attachment); -} - -void _spAttachmentLoader_setError (spAttachmentLoader* self, const char* error1, const char* error2) { - FREE(self->error1); - FREE(self->error2); - MALLOC_STR(self->error1, error1); - MALLOC_STR(self->error2, error2); -} - -void _spAttachmentLoader_setUnknownTypeError (spAttachmentLoader* self, spAttachmentType type) { - char buffer[16]; - sprintf(buffer, "%d", type); - _spAttachmentLoader_setError(self, "Unknown attachment type: ", buffer); +#include +#include +#include + +typedef struct _spAttachmentLoaderVtable { + spAttachment* (*createAttachment) (spAttachmentLoader* self, spSkin* skin, spAttachmentType type, const char* name, + const char* path); + void (*configureAttachment) (spAttachmentLoader* self, spAttachment*); + void (*disposeAttachment) (spAttachmentLoader* self, spAttachment*); + void (*dispose) (spAttachmentLoader* self); +} _spAttachmentLoaderVtable; + +void _spAttachmentLoader_init (spAttachmentLoader* self, + void (*dispose) (spAttachmentLoader* self), + spAttachment* (*createAttachment) (spAttachmentLoader* self, spSkin* skin, spAttachmentType type, const char* name, + const char* path), + void (*configureAttachment) (spAttachmentLoader* self, spAttachment*), + void (*disposeAttachment) (spAttachmentLoader* self, spAttachment*) +) { + CONST_CAST(_spAttachmentLoaderVtable*, self->vtable) = NEW(_spAttachmentLoaderVtable); + VTABLE(spAttachmentLoader, self)->dispose = dispose; + VTABLE(spAttachmentLoader, self)->createAttachment = createAttachment; + VTABLE(spAttachmentLoader, self)->configureAttachment = configureAttachment; + VTABLE(spAttachmentLoader, self)->disposeAttachment = disposeAttachment; +} + +void _spAttachmentLoader_deinit (spAttachmentLoader* self) { + FREE(self->vtable); + FREE(self->error1); + FREE(self->error2); +} + +void spAttachmentLoader_dispose (spAttachmentLoader* self) { + VTABLE(spAttachmentLoader, self)->dispose(self); + FREE(self); +} + +spAttachment* spAttachmentLoader_createAttachment (spAttachmentLoader* self, spSkin* skin, spAttachmentType type, const char* name, + const char* path) { + FREE(self->error1); + FREE(self->error2); + self->error1 = 0; + self->error2 = 0; + return VTABLE(spAttachmentLoader, self)->createAttachment(self, skin, type, name, path); +} + +void spAttachmentLoader_configureAttachment (spAttachmentLoader* self, spAttachment* attachment) { + if (!VTABLE(spAttachmentLoader, self)->configureAttachment) return; + VTABLE(spAttachmentLoader, self)->configureAttachment(self, attachment); +} + +void spAttachmentLoader_disposeAttachment (spAttachmentLoader* self, spAttachment* attachment) { + if (!VTABLE(spAttachmentLoader, self)->disposeAttachment) return; + VTABLE(spAttachmentLoader, self)->disposeAttachment(self, attachment); +} + +void _spAttachmentLoader_setError (spAttachmentLoader* self, const char* error1, const char* error2) { + FREE(self->error1); + FREE(self->error2); + MALLOC_STR(self->error1, error1); + MALLOC_STR(self->error2, error2); +} + +void _spAttachmentLoader_setUnknownTypeError (spAttachmentLoader* self, spAttachmentType type) { + char buffer[16]; + sprintf(buffer, "%d", type); + _spAttachmentLoader_setError(self, "Unknown attachment type: ", buffer); } diff --git a/spine-c/src/spine/Bone.c b/spine-c/src/spine/Bone.c index da90652506..5e9906e4d9 100644 --- a/spine-c/src/spine/Bone.c +++ b/spine-c/src/spine/Bone.c @@ -1,288 +1,287 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include -static int yDown; - -void spBone_setYDown (int value) { - yDown = value; -} - -int spBone_isYDown () { - return yDown; -} - -spBone* spBone_create (spBoneData* data, spSkeleton* skeleton, spBone* parent) { - spBone* self = NEW(spBone); - CONST_CAST(spBoneData*, self->data) = data; - CONST_CAST(spSkeleton*, self->skeleton) = skeleton; - CONST_CAST(spBone*, self->parent) = parent; - spBone_setToSetupPose(self); - return self; -} - -void spBone_dispose (spBone* self) { - FREE(self->children); - FREE(self); -} - -void spBone_updateWorldTransform (spBone* self) { - spBone_updateWorldTransformWith(self, self->x, self->y, self->rotation, self->scaleX, self->scaleY, self->shearX, self->shearY); -} - -void spBone_updateWorldTransformWith (spBone* self, float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY) { - float cosine, sine; - float rotationY = rotation + 90 + shearY; - float la = COS_DEG(rotation + shearX) * scaleX, lb = COS_DEG(rotationY) * scaleY; - float lc = SIN_DEG(rotation + shearX) * scaleX, ld = SIN_DEG(rotationY) * scaleY; - float pa, pb, pc, pd, temp; - spBone* parent = self->parent; - - CONST_CAST(float, self->appliedRotation) = rotation; - - if (!parent) { /* Root bone. */ - if (self->skeleton->flipX) { - x = -x; - la = -la; - lb = -lb; - } - if (self->skeleton->flipY != yDown) { - y = -y; - lc = -lc; - ld = -ld; - } - CONST_CAST(float, self->a) = la; - CONST_CAST(float, self->b) = lb; - CONST_CAST(float, self->c) = lc; - CONST_CAST(float, self->d) = ld; - CONST_CAST(float, self->worldX) = x; - CONST_CAST(float, self->worldY) = y; - CONST_CAST(float, self->worldSignX) = scaleX > 0 ? 1.0f : -1.0f; - CONST_CAST(float, self->worldSignY) = scaleY > 0 ? 1.0f : -1.0f; - return; - } - - pa = parent->a; - pb = parent->b; - pc = parent->c; - pd = parent->d; - - CONST_CAST(float, self->worldX) = pa * x + pb * y + parent->worldX; - CONST_CAST(float, self->worldY) = pc * x + pd * y + parent->worldY; - CONST_CAST(float, self->worldSignX) = parent->worldSignX * (scaleX > 0 ? 1 : -1); - CONST_CAST(float, self->worldSignY) = parent->worldSignY * (scaleY > 0 ? 1 : -1); - - if (self->data->inheritRotation && self->data->inheritScale) { - CONST_CAST(float, self->a) = pa * la + pb * lc; - CONST_CAST(float, self->b) = pa * lb + pb * ld; - CONST_CAST(float, self->c) = pc * la + pd * lc; - CONST_CAST(float, self->d) = pc * lb + pd * ld; - } else { - if (self->data->inheritRotation) { /* No scale inheritance. */ - pa = 1; - pb = 0; - pc = 0; - pd = 1; - do { - cosine = COS_DEG(parent->appliedRotation); sine = SIN_DEG(parent->appliedRotation); - temp = pa * cosine + pb * sine; - pb = pb * cosine - pa * sine; - pa = temp; - temp = pc * cosine + pd * sine; - pd = pd * cosine - pc * sine; - pc = temp; - - if (!parent->data->inheritRotation) break; - parent = parent->parent; - } while (parent); - CONST_CAST(float, self->a) = pa * la + pb * lc; - CONST_CAST(float, self->b) = pa * lb + pb * ld; - CONST_CAST(float, self->c) = pc * la + pd * lc; - CONST_CAST(float, self->d) = pc * lb + pd * ld; - } else if (self->data->inheritScale) { /* No rotation inheritance. */ - pa = 1; - pb = 0; - pc = 0; - pd = 1; - do { - float za, zb, zc, zd; - float psx = parent->scaleX, psy = parent->scaleY; - cosine = COS_DEG(parent->appliedRotation); - sine = SIN_DEG(parent->appliedRotation); - za = cosine * psx; zb = sine * psy; zc = sine * psx; zd = cosine * psy; - temp = pa * za + pb * zc; - pb = pb * zd - pa * zb; - pa = temp; - temp = pc * za + pd * zc; - pd = pd * zd - pc * zb; - pc = temp; - - if (psx >= 0) sine = -sine; - temp = pa * cosine + pb * sine; - pb = pb * cosine - pa * sine; - pa = temp; - temp = pc * cosine + pd * sine; - pd = pd * cosine - pc * sine; - pc = temp; - - if (!parent->data->inheritScale) break; - parent = parent->parent; - } while (parent); - CONST_CAST(float, self->a) = pa * la + pb * lc; - CONST_CAST(float, self->b) = pa * lb + pb * ld; - CONST_CAST(float, self->c) = pc * la + pd * lc; - CONST_CAST(float, self->d) = pc * lb + pd * ld; - } else { - CONST_CAST(float, self->a) = la; - CONST_CAST(float, self->b) = lb; - CONST_CAST(float, self->c) = lc; - CONST_CAST(float, self->d) = ld; - } - if (self->skeleton->flipX) { - CONST_CAST(float, self->a) = -self->a; - CONST_CAST(float, self->b) = -self->b; - } - if (self->skeleton->flipY != yDown) { - CONST_CAST(float, self->c) = -self->c; - CONST_CAST(float, self->d) = -self->d; - } - } -} - -void spBone_setToSetupPose (spBone* self) { - self->x = self->data->x; - self->y = self->data->y; - self->rotation = self->data->rotation; - self->scaleX = self->data->scaleX; - self->scaleY = self->data->scaleY; - self->shearX = self->data->shearX; - self->shearY = self->data->shearY; -} - -float spBone_getWorldRotationX (spBone* self) { - return ATAN2(self->c, self->a) * RAD_DEG; -} - -float spBone_getWorldRotationY (spBone* self) { - return ATAN2(self->d, self->b) * RAD_DEG; -} - -float spBone_getWorldScaleX (spBone* self) { - return SQRT(self->a * self->a + self->b * self->b) * self->worldSignX; -} - -float spBone_getWorldScaleY (spBone* self) { - return SQRT(self->c * self->c + self->d * self->d) * self->worldSignY; -} - -float spBone_worldToLocalRotationX (spBone* self) { - spBone* parent = self->parent; - if (!parent) return self->rotation; - return ATAN2(parent->a * self->c - parent->c * self->a, parent->d * self->a - parent->b * self->c) * RAD_DEG; -} - -float spBone_worldToLocalRotationY (spBone* self) { - spBone* parent = self->parent; - if (!parent) return self->rotation; - return ATAN2(parent->a * self->d - parent->c * self->b, parent->d * self->b - parent->b * self->d) * RAD_DEG; -} - -void spBone_rotateWorld (spBone* self, float degrees) { - float a = self->a, b = self->b, c = self->c, d = self->d; - float cosine = COS_DEG(degrees), sine = SIN_DEG(degrees); - CONST_CAST(float, self->a) = cosine * a - sine * c; - CONST_CAST(float, self->b) = cosine * b - sine * d; - CONST_CAST(float, self->c) = sine * a + cosine * c; - CONST_CAST(float, self->d) = sine * b + cosine * d; -} - -/** Computes the local transform from the world transform. This can be useful to perform processing on the local transform - * after the world transform has been modified directly (eg, by a constraint). - *

- * Some redundant information is lost by the world transform, such as -1,-1 scale versus 180 rotation. The computed local - * transform values may differ from the original values but are functionally the same. */ -void spBone_updateLocalTransform (spBone* self) { - spBone* parent = self->parent; - if (!parent) { - float det = self->a * self->d - self->b * self->c; - self->x = self->worldX; - self->y = self->worldY; - self->rotation = ATAN2(self->c, self->a) * RAD_DEG; - self->scaleX = SQRT(self->a * self->a + self->c * self->c); - self->scaleY = SQRT(self->b * self->b + self->d * self->d); - self->shearX = 0; - self->shearY = ATAN2(self->a * self->b + self->c * self->d, det) * RAD_DEG; - } else { - float pa = parent->a, pb = parent->b, pc = parent->c, pd = parent->d; - float pid = 1 / (pa * pd - pb * pc); - float dx = self->worldX - parent->worldX, dy = self->worldY - parent->worldY; - float ia = pid * pd; - float id = pid * pa; - float ib = pid * pb; - float ic = pid * pc; - float ra = ia * self->a - ib * self->c; - float rb = ia * self->b - ib * self->d; - float rc = id * self->c - ic * self->a; - float rd = id * self->d - ic * self->b; - self->x = (dx * pd * pid - dy * pb * pid); - self->y = (dy * pa * pid - dx * pc * pid); - self->shearX = 0; - self->scaleX = SQRT(ra * ra + rc * rc); - if (self->scaleX > 0.0001f) { - float det = ra * rd - rb * rc; - self->scaleY = det / self->scaleX; - self->shearY = ATAN2(ra * rb + rc * rd, det) * RAD_DEG; - self->rotation = ATAN2(rc, ra) * RAD_DEG; - } else { - self->scaleX = 0; - self->scaleY = SQRT(rb * rb + rd * rd); - self->shearY = 0; - self->rotation = 90 - ATAN2(rd, rb) * RAD_DEG; - } - self->appliedRotation = self->rotation; - } -} - -void spBone_worldToLocal (spBone* self, float worldX, float worldY, float* localX, float* localY) { - float a = self->a, b = self->b, c = self->c, d = self->d; - float invDet = 1 / (a * d - b * c); - float x = worldX - self->worldX, y = worldY - self->worldY; - *localX = (x * d * invDet - y * b * invDet); - *localY = (y * a * invDet - x * c * invDet); -} - -void spBone_localToWorld (spBone* self, float localX, float localY, float* worldX, float* worldY) { - float x = localX, y = localY; - *worldX = x * self->a + y * self->b + self->worldX; - *worldY = x * self->c + y * self->d + self->worldY; +#include +#include +#include +static int yDown; + +void spBone_setYDown (int value) { + yDown = value; +} + +int spBone_isYDown () { + return yDown; +} + +spBone* spBone_create (spBoneData* data, spSkeleton* skeleton, spBone* parent) { + spBone* self = NEW(spBone); + CONST_CAST(spBoneData*, self->data) = data; + CONST_CAST(spSkeleton*, self->skeleton) = skeleton; + CONST_CAST(spBone*, self->parent) = parent; + spBone_setToSetupPose(self); + return self; +} + +void spBone_dispose (spBone* self) { + FREE(self->children); + FREE(self); +} + +void spBone_updateWorldTransform (spBone* self) { + spBone_updateWorldTransformWith(self, self->x, self->y, self->rotation, self->scaleX, self->scaleY, self->shearX, self->shearY); +} + +void spBone_updateWorldTransformWith (spBone* self, float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY) { + float cosine, sine; + float rotationY = rotation + 90 + shearY; + float la = COS_DEG(rotation + shearX) * scaleX, lb = COS_DEG(rotationY) * scaleY; + float lc = SIN_DEG(rotation + shearX) * scaleX, ld = SIN_DEG(rotationY) * scaleY; + float pa, pb, pc, pd, temp; + spBone* parent = self->parent; + + CONST_CAST(float, self->appliedRotation) = rotation; + + if (!parent) { /* Root bone. */ + if (self->skeleton->flipX) { + x = -x; + la = -la; + lb = -lb; + } + if (self->skeleton->flipY != yDown) { + y = -y; + lc = -lc; + ld = -ld; + } + CONST_CAST(float, self->a) = la; + CONST_CAST(float, self->b) = lb; + CONST_CAST(float, self->c) = lc; + CONST_CAST(float, self->d) = ld; + CONST_CAST(float, self->worldX) = x; + CONST_CAST(float, self->worldY) = y; + CONST_CAST(float, self->worldSignX) = scaleX > 0 ? 1.0f : -1.0f; + CONST_CAST(float, self->worldSignY) = scaleY > 0 ? 1.0f : -1.0f; + return; + } + + pa = parent->a; + pb = parent->b; + pc = parent->c; + pd = parent->d; + + CONST_CAST(float, self->worldX) = pa * x + pb * y + parent->worldX; + CONST_CAST(float, self->worldY) = pc * x + pd * y + parent->worldY; + CONST_CAST(float, self->worldSignX) = parent->worldSignX * (scaleX > 0 ? 1 : -1); + CONST_CAST(float, self->worldSignY) = parent->worldSignY * (scaleY > 0 ? 1 : -1); + + if (self->data->inheritRotation && self->data->inheritScale) { + CONST_CAST(float, self->a) = pa * la + pb * lc; + CONST_CAST(float, self->b) = pa * lb + pb * ld; + CONST_CAST(float, self->c) = pc * la + pd * lc; + CONST_CAST(float, self->d) = pc * lb + pd * ld; + } else { + if (self->data->inheritRotation) { /* No scale inheritance. */ + pa = 1; + pb = 0; + pc = 0; + pd = 1; + do { + cosine = COS_DEG(parent->appliedRotation); sine = SIN_DEG(parent->appliedRotation); + temp = pa * cosine + pb * sine; + pb = pb * cosine - pa * sine; + pa = temp; + temp = pc * cosine + pd * sine; + pd = pd * cosine - pc * sine; + pc = temp; + + if (!parent->data->inheritRotation) break; + parent = parent->parent; + } while (parent); + CONST_CAST(float, self->a) = pa * la + pb * lc; + CONST_CAST(float, self->b) = pa * lb + pb * ld; + CONST_CAST(float, self->c) = pc * la + pd * lc; + CONST_CAST(float, self->d) = pc * lb + pd * ld; + } else if (self->data->inheritScale) { /* No rotation inheritance. */ + pa = 1; + pb = 0; + pc = 0; + pd = 1; + do { + float za, zb, zc, zd; + float psx = parent->scaleX, psy = parent->scaleY; + cosine = COS_DEG(parent->appliedRotation); + sine = SIN_DEG(parent->appliedRotation); + za = cosine * psx; zb = sine * psy; zc = sine * psx; zd = cosine * psy; + temp = pa * za + pb * zc; + pb = pb * zd - pa * zb; + pa = temp; + temp = pc * za + pd * zc; + pd = pd * zd - pc * zb; + pc = temp; + + if (psx >= 0) sine = -sine; + temp = pa * cosine + pb * sine; + pb = pb * cosine - pa * sine; + pa = temp; + temp = pc * cosine + pd * sine; + pd = pd * cosine - pc * sine; + pc = temp; + + if (!parent->data->inheritScale) break; + parent = parent->parent; + } while (parent); + CONST_CAST(float, self->a) = pa * la + pb * lc; + CONST_CAST(float, self->b) = pa * lb + pb * ld; + CONST_CAST(float, self->c) = pc * la + pd * lc; + CONST_CAST(float, self->d) = pc * lb + pd * ld; + } else { + CONST_CAST(float, self->a) = la; + CONST_CAST(float, self->b) = lb; + CONST_CAST(float, self->c) = lc; + CONST_CAST(float, self->d) = ld; + } + if (self->skeleton->flipX) { + CONST_CAST(float, self->a) = -self->a; + CONST_CAST(float, self->b) = -self->b; + } + if (self->skeleton->flipY != yDown) { + CONST_CAST(float, self->c) = -self->c; + CONST_CAST(float, self->d) = -self->d; + } + } +} + +void spBone_setToSetupPose (spBone* self) { + self->x = self->data->x; + self->y = self->data->y; + self->rotation = self->data->rotation; + self->scaleX = self->data->scaleX; + self->scaleY = self->data->scaleY; + self->shearX = self->data->shearX; + self->shearY = self->data->shearY; +} + +float spBone_getWorldRotationX (spBone* self) { + return ATAN2(self->c, self->a) * RAD_DEG; +} + +float spBone_getWorldRotationY (spBone* self) { + return ATAN2(self->d, self->b) * RAD_DEG; +} + +float spBone_getWorldScaleX (spBone* self) { + return SQRT(self->a * self->a + self->b * self->b) * self->worldSignX; +} + +float spBone_getWorldScaleY (spBone* self) { + return SQRT(self->c * self->c + self->d * self->d) * self->worldSignY; +} + +float spBone_worldToLocalRotationX (spBone* self) { + spBone* parent = self->parent; + if (!parent) return self->rotation; + return ATAN2(parent->a * self->c - parent->c * self->a, parent->d * self->a - parent->b * self->c) * RAD_DEG; +} + +float spBone_worldToLocalRotationY (spBone* self) { + spBone* parent = self->parent; + if (!parent) return self->rotation; + return ATAN2(parent->a * self->d - parent->c * self->b, parent->d * self->b - parent->b * self->d) * RAD_DEG; +} + +void spBone_rotateWorld (spBone* self, float degrees) { + float a = self->a, b = self->b, c = self->c, d = self->d; + float cosine = COS_DEG(degrees), sine = SIN_DEG(degrees); + CONST_CAST(float, self->a) = cosine * a - sine * c; + CONST_CAST(float, self->b) = cosine * b - sine * d; + CONST_CAST(float, self->c) = sine * a + cosine * c; + CONST_CAST(float, self->d) = sine * b + cosine * d; +} + +/** Computes the local transform from the world transform. This can be useful to perform processing on the local transform + * after the world transform has been modified directly (eg, by a constraint). + *

+ * Some redundant information is lost by the world transform, such as -1,-1 scale versus 180 rotation. The computed local + * transform values may differ from the original values but are functionally the same. */ +void spBone_updateLocalTransform (spBone* self) { + spBone* parent = self->parent; + if (!parent) { + float det = self->a * self->d - self->b * self->c; + self->x = self->worldX; + self->y = self->worldY; + self->rotation = ATAN2(self->c, self->a) * RAD_DEG; + self->scaleX = SQRT(self->a * self->a + self->c * self->c); + self->scaleY = SQRT(self->b * self->b + self->d * self->d); + self->shearX = 0; + self->shearY = ATAN2(self->a * self->b + self->c * self->d, det) * RAD_DEG; + } else { + float pa = parent->a, pb = parent->b, pc = parent->c, pd = parent->d; + float pid = 1 / (pa * pd - pb * pc); + float dx = self->worldX - parent->worldX, dy = self->worldY - parent->worldY; + float ia = pid * pd; + float id = pid * pa; + float ib = pid * pb; + float ic = pid * pc; + float ra = ia * self->a - ib * self->c; + float rb = ia * self->b - ib * self->d; + float rc = id * self->c - ic * self->a; + float rd = id * self->d - ic * self->b; + self->x = (dx * pd * pid - dy * pb * pid); + self->y = (dy * pa * pid - dx * pc * pid); + self->shearX = 0; + self->scaleX = SQRT(ra * ra + rc * rc); + if (self->scaleX > 0.0001f) { + float det = ra * rd - rb * rc; + self->scaleY = det / self->scaleX; + self->shearY = ATAN2(ra * rb + rc * rd, det) * RAD_DEG; + self->rotation = ATAN2(rc, ra) * RAD_DEG; + } else { + self->scaleX = 0; + self->scaleY = SQRT(rb * rb + rd * rd); + self->shearY = 0; + self->rotation = 90 - ATAN2(rd, rb) * RAD_DEG; + } + self->appliedRotation = self->rotation; + } +} + +void spBone_worldToLocal (spBone* self, float worldX, float worldY, float* localX, float* localY) { + float a = self->a, b = self->b, c = self->c, d = self->d; + float invDet = 1 / (a * d - b * c); + float x = worldX - self->worldX, y = worldY - self->worldY; + *localX = (x * d * invDet - y * b * invDet); + *localY = (y * a * invDet - x * c * invDet); +} + +void spBone_localToWorld (spBone* self, float localX, float localY, float* worldX, float* worldY) { + float x = localX, y = localY; + *worldX = x * self->a + y * self->b + self->worldX; + *worldY = x * self->c + y * self->d + self->worldY; } diff --git a/spine-c/src/spine/BoneData.c b/spine-c/src/spine/BoneData.c index 10df35eca2..9b3f101838 100644 --- a/spine-c/src/spine/BoneData.c +++ b/spine-c/src/spine/BoneData.c @@ -1,50 +1,49 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -spBoneData* spBoneData_create (int index, const char* name, spBoneData* parent) { - spBoneData* self = NEW(spBoneData); - CONST_CAST(int, self->index) = index; - MALLOC_STR(self->name, name); - CONST_CAST(spBoneData*, self->parent) = parent; - self->scaleX = 1; - self->scaleY = 1; - self->inheritRotation = 1; - self->inheritScale = 1; - return self; -} - -void spBoneData_dispose (spBoneData* self) { - FREE(self->name); - FREE(self); +#include +#include + +spBoneData* spBoneData_create (int index, const char* name, spBoneData* parent) { + spBoneData* self = NEW(spBoneData); + CONST_CAST(int, self->index) = index; + MALLOC_STR(self->name, name); + CONST_CAST(spBoneData*, self->parent) = parent; + self->scaleX = 1; + self->scaleY = 1; + self->inheritRotation = 1; + self->inheritScale = 1; + return self; +} + +void spBoneData_dispose (spBoneData* self) { + FREE(self->name); + FREE(self); } diff --git a/spine-c/src/spine/BoundingBoxAttachment.c b/spine-c/src/spine/BoundingBoxAttachment.c index 24166b3491..953661a8a5 100644 --- a/spine-c/src/spine/BoundingBoxAttachment.c +++ b/spine-c/src/spine/BoundingBoxAttachment.c @@ -1,51 +1,50 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -void _spBoundingBoxAttachment_dispose (spAttachment* attachment) { - spBoundingBoxAttachment* self = SUB_CAST(spBoundingBoxAttachment, attachment); - - _spVertexAttachment_deinit(SUPER(self)); - - FREE(self); -} - -spBoundingBoxAttachment* spBoundingBoxAttachment_create (const char* name) { - spBoundingBoxAttachment* self = NEW(spBoundingBoxAttachment); - _spAttachment_init(SUPER(SUPER(self)), name, SP_ATTACHMENT_BOUNDING_BOX, _spBoundingBoxAttachment_dispose); - return self; -} - -void spBoundingBoxAttachment_computeWorldVertices (spBoundingBoxAttachment* self, spSlot* slot, float* worldVertices) { - spVertexAttachment_computeWorldVertices(SUPER(self), slot, worldVertices); +#include +#include + +void _spBoundingBoxAttachment_dispose (spAttachment* attachment) { + spBoundingBoxAttachment* self = SUB_CAST(spBoundingBoxAttachment, attachment); + + _spVertexAttachment_deinit(SUPER(self)); + + FREE(self); +} + +spBoundingBoxAttachment* spBoundingBoxAttachment_create (const char* name) { + spBoundingBoxAttachment* self = NEW(spBoundingBoxAttachment); + _spAttachment_init(SUPER(SUPER(self)), name, SP_ATTACHMENT_BOUNDING_BOX, _spBoundingBoxAttachment_dispose); + return self; +} + +void spBoundingBoxAttachment_computeWorldVertices (spBoundingBoxAttachment* self, spSlot* slot, float* worldVertices) { + spVertexAttachment_computeWorldVertices(SUPER(self), slot, worldVertices); } diff --git a/spine-c/src/spine/Event.c b/spine-c/src/spine/Event.c index 061fbfd7a9..edcd335575 100644 --- a/spine-c/src/spine/Event.c +++ b/spine-c/src/spine/Event.c @@ -1,45 +1,44 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -spEvent* spEvent_create (float time, spEventData* data) { - spEvent* self = NEW(spEvent); - CONST_CAST(spEventData*, self->data) = data; - CONST_CAST(float, self->time) = time; - return self; -} - -void spEvent_dispose (spEvent* self) { - FREE(self->stringValue); - FREE(self); +#include +#include + +spEvent* spEvent_create (float time, spEventData* data) { + spEvent* self = NEW(spEvent); + CONST_CAST(spEventData*, self->data) = data; + CONST_CAST(float, self->time) = time; + return self; +} + +void spEvent_dispose (spEvent* self) { + FREE(self->stringValue); + FREE(self); } diff --git a/spine-c/src/spine/EventData.c b/spine-c/src/spine/EventData.c index 6600eb8923..e594e9cf7f 100644 --- a/spine-c/src/spine/EventData.c +++ b/spine-c/src/spine/EventData.c @@ -1,45 +1,44 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -spEventData* spEventData_create (const char* name) { - spEventData* self = NEW(spEventData); - MALLOC_STR(self->name, name); - return self; -} - -void spEventData_dispose (spEventData* self) { - FREE(self->stringValue); - FREE(self->name); - FREE(self); +#include +#include + +spEventData* spEventData_create (const char* name) { + spEventData* self = NEW(spEventData); + MALLOC_STR(self->name, name); + return self; +} + +void spEventData_dispose (spEventData* self) { + FREE(self->stringValue); + FREE(self->name); + FREE(self); } diff --git a/spine-c/src/spine/IkConstraint.c b/spine-c/src/spine/IkConstraint.c index 1430746ff8..1cbff6eed8 100644 --- a/spine-c/src/spine/IkConstraint.c +++ b/spine-c/src/spine/IkConstraint.c @@ -1,211 +1,210 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include -#include - -spIkConstraint *spIkConstraint_create(spIkConstraintData *data, const spSkeleton *skeleton) { - int i; - - spIkConstraint *self = NEW(spIkConstraint); - CONST_CAST(spIkConstraintData*, self->data) = data; - self->bendDirection = data->bendDirection; - self->mix = data->mix; - - self->bonesCount = self->data->bonesCount; - self->bones = MALLOC(spBone*, self->bonesCount); - for (i = 0; i < self->bonesCount; ++i) - self->bones[i] = spSkeleton_findBone(skeleton, self->data->bones[i]->name); - self->target = spSkeleton_findBone(skeleton, self->data->target->name); - - return self; -} - -void spIkConstraint_dispose(spIkConstraint *self) { - FREE(self->bones); - FREE(self); -} - -void spIkConstraint_apply(spIkConstraint *self) { - switch (self->bonesCount) { - case 1: - spIkConstraint_apply1(self->bones[0], self->target->worldX, self->target->worldY, self->mix); - break; - case 2: - spIkConstraint_apply2(self->bones[0], self->bones[1], self->target->worldX, self->target->worldY, self->bendDirection, self->mix); - break; - } -} - -void spIkConstraint_apply1 (spBone* bone, float targetX, float targetY, float alpha) { - spBone* pp = bone->parent; - float id = 1 / (pp->a * pp->d - pp->b * pp->c); - float x = targetX - pp->worldX, y = targetY - pp->worldY; - float tx = (x * pp->d - y * pp->b) * id - bone->x, ty = (y * pp->a - x * pp->c) * id - bone->y; - float rotationIK = ATAN2(ty, tx) * RAD_DEG - bone->shearX - bone->rotation; - if (bone->scaleX < 0) rotationIK += 180; - if (rotationIK > 180) rotationIK -= 360; - else if (rotationIK < -180) rotationIK += 360; - spBone_updateWorldTransformWith(bone, bone->x, bone->y, bone->rotation + rotationIK * alpha, bone->scaleX, - bone->scaleY, bone->shearX, bone->shearY); -} - -void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDir, float alpha) { - float px = parent->x, py = parent->y, psx = parent->scaleX, psy = parent->scaleY; - float cx = child->x, cy, csx = child->scaleX, cwx, cwy; - int o1, o2, s2, u; - spBone* pp = parent->parent; - float tx, ty, dx, dy, l1, l2, a1, a2, r; - float id, x, y; - if (alpha == 0) { - spBone_updateWorldTransform(child); - return; - } - if (psx < 0) { - psx = -psx; - o1 = 180; - s2 = -1; - } else { - o1 = 0; - s2 = 1; - } - if (psy < 0) { - psy = -psy; - s2 = -s2; - } - if (csx < 0) { - csx = -csx; - o2 = 180; - } else - o2 = 0; - r = psx - psy; - u = (r < 0 ? -r : r) <= 0.0001f; - if (!u) { - cy = 0; - cwx = parent->a * cx + parent->worldX; - cwy = parent->c * cx + parent->worldY; - } else { - cy = child->y; - cwx = parent->a * cx + parent->b * cy + parent->worldX; - cwy = parent->c * cx + parent->d * cy + parent->worldY; - } - id = 1 / (pp->a * pp->d - pp->b * pp->c); - x = targetX - pp->worldX; - y = targetY - pp->worldY; - tx = (x * pp->d - y * pp->b) * id - px; - ty = (y * pp->a - x * pp->c) * id - py; - x = cwx - pp->worldX; - y = cwy - pp->worldY; - dx = (x * pp->d - y * pp->b) * id - px; - dy = (y * pp->a - x * pp->c) * id - py; - l1 = SQRT(dx * dx + dy * dy); - l2 = child->data->length * csx; - if (u) { - float cosine, a, b; - l2 *= psx; - cosine = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2); - if (cosine < -1) cosine = -1; - else if (cosine > 1) cosine = 1; - a2 = ACOS(cosine) * bendDir; - a = l1 + l2 * cosine; - b = l2 * SIN(a2); - a1 = ATAN2(ty * a - tx * b, tx * a + ty * b); - } else { - float a = psx * l2, b = psy * l2; - float aa = a * a, bb = b * b, ll = l1 * l1, dd = tx * tx + ty * ty, ta = ATAN2(ty, tx); - float c0 = bb * ll + aa * dd - aa * bb, c1 = -2 * bb * l1, c2 = bb - aa; - float d = c1 * c1 - 4 * c2 * c0; - float minAngle = 0, minDist = FLT_MAX, minX = 0, minY = 0; - float maxAngle = 0, maxDist = 0, maxX = 0, maxY = 0; - float x = l1 + a, dist = x * x, angle, y; - if (d >= 0) { - float q = SQRT(d), r0, r1; - if (c1 < 0) q = -q; - q = -(c1 + q) / 2; - r0 = q / c2; r1 = c0 / q; - r = ABS(r0) < ABS(r1) ? r0 : r1; - if (r * r <= dd) { - y = SQRT(dd - r * r) * bendDir; - a1 = ta - ATAN2(y, r); - a2 = ATAN2(y / psy, (r - l1) / psx); - goto outer; - } - } - if (dist > maxDist) { - maxAngle = 0; - maxDist = dist; - maxX = x; - } - x = l1 - a; - dist = x * x; - if (dist < minDist) { - minAngle = PI; - minDist = dist; - minX = x; - } - angle = ACOS(-a * l1 / (aa - bb)); - x = a * COS(angle) + l1; - y = b * SIN(angle); - dist = x * x + y * y; - if (dist < minDist) { - minAngle = angle; - minDist = dist; - minX = x; - minY = y; - } - if (dist > maxDist) { - maxAngle = angle; - maxDist = dist; - maxX = x; - maxY = y; - } - if (dd <= (minDist + maxDist) / 2) { - a1 = ta - ATAN2(minY * bendDir, minX); - a2 = minAngle * bendDir; - } else { - a1 = ta - ATAN2(maxY * bendDir, maxX); - a2 = maxAngle * bendDir; - } - } - outer: { - float os = ATAN2(cy, cx) * s2; - a1 = (a1 - os) * RAD_DEG + o1 - parent->rotation; - if (a1 > 180) a1 -= 360; - else if (a1 < -180) a1 += 360; - spBone_updateWorldTransformWith(parent, px, py, parent->rotation + a1 * alpha, parent->scaleX, parent->scaleY, 0, 0); - a2 = ((a2 + os) * RAD_DEG - child->shearX) * s2 + o2 - child->rotation; - if (a2 > 180) a2 -= 360; - else if (a2 < -180) a2 += 360; - spBone_updateWorldTransformWith(child, cx, cy, child->rotation + a2 * alpha, child->scaleX, child->scaleY, child->shearX, child->shearY); - } +#include +#include +#include +#include + +spIkConstraint *spIkConstraint_create(spIkConstraintData *data, const spSkeleton *skeleton) { + int i; + + spIkConstraint *self = NEW(spIkConstraint); + CONST_CAST(spIkConstraintData*, self->data) = data; + self->bendDirection = data->bendDirection; + self->mix = data->mix; + + self->bonesCount = self->data->bonesCount; + self->bones = MALLOC(spBone*, self->bonesCount); + for (i = 0; i < self->bonesCount; ++i) + self->bones[i] = spSkeleton_findBone(skeleton, self->data->bones[i]->name); + self->target = spSkeleton_findBone(skeleton, self->data->target->name); + + return self; +} + +void spIkConstraint_dispose(spIkConstraint *self) { + FREE(self->bones); + FREE(self); +} + +void spIkConstraint_apply(spIkConstraint *self) { + switch (self->bonesCount) { + case 1: + spIkConstraint_apply1(self->bones[0], self->target->worldX, self->target->worldY, self->mix); + break; + case 2: + spIkConstraint_apply2(self->bones[0], self->bones[1], self->target->worldX, self->target->worldY, self->bendDirection, self->mix); + break; + } +} + +void spIkConstraint_apply1 (spBone* bone, float targetX, float targetY, float alpha) { + spBone* pp = bone->parent; + float id = 1 / (pp->a * pp->d - pp->b * pp->c); + float x = targetX - pp->worldX, y = targetY - pp->worldY; + float tx = (x * pp->d - y * pp->b) * id - bone->x, ty = (y * pp->a - x * pp->c) * id - bone->y; + float rotationIK = ATAN2(ty, tx) * RAD_DEG - bone->shearX - bone->rotation; + if (bone->scaleX < 0) rotationIK += 180; + if (rotationIK > 180) rotationIK -= 360; + else if (rotationIK < -180) rotationIK += 360; + spBone_updateWorldTransformWith(bone, bone->x, bone->y, bone->rotation + rotationIK * alpha, bone->scaleX, + bone->scaleY, bone->shearX, bone->shearY); +} + +void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDir, float alpha) { + float px = parent->x, py = parent->y, psx = parent->scaleX, psy = parent->scaleY; + float cx = child->x, cy, csx = child->scaleX, cwx, cwy; + int o1, o2, s2, u; + spBone* pp = parent->parent; + float tx, ty, dx, dy, l1, l2, a1, a2, r; + float id, x, y; + if (alpha == 0) { + spBone_updateWorldTransform(child); + return; + } + if (psx < 0) { + psx = -psx; + o1 = 180; + s2 = -1; + } else { + o1 = 0; + s2 = 1; + } + if (psy < 0) { + psy = -psy; + s2 = -s2; + } + if (csx < 0) { + csx = -csx; + o2 = 180; + } else + o2 = 0; + r = psx - psy; + u = (r < 0 ? -r : r) <= 0.0001f; + if (!u) { + cy = 0; + cwx = parent->a * cx + parent->worldX; + cwy = parent->c * cx + parent->worldY; + } else { + cy = child->y; + cwx = parent->a * cx + parent->b * cy + parent->worldX; + cwy = parent->c * cx + parent->d * cy + parent->worldY; + } + id = 1 / (pp->a * pp->d - pp->b * pp->c); + x = targetX - pp->worldX; + y = targetY - pp->worldY; + tx = (x * pp->d - y * pp->b) * id - px; + ty = (y * pp->a - x * pp->c) * id - py; + x = cwx - pp->worldX; + y = cwy - pp->worldY; + dx = (x * pp->d - y * pp->b) * id - px; + dy = (y * pp->a - x * pp->c) * id - py; + l1 = SQRT(dx * dx + dy * dy); + l2 = child->data->length * csx; + if (u) { + float cosine, a, b; + l2 *= psx; + cosine = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2); + if (cosine < -1) cosine = -1; + else if (cosine > 1) cosine = 1; + a2 = ACOS(cosine) * bendDir; + a = l1 + l2 * cosine; + b = l2 * SIN(a2); + a1 = ATAN2(ty * a - tx * b, tx * a + ty * b); + } else { + float a = psx * l2, b = psy * l2; + float aa = a * a, bb = b * b, ll = l1 * l1, dd = tx * tx + ty * ty, ta = ATAN2(ty, tx); + float c0 = bb * ll + aa * dd - aa * bb, c1 = -2 * bb * l1, c2 = bb - aa; + float d = c1 * c1 - 4 * c2 * c0; + float minAngle = 0, minDist = FLT_MAX, minX = 0, minY = 0; + float maxAngle = 0, maxDist = 0, maxX = 0, maxY = 0; + float x = l1 + a, dist = x * x, angle, y; + if (d >= 0) { + float q = SQRT(d), r0, r1; + if (c1 < 0) q = -q; + q = -(c1 + q) / 2; + r0 = q / c2; r1 = c0 / q; + r = ABS(r0) < ABS(r1) ? r0 : r1; + if (r * r <= dd) { + y = SQRT(dd - r * r) * bendDir; + a1 = ta - ATAN2(y, r); + a2 = ATAN2(y / psy, (r - l1) / psx); + goto outer; + } + } + if (dist > maxDist) { + maxAngle = 0; + maxDist = dist; + maxX = x; + } + x = l1 - a; + dist = x * x; + if (dist < minDist) { + minAngle = PI; + minDist = dist; + minX = x; + } + angle = ACOS(-a * l1 / (aa - bb)); + x = a * COS(angle) + l1; + y = b * SIN(angle); + dist = x * x + y * y; + if (dist < minDist) { + minAngle = angle; + minDist = dist; + minX = x; + minY = y; + } + if (dist > maxDist) { + maxAngle = angle; + maxDist = dist; + maxX = x; + maxY = y; + } + if (dd <= (minDist + maxDist) / 2) { + a1 = ta - ATAN2(minY * bendDir, minX); + a2 = minAngle * bendDir; + } else { + a1 = ta - ATAN2(maxY * bendDir, maxX); + a2 = maxAngle * bendDir; + } + } + outer: { + float os = ATAN2(cy, cx) * s2; + a1 = (a1 - os) * RAD_DEG + o1 - parent->rotation; + if (a1 > 180) a1 -= 360; + else if (a1 < -180) a1 += 360; + spBone_updateWorldTransformWith(parent, px, py, parent->rotation + a1 * alpha, parent->scaleX, parent->scaleY, 0, 0); + a2 = ((a2 + os) * RAD_DEG - child->shearX) * s2 + o2 - child->rotation; + if (a2 > 180) a2 -= 360; + else if (a2 < -180) a2 += 360; + spBone_updateWorldTransformWith(child, cx, cy, child->rotation + a2 * alpha, child->scaleX, child->scaleY, child->shearX, child->shearY); + } } diff --git a/spine-c/src/spine/IkConstraintData.c b/spine-c/src/spine/IkConstraintData.c index 11e82ba3cf..b3204c6d4c 100644 --- a/spine-c/src/spine/IkConstraintData.c +++ b/spine-c/src/spine/IkConstraintData.c @@ -1,47 +1,46 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -spIkConstraintData* spIkConstraintData_create (const char* name) { - spIkConstraintData* self = NEW(spIkConstraintData); - MALLOC_STR(self->name, name); - self->bendDirection = 1; - self->mix = 1; - return self; -} - -void spIkConstraintData_dispose (spIkConstraintData* self) { - FREE(self->name); - FREE(self->bones); - FREE(self); +#include +#include + +spIkConstraintData* spIkConstraintData_create (const char* name) { + spIkConstraintData* self = NEW(spIkConstraintData); + MALLOC_STR(self->name, name); + self->bendDirection = 1; + self->mix = 1; + return self; +} + +void spIkConstraintData_dispose (spIkConstraintData* self) { + FREE(self->name); + FREE(self->bones); + FREE(self); } diff --git a/spine-c/src/spine/MeshAttachment.c b/spine-c/src/spine/MeshAttachment.c index 2be48581be..8d3331abfd 100644 --- a/spine-c/src/spine/MeshAttachment.c +++ b/spine-c/src/spine/MeshAttachment.c @@ -1,106 +1,105 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -void _spMeshAttachment_dispose (spAttachment* attachment) { - spMeshAttachment* self = SUB_CAST(spMeshAttachment, attachment); - FREE(self->path); - FREE(self->uvs); - if (!self->parentMesh) { - _spVertexAttachment_deinit(SUPER(self)); - FREE(self->regionUVs); - FREE(self->triangles); - FREE(self->edges); - } else - _spAttachment_deinit(attachment); - FREE(self); -} - -spMeshAttachment* spMeshAttachment_create (const char* name) { - spMeshAttachment* self = NEW(spMeshAttachment); - self->r = 1; - self->g = 1; - self->b = 1; - self->a = 1; - _spAttachment_init(SUPER(SUPER(self)), name, SP_ATTACHMENT_MESH, _spMeshAttachment_dispose); - return self; -} - -void spMeshAttachment_updateUVs (spMeshAttachment* self) { - int i; - float width = self->regionU2 - self->regionU, height = self->regionV2 - self->regionV; - int verticesLength = SUPER(self)->worldVerticesLength; - FREE(self->uvs); - self->uvs = MALLOC(float, verticesLength); - if (self->regionRotate) { - for (i = 0; i < verticesLength; i += 2) { - self->uvs[i] = self->regionU + self->regionUVs[i + 1] * width; - self->uvs[i + 1] = self->regionV + height - self->regionUVs[i] * height; - } - } else { - for (i = 0; i < verticesLength; i += 2) { - self->uvs[i] = self->regionU + self->regionUVs[i] * width; - self->uvs[i + 1] = self->regionV + self->regionUVs[i + 1] * height; - } - } -} - -void spMeshAttachment_computeWorldVertices (spMeshAttachment* self, spSlot* slot, float* worldVertices) { - spVertexAttachment_computeWorldVertices(SUPER(self), slot, worldVertices); -} - -void spMeshAttachment_setParentMesh (spMeshAttachment* self, spMeshAttachment* parentMesh) { - CONST_CAST(spMeshAttachment*, self->parentMesh) = parentMesh; - if (parentMesh) { - self->super.worldVerticesLength = parentMesh->super.worldVerticesLength; - - self->super.bones = parentMesh->super.bones; - self->super.bonesCount = parentMesh->super.bonesCount; - - self->super.vertices = parentMesh->super.vertices; - self->super.verticesCount = parentMesh->super.verticesCount; - - self->regionUVs = parentMesh->regionUVs; - - self->triangles = parentMesh->triangles; - self->trianglesCount = parentMesh->trianglesCount; - - self->hullLength = parentMesh->hullLength; - - self->edges = parentMesh->edges; - self->edgesCount = parentMesh->edgesCount; - - self->width = parentMesh->width; - self->height = parentMesh->height; - } +#include +#include + +void _spMeshAttachment_dispose (spAttachment* attachment) { + spMeshAttachment* self = SUB_CAST(spMeshAttachment, attachment); + FREE(self->path); + FREE(self->uvs); + if (!self->parentMesh) { + _spVertexAttachment_deinit(SUPER(self)); + FREE(self->regionUVs); + FREE(self->triangles); + FREE(self->edges); + } else + _spAttachment_deinit(attachment); + FREE(self); +} + +spMeshAttachment* spMeshAttachment_create (const char* name) { + spMeshAttachment* self = NEW(spMeshAttachment); + self->r = 1; + self->g = 1; + self->b = 1; + self->a = 1; + _spAttachment_init(SUPER(SUPER(self)), name, SP_ATTACHMENT_MESH, _spMeshAttachment_dispose); + return self; +} + +void spMeshAttachment_updateUVs (spMeshAttachment* self) { + int i; + float width = self->regionU2 - self->regionU, height = self->regionV2 - self->regionV; + int verticesLength = SUPER(self)->worldVerticesLength; + FREE(self->uvs); + self->uvs = MALLOC(float, verticesLength); + if (self->regionRotate) { + for (i = 0; i < verticesLength; i += 2) { + self->uvs[i] = self->regionU + self->regionUVs[i + 1] * width; + self->uvs[i + 1] = self->regionV + height - self->regionUVs[i] * height; + } + } else { + for (i = 0; i < verticesLength; i += 2) { + self->uvs[i] = self->regionU + self->regionUVs[i] * width; + self->uvs[i + 1] = self->regionV + self->regionUVs[i + 1] * height; + } + } +} + +void spMeshAttachment_computeWorldVertices (spMeshAttachment* self, spSlot* slot, float* worldVertices) { + spVertexAttachment_computeWorldVertices(SUPER(self), slot, worldVertices); +} + +void spMeshAttachment_setParentMesh (spMeshAttachment* self, spMeshAttachment* parentMesh) { + CONST_CAST(spMeshAttachment*, self->parentMesh) = parentMesh; + if (parentMesh) { + self->super.worldVerticesLength = parentMesh->super.worldVerticesLength; + + self->super.bones = parentMesh->super.bones; + self->super.bonesCount = parentMesh->super.bonesCount; + + self->super.vertices = parentMesh->super.vertices; + self->super.verticesCount = parentMesh->super.verticesCount; + + self->regionUVs = parentMesh->regionUVs; + + self->triangles = parentMesh->triangles; + self->trianglesCount = parentMesh->trianglesCount; + + self->hullLength = parentMesh->hullLength; + + self->edges = parentMesh->edges; + self->edgesCount = parentMesh->edgesCount; + + self->width = parentMesh->width; + self->height = parentMesh->height; + } } diff --git a/spine-c/src/spine/PathAttachment.c b/spine-c/src/spine/PathAttachment.c index d51221789d..d3d957bb78 100644 --- a/spine-c/src/spine/PathAttachment.c +++ b/spine-c/src/spine/PathAttachment.c @@ -1,56 +1,55 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -void _spPathAttachment_dispose (spAttachment* attachment) { - spPathAttachment* self = SUB_CAST(spPathAttachment, attachment); - - _spVertexAttachment_deinit(SUPER(self)); - - FREE(self->lengths); - FREE(self); -} - -spPathAttachment* spPathAttachment_create (const char* name) { - spPathAttachment* self = NEW(spPathAttachment); - _spAttachment_init(SUPER(SUPER(self)), name, SP_ATTACHMENT_PATH, _spPathAttachment_dispose); - return self; -} - -void spPathAttachment_computeWorldVertices (spPathAttachment* self, spSlot* slot, float* worldVertices) { - spVertexAttachment_computeWorldVertices(SUPER(self), slot, worldVertices); -} - -void spPathAttachment_computeWorldVertices1 (spPathAttachment* self, spSlot* slot, int start, int count, float* worldVertices, int offset) { - spVertexAttachment_computeWorldVertices1(SUPER(self), start, count, slot, worldVertices, offset); +#include +#include + +void _spPathAttachment_dispose (spAttachment* attachment) { + spPathAttachment* self = SUB_CAST(spPathAttachment, attachment); + + _spVertexAttachment_deinit(SUPER(self)); + + FREE(self->lengths); + FREE(self); +} + +spPathAttachment* spPathAttachment_create (const char* name) { + spPathAttachment* self = NEW(spPathAttachment); + _spAttachment_init(SUPER(SUPER(self)), name, SP_ATTACHMENT_PATH, _spPathAttachment_dispose); + return self; +} + +void spPathAttachment_computeWorldVertices (spPathAttachment* self, spSlot* slot, float* worldVertices) { + spVertexAttachment_computeWorldVertices(SUPER(self), slot, worldVertices); +} + +void spPathAttachment_computeWorldVertices1 (spPathAttachment* self, spSlot* slot, int start, int count, float* worldVertices, int offset) { + spVertexAttachment_computeWorldVertices1(SUPER(self), start, count, slot, worldVertices, offset); } diff --git a/spine-c/src/spine/PathConstraint.c b/spine-c/src/spine/PathConstraint.c index f50874bb06..e2bb64634e 100644 --- a/spine-c/src/spine/PathConstraint.c +++ b/spine-c/src/spine/PathConstraint.c @@ -1,453 +1,452 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include - -#define PATHCONSTRAINT_NONE -1 -#define PATHCONSTRAINT_BEFORE -2 -#define PATHCONSTRAINT_AFTER -3 - -spPathConstraint* spPathConstraint_create (spPathConstraintData* data, const spSkeleton* skeleton) { - int i; - spPathConstraint *self = NEW(spPathConstraint); - CONST_CAST(spPathConstraintData*, self->data) = data; - self->bonesCount = data->bonesCount; - CONST_CAST(spBone**, self->bones) = MALLOC(spBone*, self->bonesCount); - for (i = 0; i < self->bonesCount; ++i) - self->bones[i] = spSkeleton_findBone(skeleton, self->data->bones[i]->name); - self->target = spSkeleton_findSlot(skeleton, self->data->target->name); - self->position = data->position; - self->spacing = data->spacing; - self->rotateMix = data->rotateMix; - self->translateMix = data->translateMix; - self->spacesCount = 0; - self->spaces = 0; - self->positionsCount = 0; - self->positions = 0; - self->worldCount = 0; - self->world = 0; - self->curvesCount = 0; - self->curves = 0; - self->lengthsCount = 0; - self->lengths = 0; - return self; -} - -void spPathConstraint_dispose (spPathConstraint* self) { - FREE(self->bones); - FREE(self->spaces); - if (self->positions) FREE(self->positions); - if (self->world) FREE(self->world); - if (self->curves) FREE(self->curves); - if (self->lengths) FREE(self->lengths); - FREE(self); -} - -void spPathConstraint_apply (spPathConstraint* self) { - int i, p, n; - float length, x, y, dx, dy, s; - float* spaces, *lengths, *positions; - float spacing; - spSkeleton* skeleton; - float skeletonX, skeletonY, boneX, boneY, offsetRotation; - int/*bool*/tip; - float rotateMix = self->rotateMix, translateMix = self->translateMix; - int/*bool*/ translate = translateMix > 0, rotate = rotateMix > 0; - spPathAttachment* attachment = (spPathAttachment*)self->target->attachment; - spPathConstraintData* data = self->data; - spSpacingMode spacingMode = data->spacingMode; - int lengthSpacing = spacingMode == SP_SPACING_MODE_LENGTH; - spRotateMode rotateMode = data->rotateMode; - int tangents = rotateMode == SP_ROTATE_MODE_TANGENT, scale = rotateMode == SP_ROTATE_MODE_CHAIN_SCALE; - int boneCount = self->bonesCount, spacesCount = tangents ? boneCount : boneCount + 1; - spBone** bones = self->bones; - - if (!translate && !rotate) return; - if ((attachment == 0) || (attachment->super.super.type != SP_ATTACHMENT_PATH)) return; - - if (self->spacesCount != spacesCount) { - if (self->spaces) FREE(self->spaces); - self->spaces = MALLOC(float, spacesCount); - self->spacesCount = spacesCount; - } - spaces = self->spaces; - spaces[0] = 0; - lengths = 0; - spacing = self->spacing; - if (scale || lengthSpacing) { - if (scale) { - if (self->lengthsCount != boneCount) { - if (self->lengths) FREE(self->lengths); - self->lengths = MALLOC(float, boneCount); - self->lengthsCount = boneCount; - } - lengths = self->lengths; - } - for (i = 0, n = spacesCount - 1; i < n;) { - spBone* bone = bones[i]; - length = bone->data->length, x = length * bone->a, y = length * bone->c; - length = SQRT(x * x + y * y); - if (scale) lengths[i] = length; - spaces[++i] = lengthSpacing ? MAX(0, length + spacing) : spacing; - } - } else { - for (i = 1; i < spacesCount; i++) { - spaces[i] = spacing; - } - } - - positions = spPathConstraint_computeWorldPositions(self, attachment, spacesCount, tangents, - data->positionMode == SP_POSITION_MODE_PERCENT, spacingMode == SP_SPACING_MODE_PERCENT); - skeleton = self->target->bone->skeleton; - skeletonX = skeleton->x, skeletonY = skeleton->y; - boneX = positions[0], boneY = positions[1], offsetRotation = self->data->offsetRotation; - tip = rotateMode == SP_ROTATE_MODE_CHAIN_SCALE && offsetRotation == 0; - for (i = 0, p = 3; i < boneCount; i++, p += 3) { - spBone* bone = bones[i]; - CONST_CAST(float, bone->worldX) += (boneX - skeletonX - bone->worldX) * translateMix; - CONST_CAST(float, bone->worldY) += (boneY - skeletonY - bone->worldY) * translateMix; - x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY; - if (scale) { - length = lengths[i]; - if (length != 0) { - s = (SQRT(dx * dx + dy * dy) / length - 1) * rotateMix + 1; - CONST_CAST(float, bone->a) *= s; - CONST_CAST(float, bone->c) *= s; - } - } - boneX = x; - boneY = y; - if (rotate) { - float a = bone->a, b = bone->b, c = bone->c, d = bone->d, r, cosine, sine; - if (tangents) - r = positions[p - 1]; - else if (spaces[i + 1] == 0) - r = positions[p + 2]; - else - r = ATAN2(dy, dx); - r -= ATAN2(c, a) - offsetRotation * DEG_RAD; - if (tip) { - cosine = COS(r); - sine = SIN(r); - length = bone->data->length; - boneX += (length * (cosine * a - sine * c) - dx) * rotateMix; - boneY += (length * (sine * a + cosine * c) - dy) * rotateMix; - } - if (r > PI) - r -= PI2; - else if (r < -PI) - r += PI2; - r *= rotateMix; - cosine = COS(r); - sine = SIN(r); - CONST_CAST(float, bone->a) = cosine * a - sine * c; - CONST_CAST(float, bone->b) = cosine * b - sine * d; - CONST_CAST(float, bone->c) = sine * a + cosine * c; - CONST_CAST(float, bone->d) = sine * b + cosine * d; - } - } -} - -static void _addBeforePosition(float p, float* temp, int i, float* out, int o) { - float x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = ATAN2(dy, dx); - out[o] = x1 + p * COS(r); - out[o + 1] = y1 + p * SIN(r); - out[o + 2] = r; -} - -static void _addAfterPosition (float p, float* temp, int i, float* out, int o) { - float x1 = temp[i + 2], y1 = temp[i + 3], dx = x1 - temp[i], dy = y1 - temp[i + 1], r = ATAN2(dy, dx); - out[o] = x1 + p * COS(r); - out[o + 1] = y1 + p * SIN(r); - out[o + 2] = r; -} - -static void _addCurvePosition (float p, float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2, - float* out, int o, int/*bool*/tangents) { - float tt, ttt, u, uu, uuu; - float ut, ut3, uut3, utt3; - float x, y; - if (p == 0) p = 0.0001f; - tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u; - ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p; - x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt; - out[o] = x; - out[o + 1] = y; - if (tangents) out[o + 2] = ATAN2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); -} - -float* spPathConstraint_computeWorldPositions(spPathConstraint* self, spPathAttachment* path, int spacesCount, int/*bool*/ tangents, int/*bool*/percentPosition, int/**/percentSpacing) { - int i, o, w, curve, segment, /*bool*/closed, verticesLength, curveCount, prevCurve; - float* out, *curves, *segments; - float tmpx, tmpy, dddfx, dddfy, ddfx, ddfy, dfx, dfy, pathLength, curveLength, p; - float x1, y1, cx1, cy1, cx2, cy2, x2, y2; - spSlot* target = self->target; - float position = self->position; - float* spaces = self->spaces, *world = 0; - if (self->positionsCount != spacesCount * 3 + 2) { - if (self->positions) FREE(self->positions); - self->positions = MALLOC(float, spacesCount * 3 + 2); - self->positionsCount = spacesCount * 3 + 2; - } - out = self->positions; - closed = path->closed; - verticesLength = path->super.worldVerticesLength, curveCount = verticesLength / 6, prevCurve = PATHCONSTRAINT_NONE; - - if (!path->constantSpeed) { - float* lengths = path->lengths; - curveCount -= closed ? 1 : 2; - pathLength = lengths[curveCount]; - if (percentPosition) position *= pathLength; - if (percentSpacing) { - for (i = 0; i < spacesCount; i++) - spaces[i] *= pathLength; - } - if (self->worldCount != 8) { - if (self->world) FREE(self->world); - self->world = MALLOC(float, 8); - self->worldCount = 8; - } - world = self->world; - for (i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) { - float space = spaces[i]; - position += space; - p = position; - - if (closed) { - p = FMOD(p, pathLength); - if (p < 0) p += pathLength; - curve = 0; - } else if (p < 0) { - if (prevCurve != PATHCONSTRAINT_BEFORE) { - prevCurve = PATHCONSTRAINT_BEFORE; - spPathAttachment_computeWorldVertices1(path, target, 2, 4, world, 0); - } - _addBeforePosition(p, world, 0, out, o); - continue; - } else if (p > pathLength) { - if (prevCurve != PATHCONSTRAINT_AFTER) { - prevCurve = PATHCONSTRAINT_AFTER; - spPathAttachment_computeWorldVertices1(path, target, verticesLength - 6, 4, world, 0); - } - _addAfterPosition(p - pathLength, world, 0, out, o); - continue; - } - - /* Determine curve containing position. */ - for (;; curve++) { - float length = lengths[curve]; - if (p > length) continue; - if (curve == 0) - p /= length; - else { - float prev = lengths[curve - 1]; - p = (p - prev) / (length - prev); - } - break; - } - if (curve != prevCurve) { - prevCurve = curve; - if (closed && curve == curveCount) { - spPathAttachment_computeWorldVertices1(path, target, verticesLength - 4, 4, world, 0); - spPathAttachment_computeWorldVertices1(path, target, 0, 4, world, 4); - } else - spPathAttachment_computeWorldVertices1(path, target, curve * 6 + 2, 8, world, 0); - } - _addCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], out, o, - tangents || (i > 0 && space == 0)); - } - return out; - } - - /* World vertices. */ - if (closed) { - verticesLength += 2; - if (self->worldCount != verticesLength) { - if (self->world) FREE(self->world); - self->world = MALLOC(float, verticesLength); - self->worldCount = verticesLength; - } - world = self->world; - spPathAttachment_computeWorldVertices1(path, target, 2, verticesLength - 4, world, 0); - spPathAttachment_computeWorldVertices1(path, target, 0, 2, world, verticesLength - 4); - world[verticesLength - 2] = world[0]; - world[verticesLength - 1] = world[1]; - } else { - curveCount--; - verticesLength -= 4; - if (self->worldCount != verticesLength) { - if (self->world) FREE(self->world); - self->world = MALLOC(float, verticesLength); - self->worldCount = verticesLength; - } - world = self->world; - spPathAttachment_computeWorldVertices1(path, target, 2, verticesLength, world, 0); - } - - /* Curve lengths. */ - if (self->curvesCount != curveCount) { - if (self->curves) FREE(self->curves); - self->curves = MALLOC(float, curveCount); - self->curvesCount = curveCount; - } - curves = self->curves; - pathLength = 0; - x1 = world[0], y1 = world[1], cx1 = 0, cy1 = 0, cx2 = 0, cy2 = 0, x2 = 0, y2 = 0; - for (i = 0, w = 2; i < curveCount; i++, w += 6) { - cx1 = world[w]; - cy1 = world[w + 1]; - cx2 = world[w + 2]; - cy2 = world[w + 3]; - x2 = world[w + 4]; - y2 = world[w + 5]; - tmpx = (x1 - cx1 * 2 + cx2) * 0.1875f; - tmpy = (y1 - cy1 * 2 + cy2) * 0.1875f; - dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375f; - dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375f; - ddfx = tmpx * 2 + dddfx; - ddfy = tmpy * 2 + dddfy; - dfx = (cx1 - x1) * 0.75f + tmpx + dddfx * 0.16666667f; - dfy = (cy1 - y1) * 0.75f + tmpy + dddfy * 0.16666667f; - pathLength += SQRT(dfx * dfx + dfy * dfy); - dfx += ddfx; - dfy += ddfy; - ddfx += dddfx; - ddfy += dddfy; - pathLength += SQRT(dfx * dfx + dfy * dfy); - dfx += ddfx; - dfy += ddfy; - pathLength += SQRT(dfx * dfx + dfy * dfy); - dfx += ddfx + dddfx; - dfy += ddfy + dddfy; - pathLength += SQRT(dfx * dfx + dfy * dfy); - curves[i] = pathLength; - x1 = x2; - y1 = y2; - } - if (percentPosition) position *= pathLength; - if (percentSpacing) { - for (i = 0; i < spacesCount; i++) - spaces[i] *= pathLength; - } - - segments = self->segments; - curveLength = 0; - for (i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) { - float space = spaces[i]; - position += space; - p = position; - - if (closed) { - p = FMOD(p, pathLength); - if (p < 0) p += pathLength; - curve = 0; - } else if (p < 0) { - _addBeforePosition(p, world, 0, out, o); - continue; - } else if (p > pathLength) { - _addAfterPosition(p - pathLength, world, verticesLength - 4, out, o); - continue; - } - - /* Determine curve containing position. */ - for (;; curve++) { - float length = curves[curve]; - if (p > length) continue; - if (curve == 0) - p /= length; - else { - float prev = curves[curve - 1]; - p = (p - prev) / (length - prev); - } - break; - } - - /* Curve segment lengths. */ - if (curve != prevCurve) { - int ii; - prevCurve = curve; - ii = curve * 6; - x1 = world[ii]; - y1 = world[ii + 1]; - cx1 = world[ii + 2]; - cy1 = world[ii + 3]; - cx2 = world[ii + 4]; - cy2 = world[ii + 5]; - x2 = world[ii + 6]; - y2 = world[ii + 7]; - tmpx = (x1 - cx1 * 2 + cx2) * 0.03f; - tmpy = (y1 - cy1 * 2 + cy2) * 0.03f; - dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006f; - dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006f; - ddfx = tmpx * 2 + dddfx; - ddfy = tmpy * 2 + dddfy; - dfx = (cx1 - x1) * 0.3f + tmpx + dddfx * 0.16666667f; - dfy = (cy1 - y1) * 0.3f + tmpy + dddfy * 0.16666667f; - curveLength = SQRT(dfx * dfx + dfy * dfy); - segments[0] = curveLength; - for (ii = 1; ii < 8; ii++) { - dfx += ddfx; - dfy += ddfy; - ddfx += dddfx; - ddfy += dddfy; - curveLength += SQRT(dfx * dfx + dfy * dfy); - segments[ii] = curveLength; - } - dfx += ddfx; - dfy += ddfy; - curveLength += SQRT(dfx * dfx + dfy * dfy); - segments[8] = curveLength; - dfx += ddfx + dddfx; - dfy += ddfy + dddfy; - curveLength += SQRT(dfx * dfx + dfy * dfy); - segments[9] = curveLength; - segment = 0; - } - - /* Weight by segment length. */ - p *= curveLength; - for (;; segment++) { - float length = segments[segment]; - if (p > length) continue; - if (segment == 0) - p /= length; - else { - float prev = segments[segment - 1]; - p = segment + (p - prev) / (length - prev); - } - break; - } - _addCurvePosition(p * 0.1f, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || (i > 0 && space == 0)); - } - return out; +#include +#include +#include + +#define PATHCONSTRAINT_NONE -1 +#define PATHCONSTRAINT_BEFORE -2 +#define PATHCONSTRAINT_AFTER -3 + +spPathConstraint* spPathConstraint_create (spPathConstraintData* data, const spSkeleton* skeleton) { + int i; + spPathConstraint *self = NEW(spPathConstraint); + CONST_CAST(spPathConstraintData*, self->data) = data; + self->bonesCount = data->bonesCount; + CONST_CAST(spBone**, self->bones) = MALLOC(spBone*, self->bonesCount); + for (i = 0; i < self->bonesCount; ++i) + self->bones[i] = spSkeleton_findBone(skeleton, self->data->bones[i]->name); + self->target = spSkeleton_findSlot(skeleton, self->data->target->name); + self->position = data->position; + self->spacing = data->spacing; + self->rotateMix = data->rotateMix; + self->translateMix = data->translateMix; + self->spacesCount = 0; + self->spaces = 0; + self->positionsCount = 0; + self->positions = 0; + self->worldCount = 0; + self->world = 0; + self->curvesCount = 0; + self->curves = 0; + self->lengthsCount = 0; + self->lengths = 0; + return self; +} + +void spPathConstraint_dispose (spPathConstraint* self) { + FREE(self->bones); + FREE(self->spaces); + if (self->positions) FREE(self->positions); + if (self->world) FREE(self->world); + if (self->curves) FREE(self->curves); + if (self->lengths) FREE(self->lengths); + FREE(self); +} + +void spPathConstraint_apply (spPathConstraint* self) { + int i, p, n; + float length, x, y, dx, dy, s; + float* spaces, *lengths, *positions; + float spacing; + spSkeleton* skeleton; + float skeletonX, skeletonY, boneX, boneY, offsetRotation; + int/*bool*/tip; + float rotateMix = self->rotateMix, translateMix = self->translateMix; + int/*bool*/ translate = translateMix > 0, rotate = rotateMix > 0; + spPathAttachment* attachment = (spPathAttachment*)self->target->attachment; + spPathConstraintData* data = self->data; + spSpacingMode spacingMode = data->spacingMode; + int lengthSpacing = spacingMode == SP_SPACING_MODE_LENGTH; + spRotateMode rotateMode = data->rotateMode; + int tangents = rotateMode == SP_ROTATE_MODE_TANGENT, scale = rotateMode == SP_ROTATE_MODE_CHAIN_SCALE; + int boneCount = self->bonesCount, spacesCount = tangents ? boneCount : boneCount + 1; + spBone** bones = self->bones; + + if (!translate && !rotate) return; + if ((attachment == 0) || (attachment->super.super.type != SP_ATTACHMENT_PATH)) return; + + if (self->spacesCount != spacesCount) { + if (self->spaces) FREE(self->spaces); + self->spaces = MALLOC(float, spacesCount); + self->spacesCount = spacesCount; + } + spaces = self->spaces; + spaces[0] = 0; + lengths = 0; + spacing = self->spacing; + if (scale || lengthSpacing) { + if (scale) { + if (self->lengthsCount != boneCount) { + if (self->lengths) FREE(self->lengths); + self->lengths = MALLOC(float, boneCount); + self->lengthsCount = boneCount; + } + lengths = self->lengths; + } + for (i = 0, n = spacesCount - 1; i < n;) { + spBone* bone = bones[i]; + length = bone->data->length, x = length * bone->a, y = length * bone->c; + length = SQRT(x * x + y * y); + if (scale) lengths[i] = length; + spaces[++i] = lengthSpacing ? MAX(0, length + spacing) : spacing; + } + } else { + for (i = 1; i < spacesCount; i++) { + spaces[i] = spacing; + } + } + + positions = spPathConstraint_computeWorldPositions(self, attachment, spacesCount, tangents, + data->positionMode == SP_POSITION_MODE_PERCENT, spacingMode == SP_SPACING_MODE_PERCENT); + skeleton = self->target->bone->skeleton; + skeletonX = skeleton->x, skeletonY = skeleton->y; + boneX = positions[0], boneY = positions[1], offsetRotation = self->data->offsetRotation; + tip = rotateMode == SP_ROTATE_MODE_CHAIN_SCALE && offsetRotation == 0; + for (i = 0, p = 3; i < boneCount; i++, p += 3) { + spBone* bone = bones[i]; + CONST_CAST(float, bone->worldX) += (boneX - skeletonX - bone->worldX) * translateMix; + CONST_CAST(float, bone->worldY) += (boneY - skeletonY - bone->worldY) * translateMix; + x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY; + if (scale) { + length = lengths[i]; + if (length != 0) { + s = (SQRT(dx * dx + dy * dy) / length - 1) * rotateMix + 1; + CONST_CAST(float, bone->a) *= s; + CONST_CAST(float, bone->c) *= s; + } + } + boneX = x; + boneY = y; + if (rotate) { + float a = bone->a, b = bone->b, c = bone->c, d = bone->d, r, cosine, sine; + if (tangents) + r = positions[p - 1]; + else if (spaces[i + 1] == 0) + r = positions[p + 2]; + else + r = ATAN2(dy, dx); + r -= ATAN2(c, a) - offsetRotation * DEG_RAD; + if (tip) { + cosine = COS(r); + sine = SIN(r); + length = bone->data->length; + boneX += (length * (cosine * a - sine * c) - dx) * rotateMix; + boneY += (length * (sine * a + cosine * c) - dy) * rotateMix; + } + if (r > PI) + r -= PI2; + else if (r < -PI) + r += PI2; + r *= rotateMix; + cosine = COS(r); + sine = SIN(r); + CONST_CAST(float, bone->a) = cosine * a - sine * c; + CONST_CAST(float, bone->b) = cosine * b - sine * d; + CONST_CAST(float, bone->c) = sine * a + cosine * c; + CONST_CAST(float, bone->d) = sine * b + cosine * d; + } + } +} + +static void _addBeforePosition(float p, float* temp, int i, float* out, int o) { + float x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = ATAN2(dy, dx); + out[o] = x1 + p * COS(r); + out[o + 1] = y1 + p * SIN(r); + out[o + 2] = r; +} + +static void _addAfterPosition (float p, float* temp, int i, float* out, int o) { + float x1 = temp[i + 2], y1 = temp[i + 3], dx = x1 - temp[i], dy = y1 - temp[i + 1], r = ATAN2(dy, dx); + out[o] = x1 + p * COS(r); + out[o + 1] = y1 + p * SIN(r); + out[o + 2] = r; +} + +static void _addCurvePosition (float p, float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2, + float* out, int o, int/*bool*/tangents) { + float tt, ttt, u, uu, uuu; + float ut, ut3, uut3, utt3; + float x, y; + if (p == 0) p = 0.0001f; + tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u; + ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p; + x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt; + out[o] = x; + out[o + 1] = y; + if (tangents) out[o + 2] = ATAN2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); +} + +float* spPathConstraint_computeWorldPositions(spPathConstraint* self, spPathAttachment* path, int spacesCount, int/*bool*/ tangents, int/*bool*/percentPosition, int/**/percentSpacing) { + int i, o, w, curve, segment, /*bool*/closed, verticesLength, curveCount, prevCurve; + float* out, *curves, *segments; + float tmpx, tmpy, dddfx, dddfy, ddfx, ddfy, dfx, dfy, pathLength, curveLength, p; + float x1, y1, cx1, cy1, cx2, cy2, x2, y2; + spSlot* target = self->target; + float position = self->position; + float* spaces = self->spaces, *world = 0; + if (self->positionsCount != spacesCount * 3 + 2) { + if (self->positions) FREE(self->positions); + self->positions = MALLOC(float, spacesCount * 3 + 2); + self->positionsCount = spacesCount * 3 + 2; + } + out = self->positions; + closed = path->closed; + verticesLength = path->super.worldVerticesLength, curveCount = verticesLength / 6, prevCurve = PATHCONSTRAINT_NONE; + + if (!path->constantSpeed) { + float* lengths = path->lengths; + curveCount -= closed ? 1 : 2; + pathLength = lengths[curveCount]; + if (percentPosition) position *= pathLength; + if (percentSpacing) { + for (i = 0; i < spacesCount; i++) + spaces[i] *= pathLength; + } + if (self->worldCount != 8) { + if (self->world) FREE(self->world); + self->world = MALLOC(float, 8); + self->worldCount = 8; + } + world = self->world; + for (i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) { + float space = spaces[i]; + position += space; + p = position; + + if (closed) { + p = FMOD(p, pathLength); + if (p < 0) p += pathLength; + curve = 0; + } else if (p < 0) { + if (prevCurve != PATHCONSTRAINT_BEFORE) { + prevCurve = PATHCONSTRAINT_BEFORE; + spPathAttachment_computeWorldVertices1(path, target, 2, 4, world, 0); + } + _addBeforePosition(p, world, 0, out, o); + continue; + } else if (p > pathLength) { + if (prevCurve != PATHCONSTRAINT_AFTER) { + prevCurve = PATHCONSTRAINT_AFTER; + spPathAttachment_computeWorldVertices1(path, target, verticesLength - 6, 4, world, 0); + } + _addAfterPosition(p - pathLength, world, 0, out, o); + continue; + } + + /* Determine curve containing position. */ + for (;; curve++) { + float length = lengths[curve]; + if (p > length) continue; + if (curve == 0) + p /= length; + else { + float prev = lengths[curve - 1]; + p = (p - prev) / (length - prev); + } + break; + } + if (curve != prevCurve) { + prevCurve = curve; + if (closed && curve == curveCount) { + spPathAttachment_computeWorldVertices1(path, target, verticesLength - 4, 4, world, 0); + spPathAttachment_computeWorldVertices1(path, target, 0, 4, world, 4); + } else + spPathAttachment_computeWorldVertices1(path, target, curve * 6 + 2, 8, world, 0); + } + _addCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], out, o, + tangents || (i > 0 && space == 0)); + } + return out; + } + + /* World vertices. */ + if (closed) { + verticesLength += 2; + if (self->worldCount != verticesLength) { + if (self->world) FREE(self->world); + self->world = MALLOC(float, verticesLength); + self->worldCount = verticesLength; + } + world = self->world; + spPathAttachment_computeWorldVertices1(path, target, 2, verticesLength - 4, world, 0); + spPathAttachment_computeWorldVertices1(path, target, 0, 2, world, verticesLength - 4); + world[verticesLength - 2] = world[0]; + world[verticesLength - 1] = world[1]; + } else { + curveCount--; + verticesLength -= 4; + if (self->worldCount != verticesLength) { + if (self->world) FREE(self->world); + self->world = MALLOC(float, verticesLength); + self->worldCount = verticesLength; + } + world = self->world; + spPathAttachment_computeWorldVertices1(path, target, 2, verticesLength, world, 0); + } + + /* Curve lengths. */ + if (self->curvesCount != curveCount) { + if (self->curves) FREE(self->curves); + self->curves = MALLOC(float, curveCount); + self->curvesCount = curveCount; + } + curves = self->curves; + pathLength = 0; + x1 = world[0], y1 = world[1], cx1 = 0, cy1 = 0, cx2 = 0, cy2 = 0, x2 = 0, y2 = 0; + for (i = 0, w = 2; i < curveCount; i++, w += 6) { + cx1 = world[w]; + cy1 = world[w + 1]; + cx2 = world[w + 2]; + cy2 = world[w + 3]; + x2 = world[w + 4]; + y2 = world[w + 5]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.1875f; + tmpy = (y1 - cy1 * 2 + cy2) * 0.1875f; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375f; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375f; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.75f + tmpx + dddfx * 0.16666667f; + dfy = (cy1 - y1) * 0.75f + tmpy + dddfy * 0.16666667f; + pathLength += SQRT(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + pathLength += SQRT(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + pathLength += SQRT(dfx * dfx + dfy * dfy); + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + pathLength += SQRT(dfx * dfx + dfy * dfy); + curves[i] = pathLength; + x1 = x2; + y1 = y2; + } + if (percentPosition) position *= pathLength; + if (percentSpacing) { + for (i = 0; i < spacesCount; i++) + spaces[i] *= pathLength; + } + + segments = self->segments; + curveLength = 0; + for (i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) { + float space = spaces[i]; + position += space; + p = position; + + if (closed) { + p = FMOD(p, pathLength); + if (p < 0) p += pathLength; + curve = 0; + } else if (p < 0) { + _addBeforePosition(p, world, 0, out, o); + continue; + } else if (p > pathLength) { + _addAfterPosition(p - pathLength, world, verticesLength - 4, out, o); + continue; + } + + /* Determine curve containing position. */ + for (;; curve++) { + float length = curves[curve]; + if (p > length) continue; + if (curve == 0) + p /= length; + else { + float prev = curves[curve - 1]; + p = (p - prev) / (length - prev); + } + break; + } + + /* Curve segment lengths. */ + if (curve != prevCurve) { + int ii; + prevCurve = curve; + ii = curve * 6; + x1 = world[ii]; + y1 = world[ii + 1]; + cx1 = world[ii + 2]; + cy1 = world[ii + 3]; + cx2 = world[ii + 4]; + cy2 = world[ii + 5]; + x2 = world[ii + 6]; + y2 = world[ii + 7]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.03f; + tmpy = (y1 - cy1 * 2 + cy2) * 0.03f; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006f; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006f; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.3f + tmpx + dddfx * 0.16666667f; + dfy = (cy1 - y1) * 0.3f + tmpy + dddfy * 0.16666667f; + curveLength = SQRT(dfx * dfx + dfy * dfy); + segments[0] = curveLength; + for (ii = 1; ii < 8; ii++) { + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + curveLength += SQRT(dfx * dfx + dfy * dfy); + segments[ii] = curveLength; + } + dfx += ddfx; + dfy += ddfy; + curveLength += SQRT(dfx * dfx + dfy * dfy); + segments[8] = curveLength; + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + curveLength += SQRT(dfx * dfx + dfy * dfy); + segments[9] = curveLength; + segment = 0; + } + + /* Weight by segment length. */ + p *= curveLength; + for (;; segment++) { + float length = segments[segment]; + if (p > length) continue; + if (segment == 0) + p /= length; + else { + float prev = segments[segment - 1]; + p = segment + (p - prev) / (length - prev); + } + break; + } + _addCurvePosition(p * 0.1f, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || (i > 0 && space == 0)); + } + return out; } diff --git a/spine-c/src/spine/PathConstraintData.c b/spine-c/src/spine/PathConstraintData.c index ffd8167963..1f96b46ca7 100644 --- a/spine-c/src/spine/PathConstraintData.c +++ b/spine-c/src/spine/PathConstraintData.c @@ -1,45 +1,44 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -spPathConstraintData* spPathConstraintData_create (const char* name) { - spPathConstraintData* self = NEW(spPathConstraintData); - MALLOC_STR(self->name, name); - return self; -} - -void spPathConstraintData_dispose (spPathConstraintData* self) { - FREE(self->name); - FREE(self->bones); - FREE(self); +#include +#include + +spPathConstraintData* spPathConstraintData_create (const char* name) { + spPathConstraintData* self = NEW(spPathConstraintData); + MALLOC_STR(self->name, name); + return self; +} + +void spPathConstraintData_dispose (spPathConstraintData* self) { + FREE(self->name); + FREE(self->bones); + FREE(self); } diff --git a/spine-c/src/spine/RegionAttachment.c b/spine-c/src/spine/RegionAttachment.c index e872d252fa..6d0306fb65 100644 --- a/spine-c/src/spine/RegionAttachment.c +++ b/spine-c/src/spine/RegionAttachment.c @@ -1,114 +1,113 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -void _spRegionAttachment_dispose (spAttachment* attachment) { - spRegionAttachment* self = SUB_CAST(spRegionAttachment, attachment); - _spAttachment_deinit(attachment); - FREE(self->path); - FREE(self); -} - -spRegionAttachment* spRegionAttachment_create (const char* name) { - spRegionAttachment* self = NEW(spRegionAttachment); - self->scaleX = 1; - self->scaleY = 1; - self->r = 1; - self->g = 1; - self->b = 1; - self->a = 1; - _spAttachment_init(SUPER(self), name, SP_ATTACHMENT_REGION, _spRegionAttachment_dispose); - return self; -} - -void spRegionAttachment_setUVs (spRegionAttachment* self, float u, float v, float u2, float v2, int/*bool*/rotate) { - if (rotate) { - self->uvs[SP_VERTEX_X2] = u; - self->uvs[SP_VERTEX_Y2] = v2; - self->uvs[SP_VERTEX_X3] = u; - self->uvs[SP_VERTEX_Y3] = v; - self->uvs[SP_VERTEX_X4] = u2; - self->uvs[SP_VERTEX_Y4] = v; - self->uvs[SP_VERTEX_X1] = u2; - self->uvs[SP_VERTEX_Y1] = v2; - } else { - self->uvs[SP_VERTEX_X1] = u; - self->uvs[SP_VERTEX_Y1] = v2; - self->uvs[SP_VERTEX_X2] = u; - self->uvs[SP_VERTEX_Y2] = v; - self->uvs[SP_VERTEX_X3] = u2; - self->uvs[SP_VERTEX_Y3] = v; - self->uvs[SP_VERTEX_X4] = u2; - self->uvs[SP_VERTEX_Y4] = v2; - } -} - -void spRegionAttachment_updateOffset (spRegionAttachment* self) { - float regionScaleX = self->width / self->regionOriginalWidth * self->scaleX; - float regionScaleY = self->height / self->regionOriginalHeight * self->scaleY; - float localX = -self->width / 2 * self->scaleX + self->regionOffsetX * regionScaleX; - float localY = -self->height / 2 * self->scaleY + self->regionOffsetY * regionScaleY; - float localX2 = localX + self->regionWidth * regionScaleX; - float localY2 = localY + self->regionHeight * regionScaleY; - float radians = self->rotation * DEG_RAD; - float cosine = COS(radians), sine = SIN(radians); - float localXCos = localX * cosine + self->x; - float localXSin = localX * sine; - float localYCos = localY * cosine + self->y; - float localYSin = localY * sine; - float localX2Cos = localX2 * cosine + self->x; - float localX2Sin = localX2 * sine; - float localY2Cos = localY2 * cosine + self->y; - float localY2Sin = localY2 * sine; - self->offset[SP_VERTEX_X1] = localXCos - localYSin; - self->offset[SP_VERTEX_Y1] = localYCos + localXSin; - self->offset[SP_VERTEX_X2] = localXCos - localY2Sin; - self->offset[SP_VERTEX_Y2] = localY2Cos + localXSin; - self->offset[SP_VERTEX_X3] = localX2Cos - localY2Sin; - self->offset[SP_VERTEX_Y3] = localY2Cos + localX2Sin; - self->offset[SP_VERTEX_X4] = localX2Cos - localYSin; - self->offset[SP_VERTEX_Y4] = localYCos + localX2Sin; -} - -void spRegionAttachment_computeWorldVertices (spRegionAttachment* self, spBone* bone, float* vertices) { - const float* offset = self->offset; - float x = bone->skeleton->x + bone->worldX, y = bone->skeleton->y + bone->worldY; - vertices[SP_VERTEX_X1] = offset[SP_VERTEX_X1] * bone->a + offset[SP_VERTEX_Y1] * bone->b + x; - vertices[SP_VERTEX_Y1] = offset[SP_VERTEX_X1] * bone->c + offset[SP_VERTEX_Y1] * bone->d + y; - vertices[SP_VERTEX_X2] = offset[SP_VERTEX_X2] * bone->a + offset[SP_VERTEX_Y2] * bone->b + x; - vertices[SP_VERTEX_Y2] = offset[SP_VERTEX_X2] * bone->c + offset[SP_VERTEX_Y2] * bone->d + y; - vertices[SP_VERTEX_X3] = offset[SP_VERTEX_X3] * bone->a + offset[SP_VERTEX_Y3] * bone->b + x; - vertices[SP_VERTEX_Y3] = offset[SP_VERTEX_X3] * bone->c + offset[SP_VERTEX_Y3] * bone->d + y; - vertices[SP_VERTEX_X4] = offset[SP_VERTEX_X4] * bone->a + offset[SP_VERTEX_Y4] * bone->b + x; - vertices[SP_VERTEX_Y4] = offset[SP_VERTEX_X4] * bone->c + offset[SP_VERTEX_Y4] * bone->d + y; +#include +#include + +void _spRegionAttachment_dispose (spAttachment* attachment) { + spRegionAttachment* self = SUB_CAST(spRegionAttachment, attachment); + _spAttachment_deinit(attachment); + FREE(self->path); + FREE(self); +} + +spRegionAttachment* spRegionAttachment_create (const char* name) { + spRegionAttachment* self = NEW(spRegionAttachment); + self->scaleX = 1; + self->scaleY = 1; + self->r = 1; + self->g = 1; + self->b = 1; + self->a = 1; + _spAttachment_init(SUPER(self), name, SP_ATTACHMENT_REGION, _spRegionAttachment_dispose); + return self; +} + +void spRegionAttachment_setUVs (spRegionAttachment* self, float u, float v, float u2, float v2, int/*bool*/rotate) { + if (rotate) { + self->uvs[SP_VERTEX_X2] = u; + self->uvs[SP_VERTEX_Y2] = v2; + self->uvs[SP_VERTEX_X3] = u; + self->uvs[SP_VERTEX_Y3] = v; + self->uvs[SP_VERTEX_X4] = u2; + self->uvs[SP_VERTEX_Y4] = v; + self->uvs[SP_VERTEX_X1] = u2; + self->uvs[SP_VERTEX_Y1] = v2; + } else { + self->uvs[SP_VERTEX_X1] = u; + self->uvs[SP_VERTEX_Y1] = v2; + self->uvs[SP_VERTEX_X2] = u; + self->uvs[SP_VERTEX_Y2] = v; + self->uvs[SP_VERTEX_X3] = u2; + self->uvs[SP_VERTEX_Y3] = v; + self->uvs[SP_VERTEX_X4] = u2; + self->uvs[SP_VERTEX_Y4] = v2; + } +} + +void spRegionAttachment_updateOffset (spRegionAttachment* self) { + float regionScaleX = self->width / self->regionOriginalWidth * self->scaleX; + float regionScaleY = self->height / self->regionOriginalHeight * self->scaleY; + float localX = -self->width / 2 * self->scaleX + self->regionOffsetX * regionScaleX; + float localY = -self->height / 2 * self->scaleY + self->regionOffsetY * regionScaleY; + float localX2 = localX + self->regionWidth * regionScaleX; + float localY2 = localY + self->regionHeight * regionScaleY; + float radians = self->rotation * DEG_RAD; + float cosine = COS(radians), sine = SIN(radians); + float localXCos = localX * cosine + self->x; + float localXSin = localX * sine; + float localYCos = localY * cosine + self->y; + float localYSin = localY * sine; + float localX2Cos = localX2 * cosine + self->x; + float localX2Sin = localX2 * sine; + float localY2Cos = localY2 * cosine + self->y; + float localY2Sin = localY2 * sine; + self->offset[SP_VERTEX_X1] = localXCos - localYSin; + self->offset[SP_VERTEX_Y1] = localYCos + localXSin; + self->offset[SP_VERTEX_X2] = localXCos - localY2Sin; + self->offset[SP_VERTEX_Y2] = localY2Cos + localXSin; + self->offset[SP_VERTEX_X3] = localX2Cos - localY2Sin; + self->offset[SP_VERTEX_Y3] = localY2Cos + localX2Sin; + self->offset[SP_VERTEX_X4] = localX2Cos - localYSin; + self->offset[SP_VERTEX_Y4] = localYCos + localX2Sin; +} + +void spRegionAttachment_computeWorldVertices (spRegionAttachment* self, spBone* bone, float* vertices) { + const float* offset = self->offset; + float x = bone->skeleton->x + bone->worldX, y = bone->skeleton->y + bone->worldY; + vertices[SP_VERTEX_X1] = offset[SP_VERTEX_X1] * bone->a + offset[SP_VERTEX_Y1] * bone->b + x; + vertices[SP_VERTEX_Y1] = offset[SP_VERTEX_X1] * bone->c + offset[SP_VERTEX_Y1] * bone->d + y; + vertices[SP_VERTEX_X2] = offset[SP_VERTEX_X2] * bone->a + offset[SP_VERTEX_Y2] * bone->b + x; + vertices[SP_VERTEX_Y2] = offset[SP_VERTEX_X2] * bone->c + offset[SP_VERTEX_Y2] * bone->d + y; + vertices[SP_VERTEX_X3] = offset[SP_VERTEX_X3] * bone->a + offset[SP_VERTEX_Y3] * bone->b + x; + vertices[SP_VERTEX_Y3] = offset[SP_VERTEX_X3] * bone->c + offset[SP_VERTEX_Y3] * bone->d + y; + vertices[SP_VERTEX_X4] = offset[SP_VERTEX_X4] * bone->a + offset[SP_VERTEX_Y4] * bone->b + x; + vertices[SP_VERTEX_Y4] = offset[SP_VERTEX_X4] * bone->c + offset[SP_VERTEX_Y4] * bone->d + y; } diff --git a/spine-c/src/spine/Skeleton.c b/spine-c/src/spine/Skeleton.c index 47e946bb17..fae441b1be 100644 --- a/spine-c/src/spine/Skeleton.c +++ b/spine-c/src/spine/Skeleton.c @@ -1,511 +1,510 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include -#include -#include - -typedef enum { - SP_UPDATE_BONE, SP_UPDATE_IK_CONSTRAINT, SP_UPDATE_PATH_CONSTRAINT, SP_UPDATE_TRANSFORM_CONSTRAINT -} _spUpdateType; - -typedef struct { - _spUpdateType type; - void* object; -} _spUpdate; - -typedef struct { - spSkeleton super; - - int updateCacheCount; - int updateCacheCapacity; - _spUpdate* updateCache; -} _spSkeleton; - -spSkeleton* spSkeleton_create (spSkeletonData* data) { - int i; - int* childrenCounts; - - _spSkeleton* internal = NEW(_spSkeleton); - spSkeleton* self = SUPER(internal); - CONST_CAST(spSkeletonData*, self->data) = data; - - self->bonesCount = self->data->bonesCount; - self->bones = MALLOC(spBone*, self->bonesCount); - childrenCounts = CALLOC(int, self->bonesCount); - - for (i = 0; i < self->bonesCount; ++i) { - spBoneData* boneData = self->data->bones[i]; - spBone* bone; - if (!boneData->parent) - bone = spBone_create(boneData, self, 0); - else { - spBone* parent = self->bones[boneData->parent->index]; - bone = spBone_create(boneData, self, parent); - ++childrenCounts[boneData->parent->index]; - } - self->bones[i] = bone; - } - for (i = 0; i < self->bonesCount; ++i) { - spBoneData* boneData = self->data->bones[i]; - spBone* bone = self->bones[i]; - CONST_CAST(spBone**, bone->children) = MALLOC(spBone*, childrenCounts[boneData->index]); - } - for (i = 0; i < self->bonesCount; ++i) { - spBone* bone = self->bones[i]; - spBone* parent = bone->parent; - if (parent) - parent->children[parent->childrenCount++] = bone; - } - CONST_CAST(spBone*, self->root) = (self->bonesCount > 0 ? self->bones[0] : NULL); - - self->slotsCount = data->slotsCount; - self->slots = MALLOC(spSlot*, self->slotsCount); - for (i = 0; i < self->slotsCount; ++i) { - spSlotData *slotData = data->slots[i]; - spBone* bone = self->bones[slotData->boneData->index]; - self->slots[i] = spSlot_create(slotData, bone); - } - - self->drawOrder = MALLOC(spSlot*, self->slotsCount); - memcpy(self->drawOrder, self->slots, sizeof(spSlot*) * self->slotsCount); - - self->ikConstraintsCount = data->ikConstraintsCount; - self->ikConstraints = MALLOC(spIkConstraint*, self->ikConstraintsCount); - self->ikConstraintsSorted = MALLOC(spIkConstraint*, self->ikConstraintsCount); - for (i = 0; i < self->data->ikConstraintsCount; ++i) - self->ikConstraints[i] = spIkConstraint_create(self->data->ikConstraints[i], self); - - self->transformConstraintsCount = data->transformConstraintsCount; - self->transformConstraints = MALLOC(spTransformConstraint*, self->transformConstraintsCount); - for (i = 0; i < self->data->transformConstraintsCount; ++i) - self->transformConstraints[i] = spTransformConstraint_create(self->data->transformConstraints[i], self); - - self->pathConstraintsCount = data->pathConstraintsCount; - self->pathConstraints = MALLOC(spPathConstraint*, self->pathConstraintsCount); - for (i = 0; i < self->data->pathConstraintsCount; i++) - self->pathConstraints[i] = spPathConstraint_create(self->data->pathConstraints[i], self); - - self->r = 1; self->g = 1; self->b = 1; self->a = 1; - - spSkeleton_updateCache(self); - - FREE(childrenCounts); - - return self; -} - -void spSkeleton_dispose (spSkeleton* self) { - int i; - _spSkeleton* internal = SUB_CAST(_spSkeleton, self); - - FREE(internal->updateCache); - - for (i = 0; i < self->bonesCount; ++i) - spBone_dispose(self->bones[i]); - FREE(self->bones); - - for (i = 0; i < self->slotsCount; ++i) - spSlot_dispose(self->slots[i]); - FREE(self->slots); - - for (i = 0; i < self->ikConstraintsCount; ++i) - spIkConstraint_dispose(self->ikConstraints[i]); - FREE(self->ikConstraints); - FREE(self->ikConstraintsSorted); - - for (i = 0; i < self->transformConstraintsCount; ++i) - spTransformConstraint_dispose(self->transformConstraints[i]); - FREE(self->transformConstraints); - - for (i = 0; i < self->pathConstraintsCount; i++) - spPathConstraint_dispose(self->pathConstraints[i]); - FREE(self->pathConstraints); - - FREE(self->drawOrder); - FREE(self); -} - -static void _addToUpdateCache(_spSkeleton* const internal, _spUpdateType type, void *object) { - _spUpdate* update; - if (internal->updateCacheCount == internal->updateCacheCapacity) { - internal->updateCacheCapacity *= 2; - internal->updateCache = realloc(internal->updateCache, sizeof(_spUpdate) * internal->updateCacheCapacity); - } - update = internal->updateCache + internal->updateCacheCount; - update->type = type; - update->object = object; - ++internal->updateCacheCount; -} - -static void _sortBone(_spSkeleton* const internal, spBone* bone) { - if (bone->sorted) return; - if (bone->parent) _sortBone(internal, bone->parent); - bone->sorted = 1; - _addToUpdateCache(internal, SP_UPDATE_BONE, bone); -} - -static void _sortPathConstraintAttachmentBones(_spSkeleton* const internal, spAttachment* attachment, spBone* slotBone) { - spPathAttachment* pathAttachment = (spPathAttachment*)attachment; - int* pathBones; - int pathBonesCount; - if (pathAttachment->super.super.type != SP_ATTACHMENT_PATH) return; - pathBones = pathAttachment->super.bones; - pathBonesCount = pathAttachment->super.bonesCount; - if (pathBones == 0) - _sortBone(internal, slotBone); - else { - spBone** bones = internal->super.bones; - int i = 0; - while (i < pathBonesCount) { - int boneCount = pathBones[i++]; - for (int n = i + boneCount; i < n; i++) - _sortBone(internal, bones[pathBones[i]]); - } - } -} - -static void _sortPathConstraintAttachment(_spSkeleton* const internal, spSkin* skin, int slotIndex, spBone* slotBone) { - _Entry* entry = SUB_CAST(_spSkin, skin)->entries; - while (entry) { - if (entry->slotIndex == slotIndex) _sortPathConstraintAttachmentBones(internal, entry->attachment, slotBone); - entry = entry->next; - } -} - -static void _sortReset(spBone** bones, int bonesCount) { - int i; - for (i = 0; i < bonesCount; ++i) { - spBone* bone = bones[i]; - if (bone->sorted) _sortReset(bone->children, bone->childrenCount); - bone->sorted = 0; - } -} - -void spSkeleton_updateCache (spSkeleton* self) { - int i, ii, n, nn, level; - spBone** bones; - spIkConstraint** ikConstraints; - spPathConstraint** pathConstraints; - spTransformConstraint** transformConstraints; - _spSkeleton* internal = SUB_CAST(_spSkeleton, self); - internal->updateCacheCapacity = self->bonesCount + self->ikConstraintsCount + self->transformConstraintsCount + self->pathConstraintsCount; - - FREE(internal->updateCache); - internal->updateCache = MALLOC(_spUpdate, internal->updateCacheCapacity); - internal->updateCacheCount = 0; - - bones = self->bones; - for (i = 0; i < self->bonesCount; ++i) - bones[i]->sorted = 0; - - /* IK first, lowest hierarchy depth first. */ - if (self->ikConstraintsSorted) FREE(self->ikConstraintsSorted); - self->ikConstraintsSorted = MALLOC(spIkConstraint*, self->ikConstraintsCount); - ikConstraints = self->ikConstraintsSorted; - for (i = 0; i < self->ikConstraintsCount; ++i) - ikConstraints[i] = self->ikConstraints[i]; - for (i = 0; i < self->ikConstraintsCount; ++i) { - spIkConstraint* ik = ikConstraints[i]; - spBone* bone = ik->bones[0]->parent; - for (level = 0; bone; ++level) - bone = bone->parent; - ik->level = level; - } - for (i = 1; i < self->ikConstraintsCount; ++i) { - spIkConstraint* ik = ikConstraints[i]; - level = ik->level; - for (ii = i - 1; ii >= 0; --ii) { - spIkConstraint* other = ikConstraints[ii]; - if (other->level < level) break; - ikConstraints[ii + 1] = other; - } - ikConstraints[ii + 1] = ik; - } - for (i = 0; i < self->ikConstraintsCount; ++i) { - spBone** constrained; - spBone* parent; - spIkConstraint* constraint = ikConstraints[i]; - spBone* target = constraint->target; - _sortBone(internal, target); - - constrained = constraint->bones; - parent = constrained[0]; - _sortBone(internal, parent); - - _addToUpdateCache(internal, SP_UPDATE_IK_CONSTRAINT, constraint); - - _sortReset(parent->children, parent->childrenCount); - constrained[constraint->bonesCount - 1]->sorted = 1; - } - - pathConstraints = self->pathConstraints; - for (i = 0, n = self->pathConstraintsCount; i < n; i++) { - spAttachment* attachment; - spBone** constrained; - int boneCount; - spPathConstraint* constraint = pathConstraints[i]; - - spSlot* slot = constraint->target; - int slotIndex = slot->data->index; - spBone* slotBone = slot->bone; - if (self->skin) _sortPathConstraintAttachment(internal, self->skin, slotIndex, slotBone); - if (self->data->defaultSkin && self->data->defaultSkin != self->skin) - _sortPathConstraintAttachment(internal, self->data->defaultSkin, slotIndex, slotBone); - for (ii = 0, nn = self->data->skinsCount; ii < nn; ii++) - _sortPathConstraintAttachment(internal, self->data->skins[ii], slotIndex, slotBone); - - attachment = slot->attachment; - if (attachment->type == SP_ATTACHMENT_PATH) _sortPathConstraintAttachmentBones(internal, attachment, slotBone); - - constrained = constraint->bones; - boneCount = constraint->bonesCount; - for (ii = 0; ii < boneCount; ii++) - _sortBone(internal, constrained[ii]); - - _addToUpdateCache(internal, SP_UPDATE_PATH_CONSTRAINT, constraint); - - for (ii = 0; ii < boneCount; ii++) - _sortReset(constrained[ii]->children, constrained[ii]->childrenCount); - for (ii = 0; ii < boneCount; ii++) - constrained[ii]->sorted = 1; - } - - transformConstraints = self->transformConstraints; - for (i = 0, n = self->transformConstraintsCount; i < n; ++i) { - spTransformConstraint* constraint = transformConstraints[i]; - spBone** constrained = constraint->bones; - - _sortBone(internal, constraint->target); - - for (ii = 0; ii < constraint->bonesCount; ++ii) - _sortBone(internal, constrained[ii]); - - _addToUpdateCache(internal, SP_UPDATE_TRANSFORM_CONSTRAINT, constraint); - - for (ii = 0; ii < constraint->bonesCount; ++ii) { - spBone* bone = constrained[ii]; - _sortReset(bone->children, bone->childrenCount); - } - for (ii = 0; ii < constraint->bonesCount; ++ii) - constrained[ii]->sorted = 1; - } - - for (i = 0; i < self->bonesCount; ++i) - _sortBone(internal, self->bones[i]); -} - -void spSkeleton_updateWorldTransform (const spSkeleton* self) { - int i; - _spSkeleton* internal = SUB_CAST(_spSkeleton, self); - - for (i = 0; i < internal->updateCacheCount; ++i) { - _spUpdate* update = internal->updateCache + i; - switch (update->type) { - case SP_UPDATE_BONE: - spBone_updateWorldTransform((spBone*)update->object); - break; - case SP_UPDATE_IK_CONSTRAINT: - spIkConstraint_apply((spIkConstraint*)update->object); - break; - case SP_UPDATE_TRANSFORM_CONSTRAINT: - spTransformConstraint_apply((spTransformConstraint*)update->object); - break; - case SP_UPDATE_PATH_CONSTRAINT: - spPathConstraint_apply((spPathConstraint*)update->object); - break; - } - } -} - -void spSkeleton_setToSetupPose (const spSkeleton* self) { - spSkeleton_setBonesToSetupPose(self); - spSkeleton_setSlotsToSetupPose(self); -} - -void spSkeleton_setBonesToSetupPose (const spSkeleton* self) { - int i; - for (i = 0; i < self->bonesCount; ++i) - spBone_setToSetupPose(self->bones[i]); - - for (i = 0; i < self->ikConstraintsCount; ++i) { - spIkConstraint* ikConstraint = self->ikConstraints[i]; - ikConstraint->bendDirection = ikConstraint->data->bendDirection; - ikConstraint->mix = ikConstraint->data->mix; - } - - for (i = 0; i < self->transformConstraintsCount; ++i) { - spTransformConstraint* constraint = self->transformConstraints[i]; - spTransformConstraintData* data = constraint->data; - constraint->rotateMix = data->rotateMix; - constraint->translateMix = data->translateMix; - constraint->scaleMix = data->scaleMix; - constraint->shearMix = data->shearMix; - } - - for (i = 0; i < self->pathConstraintsCount; ++i) { - spPathConstraint* constraint = self->pathConstraints[i]; - spPathConstraintData* data = constraint->data; - constraint->position = data->position; - constraint->spacing = data->spacing; - constraint->rotateMix = data->rotateMix; - constraint->translateMix = data->translateMix; - } -} - -void spSkeleton_setSlotsToSetupPose (const spSkeleton* self) { - int i; - memcpy(self->drawOrder, self->slots, self->slotsCount * sizeof(spSlot*)); - for (i = 0; i < self->slotsCount; ++i) - spSlot_setToSetupPose(self->slots[i]); -} - -spBone* spSkeleton_findBone (const spSkeleton* self, const char* boneName) { - int i; - for (i = 0; i < self->bonesCount; ++i) - if (strcmp(self->data->bones[i]->name, boneName) == 0) return self->bones[i]; - return 0; -} - -int spSkeleton_findBoneIndex (const spSkeleton* self, const char* boneName) { - int i; - for (i = 0; i < self->bonesCount; ++i) - if (strcmp(self->data->bones[i]->name, boneName) == 0) return i; - return -1; -} - -spSlot* spSkeleton_findSlot (const spSkeleton* self, const char* slotName) { - int i; - for (i = 0; i < self->slotsCount; ++i) - if (strcmp(self->data->slots[i]->name, slotName) == 0) return self->slots[i]; - return 0; -} - -int spSkeleton_findSlotIndex (const spSkeleton* self, const char* slotName) { - int i; - for (i = 0; i < self->slotsCount; ++i) - if (strcmp(self->data->slots[i]->name, slotName) == 0) return i; - return -1; -} - -int spSkeleton_setSkinByName (spSkeleton* self, const char* skinName) { - spSkin *skin; - if (!skinName) { - spSkeleton_setSkin(self, 0); - return 1; - } - skin = spSkeletonData_findSkin(self->data, skinName); - if (!skin) return 0; - spSkeleton_setSkin(self, skin); - return 1; -} - -void spSkeleton_setSkin (spSkeleton* self, spSkin* newSkin) { - if (newSkin) { - if (self->skin) - spSkin_attachAll(newSkin, self, self->skin); - else { - /* No previous skin, attach setup pose attachments. */ - int i; - for (i = 0; i < self->slotsCount; ++i) { - spSlot* slot = self->slots[i]; - if (slot->data->attachmentName) { - spAttachment* attachment = spSkin_getAttachment(newSkin, i, slot->data->attachmentName); - if (attachment) spSlot_setAttachment(slot, attachment); - } - } - } - } - CONST_CAST(spSkin*, self->skin) = newSkin; -} - -spAttachment* spSkeleton_getAttachmentForSlotName (const spSkeleton* self, const char* slotName, const char* attachmentName) { - int slotIndex = spSkeletonData_findSlotIndex(self->data, slotName); - return spSkeleton_getAttachmentForSlotIndex(self, slotIndex, attachmentName); -} - -spAttachment* spSkeleton_getAttachmentForSlotIndex (const spSkeleton* self, int slotIndex, const char* attachmentName) { - if (slotIndex == -1) return 0; - if (self->skin) { - spAttachment *attachment = spSkin_getAttachment(self->skin, slotIndex, attachmentName); - if (attachment) return attachment; - } - if (self->data->defaultSkin) { - spAttachment *attachment = spSkin_getAttachment(self->data->defaultSkin, slotIndex, attachmentName); - if (attachment) return attachment; - } - return 0; -} - -int spSkeleton_setAttachment (spSkeleton* self, const char* slotName, const char* attachmentName) { - int i; - for (i = 0; i < self->slotsCount; ++i) { - spSlot *slot = self->slots[i]; - if (strcmp(slot->data->name, slotName) == 0) { - if (!attachmentName) - spSlot_setAttachment(slot, 0); - else { - spAttachment* attachment = spSkeleton_getAttachmentForSlotIndex(self, i, attachmentName); - if (!attachment) return 0; - spSlot_setAttachment(slot, attachment); - } - return 1; - } - } - return 0; -} - -spIkConstraint* spSkeleton_findIkConstraint (const spSkeleton* self, const char* constraintName) { - int i; - for (i = 0; i < self->ikConstraintsCount; ++i) - if (strcmp(self->ikConstraints[i]->data->name, constraintName) == 0) return self->ikConstraints[i]; - return 0; -} - -spTransformConstraint* spSkeleton_findTransformConstraint (const spSkeleton* self, const char* constraintName) { - int i; - for (i = 0; i < self->transformConstraintsCount; ++i) - if (strcmp(self->transformConstraints[i]->data->name, constraintName) == 0) return self->transformConstraints[i]; - return 0; -} - -spPathConstraint* spSkeleton_findPathConstraint (const spSkeleton* self, const char* constraintName) { - int i; - for (i = 0; i < self->pathConstraintsCount; ++i) - if (strcmp(self->pathConstraints[i]->data->name, constraintName) == 0) return self->pathConstraints[i]; - return 0; -} - -void spSkeleton_update (spSkeleton* self, float deltaTime) { - self->time += deltaTime; +#include +#include +#include +#include +#include + +typedef enum { + SP_UPDATE_BONE, SP_UPDATE_IK_CONSTRAINT, SP_UPDATE_PATH_CONSTRAINT, SP_UPDATE_TRANSFORM_CONSTRAINT +} _spUpdateType; + +typedef struct { + _spUpdateType type; + void* object; +} _spUpdate; + +typedef struct { + spSkeleton super; + + int updateCacheCount; + int updateCacheCapacity; + _spUpdate* updateCache; +} _spSkeleton; + +spSkeleton* spSkeleton_create (spSkeletonData* data) { + int i; + int* childrenCounts; + + _spSkeleton* internal = NEW(_spSkeleton); + spSkeleton* self = SUPER(internal); + CONST_CAST(spSkeletonData*, self->data) = data; + + self->bonesCount = self->data->bonesCount; + self->bones = MALLOC(spBone*, self->bonesCount); + childrenCounts = CALLOC(int, self->bonesCount); + + for (i = 0; i < self->bonesCount; ++i) { + spBoneData* boneData = self->data->bones[i]; + spBone* bone; + if (!boneData->parent) + bone = spBone_create(boneData, self, 0); + else { + spBone* parent = self->bones[boneData->parent->index]; + bone = spBone_create(boneData, self, parent); + ++childrenCounts[boneData->parent->index]; + } + self->bones[i] = bone; + } + for (i = 0; i < self->bonesCount; ++i) { + spBoneData* boneData = self->data->bones[i]; + spBone* bone = self->bones[i]; + CONST_CAST(spBone**, bone->children) = MALLOC(spBone*, childrenCounts[boneData->index]); + } + for (i = 0; i < self->bonesCount; ++i) { + spBone* bone = self->bones[i]; + spBone* parent = bone->parent; + if (parent) + parent->children[parent->childrenCount++] = bone; + } + CONST_CAST(spBone*, self->root) = (self->bonesCount > 0 ? self->bones[0] : NULL); + + self->slotsCount = data->slotsCount; + self->slots = MALLOC(spSlot*, self->slotsCount); + for (i = 0; i < self->slotsCount; ++i) { + spSlotData *slotData = data->slots[i]; + spBone* bone = self->bones[slotData->boneData->index]; + self->slots[i] = spSlot_create(slotData, bone); + } + + self->drawOrder = MALLOC(spSlot*, self->slotsCount); + memcpy(self->drawOrder, self->slots, sizeof(spSlot*) * self->slotsCount); + + self->ikConstraintsCount = data->ikConstraintsCount; + self->ikConstraints = MALLOC(spIkConstraint*, self->ikConstraintsCount); + self->ikConstraintsSorted = MALLOC(spIkConstraint*, self->ikConstraintsCount); + for (i = 0; i < self->data->ikConstraintsCount; ++i) + self->ikConstraints[i] = spIkConstraint_create(self->data->ikConstraints[i], self); + + self->transformConstraintsCount = data->transformConstraintsCount; + self->transformConstraints = MALLOC(spTransformConstraint*, self->transformConstraintsCount); + for (i = 0; i < self->data->transformConstraintsCount; ++i) + self->transformConstraints[i] = spTransformConstraint_create(self->data->transformConstraints[i], self); + + self->pathConstraintsCount = data->pathConstraintsCount; + self->pathConstraints = MALLOC(spPathConstraint*, self->pathConstraintsCount); + for (i = 0; i < self->data->pathConstraintsCount; i++) + self->pathConstraints[i] = spPathConstraint_create(self->data->pathConstraints[i], self); + + self->r = 1; self->g = 1; self->b = 1; self->a = 1; + + spSkeleton_updateCache(self); + + FREE(childrenCounts); + + return self; +} + +void spSkeleton_dispose (spSkeleton* self) { + int i; + _spSkeleton* internal = SUB_CAST(_spSkeleton, self); + + FREE(internal->updateCache); + + for (i = 0; i < self->bonesCount; ++i) + spBone_dispose(self->bones[i]); + FREE(self->bones); + + for (i = 0; i < self->slotsCount; ++i) + spSlot_dispose(self->slots[i]); + FREE(self->slots); + + for (i = 0; i < self->ikConstraintsCount; ++i) + spIkConstraint_dispose(self->ikConstraints[i]); + FREE(self->ikConstraints); + FREE(self->ikConstraintsSorted); + + for (i = 0; i < self->transformConstraintsCount; ++i) + spTransformConstraint_dispose(self->transformConstraints[i]); + FREE(self->transformConstraints); + + for (i = 0; i < self->pathConstraintsCount; i++) + spPathConstraint_dispose(self->pathConstraints[i]); + FREE(self->pathConstraints); + + FREE(self->drawOrder); + FREE(self); +} + +static void _addToUpdateCache(_spSkeleton* const internal, _spUpdateType type, void *object) { + _spUpdate* update; + if (internal->updateCacheCount == internal->updateCacheCapacity) { + internal->updateCacheCapacity *= 2; + internal->updateCache = realloc(internal->updateCache, sizeof(_spUpdate) * internal->updateCacheCapacity); + } + update = internal->updateCache + internal->updateCacheCount; + update->type = type; + update->object = object; + ++internal->updateCacheCount; +} + +static void _sortBone(_spSkeleton* const internal, spBone* bone) { + if (bone->sorted) return; + if (bone->parent) _sortBone(internal, bone->parent); + bone->sorted = 1; + _addToUpdateCache(internal, SP_UPDATE_BONE, bone); +} + +static void _sortPathConstraintAttachmentBones(_spSkeleton* const internal, spAttachment* attachment, spBone* slotBone) { + spPathAttachment* pathAttachment = (spPathAttachment*)attachment; + int* pathBones; + int pathBonesCount; + if (pathAttachment->super.super.type != SP_ATTACHMENT_PATH) return; + pathBones = pathAttachment->super.bones; + pathBonesCount = pathAttachment->super.bonesCount; + if (pathBones == 0) + _sortBone(internal, slotBone); + else { + spBone** bones = internal->super.bones; + int i = 0; + while (i < pathBonesCount) { + int boneCount = pathBones[i++]; + for (int n = i + boneCount; i < n; i++) + _sortBone(internal, bones[pathBones[i]]); + } + } +} + +static void _sortPathConstraintAttachment(_spSkeleton* const internal, spSkin* skin, int slotIndex, spBone* slotBone) { + _Entry* entry = SUB_CAST(_spSkin, skin)->entries; + while (entry) { + if (entry->slotIndex == slotIndex) _sortPathConstraintAttachmentBones(internal, entry->attachment, slotBone); + entry = entry->next; + } +} + +static void _sortReset(spBone** bones, int bonesCount) { + int i; + for (i = 0; i < bonesCount; ++i) { + spBone* bone = bones[i]; + if (bone->sorted) _sortReset(bone->children, bone->childrenCount); + bone->sorted = 0; + } +} + +void spSkeleton_updateCache (spSkeleton* self) { + int i, ii, n, nn, level; + spBone** bones; + spIkConstraint** ikConstraints; + spPathConstraint** pathConstraints; + spTransformConstraint** transformConstraints; + _spSkeleton* internal = SUB_CAST(_spSkeleton, self); + internal->updateCacheCapacity = self->bonesCount + self->ikConstraintsCount + self->transformConstraintsCount + self->pathConstraintsCount; + + FREE(internal->updateCache); + internal->updateCache = MALLOC(_spUpdate, internal->updateCacheCapacity); + internal->updateCacheCount = 0; + + bones = self->bones; + for (i = 0; i < self->bonesCount; ++i) + bones[i]->sorted = 0; + + /* IK first, lowest hierarchy depth first. */ + if (self->ikConstraintsSorted) FREE(self->ikConstraintsSorted); + self->ikConstraintsSorted = MALLOC(spIkConstraint*, self->ikConstraintsCount); + ikConstraints = self->ikConstraintsSorted; + for (i = 0; i < self->ikConstraintsCount; ++i) + ikConstraints[i] = self->ikConstraints[i]; + for (i = 0; i < self->ikConstraintsCount; ++i) { + spIkConstraint* ik = ikConstraints[i]; + spBone* bone = ik->bones[0]->parent; + for (level = 0; bone; ++level) + bone = bone->parent; + ik->level = level; + } + for (i = 1; i < self->ikConstraintsCount; ++i) { + spIkConstraint* ik = ikConstraints[i]; + level = ik->level; + for (ii = i - 1; ii >= 0; --ii) { + spIkConstraint* other = ikConstraints[ii]; + if (other->level < level) break; + ikConstraints[ii + 1] = other; + } + ikConstraints[ii + 1] = ik; + } + for (i = 0; i < self->ikConstraintsCount; ++i) { + spBone** constrained; + spBone* parent; + spIkConstraint* constraint = ikConstraints[i]; + spBone* target = constraint->target; + _sortBone(internal, target); + + constrained = constraint->bones; + parent = constrained[0]; + _sortBone(internal, parent); + + _addToUpdateCache(internal, SP_UPDATE_IK_CONSTRAINT, constraint); + + _sortReset(parent->children, parent->childrenCount); + constrained[constraint->bonesCount - 1]->sorted = 1; + } + + pathConstraints = self->pathConstraints; + for (i = 0, n = self->pathConstraintsCount; i < n; i++) { + spAttachment* attachment; + spBone** constrained; + int boneCount; + spPathConstraint* constraint = pathConstraints[i]; + + spSlot* slot = constraint->target; + int slotIndex = slot->data->index; + spBone* slotBone = slot->bone; + if (self->skin) _sortPathConstraintAttachment(internal, self->skin, slotIndex, slotBone); + if (self->data->defaultSkin && self->data->defaultSkin != self->skin) + _sortPathConstraintAttachment(internal, self->data->defaultSkin, slotIndex, slotBone); + for (ii = 0, nn = self->data->skinsCount; ii < nn; ii++) + _sortPathConstraintAttachment(internal, self->data->skins[ii], slotIndex, slotBone); + + attachment = slot->attachment; + if (attachment->type == SP_ATTACHMENT_PATH) _sortPathConstraintAttachmentBones(internal, attachment, slotBone); + + constrained = constraint->bones; + boneCount = constraint->bonesCount; + for (ii = 0; ii < boneCount; ii++) + _sortBone(internal, constrained[ii]); + + _addToUpdateCache(internal, SP_UPDATE_PATH_CONSTRAINT, constraint); + + for (ii = 0; ii < boneCount; ii++) + _sortReset(constrained[ii]->children, constrained[ii]->childrenCount); + for (ii = 0; ii < boneCount; ii++) + constrained[ii]->sorted = 1; + } + + transformConstraints = self->transformConstraints; + for (i = 0, n = self->transformConstraintsCount; i < n; ++i) { + spTransformConstraint* constraint = transformConstraints[i]; + spBone** constrained = constraint->bones; + + _sortBone(internal, constraint->target); + + for (ii = 0; ii < constraint->bonesCount; ++ii) + _sortBone(internal, constrained[ii]); + + _addToUpdateCache(internal, SP_UPDATE_TRANSFORM_CONSTRAINT, constraint); + + for (ii = 0; ii < constraint->bonesCount; ++ii) { + spBone* bone = constrained[ii]; + _sortReset(bone->children, bone->childrenCount); + } + for (ii = 0; ii < constraint->bonesCount; ++ii) + constrained[ii]->sorted = 1; + } + + for (i = 0; i < self->bonesCount; ++i) + _sortBone(internal, self->bones[i]); +} + +void spSkeleton_updateWorldTransform (const spSkeleton* self) { + int i; + _spSkeleton* internal = SUB_CAST(_spSkeleton, self); + + for (i = 0; i < internal->updateCacheCount; ++i) { + _spUpdate* update = internal->updateCache + i; + switch (update->type) { + case SP_UPDATE_BONE: + spBone_updateWorldTransform((spBone*)update->object); + break; + case SP_UPDATE_IK_CONSTRAINT: + spIkConstraint_apply((spIkConstraint*)update->object); + break; + case SP_UPDATE_TRANSFORM_CONSTRAINT: + spTransformConstraint_apply((spTransformConstraint*)update->object); + break; + case SP_UPDATE_PATH_CONSTRAINT: + spPathConstraint_apply((spPathConstraint*)update->object); + break; + } + } +} + +void spSkeleton_setToSetupPose (const spSkeleton* self) { + spSkeleton_setBonesToSetupPose(self); + spSkeleton_setSlotsToSetupPose(self); +} + +void spSkeleton_setBonesToSetupPose (const spSkeleton* self) { + int i; + for (i = 0; i < self->bonesCount; ++i) + spBone_setToSetupPose(self->bones[i]); + + for (i = 0; i < self->ikConstraintsCount; ++i) { + spIkConstraint* ikConstraint = self->ikConstraints[i]; + ikConstraint->bendDirection = ikConstraint->data->bendDirection; + ikConstraint->mix = ikConstraint->data->mix; + } + + for (i = 0; i < self->transformConstraintsCount; ++i) { + spTransformConstraint* constraint = self->transformConstraints[i]; + spTransformConstraintData* data = constraint->data; + constraint->rotateMix = data->rotateMix; + constraint->translateMix = data->translateMix; + constraint->scaleMix = data->scaleMix; + constraint->shearMix = data->shearMix; + } + + for (i = 0; i < self->pathConstraintsCount; ++i) { + spPathConstraint* constraint = self->pathConstraints[i]; + spPathConstraintData* data = constraint->data; + constraint->position = data->position; + constraint->spacing = data->spacing; + constraint->rotateMix = data->rotateMix; + constraint->translateMix = data->translateMix; + } +} + +void spSkeleton_setSlotsToSetupPose (const spSkeleton* self) { + int i; + memcpy(self->drawOrder, self->slots, self->slotsCount * sizeof(spSlot*)); + for (i = 0; i < self->slotsCount; ++i) + spSlot_setToSetupPose(self->slots[i]); +} + +spBone* spSkeleton_findBone (const spSkeleton* self, const char* boneName) { + int i; + for (i = 0; i < self->bonesCount; ++i) + if (strcmp(self->data->bones[i]->name, boneName) == 0) return self->bones[i]; + return 0; +} + +int spSkeleton_findBoneIndex (const spSkeleton* self, const char* boneName) { + int i; + for (i = 0; i < self->bonesCount; ++i) + if (strcmp(self->data->bones[i]->name, boneName) == 0) return i; + return -1; +} + +spSlot* spSkeleton_findSlot (const spSkeleton* self, const char* slotName) { + int i; + for (i = 0; i < self->slotsCount; ++i) + if (strcmp(self->data->slots[i]->name, slotName) == 0) return self->slots[i]; + return 0; +} + +int spSkeleton_findSlotIndex (const spSkeleton* self, const char* slotName) { + int i; + for (i = 0; i < self->slotsCount; ++i) + if (strcmp(self->data->slots[i]->name, slotName) == 0) return i; + return -1; +} + +int spSkeleton_setSkinByName (spSkeleton* self, const char* skinName) { + spSkin *skin; + if (!skinName) { + spSkeleton_setSkin(self, 0); + return 1; + } + skin = spSkeletonData_findSkin(self->data, skinName); + if (!skin) return 0; + spSkeleton_setSkin(self, skin); + return 1; +} + +void spSkeleton_setSkin (spSkeleton* self, spSkin* newSkin) { + if (newSkin) { + if (self->skin) + spSkin_attachAll(newSkin, self, self->skin); + else { + /* No previous skin, attach setup pose attachments. */ + int i; + for (i = 0; i < self->slotsCount; ++i) { + spSlot* slot = self->slots[i]; + if (slot->data->attachmentName) { + spAttachment* attachment = spSkin_getAttachment(newSkin, i, slot->data->attachmentName); + if (attachment) spSlot_setAttachment(slot, attachment); + } + } + } + } + CONST_CAST(spSkin*, self->skin) = newSkin; +} + +spAttachment* spSkeleton_getAttachmentForSlotName (const spSkeleton* self, const char* slotName, const char* attachmentName) { + int slotIndex = spSkeletonData_findSlotIndex(self->data, slotName); + return spSkeleton_getAttachmentForSlotIndex(self, slotIndex, attachmentName); +} + +spAttachment* spSkeleton_getAttachmentForSlotIndex (const spSkeleton* self, int slotIndex, const char* attachmentName) { + if (slotIndex == -1) return 0; + if (self->skin) { + spAttachment *attachment = spSkin_getAttachment(self->skin, slotIndex, attachmentName); + if (attachment) return attachment; + } + if (self->data->defaultSkin) { + spAttachment *attachment = spSkin_getAttachment(self->data->defaultSkin, slotIndex, attachmentName); + if (attachment) return attachment; + } + return 0; +} + +int spSkeleton_setAttachment (spSkeleton* self, const char* slotName, const char* attachmentName) { + int i; + for (i = 0; i < self->slotsCount; ++i) { + spSlot *slot = self->slots[i]; + if (strcmp(slot->data->name, slotName) == 0) { + if (!attachmentName) + spSlot_setAttachment(slot, 0); + else { + spAttachment* attachment = spSkeleton_getAttachmentForSlotIndex(self, i, attachmentName); + if (!attachment) return 0; + spSlot_setAttachment(slot, attachment); + } + return 1; + } + } + return 0; +} + +spIkConstraint* spSkeleton_findIkConstraint (const spSkeleton* self, const char* constraintName) { + int i; + for (i = 0; i < self->ikConstraintsCount; ++i) + if (strcmp(self->ikConstraints[i]->data->name, constraintName) == 0) return self->ikConstraints[i]; + return 0; +} + +spTransformConstraint* spSkeleton_findTransformConstraint (const spSkeleton* self, const char* constraintName) { + int i; + for (i = 0; i < self->transformConstraintsCount; ++i) + if (strcmp(self->transformConstraints[i]->data->name, constraintName) == 0) return self->transformConstraints[i]; + return 0; +} + +spPathConstraint* spSkeleton_findPathConstraint (const spSkeleton* self, const char* constraintName) { + int i; + for (i = 0; i < self->pathConstraintsCount; ++i) + if (strcmp(self->pathConstraints[i]->data->name, constraintName) == 0) return self->pathConstraints[i]; + return 0; +} + +void spSkeleton_update (spSkeleton* self, float deltaTime) { + self->time += deltaTime; } diff --git a/spine-c/src/spine/SkeletonBinary.c b/spine-c/src/spine/SkeletonBinary.c index 2cde56d701..2084e1330a 100644 --- a/spine-c/src/spine/SkeletonBinary.c +++ b/spine-c/src/spine/SkeletonBinary.c @@ -1,1032 +1,1031 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include -#include -#include -#include "kvec.h" - -typedef struct { - const unsigned char* cursor; - const unsigned char* end; -} _dataInput; - -typedef struct { - const char* parent; - const char* skin; - int slotIndex; - spMeshAttachment* mesh; -} _spLinkedMesh; - -typedef struct { - spSkeletonBinary super; - int ownsLoader; - - int linkedMeshCount; - int linkedMeshCapacity; - _spLinkedMesh* linkedMeshes; -} _spSkeletonBinary; - -spSkeletonBinary* spSkeletonBinary_createWithLoader (spAttachmentLoader* attachmentLoader) { - spSkeletonBinary* self = SUPER(NEW(_spSkeletonBinary)); - self->scale = 1; - self->attachmentLoader = attachmentLoader; - return self; -} - -spSkeletonBinary* spSkeletonBinary_create (spAtlas* atlas) { - spAtlasAttachmentLoader* attachmentLoader = spAtlasAttachmentLoader_create(atlas); - spSkeletonBinary* self = spSkeletonBinary_createWithLoader(SUPER(attachmentLoader)); - SUB_CAST(_spSkeletonBinary, self)->ownsLoader = 1; - return self; -} - -void spSkeletonBinary_dispose (spSkeletonBinary* self) { - int i; - _spSkeletonBinary* internal = SUB_CAST(_spSkeletonBinary, self); - if (internal->ownsLoader) spAttachmentLoader_dispose(self->attachmentLoader); - for (i = 0; i < internal->linkedMeshCount; ++i) { - FREE(internal->linkedMeshes[i].parent); - FREE(internal->linkedMeshes[i].skin); - } - FREE(internal->linkedMeshes); - FREE(self->error); - FREE(self); -} - -void _spSkeletonBinary_setError (spSkeletonBinary* self, const char* value1, const char* value2) { - char message[256]; - int length; - FREE(self->error); - strcpy(message, value1); - length = (int)strlen(value1); - if (value2) strncat(message + length, value2, 255 - length); - MALLOC_STR(self->error, message); -} - -static unsigned char readByte (_dataInput* input) { - return *input->cursor++; -} - -static char readSByte (_dataInput* input) { - return (char)readByte(input); -} - -static int readBoolean (_dataInput* input) { - return readByte(input) != 0; -} - -static int readInt (_dataInput* input) { - int result = readByte(input); - result <<= 8; - result |= readByte(input); - result <<= 8; - result |= readByte(input); - result <<= 8; - result |= readByte(input); - return result; -} - -static int readVarint (_dataInput* input, int/*bool*/optimizePositive) { - unsigned char b = readByte(input); - int value = b & 0x7F; - if (b & 0x80) { - b = readByte(input); - value |= (b & 0x7F) << 7; - if (b & 0x80) { - b = readByte(input); - value |= (b & 0x7F) << 14; - if (b & 0x80) { - b = readByte(input); - value |= (b & 0x7F) << 21; - if (b & 0x80) value |= (readByte(input) & 0x7F) << 28; - } - } - } - if (!optimizePositive) value = (((unsigned int)value >> 1) ^ -(value & 1)); - return value; -} - -float readFloat (_dataInput* input) { - union { - int intValue; - float floatValue; - } intToFloat; - intToFloat.intValue = readInt(input); - return intToFloat.floatValue; -} - -char* readString (_dataInput* input) { - int length = readVarint(input, 1); - char* string; - if (length == 0) { - return 0; - } - string = MALLOC(char, length); - memcpy(string, input->cursor, length - 1); - input->cursor += length - 1; - string[length - 1] = '\0'; - return string; -} - -static void readColor (_dataInput* input, float *r, float *g, float *b, float *a) { - *r = readByte(input) / 255.0f; - *g = readByte(input) / 255.0f; - *b = readByte(input) / 255.0f; - *a = readByte(input) / 255.0f; -} - -#define ATTACHMENT_REGION 0 -#define ATTACHMENT_BOUNDING_BOX 1 -#define ATTACHMENT_MESH 2 -#define ATTACHMENT_LINKED_MESH 3 -#define ATTACHMENT_PATH 4 - -#define BLEND_MODE_NORMAL 0 -#define BLEND_MODE_ADDITIVE 1 -#define BLEND_MODE_MULTIPLY 2 -#define BLEND_MODE_SCREEN 3 - -#define CURVE_LINEAR 0 -#define CURVE_STEPPED 1 -#define CURVE_BEZIER 2 - -#define BONE_ROTATE 0 -#define BONE_TRANSLATE 1 -#define BONE_SCALE 2 -#define BONE_SHEAR 3 - -#define SLOT_ATTACHMENT 0 -#define SLOT_COLOR 1 - -#define PATH_POSITION 0 -#define PATH_SPACING 1 -#define PATH_MIX 2 - -#define PATH_POSITION_FIXED 0 -#define PATH_POSITION_PERCENT 1 - -#define PATH_SPACING_LENGTH 0 -#define PATH_SPACING_FIXED 1 -#define PATH_SPACING_PERCENT 2 - -#define PATH_ROTATE_TANGENT 0 -#define PATH_ROTATE_CHAIN 1 -#define PATH_ROTATE_CHAIN_SCALE 2 - -static void readCurve (_dataInput* input, spCurveTimeline* timeline, int frameIndex) { - switch (readByte(input)) { - case CURVE_STEPPED: { - spCurveTimeline_setStepped(timeline, frameIndex); - break; - } - case CURVE_BEZIER: { - float cx1 = readFloat(input); - float cy1 = readFloat(input); - float cx2 = readFloat(input); - float cy2 = readFloat(input); - spCurveTimeline_setCurve(timeline, frameIndex, cx1, cy1, cx2, cy2); - break; - } - } -} - -static void _spSkeletonBinary_addLinkedMesh (spSkeletonBinary* self, spMeshAttachment* mesh, - const char* skin, int slotIndex, const char* parent) { - _spLinkedMesh* linkedMesh; - _spSkeletonBinary* internal = SUB_CAST(_spSkeletonBinary, self); - - if (internal->linkedMeshCount == internal->linkedMeshCapacity) { - _spLinkedMesh* linkedMeshes; - internal->linkedMeshCapacity *= 2; - if (internal->linkedMeshCapacity < 8) internal->linkedMeshCapacity = 8; - /* TODO Why not realloc? */ - linkedMeshes = MALLOC(_spLinkedMesh, internal->linkedMeshCapacity); - memcpy(linkedMeshes, internal->linkedMeshes, sizeof(_spLinkedMesh) * internal->linkedMeshCount); - FREE(internal->linkedMeshes); - internal->linkedMeshes = linkedMeshes; - } - - linkedMesh = internal->linkedMeshes + internal->linkedMeshCount++; - linkedMesh->mesh = mesh; - linkedMesh->skin = skin; - linkedMesh->slotIndex = slotIndex; - linkedMesh->parent = parent; -} - -static spAnimation* _spSkeletonBinary_readAnimation (spSkeletonBinary* self, const char* name, - _dataInput* input, spSkeletonData *skeletonData) { - kvec_t(spTimeline*) timelines; - float duration = 0; - int i, n, ii, nn, iii, nnn; - int frameIndex; - int drawOrderCount, eventCount; - spAnimation* animation; - - kv_init(timelines); - - /* Slot timelines. */ - for (i = 0, n = readVarint(input, 1); i < n; ++i) { - int slotIndex = readVarint(input, 1); - for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) { - unsigned char timelineType = readByte(input); - int frameCount = readVarint(input, 1); - switch (timelineType) { - case SLOT_COLOR: { - spColorTimeline* timeline = spColorTimeline_create(frameCount); - timeline->slotIndex = slotIndex; - for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); - float r, g, b, a; - readColor(input, &r, &g, &b, &a); - spColorTimeline_setFrame(timeline, frameIndex, time, r, g, b, a); - if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); - } - kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); - duration = MAX(duration, timeline->frames[(frameCount - 1) * COLOR_ENTRIES]); - break; - } - case SLOT_ATTACHMENT: { - spAttachmentTimeline* timeline = spAttachmentTimeline_create(frameCount); - timeline->slotIndex = slotIndex; - for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); - const char* attachmentName = readString(input); - /* TODO Avoid copying of attachmentName inside */ - spAttachmentTimeline_setFrame(timeline, frameIndex, time, attachmentName); - FREE(attachmentName); - } - kv_push(spTimeline*, timelines, SUPER(timeline)); - duration = MAX(duration, timeline->frames[frameCount - 1]); - break; - } - default: { - int i; - for (i = 0; i < kv_size(timelines); ++i) - spTimeline_dispose(kv_A(timelines, i)); - kv_destroy(timelines); - _spSkeletonBinary_setError(self, "Invalid timeline type for a slot: ", skeletonData->slots[slotIndex]->name); - return 0; - } - } - } - } - - /* Bone timelines. */ - for (i = 0, n = readVarint(input, 1); i < n; ++i) { - int boneIndex = readVarint(input, 1); - for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) { - unsigned char timelineType = readByte(input); - int frameCount = readVarint(input, 1); - switch (timelineType) { - case BONE_ROTATE: { - spRotateTimeline *timeline = spRotateTimeline_create(frameCount); - timeline->boneIndex = boneIndex; - for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); - float degrees = readFloat(input); - spRotateTimeline_setFrame(timeline, frameIndex, time, degrees); - if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); - } - kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); - duration = MAX(duration, timeline->frames[(frameCount - 1) * ROTATE_ENTRIES]); - break; - } - case BONE_TRANSLATE: - case BONE_SCALE: - case BONE_SHEAR: { - float timelineScale = 1; - spTranslateTimeline *timeline = 0; - switch (timelineType) { - case BONE_SCALE: - timeline = spScaleTimeline_create(frameCount); - break; - case BONE_SHEAR: - timeline = spShearTimeline_create(frameCount); - break; - case BONE_TRANSLATE: - timeline = spTranslateTimeline_create(frameCount); - timelineScale = self->scale; - break; - default: - break; - } - timeline->boneIndex = boneIndex; - for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); - float x = readFloat(input) * timelineScale; - float y = readFloat(input) * timelineScale; - spTranslateTimeline_setFrame(timeline, frameIndex, time, x, y); - if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); - } - kv_push(spTimeline*, timelines, SUPER_CAST(spTimeline, timeline)); - duration = MAX(duration, timeline->frames[(frameCount - 1) * TRANSLATE_ENTRIES]); - break; - } - default: { - int i; - for (i = 0; i < kv_size(timelines); ++i) - spTimeline_dispose(kv_A(timelines, i)); - kv_destroy(timelines); - _spSkeletonBinary_setError(self, "Invalid timeline type for a bone: ", skeletonData->bones[boneIndex]->name); - return 0; - } - } - } - } - - /* IK constraint timelines. */ - for (i = 0, n = readVarint(input, 1); i < n; ++i) { - int index = readVarint(input, 1); - int frameCount = readVarint(input, 1); - spIkConstraintTimeline* timeline = spIkConstraintTimeline_create(frameCount); - timeline->ikConstraintIndex = index; - for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); - float mix = readFloat(input); - char bendDirection = readSByte(input); - spIkConstraintTimeline_setFrame(timeline, frameIndex, time, mix, bendDirection); - if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); - } - kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); - duration = MAX(duration, timeline->frames[(frameCount - 1) * IKCONSTRAINT_ENTRIES]); - } - - /* Transform constraint timelines. */ - for (i = 0, n = readVarint(input, 1); i < n; ++i) { - int index = readVarint(input, 1); - int frameCount = readVarint(input, 1); - spTransformConstraintTimeline* timeline = spTransformConstraintTimeline_create(frameCount); - timeline->transformConstraintIndex = index; - for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); - float rotateMix = readFloat(input); - float translateMix = readFloat(input); - float scaleMix = readFloat(input); - float shearMix = readFloat(input); - spTransformConstraintTimeline_setFrame(timeline, frameIndex, time, rotateMix, translateMix, - scaleMix, shearMix); - if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); - } - kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); - duration = MAX(duration, timeline->frames[(frameCount - 1) * TRANSFORMCONSTRAINT_ENTRIES]); - } - - /* Path constraint timelines. */ - for (i = 0, n = readVarint(input, 1); i < n; ++i) { - int index = readVarint(input, 1); - spPathConstraintData* data = skeletonData->pathConstraints[index]; - for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) { - unsigned char timelineType = readByte(input); - int frameCount = readVarint(input, 1); - switch (timelineType) { - case PATH_POSITION: - case PATH_SPACING: { - spPathConstraintPositionTimeline* timeline = 0; - float timelineScale = 1; - if (timelineType == PATH_SPACING) { - timeline = (spPathConstraintPositionTimeline*)spPathConstraintSpacingTimeline_create(frameCount); - if (data->spacingMode == SP_SPACING_MODE_LENGTH || data->spacingMode == SP_SPACING_MODE_FIXED) - timelineScale = self->scale; - } else { - timeline = spPathConstraintPositionTimeline_create(frameCount); - if (data->positionMode == SP_POSITION_MODE_FIXED) - timelineScale = self->scale; - } - timeline->pathConstraintIndex = index; - for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); - float value = readFloat(input) * timelineScale; - spPathConstraintPositionTimeline_setFrame(timeline, frameIndex, time, value); - if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); - } - kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); - duration = MAX(duration, timeline->frames[(frameCount - 1) * PATHCONSTRAINTPOSITION_ENTRIES]); - break; - } - case PATH_MIX: { - spPathConstraintMixTimeline* timeline = spPathConstraintMixTimeline_create(frameCount); - timeline->pathConstraintIndex = index; - for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); - float rotateMix = readFloat(input); - float translateMix = readFloat(input); - spPathConstraintMixTimeline_setFrame(timeline, frameIndex, time, rotateMix, translateMix); - if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); - } - kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); - duration = MAX(duration, timeline->frames[(frameCount - 1) * PATHCONSTRAINTMIX_ENTRIES]); - } - } - } - } - - /* Deform timelines. */ - for (i = 0, n = readVarint(input, 1); i < n; ++i) { - spSkin* skin = skeletonData->skins[readVarint(input, 1)]; - for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) { - int slotIndex = readVarint(input, 1); - for (iii = 0, nnn = readVarint(input, 1); iii < nnn; ++iii) { - float* tempDeform; - spDeformTimeline *timeline; - int weighted, deformLength; - const char* attachmentName = readString(input); - int frameCount; - - spVertexAttachment* attachment = SUB_CAST(spVertexAttachment, - spSkin_getAttachment(skin, slotIndex, attachmentName)); - if (!attachment) { - int i; - for (i = 0; i < kv_size(timelines); ++i) - spTimeline_dispose(kv_A(timelines, i)); - kv_destroy(timelines); - _spSkeletonBinary_setError(self, "Attachment not found: ", attachmentName); - FREE(attachmentName); - return 0; - } - FREE(attachmentName); - - weighted = attachment->bones != 0; - deformLength = weighted ? attachment->verticesCount / 3 * 2 : attachment->verticesCount; - tempDeform = MALLOC(float, deformLength); - - frameCount = readVarint(input, 1); - timeline = spDeformTimeline_create(frameCount, deformLength); - timeline->slotIndex = slotIndex; - timeline->attachment = SUPER(attachment); - - for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - float time = readFloat(input); - float* deform; - int end = readVarint(input, 1); - if (!end) { - if (weighted) { - deform = tempDeform; - memset(deform, 0, sizeof(float) * deformLength); - } else - deform = attachment->vertices; - } else { - int v, start = readVarint(input, 1); - deform = tempDeform; - memset(deform, 0, sizeof(float) * start); - end += start; - if (self->scale == 1) { - for (v = start; v < end; ++v) - deform[v] = readFloat(input); - } else { - for (v = start; v < end; ++v) - deform[v] = readFloat(input) * self->scale; - } - memset(deform + v, 0, sizeof(float) * (deformLength - v)); - if (!weighted) { - float* vertices = attachment->vertices; - for (v = 0; v < deformLength; ++v) - deform[v] += vertices[v]; - } - } - spDeformTimeline_setFrame(timeline, frameIndex, time, deform); - if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); - } - FREE(tempDeform); - - kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); - duration = MAX(duration, timeline->frames[frameCount - 1]); - } - } - } - - /* Draw order timeline. */ - drawOrderCount = readVarint(input, 1); - if (drawOrderCount) { - spDrawOrderTimeline* timeline = spDrawOrderTimeline_create(drawOrderCount, skeletonData->slotsCount); - for (i = 0; i < drawOrderCount; ++i) { - float time = readFloat(input); - int offsetCount = readVarint(input, 1); - int* drawOrder = MALLOC(int, skeletonData->slotsCount); - int* unchanged = MALLOC(int, skeletonData->slotsCount - offsetCount); - int originalIndex = 0, unchangedIndex = 0; - memset(drawOrder, -1, sizeof(int) * skeletonData->slotsCount); - for (ii = 0; ii < offsetCount; ++ii) { - int slotIndex = readVarint(input, 1); - /* Collect unchanged items. */ - while (originalIndex != slotIndex) - unchanged[unchangedIndex++] = originalIndex++; - /* Set changed items. */ - drawOrder[originalIndex + readVarint(input, 1)] = originalIndex; - ++originalIndex; - } - /* Collect remaining unchanged items. */ - while (originalIndex < skeletonData->slotsCount) - unchanged[unchangedIndex++] = originalIndex++; - /* Fill in unchanged items. */ - for (ii = skeletonData->slotsCount - 1; ii >= 0; ii--) - if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex]; - FREE(unchanged); - /* TODO Avoid copying of drawOrder inside */ - spDrawOrderTimeline_setFrame(timeline, i, time, drawOrder); - FREE(drawOrder); - } - kv_push(spTimeline*, timelines, SUPER(timeline)); - duration = MAX(duration, timeline->frames[drawOrderCount - 1]); - } - - /* Event timeline. */ - eventCount = readVarint(input, 1); - if (eventCount) { - spEventTimeline* timeline = spEventTimeline_create(eventCount); - for (i = 0; i < eventCount; ++i) { - float time = readFloat(input); - spEventData* eventData = skeletonData->events[readVarint(input, 1)]; - spEvent* event = spEvent_create(time, eventData); - event->intValue = readVarint(input, 0); - event->floatValue = readFloat(input); - if (readBoolean(input)) - event->stringValue = readString(input); - else - MALLOC_STR(event->stringValue, eventData->stringValue); - spEventTimeline_setFrame(timeline, i, event); - } - kv_push(spTimeline*, timelines, SUPER(timeline)); - duration = MAX(duration, timeline->frames[eventCount - 1]); - } - - kv_trim(spTimeline*, timelines); - - animation = spAnimation_create(name, 0); - animation->duration = duration; - animation->timelinesCount = kv_size(timelines); - animation->timelines = kv_array(timelines); - return animation; -} - -static float* _readFloatArray(_dataInput *input, int n, float scale) { - float* array = MALLOC(float, n); - int i; - if (scale == 1) - for (i = 0; i < n; ++i) - array[i] = readFloat(input); - else - for (i = 0; i < n; ++i) - array[i] = readFloat(input) * scale; - return array; -} - -static short* _readShortArray(_dataInput *input, int *length) { - int n = readVarint(input, 1); - short* array = MALLOC(short, n); - int i; - *length = n; - for (i = 0; i < n; ++i) { - array[i] = readByte(input) << 8; - array[i] |= readByte(input); - } - return array; -} - -static void _readVertices(spSkeletonBinary* self, _dataInput* input, spVertexAttachment* attachment, - int vertexCount) { - int i, ii; - int verticesLength = vertexCount << 1; - kvec_t(float) weights; - kvec_t(int) bones; - - attachment->worldVerticesLength = verticesLength; - - if (!readBoolean(input)) { - attachment->verticesCount = verticesLength; - attachment->vertices = _readFloatArray(input, verticesLength, self->scale); - attachment->bonesCount = 0; - attachment->bones = 0; - return; - } - - kv_init(weights); - kv_resize(float, weights, verticesLength * 3 * 3); - - kv_init(bones); - kv_resize(int, bones, verticesLength * 3); - - for (i = 0; i < vertexCount; ++i) { - int boneCount = readVarint(input, 1); - kv_push(int, bones, boneCount); - for (ii = 0; ii < boneCount; ++ii) { - kv_push(int, bones, readVarint(input, 1)); - kv_push(float, weights, readFloat(input) * self->scale); - kv_push(float, weights, readFloat(input) * self->scale); - kv_push(float, weights, readFloat(input)); - } - } - - kv_trim(float, weights); - attachment->verticesCount = kv_size(weights); - attachment->vertices = kv_array(weights); - - kv_trim(int, bones); - attachment->bonesCount = kv_size(bones); - attachment->bones = kv_array(bones); -} - -spAttachment* spSkeletonBinary_readAttachment(spSkeletonBinary* self, _dataInput* input, - spSkin* skin, int slotIndex, const char* attachmentName, int/*bool*/ nonessential) { - int i; - spAttachmentType type; - const char* name = readString(input); - int freeName = name != 0; - if (!name) { - freeName = 0; - name = attachmentName; - } - - type = (spAttachmentType)readByte(input); - - switch (type) { - case SP_ATTACHMENT_REGION: { - const char* path = readString(input); - spAttachment* attachment; - spRegionAttachment* region; - if (!path) MALLOC_STR(path, name); - attachment = spAttachmentLoader_createAttachment( - self->attachmentLoader, skin, type, name, path); - region = SUB_CAST(spRegionAttachment, attachment); - region->path = path; - region->rotation = readFloat(input); - region->x = readFloat(input) * self->scale; - region->y = readFloat(input) * self->scale; - region->scaleX = readFloat(input); - region->scaleY = readFloat(input); - region->width = readFloat(input) * self->scale; - region->height = readFloat(input) * self->scale; - readColor(input, ®ion->r, ®ion->g, ®ion->b, ®ion->a); - spRegionAttachment_updateOffset(region); - spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); - if (freeName) FREE(name); - return attachment; - } - case SP_ATTACHMENT_BOUNDING_BOX: { - int vertexCount = readVarint(input, 1); - spAttachment* attachment = spAttachmentLoader_createAttachment( - self->attachmentLoader, skin, type, name, 0); - _readVertices(self, input, SUB_CAST(spVertexAttachment, attachment), vertexCount); - if (nonessential) readInt(input); /* Skip color. */ - spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); - if (freeName) FREE(name); - return attachment; - } - case SP_ATTACHMENT_MESH: { - int vertexCount; - spAttachment* attachment; - spMeshAttachment* mesh; - const char* path = readString(input); - if (!path) MALLOC_STR(path, name); - attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, path); - mesh = SUB_CAST(spMeshAttachment, attachment); - mesh->path = path; - readColor(input, &mesh->r, &mesh->g, &mesh->b, &mesh->a); - vertexCount = readVarint(input, 1); - mesh->regionUVs = _readFloatArray(input, vertexCount << 1, 1); - mesh->triangles = (unsigned short*)_readShortArray(input, &mesh->trianglesCount); - _readVertices(self, input, SUPER(mesh), vertexCount); - spMeshAttachment_updateUVs(mesh); - mesh->hullLength = readVarint(input, 1) << 1; - if (nonessential) { - mesh->edges = (int*)_readShortArray(input, &mesh->edgesCount); - mesh->width = readFloat(input) * self->scale; - mesh->height = readFloat(input) * self->scale; - } else { - mesh->edges = 0; - mesh->width = 0; - mesh->height = 0; - } - spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); - if (freeName) FREE(name); - return attachment; - } - case SP_ATTACHMENT_LINKED_MESH: { - const char* skinName; - const char* parent; - spAttachment* attachment; - spMeshAttachment* mesh; - const char* path = readString(input); - if (!path) MALLOC_STR(path, name); - attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, path); - mesh = SUB_CAST(spMeshAttachment, attachment); - mesh->path = path; - readColor(input, &mesh->r, &mesh->g, &mesh->b, &mesh->a); - skinName = readString(input); - parent = readString(input); - mesh->inheritDeform = readBoolean(input); - if (nonessential) { - mesh->width = readFloat(input) * self->scale; - mesh->height = readFloat(input) * self->scale; - } - _spSkeletonBinary_addLinkedMesh(self, mesh, skinName, slotIndex, parent); - if (freeName) FREE(name); - return attachment; - } - case SP_ATTACHMENT_PATH: { - spAttachment* attachment = spAttachmentLoader_createAttachment( - self->attachmentLoader, skin, type, name, 0); - spPathAttachment* path = SUB_CAST(spPathAttachment, attachment); - int vertexCount = 0; - path->closed = readBoolean(input); - path->constantSpeed = readBoolean(input); - vertexCount = readVarint(input, 1); - _readVertices(self, input, SUPER(path), vertexCount); - path->lengthsLength = vertexCount / 3; - path->lengths = MALLOC(float, path->lengthsLength); - for (i = 0; i < path->lengthsLength; ++i) { - path->lengths[i] = readFloat(input) * self->scale; - } - if (nonessential) readInt(input); /* Skip color. */ - if (freeName) FREE(name); - return attachment; - } - } - - if (freeName) FREE(name); - return 0; -} - -spSkin* spSkeletonBinary_readSkin(spSkeletonBinary* self, _dataInput* input, - const char* skinName, int/*bool*/ nonessential) { - spSkin* skin; - int slotCount = readVarint(input, 1); - int i, ii, nn; - if (slotCount == 0) - return 0; - skin = spSkin_create(skinName); - for (i = 0; i < slotCount; ++i) { - int slotIndex = readVarint(input, 1); - for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) { - const char* name = readString(input); - spSkin_addAttachment(skin, slotIndex, name, - spSkeletonBinary_readAttachment(self, input, skin, slotIndex, name, nonessential)); - FREE(name); - } - } - return skin; -} - -spSkeletonData* spSkeletonBinary_readSkeletonDataFile (spSkeletonBinary* self, const char* path) { - int length; - spSkeletonData* skeletonData; - const char* binary = _spUtil_readFile(path, &length); - if (length == 0 || !binary) { - _spSkeletonBinary_setError(self, "Unable to read skeleton file: ", path); - return 0; - } - skeletonData = spSkeletonBinary_readSkeletonData(self, (unsigned char*)binary, length); - FREE(binary); - return skeletonData; -} - -spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const unsigned char* binary, - const int length) { - int i, ii, nonessential; - spSkeletonData* skeletonData; - _spSkeletonBinary* internal = SUB_CAST(_spSkeletonBinary, self); - - _dataInput* input = NEW(_dataInput); - input->cursor = binary; - input->end = binary + length; - - FREE(self->error); - CONST_CAST(char*, self->error) = 0; - internal->linkedMeshCount = 0; - - skeletonData = spSkeletonData_create(); - - skeletonData->hash = readString(input); - if (!strlen(skeletonData->hash)) { - FREE(skeletonData->hash); - skeletonData->hash = 0; - } - - skeletonData->version = readString(input); - if (!strlen(skeletonData->version)) { - FREE(skeletonData->version); - skeletonData->version = 0; - } - - skeletonData->width = readFloat(input); - skeletonData->height = readFloat(input); - - nonessential = readBoolean(input); - - if (nonessential) FREE(readString(input)); /* Skip images path. */ - - /* Bones. */ - skeletonData->bonesCount = readVarint(input, 1); - skeletonData->bones = MALLOC(spBoneData*, skeletonData->bonesCount); - for (i = 0; i < skeletonData->bonesCount; ++i) { - spBoneData* data; - const char* name = readString(input); - spBoneData* parent = i == 0 ? 0 : skeletonData->bones[readVarint(input, 1)]; - /* TODO Avoid copying of name */ - data = spBoneData_create(i, name, parent); - FREE(name); - data->rotation = readFloat(input); - data->x = readFloat(input) * self->scale; - data->y = readFloat(input) * self->scale; - data->scaleX = readFloat(input); - data->scaleY = readFloat(input); - data->shearX = readFloat(input); - data->shearY = readFloat(input); - data->length = readFloat(input) * self->scale; - data->inheritRotation = readBoolean(input); - data->inheritScale = readBoolean(input); - if (nonessential) readInt(input); /* Skip bone color. */ - skeletonData->bones[i] = data; - } - - /* Slots. */ - skeletonData->slotsCount = readVarint(input, 1); - skeletonData->slots = MALLOC(spSlotData*, skeletonData->slotsCount); - for (i = 0; i < skeletonData->slotsCount; ++i) { - const char* slotName = readString(input); - spBoneData* boneData = skeletonData->bones[readVarint(input, 1)]; - /* TODO Avoid copying of slotName */ - spSlotData* slotData = spSlotData_create(i, slotName, boneData); - FREE(slotName); - readColor(input, &slotData->r, &slotData->g, &slotData->b, &slotData->a); - slotData->attachmentName = readString(input); - slotData->blendMode = (spBlendMode)readVarint(input, 1); - skeletonData->slots[i] = slotData; - } - - /* IK constraints. */ - skeletonData->ikConstraintsCount = readVarint(input, 1); - skeletonData->ikConstraints = MALLOC(spIkConstraintData*, skeletonData->ikConstraintsCount); - for (i = 0; i < skeletonData->ikConstraintsCount; ++i) { - const char* name = readString(input); - /* TODO Avoid copying of name */ - spIkConstraintData* data = spIkConstraintData_create(name); - FREE(name); - data->bonesCount = readVarint(input, 1); - data->bones = MALLOC(spBoneData*, data->bonesCount); - for (ii = 0; ii < data->bonesCount; ++ii) - data->bones[ii] = skeletonData->bones[readVarint(input, 1)]; - data->target = skeletonData->bones[readVarint(input, 1)]; - data->mix = readFloat(input); - data->bendDirection = readSByte(input); - skeletonData->ikConstraints[i] = data; - } - - /* Transform constraints. */ - skeletonData->transformConstraintsCount = readVarint(input, 1); - skeletonData->transformConstraints = MALLOC( - spTransformConstraintData*, skeletonData->transformConstraintsCount); - for (i = 0; i < skeletonData->transformConstraintsCount; ++i) { - const char* name = readString(input); - /* TODO Avoid copying of name */ - spTransformConstraintData* data = spTransformConstraintData_create(name); - FREE(name); - data->bonesCount = readVarint(input, 1); - CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, data->bonesCount); - for (ii = 0; ii < data->bonesCount; ++ii) - data->bones[ii] = skeletonData->bones[readVarint(input, 1)]; - data->target = skeletonData->bones[readVarint(input, 1)]; - data->offsetRotation = readFloat(input); - data->offsetX = readFloat(input) * self->scale; - data->offsetY = readFloat(input) * self->scale; - data->offsetScaleX = readFloat(input); - data->offsetScaleY = readFloat(input); - data->offsetShearY = readFloat(input); - data->rotateMix = readFloat(input); - data->translateMix = readFloat(input); - data->scaleMix = readFloat(input); - data->shearMix = readFloat(input); - skeletonData->transformConstraints[i] = data; - } - - /* Path constraints */ - skeletonData->pathConstraintsCount = readVarint(input, 1); - skeletonData->pathConstraints = MALLOC(spPathConstraintData*, skeletonData->pathConstraintsCount); - for (i = 0; i < skeletonData->pathConstraintsCount; ++i) { - const char* name = readString(input); - /* TODO Avoid copying of name */ - spPathConstraintData* data = spPathConstraintData_create(name); - FREE(name); - data->bonesCount = readVarint(input, 1); - CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, data->bonesCount); - for (ii = 0; ii < data->bonesCount; ++ii) - data->bones[ii] = skeletonData->bones[readVarint(input, 1)]; - data->target = skeletonData->slots[readVarint(input, 1)]; - data->positionMode = (spPositionMode)readVarint(input, 1); - data->spacingMode = (spSpacingMode)readVarint(input, 1); - data->rotateMode = (spRotateMode)readVarint(input, 1); - data->offsetRotation = readFloat(input); - data->position = readFloat(input); - if (data->positionMode == SP_POSITION_MODE_FIXED) data->position *= self->scale; - data->spacing = readFloat(input); - if (data->spacingMode == SP_SPACING_MODE_LENGTH || data->spacingMode == SP_SPACING_MODE_FIXED) data->spacing *= self->scale; - data->rotateMix = readFloat(input); - data->translateMix = readFloat(input); - skeletonData->pathConstraints[i] = data; - } - - /* Default skin. */ - skeletonData->defaultSkin = spSkeletonBinary_readSkin(self, input, "default", nonessential); - skeletonData->skinsCount = readVarint(input, 1); - - if (skeletonData->defaultSkin) - ++skeletonData->skinsCount; - - skeletonData->skins = MALLOC(spSkin*, skeletonData->skinsCount); - - if (skeletonData->defaultSkin) - skeletonData->skins[0] = skeletonData->defaultSkin; - - /* Skins. */ - for (i = skeletonData->defaultSkin ? 1 : 0; i < skeletonData->skinsCount; ++i) { - const char* skinName = readString(input); - /* TODO Avoid copying of skinName */ - skeletonData->skins[i] = spSkeletonBinary_readSkin(self, input, skinName, nonessential); - FREE(skinName); - } - - /* Linked meshes. */ - for (i = 0; i < internal->linkedMeshCount; ++i) { - _spLinkedMesh* linkedMesh = internal->linkedMeshes + i; - spSkin* skin = !linkedMesh->skin ? skeletonData->defaultSkin : spSkeletonData_findSkin(skeletonData, linkedMesh->skin); - spAttachment* parent; - if (!skin) { - FREE(input); - spSkeletonData_dispose(skeletonData); - _spSkeletonBinary_setError(self, "Skin not found: ", linkedMesh->skin); - return 0; - } - parent = spSkin_getAttachment(skin, linkedMesh->slotIndex, linkedMesh->parent); - if (!parent) { - FREE(input); - spSkeletonData_dispose(skeletonData); - _spSkeletonBinary_setError(self, "Parent mesh not found: ", linkedMesh->parent); - return 0; - } - spMeshAttachment_setParentMesh(linkedMesh->mesh, SUB_CAST(spMeshAttachment, parent)); - spMeshAttachment_updateUVs(linkedMesh->mesh); - spAttachmentLoader_configureAttachment(self->attachmentLoader, SUPER(SUPER(linkedMesh->mesh))); - } - - /* Events. */ - skeletonData->eventsCount = readVarint(input, 1); - skeletonData->events = MALLOC(spEventData*, skeletonData->eventsCount); - for (i = 0; i < skeletonData->eventsCount; ++i) { - const char* name = readString(input); - /* TODO Avoid copying of skinName */ - spEventData* eventData = spEventData_create(name); - FREE(name); - eventData->intValue = readVarint(input, 0); - eventData->floatValue = readFloat(input); - eventData->stringValue = readString(input); - skeletonData->events[i] = eventData; - } - - /* Animations. */ - skeletonData->animationsCount = readVarint(input, 1); - skeletonData->animations = MALLOC(spAnimation*, skeletonData->animationsCount); - for (i = 0; i < skeletonData->animationsCount; ++i) { - const char* name = readString(input); - spAnimation* animation = _spSkeletonBinary_readAnimation(self, name, input, skeletonData); - FREE(name); - if (!animation) { - FREE(input); - spSkeletonData_dispose(skeletonData); - return 0; - } - skeletonData->animations[i] = animation; - } - - FREE(input); - return skeletonData; +#include +#include +#include +#include +#include +#include "kvec.h" + +typedef struct { + const unsigned char* cursor; + const unsigned char* end; +} _dataInput; + +typedef struct { + const char* parent; + const char* skin; + int slotIndex; + spMeshAttachment* mesh; +} _spLinkedMesh; + +typedef struct { + spSkeletonBinary super; + int ownsLoader; + + int linkedMeshCount; + int linkedMeshCapacity; + _spLinkedMesh* linkedMeshes; +} _spSkeletonBinary; + +spSkeletonBinary* spSkeletonBinary_createWithLoader (spAttachmentLoader* attachmentLoader) { + spSkeletonBinary* self = SUPER(NEW(_spSkeletonBinary)); + self->scale = 1; + self->attachmentLoader = attachmentLoader; + return self; +} + +spSkeletonBinary* spSkeletonBinary_create (spAtlas* atlas) { + spAtlasAttachmentLoader* attachmentLoader = spAtlasAttachmentLoader_create(atlas); + spSkeletonBinary* self = spSkeletonBinary_createWithLoader(SUPER(attachmentLoader)); + SUB_CAST(_spSkeletonBinary, self)->ownsLoader = 1; + return self; +} + +void spSkeletonBinary_dispose (spSkeletonBinary* self) { + int i; + _spSkeletonBinary* internal = SUB_CAST(_spSkeletonBinary, self); + if (internal->ownsLoader) spAttachmentLoader_dispose(self->attachmentLoader); + for (i = 0; i < internal->linkedMeshCount; ++i) { + FREE(internal->linkedMeshes[i].parent); + FREE(internal->linkedMeshes[i].skin); + } + FREE(internal->linkedMeshes); + FREE(self->error); + FREE(self); +} + +void _spSkeletonBinary_setError (spSkeletonBinary* self, const char* value1, const char* value2) { + char message[256]; + int length; + FREE(self->error); + strcpy(message, value1); + length = (int)strlen(value1); + if (value2) strncat(message + length, value2, 255 - length); + MALLOC_STR(self->error, message); +} + +static unsigned char readByte (_dataInput* input) { + return *input->cursor++; +} + +static char readSByte (_dataInput* input) { + return (char)readByte(input); +} + +static int readBoolean (_dataInput* input) { + return readByte(input) != 0; +} + +static int readInt (_dataInput* input) { + int result = readByte(input); + result <<= 8; + result |= readByte(input); + result <<= 8; + result |= readByte(input); + result <<= 8; + result |= readByte(input); + return result; +} + +static int readVarint (_dataInput* input, int/*bool*/optimizePositive) { + unsigned char b = readByte(input); + int value = b & 0x7F; + if (b & 0x80) { + b = readByte(input); + value |= (b & 0x7F) << 7; + if (b & 0x80) { + b = readByte(input); + value |= (b & 0x7F) << 14; + if (b & 0x80) { + b = readByte(input); + value |= (b & 0x7F) << 21; + if (b & 0x80) value |= (readByte(input) & 0x7F) << 28; + } + } + } + if (!optimizePositive) value = (((unsigned int)value >> 1) ^ -(value & 1)); + return value; +} + +float readFloat (_dataInput* input) { + union { + int intValue; + float floatValue; + } intToFloat; + intToFloat.intValue = readInt(input); + return intToFloat.floatValue; +} + +char* readString (_dataInput* input) { + int length = readVarint(input, 1); + char* string; + if (length == 0) { + return 0; + } + string = MALLOC(char, length); + memcpy(string, input->cursor, length - 1); + input->cursor += length - 1; + string[length - 1] = '\0'; + return string; +} + +static void readColor (_dataInput* input, float *r, float *g, float *b, float *a) { + *r = readByte(input) / 255.0f; + *g = readByte(input) / 255.0f; + *b = readByte(input) / 255.0f; + *a = readByte(input) / 255.0f; +} + +#define ATTACHMENT_REGION 0 +#define ATTACHMENT_BOUNDING_BOX 1 +#define ATTACHMENT_MESH 2 +#define ATTACHMENT_LINKED_MESH 3 +#define ATTACHMENT_PATH 4 + +#define BLEND_MODE_NORMAL 0 +#define BLEND_MODE_ADDITIVE 1 +#define BLEND_MODE_MULTIPLY 2 +#define BLEND_MODE_SCREEN 3 + +#define CURVE_LINEAR 0 +#define CURVE_STEPPED 1 +#define CURVE_BEZIER 2 + +#define BONE_ROTATE 0 +#define BONE_TRANSLATE 1 +#define BONE_SCALE 2 +#define BONE_SHEAR 3 + +#define SLOT_ATTACHMENT 0 +#define SLOT_COLOR 1 + +#define PATH_POSITION 0 +#define PATH_SPACING 1 +#define PATH_MIX 2 + +#define PATH_POSITION_FIXED 0 +#define PATH_POSITION_PERCENT 1 + +#define PATH_SPACING_LENGTH 0 +#define PATH_SPACING_FIXED 1 +#define PATH_SPACING_PERCENT 2 + +#define PATH_ROTATE_TANGENT 0 +#define PATH_ROTATE_CHAIN 1 +#define PATH_ROTATE_CHAIN_SCALE 2 + +static void readCurve (_dataInput* input, spCurveTimeline* timeline, int frameIndex) { + switch (readByte(input)) { + case CURVE_STEPPED: { + spCurveTimeline_setStepped(timeline, frameIndex); + break; + } + case CURVE_BEZIER: { + float cx1 = readFloat(input); + float cy1 = readFloat(input); + float cx2 = readFloat(input); + float cy2 = readFloat(input); + spCurveTimeline_setCurve(timeline, frameIndex, cx1, cy1, cx2, cy2); + break; + } + } +} + +static void _spSkeletonBinary_addLinkedMesh (spSkeletonBinary* self, spMeshAttachment* mesh, + const char* skin, int slotIndex, const char* parent) { + _spLinkedMesh* linkedMesh; + _spSkeletonBinary* internal = SUB_CAST(_spSkeletonBinary, self); + + if (internal->linkedMeshCount == internal->linkedMeshCapacity) { + _spLinkedMesh* linkedMeshes; + internal->linkedMeshCapacity *= 2; + if (internal->linkedMeshCapacity < 8) internal->linkedMeshCapacity = 8; + /* TODO Why not realloc? */ + linkedMeshes = MALLOC(_spLinkedMesh, internal->linkedMeshCapacity); + memcpy(linkedMeshes, internal->linkedMeshes, sizeof(_spLinkedMesh) * internal->linkedMeshCount); + FREE(internal->linkedMeshes); + internal->linkedMeshes = linkedMeshes; + } + + linkedMesh = internal->linkedMeshes + internal->linkedMeshCount++; + linkedMesh->mesh = mesh; + linkedMesh->skin = skin; + linkedMesh->slotIndex = slotIndex; + linkedMesh->parent = parent; +} + +static spAnimation* _spSkeletonBinary_readAnimation (spSkeletonBinary* self, const char* name, + _dataInput* input, spSkeletonData *skeletonData) { + kvec_t(spTimeline*) timelines; + float duration = 0; + int i, n, ii, nn, iii, nnn; + int frameIndex; + int drawOrderCount, eventCount; + spAnimation* animation; + + kv_init(timelines); + + /* Slot timelines. */ + for (i = 0, n = readVarint(input, 1); i < n; ++i) { + int slotIndex = readVarint(input, 1); + for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) { + unsigned char timelineType = readByte(input); + int frameCount = readVarint(input, 1); + switch (timelineType) { + case SLOT_COLOR: { + spColorTimeline* timeline = spColorTimeline_create(frameCount); + timeline->slotIndex = slotIndex; + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + float r, g, b, a; + readColor(input, &r, &g, &b, &a); + spColorTimeline_setFrame(timeline, frameIndex, time, r, g, b, a); + if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); + } + kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); + duration = MAX(duration, timeline->frames[(frameCount - 1) * COLOR_ENTRIES]); + break; + } + case SLOT_ATTACHMENT: { + spAttachmentTimeline* timeline = spAttachmentTimeline_create(frameCount); + timeline->slotIndex = slotIndex; + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + const char* attachmentName = readString(input); + /* TODO Avoid copying of attachmentName inside */ + spAttachmentTimeline_setFrame(timeline, frameIndex, time, attachmentName); + FREE(attachmentName); + } + kv_push(spTimeline*, timelines, SUPER(timeline)); + duration = MAX(duration, timeline->frames[frameCount - 1]); + break; + } + default: { + int i; + for (i = 0; i < kv_size(timelines); ++i) + spTimeline_dispose(kv_A(timelines, i)); + kv_destroy(timelines); + _spSkeletonBinary_setError(self, "Invalid timeline type for a slot: ", skeletonData->slots[slotIndex]->name); + return 0; + } + } + } + } + + /* Bone timelines. */ + for (i = 0, n = readVarint(input, 1); i < n; ++i) { + int boneIndex = readVarint(input, 1); + for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) { + unsigned char timelineType = readByte(input); + int frameCount = readVarint(input, 1); + switch (timelineType) { + case BONE_ROTATE: { + spRotateTimeline *timeline = spRotateTimeline_create(frameCount); + timeline->boneIndex = boneIndex; + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + float degrees = readFloat(input); + spRotateTimeline_setFrame(timeline, frameIndex, time, degrees); + if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); + } + kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); + duration = MAX(duration, timeline->frames[(frameCount - 1) * ROTATE_ENTRIES]); + break; + } + case BONE_TRANSLATE: + case BONE_SCALE: + case BONE_SHEAR: { + float timelineScale = 1; + spTranslateTimeline *timeline = 0; + switch (timelineType) { + case BONE_SCALE: + timeline = spScaleTimeline_create(frameCount); + break; + case BONE_SHEAR: + timeline = spShearTimeline_create(frameCount); + break; + case BONE_TRANSLATE: + timeline = spTranslateTimeline_create(frameCount); + timelineScale = self->scale; + break; + default: + break; + } + timeline->boneIndex = boneIndex; + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + float x = readFloat(input) * timelineScale; + float y = readFloat(input) * timelineScale; + spTranslateTimeline_setFrame(timeline, frameIndex, time, x, y); + if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); + } + kv_push(spTimeline*, timelines, SUPER_CAST(spTimeline, timeline)); + duration = MAX(duration, timeline->frames[(frameCount - 1) * TRANSLATE_ENTRIES]); + break; + } + default: { + int i; + for (i = 0; i < kv_size(timelines); ++i) + spTimeline_dispose(kv_A(timelines, i)); + kv_destroy(timelines); + _spSkeletonBinary_setError(self, "Invalid timeline type for a bone: ", skeletonData->bones[boneIndex]->name); + return 0; + } + } + } + } + + /* IK constraint timelines. */ + for (i = 0, n = readVarint(input, 1); i < n; ++i) { + int index = readVarint(input, 1); + int frameCount = readVarint(input, 1); + spIkConstraintTimeline* timeline = spIkConstraintTimeline_create(frameCount); + timeline->ikConstraintIndex = index; + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + float mix = readFloat(input); + char bendDirection = readSByte(input); + spIkConstraintTimeline_setFrame(timeline, frameIndex, time, mix, bendDirection); + if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); + } + kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); + duration = MAX(duration, timeline->frames[(frameCount - 1) * IKCONSTRAINT_ENTRIES]); + } + + /* Transform constraint timelines. */ + for (i = 0, n = readVarint(input, 1); i < n; ++i) { + int index = readVarint(input, 1); + int frameCount = readVarint(input, 1); + spTransformConstraintTimeline* timeline = spTransformConstraintTimeline_create(frameCount); + timeline->transformConstraintIndex = index; + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + float rotateMix = readFloat(input); + float translateMix = readFloat(input); + float scaleMix = readFloat(input); + float shearMix = readFloat(input); + spTransformConstraintTimeline_setFrame(timeline, frameIndex, time, rotateMix, translateMix, + scaleMix, shearMix); + if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); + } + kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); + duration = MAX(duration, timeline->frames[(frameCount - 1) * TRANSFORMCONSTRAINT_ENTRIES]); + } + + /* Path constraint timelines. */ + for (i = 0, n = readVarint(input, 1); i < n; ++i) { + int index = readVarint(input, 1); + spPathConstraintData* data = skeletonData->pathConstraints[index]; + for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) { + unsigned char timelineType = readByte(input); + int frameCount = readVarint(input, 1); + switch (timelineType) { + case PATH_POSITION: + case PATH_SPACING: { + spPathConstraintPositionTimeline* timeline = 0; + float timelineScale = 1; + if (timelineType == PATH_SPACING) { + timeline = (spPathConstraintPositionTimeline*)spPathConstraintSpacingTimeline_create(frameCount); + if (data->spacingMode == SP_SPACING_MODE_LENGTH || data->spacingMode == SP_SPACING_MODE_FIXED) + timelineScale = self->scale; + } else { + timeline = spPathConstraintPositionTimeline_create(frameCount); + if (data->positionMode == SP_POSITION_MODE_FIXED) + timelineScale = self->scale; + } + timeline->pathConstraintIndex = index; + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + float value = readFloat(input) * timelineScale; + spPathConstraintPositionTimeline_setFrame(timeline, frameIndex, time, value); + if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); + } + kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); + duration = MAX(duration, timeline->frames[(frameCount - 1) * PATHCONSTRAINTPOSITION_ENTRIES]); + break; + } + case PATH_MIX: { + spPathConstraintMixTimeline* timeline = spPathConstraintMixTimeline_create(frameCount); + timeline->pathConstraintIndex = index; + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + float rotateMix = readFloat(input); + float translateMix = readFloat(input); + spPathConstraintMixTimeline_setFrame(timeline, frameIndex, time, rotateMix, translateMix); + if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); + } + kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); + duration = MAX(duration, timeline->frames[(frameCount - 1) * PATHCONSTRAINTMIX_ENTRIES]); + } + } + } + } + + /* Deform timelines. */ + for (i = 0, n = readVarint(input, 1); i < n; ++i) { + spSkin* skin = skeletonData->skins[readVarint(input, 1)]; + for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) { + int slotIndex = readVarint(input, 1); + for (iii = 0, nnn = readVarint(input, 1); iii < nnn; ++iii) { + float* tempDeform; + spDeformTimeline *timeline; + int weighted, deformLength; + const char* attachmentName = readString(input); + int frameCount; + + spVertexAttachment* attachment = SUB_CAST(spVertexAttachment, + spSkin_getAttachment(skin, slotIndex, attachmentName)); + if (!attachment) { + int i; + for (i = 0; i < kv_size(timelines); ++i) + spTimeline_dispose(kv_A(timelines, i)); + kv_destroy(timelines); + _spSkeletonBinary_setError(self, "Attachment not found: ", attachmentName); + FREE(attachmentName); + return 0; + } + FREE(attachmentName); + + weighted = attachment->bones != 0; + deformLength = weighted ? attachment->verticesCount / 3 * 2 : attachment->verticesCount; + tempDeform = MALLOC(float, deformLength); + + frameCount = readVarint(input, 1); + timeline = spDeformTimeline_create(frameCount, deformLength); + timeline->slotIndex = slotIndex; + timeline->attachment = SUPER(attachment); + + for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) { + float time = readFloat(input); + float* deform; + int end = readVarint(input, 1); + if (!end) { + if (weighted) { + deform = tempDeform; + memset(deform, 0, sizeof(float) * deformLength); + } else + deform = attachment->vertices; + } else { + int v, start = readVarint(input, 1); + deform = tempDeform; + memset(deform, 0, sizeof(float) * start); + end += start; + if (self->scale == 1) { + for (v = start; v < end; ++v) + deform[v] = readFloat(input); + } else { + for (v = start; v < end; ++v) + deform[v] = readFloat(input) * self->scale; + } + memset(deform + v, 0, sizeof(float) * (deformLength - v)); + if (!weighted) { + float* vertices = attachment->vertices; + for (v = 0; v < deformLength; ++v) + deform[v] += vertices[v]; + } + } + spDeformTimeline_setFrame(timeline, frameIndex, time, deform); + if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex); + } + FREE(tempDeform); + + kv_push(spTimeline*, timelines, SUPER(SUPER(timeline))); + duration = MAX(duration, timeline->frames[frameCount - 1]); + } + } + } + + /* Draw order timeline. */ + drawOrderCount = readVarint(input, 1); + if (drawOrderCount) { + spDrawOrderTimeline* timeline = spDrawOrderTimeline_create(drawOrderCount, skeletonData->slotsCount); + for (i = 0; i < drawOrderCount; ++i) { + float time = readFloat(input); + int offsetCount = readVarint(input, 1); + int* drawOrder = MALLOC(int, skeletonData->slotsCount); + int* unchanged = MALLOC(int, skeletonData->slotsCount - offsetCount); + int originalIndex = 0, unchangedIndex = 0; + memset(drawOrder, -1, sizeof(int) * skeletonData->slotsCount); + for (ii = 0; ii < offsetCount; ++ii) { + int slotIndex = readVarint(input, 1); + /* Collect unchanged items. */ + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + /* Set changed items. */ + drawOrder[originalIndex + readVarint(input, 1)] = originalIndex; + ++originalIndex; + } + /* Collect remaining unchanged items. */ + while (originalIndex < skeletonData->slotsCount) + unchanged[unchangedIndex++] = originalIndex++; + /* Fill in unchanged items. */ + for (ii = skeletonData->slotsCount - 1; ii >= 0; ii--) + if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex]; + FREE(unchanged); + /* TODO Avoid copying of drawOrder inside */ + spDrawOrderTimeline_setFrame(timeline, i, time, drawOrder); + FREE(drawOrder); + } + kv_push(spTimeline*, timelines, SUPER(timeline)); + duration = MAX(duration, timeline->frames[drawOrderCount - 1]); + } + + /* Event timeline. */ + eventCount = readVarint(input, 1); + if (eventCount) { + spEventTimeline* timeline = spEventTimeline_create(eventCount); + for (i = 0; i < eventCount; ++i) { + float time = readFloat(input); + spEventData* eventData = skeletonData->events[readVarint(input, 1)]; + spEvent* event = spEvent_create(time, eventData); + event->intValue = readVarint(input, 0); + event->floatValue = readFloat(input); + if (readBoolean(input)) + event->stringValue = readString(input); + else + MALLOC_STR(event->stringValue, eventData->stringValue); + spEventTimeline_setFrame(timeline, i, event); + } + kv_push(spTimeline*, timelines, SUPER(timeline)); + duration = MAX(duration, timeline->frames[eventCount - 1]); + } + + kv_trim(spTimeline*, timelines); + + animation = spAnimation_create(name, 0); + animation->duration = duration; + animation->timelinesCount = kv_size(timelines); + animation->timelines = kv_array(timelines); + return animation; +} + +static float* _readFloatArray(_dataInput *input, int n, float scale) { + float* array = MALLOC(float, n); + int i; + if (scale == 1) + for (i = 0; i < n; ++i) + array[i] = readFloat(input); + else + for (i = 0; i < n; ++i) + array[i] = readFloat(input) * scale; + return array; +} + +static short* _readShortArray(_dataInput *input, int *length) { + int n = readVarint(input, 1); + short* array = MALLOC(short, n); + int i; + *length = n; + for (i = 0; i < n; ++i) { + array[i] = readByte(input) << 8; + array[i] |= readByte(input); + } + return array; +} + +static void _readVertices(spSkeletonBinary* self, _dataInput* input, spVertexAttachment* attachment, + int vertexCount) { + int i, ii; + int verticesLength = vertexCount << 1; + kvec_t(float) weights; + kvec_t(int) bones; + + attachment->worldVerticesLength = verticesLength; + + if (!readBoolean(input)) { + attachment->verticesCount = verticesLength; + attachment->vertices = _readFloatArray(input, verticesLength, self->scale); + attachment->bonesCount = 0; + attachment->bones = 0; + return; + } + + kv_init(weights); + kv_resize(float, weights, verticesLength * 3 * 3); + + kv_init(bones); + kv_resize(int, bones, verticesLength * 3); + + for (i = 0; i < vertexCount; ++i) { + int boneCount = readVarint(input, 1); + kv_push(int, bones, boneCount); + for (ii = 0; ii < boneCount; ++ii) { + kv_push(int, bones, readVarint(input, 1)); + kv_push(float, weights, readFloat(input) * self->scale); + kv_push(float, weights, readFloat(input) * self->scale); + kv_push(float, weights, readFloat(input)); + } + } + + kv_trim(float, weights); + attachment->verticesCount = kv_size(weights); + attachment->vertices = kv_array(weights); + + kv_trim(int, bones); + attachment->bonesCount = kv_size(bones); + attachment->bones = kv_array(bones); +} + +spAttachment* spSkeletonBinary_readAttachment(spSkeletonBinary* self, _dataInput* input, + spSkin* skin, int slotIndex, const char* attachmentName, int/*bool*/ nonessential) { + int i; + spAttachmentType type; + const char* name = readString(input); + int freeName = name != 0; + if (!name) { + freeName = 0; + name = attachmentName; + } + + type = (spAttachmentType)readByte(input); + + switch (type) { + case SP_ATTACHMENT_REGION: { + const char* path = readString(input); + spAttachment* attachment; + spRegionAttachment* region; + if (!path) MALLOC_STR(path, name); + attachment = spAttachmentLoader_createAttachment( + self->attachmentLoader, skin, type, name, path); + region = SUB_CAST(spRegionAttachment, attachment); + region->path = path; + region->rotation = readFloat(input); + region->x = readFloat(input) * self->scale; + region->y = readFloat(input) * self->scale; + region->scaleX = readFloat(input); + region->scaleY = readFloat(input); + region->width = readFloat(input) * self->scale; + region->height = readFloat(input) * self->scale; + readColor(input, ®ion->r, ®ion->g, ®ion->b, ®ion->a); + spRegionAttachment_updateOffset(region); + spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); + if (freeName) FREE(name); + return attachment; + } + case SP_ATTACHMENT_BOUNDING_BOX: { + int vertexCount = readVarint(input, 1); + spAttachment* attachment = spAttachmentLoader_createAttachment( + self->attachmentLoader, skin, type, name, 0); + _readVertices(self, input, SUB_CAST(spVertexAttachment, attachment), vertexCount); + if (nonessential) readInt(input); /* Skip color. */ + spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); + if (freeName) FREE(name); + return attachment; + } + case SP_ATTACHMENT_MESH: { + int vertexCount; + spAttachment* attachment; + spMeshAttachment* mesh; + const char* path = readString(input); + if (!path) MALLOC_STR(path, name); + attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, path); + mesh = SUB_CAST(spMeshAttachment, attachment); + mesh->path = path; + readColor(input, &mesh->r, &mesh->g, &mesh->b, &mesh->a); + vertexCount = readVarint(input, 1); + mesh->regionUVs = _readFloatArray(input, vertexCount << 1, 1); + mesh->triangles = (unsigned short*)_readShortArray(input, &mesh->trianglesCount); + _readVertices(self, input, SUPER(mesh), vertexCount); + spMeshAttachment_updateUVs(mesh); + mesh->hullLength = readVarint(input, 1) << 1; + if (nonessential) { + mesh->edges = (int*)_readShortArray(input, &mesh->edgesCount); + mesh->width = readFloat(input) * self->scale; + mesh->height = readFloat(input) * self->scale; + } else { + mesh->edges = 0; + mesh->width = 0; + mesh->height = 0; + } + spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); + if (freeName) FREE(name); + return attachment; + } + case SP_ATTACHMENT_LINKED_MESH: { + const char* skinName; + const char* parent; + spAttachment* attachment; + spMeshAttachment* mesh; + const char* path = readString(input); + if (!path) MALLOC_STR(path, name); + attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, name, path); + mesh = SUB_CAST(spMeshAttachment, attachment); + mesh->path = path; + readColor(input, &mesh->r, &mesh->g, &mesh->b, &mesh->a); + skinName = readString(input); + parent = readString(input); + mesh->inheritDeform = readBoolean(input); + if (nonessential) { + mesh->width = readFloat(input) * self->scale; + mesh->height = readFloat(input) * self->scale; + } + _spSkeletonBinary_addLinkedMesh(self, mesh, skinName, slotIndex, parent); + if (freeName) FREE(name); + return attachment; + } + case SP_ATTACHMENT_PATH: { + spAttachment* attachment = spAttachmentLoader_createAttachment( + self->attachmentLoader, skin, type, name, 0); + spPathAttachment* path = SUB_CAST(spPathAttachment, attachment); + int vertexCount = 0; + path->closed = readBoolean(input); + path->constantSpeed = readBoolean(input); + vertexCount = readVarint(input, 1); + _readVertices(self, input, SUPER(path), vertexCount); + path->lengthsLength = vertexCount / 3; + path->lengths = MALLOC(float, path->lengthsLength); + for (i = 0; i < path->lengthsLength; ++i) { + path->lengths[i] = readFloat(input) * self->scale; + } + if (nonessential) readInt(input); /* Skip color. */ + if (freeName) FREE(name); + return attachment; + } + } + + if (freeName) FREE(name); + return 0; +} + +spSkin* spSkeletonBinary_readSkin(spSkeletonBinary* self, _dataInput* input, + const char* skinName, int/*bool*/ nonessential) { + spSkin* skin; + int slotCount = readVarint(input, 1); + int i, ii, nn; + if (slotCount == 0) + return 0; + skin = spSkin_create(skinName); + for (i = 0; i < slotCount; ++i) { + int slotIndex = readVarint(input, 1); + for (ii = 0, nn = readVarint(input, 1); ii < nn; ++ii) { + const char* name = readString(input); + spSkin_addAttachment(skin, slotIndex, name, + spSkeletonBinary_readAttachment(self, input, skin, slotIndex, name, nonessential)); + FREE(name); + } + } + return skin; +} + +spSkeletonData* spSkeletonBinary_readSkeletonDataFile (spSkeletonBinary* self, const char* path) { + int length; + spSkeletonData* skeletonData; + const char* binary = _spUtil_readFile(path, &length); + if (length == 0 || !binary) { + _spSkeletonBinary_setError(self, "Unable to read skeleton file: ", path); + return 0; + } + skeletonData = spSkeletonBinary_readSkeletonData(self, (unsigned char*)binary, length); + FREE(binary); + return skeletonData; +} + +spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const unsigned char* binary, + const int length) { + int i, ii, nonessential; + spSkeletonData* skeletonData; + _spSkeletonBinary* internal = SUB_CAST(_spSkeletonBinary, self); + + _dataInput* input = NEW(_dataInput); + input->cursor = binary; + input->end = binary + length; + + FREE(self->error); + CONST_CAST(char*, self->error) = 0; + internal->linkedMeshCount = 0; + + skeletonData = spSkeletonData_create(); + + skeletonData->hash = readString(input); + if (!strlen(skeletonData->hash)) { + FREE(skeletonData->hash); + skeletonData->hash = 0; + } + + skeletonData->version = readString(input); + if (!strlen(skeletonData->version)) { + FREE(skeletonData->version); + skeletonData->version = 0; + } + + skeletonData->width = readFloat(input); + skeletonData->height = readFloat(input); + + nonessential = readBoolean(input); + + if (nonessential) FREE(readString(input)); /* Skip images path. */ + + /* Bones. */ + skeletonData->bonesCount = readVarint(input, 1); + skeletonData->bones = MALLOC(spBoneData*, skeletonData->bonesCount); + for (i = 0; i < skeletonData->bonesCount; ++i) { + spBoneData* data; + const char* name = readString(input); + spBoneData* parent = i == 0 ? 0 : skeletonData->bones[readVarint(input, 1)]; + /* TODO Avoid copying of name */ + data = spBoneData_create(i, name, parent); + FREE(name); + data->rotation = readFloat(input); + data->x = readFloat(input) * self->scale; + data->y = readFloat(input) * self->scale; + data->scaleX = readFloat(input); + data->scaleY = readFloat(input); + data->shearX = readFloat(input); + data->shearY = readFloat(input); + data->length = readFloat(input) * self->scale; + data->inheritRotation = readBoolean(input); + data->inheritScale = readBoolean(input); + if (nonessential) readInt(input); /* Skip bone color. */ + skeletonData->bones[i] = data; + } + + /* Slots. */ + skeletonData->slotsCount = readVarint(input, 1); + skeletonData->slots = MALLOC(spSlotData*, skeletonData->slotsCount); + for (i = 0; i < skeletonData->slotsCount; ++i) { + const char* slotName = readString(input); + spBoneData* boneData = skeletonData->bones[readVarint(input, 1)]; + /* TODO Avoid copying of slotName */ + spSlotData* slotData = spSlotData_create(i, slotName, boneData); + FREE(slotName); + readColor(input, &slotData->r, &slotData->g, &slotData->b, &slotData->a); + slotData->attachmentName = readString(input); + slotData->blendMode = (spBlendMode)readVarint(input, 1); + skeletonData->slots[i] = slotData; + } + + /* IK constraints. */ + skeletonData->ikConstraintsCount = readVarint(input, 1); + skeletonData->ikConstraints = MALLOC(spIkConstraintData*, skeletonData->ikConstraintsCount); + for (i = 0; i < skeletonData->ikConstraintsCount; ++i) { + const char* name = readString(input); + /* TODO Avoid copying of name */ + spIkConstraintData* data = spIkConstraintData_create(name); + FREE(name); + data->bonesCount = readVarint(input, 1); + data->bones = MALLOC(spBoneData*, data->bonesCount); + for (ii = 0; ii < data->bonesCount; ++ii) + data->bones[ii] = skeletonData->bones[readVarint(input, 1)]; + data->target = skeletonData->bones[readVarint(input, 1)]; + data->mix = readFloat(input); + data->bendDirection = readSByte(input); + skeletonData->ikConstraints[i] = data; + } + + /* Transform constraints. */ + skeletonData->transformConstraintsCount = readVarint(input, 1); + skeletonData->transformConstraints = MALLOC( + spTransformConstraintData*, skeletonData->transformConstraintsCount); + for (i = 0; i < skeletonData->transformConstraintsCount; ++i) { + const char* name = readString(input); + /* TODO Avoid copying of name */ + spTransformConstraintData* data = spTransformConstraintData_create(name); + FREE(name); + data->bonesCount = readVarint(input, 1); + CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, data->bonesCount); + for (ii = 0; ii < data->bonesCount; ++ii) + data->bones[ii] = skeletonData->bones[readVarint(input, 1)]; + data->target = skeletonData->bones[readVarint(input, 1)]; + data->offsetRotation = readFloat(input); + data->offsetX = readFloat(input) * self->scale; + data->offsetY = readFloat(input) * self->scale; + data->offsetScaleX = readFloat(input); + data->offsetScaleY = readFloat(input); + data->offsetShearY = readFloat(input); + data->rotateMix = readFloat(input); + data->translateMix = readFloat(input); + data->scaleMix = readFloat(input); + data->shearMix = readFloat(input); + skeletonData->transformConstraints[i] = data; + } + + /* Path constraints */ + skeletonData->pathConstraintsCount = readVarint(input, 1); + skeletonData->pathConstraints = MALLOC(spPathConstraintData*, skeletonData->pathConstraintsCount); + for (i = 0; i < skeletonData->pathConstraintsCount; ++i) { + const char* name = readString(input); + /* TODO Avoid copying of name */ + spPathConstraintData* data = spPathConstraintData_create(name); + FREE(name); + data->bonesCount = readVarint(input, 1); + CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, data->bonesCount); + for (ii = 0; ii < data->bonesCount; ++ii) + data->bones[ii] = skeletonData->bones[readVarint(input, 1)]; + data->target = skeletonData->slots[readVarint(input, 1)]; + data->positionMode = (spPositionMode)readVarint(input, 1); + data->spacingMode = (spSpacingMode)readVarint(input, 1); + data->rotateMode = (spRotateMode)readVarint(input, 1); + data->offsetRotation = readFloat(input); + data->position = readFloat(input); + if (data->positionMode == SP_POSITION_MODE_FIXED) data->position *= self->scale; + data->spacing = readFloat(input); + if (data->spacingMode == SP_SPACING_MODE_LENGTH || data->spacingMode == SP_SPACING_MODE_FIXED) data->spacing *= self->scale; + data->rotateMix = readFloat(input); + data->translateMix = readFloat(input); + skeletonData->pathConstraints[i] = data; + } + + /* Default skin. */ + skeletonData->defaultSkin = spSkeletonBinary_readSkin(self, input, "default", nonessential); + skeletonData->skinsCount = readVarint(input, 1); + + if (skeletonData->defaultSkin) + ++skeletonData->skinsCount; + + skeletonData->skins = MALLOC(spSkin*, skeletonData->skinsCount); + + if (skeletonData->defaultSkin) + skeletonData->skins[0] = skeletonData->defaultSkin; + + /* Skins. */ + for (i = skeletonData->defaultSkin ? 1 : 0; i < skeletonData->skinsCount; ++i) { + const char* skinName = readString(input); + /* TODO Avoid copying of skinName */ + skeletonData->skins[i] = spSkeletonBinary_readSkin(self, input, skinName, nonessential); + FREE(skinName); + } + + /* Linked meshes. */ + for (i = 0; i < internal->linkedMeshCount; ++i) { + _spLinkedMesh* linkedMesh = internal->linkedMeshes + i; + spSkin* skin = !linkedMesh->skin ? skeletonData->defaultSkin : spSkeletonData_findSkin(skeletonData, linkedMesh->skin); + spAttachment* parent; + if (!skin) { + FREE(input); + spSkeletonData_dispose(skeletonData); + _spSkeletonBinary_setError(self, "Skin not found: ", linkedMesh->skin); + return 0; + } + parent = spSkin_getAttachment(skin, linkedMesh->slotIndex, linkedMesh->parent); + if (!parent) { + FREE(input); + spSkeletonData_dispose(skeletonData); + _spSkeletonBinary_setError(self, "Parent mesh not found: ", linkedMesh->parent); + return 0; + } + spMeshAttachment_setParentMesh(linkedMesh->mesh, SUB_CAST(spMeshAttachment, parent)); + spMeshAttachment_updateUVs(linkedMesh->mesh); + spAttachmentLoader_configureAttachment(self->attachmentLoader, SUPER(SUPER(linkedMesh->mesh))); + } + + /* Events. */ + skeletonData->eventsCount = readVarint(input, 1); + skeletonData->events = MALLOC(spEventData*, skeletonData->eventsCount); + for (i = 0; i < skeletonData->eventsCount; ++i) { + const char* name = readString(input); + /* TODO Avoid copying of skinName */ + spEventData* eventData = spEventData_create(name); + FREE(name); + eventData->intValue = readVarint(input, 0); + eventData->floatValue = readFloat(input); + eventData->stringValue = readString(input); + skeletonData->events[i] = eventData; + } + + /* Animations. */ + skeletonData->animationsCount = readVarint(input, 1); + skeletonData->animations = MALLOC(spAnimation*, skeletonData->animationsCount); + for (i = 0; i < skeletonData->animationsCount; ++i) { + const char* name = readString(input); + spAnimation* animation = _spSkeletonBinary_readAnimation(self, name, input, skeletonData); + FREE(name); + if (!animation) { + FREE(input); + spSkeletonData_dispose(skeletonData); + return 0; + } + skeletonData->animations[i] = animation; + } + + FREE(input); + return skeletonData; } diff --git a/spine-c/src/spine/SkeletonBounds.c b/spine-c/src/spine/SkeletonBounds.c index 22ba5f5947..0f9ac0b744 100644 --- a/spine-c/src/spine/SkeletonBounds.c +++ b/spine-c/src/spine/SkeletonBounds.c @@ -1,206 +1,205 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include - -spPolygon* spPolygon_create (int capacity) { - spPolygon* self = NEW(spPolygon); - self->capacity = capacity; - CONST_CAST(float*, self->vertices) = MALLOC(float, capacity); - return self; -} - -void spPolygon_dispose (spPolygon* self) { - FREE(self->vertices); - FREE(self); -} - -int/*bool*/spPolygon_containsPoint (spPolygon* self, float x, float y) { - int prevIndex = self->count - 2; - int inside = 0; - int i; - for (i = 0; i < self->count; i += 2) { - float vertexY = self->vertices[i + 1]; - float prevY = self->vertices[prevIndex + 1]; - if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { - float vertexX = self->vertices[i]; - if (vertexX + (y - vertexY) / (prevY - vertexY) * (self->vertices[prevIndex] - vertexX) < x) inside = !inside; - } - prevIndex = i; - } - return inside; -} - -int/*bool*/spPolygon_intersectsSegment (spPolygon* self, float x1, float y1, float x2, float y2) { - float width12 = x1 - x2, height12 = y1 - y2; - float det1 = x1 * y2 - y1 * x2; - float x3 = self->vertices[self->count - 2], y3 = self->vertices[self->count - 1]; - int i; - for (i = 0; i < self->count; i += 2) { - float x4 = self->vertices[i], y4 = self->vertices[i + 1]; - float det2 = x3 * y4 - y3 * x4; - float width34 = x3 - x4, height34 = y3 - y4; - float det3 = width12 * height34 - height12 * width34; - float x = (det1 * width34 - width12 * det2) / det3; - if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { - float y = (det1 * height34 - height12 * det2) / det3; - if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return 1; - } - x3 = x4; - y3 = y4; - } - return 0; -} - -/**/ - -typedef struct { - spSkeletonBounds super; - int capacity; -} _spSkeletonBounds; - -spSkeletonBounds* spSkeletonBounds_create () { - return SUPER(NEW(_spSkeletonBounds)); -} - -void spSkeletonBounds_dispose (spSkeletonBounds* self) { - int i; - for (i = 0; i < SUB_CAST(_spSkeletonBounds, self)->capacity; ++i) - if (self->polygons[i]) spPolygon_dispose(self->polygons[i]); - FREE(self->polygons); - FREE(self->boundingBoxes); - FREE(self); -} - -void spSkeletonBounds_update (spSkeletonBounds* self, spSkeleton* skeleton, int/*bool*/updateAabb) { - int i; - - _spSkeletonBounds* internal = SUB_CAST(_spSkeletonBounds, self); - if (internal->capacity < skeleton->slotsCount) { - spPolygon** newPolygons; - - FREE(self->boundingBoxes); - self->boundingBoxes = MALLOC(spBoundingBoxAttachment*, skeleton->slotsCount); - - newPolygons = CALLOC(spPolygon*, skeleton->slotsCount); - memcpy(newPolygons, self->polygons, internal->capacity); - FREE(self->polygons); - self->polygons = newPolygons; - - internal->capacity = skeleton->slotsCount; - } - - self->minX = (float)INT_MAX; - self->minY = (float)INT_MAX; - self->maxX = (float)INT_MIN; - self->maxY = (float)INT_MIN; - - self->count = 0; - for (i = 0; i < skeleton->slotsCount; ++i) { - spPolygon* polygon; - spBoundingBoxAttachment* boundingBox; - - spSlot* slot = skeleton->slots[i]; - spAttachment* attachment = slot->attachment; - if (!attachment || attachment->type != SP_ATTACHMENT_BOUNDING_BOX) continue; - boundingBox = (spBoundingBoxAttachment*)attachment; - self->boundingBoxes[self->count] = boundingBox; - - polygon = self->polygons[self->count]; - if (!polygon || polygon->capacity < boundingBox->super.worldVerticesLength) { - if (polygon) spPolygon_dispose(polygon); - self->polygons[self->count] = polygon = spPolygon_create(boundingBox->super.worldVerticesLength); - } - polygon->count = boundingBox->super.worldVerticesLength; - spBoundingBoxAttachment_computeWorldVertices(boundingBox, slot, polygon->vertices); - - if (updateAabb) { - int ii = 0; - for (; ii < polygon->count; ii += 2) { - float x = polygon->vertices[ii]; - float y = polygon->vertices[ii + 1]; - if (x < self->minX) self->minX = x; - if (y < self->minY) self->minY = y; - if (x > self->maxX) self->maxX = x; - if (y > self->maxY) self->maxY = y; - } - } - - self->count++; - } -} - -int/*bool*/spSkeletonBounds_aabbContainsPoint (spSkeletonBounds* self, float x, float y) { - return x >= self->minX && x <= self->maxX && y >= self->minY && y <= self->maxY; -} - -int/*bool*/spSkeletonBounds_aabbIntersectsSegment (spSkeletonBounds* self, float x1, float y1, float x2, float y2) { - float m, x, y; - if ((x1 <= self->minX && x2 <= self->minX) || (y1 <= self->minY && y2 <= self->minY) || (x1 >= self->maxX && x2 >= self->maxX) - || (y1 >= self->maxY && y2 >= self->maxY)) return 0; - m = (y2 - y1) / (x2 - x1); - y = m * (self->minX - x1) + y1; - if (y > self->minY && y < self->maxY) return 1; - y = m * (self->maxX - x1) + y1; - if (y > self->minY && y < self->maxY) return 1; - x = (self->minY - y1) / m + x1; - if (x > self->minX && x < self->maxX) return 1; - x = (self->maxY - y1) / m + x1; - if (x > self->minX && x < self->maxX) return 1; - return 0; -} - -int/*bool*/spSkeletonBounds_aabbIntersectsSkeleton (spSkeletonBounds* self, spSkeletonBounds* bounds) { - return self->minX < bounds->maxX && self->maxX > bounds->minX && self->minY < bounds->maxY && self->maxY > bounds->minY; -} - -spBoundingBoxAttachment* spSkeletonBounds_containsPoint (spSkeletonBounds* self, float x, float y) { - int i; - for (i = 0; i < self->count; ++i) - if (spPolygon_containsPoint(self->polygons[i], x, y)) return self->boundingBoxes[i]; - return 0; -} - -spBoundingBoxAttachment* spSkeletonBounds_intersectsSegment (spSkeletonBounds* self, float x1, float y1, float x2, float y2) { - int i; - for (i = 0; i < self->count; ++i) - if (spPolygon_intersectsSegment(self->polygons[i], x1, y1, x2, y2)) return self->boundingBoxes[i]; - return 0; -} - -spPolygon* spSkeletonBounds_getPolygon (spSkeletonBounds* self, spBoundingBoxAttachment* boundingBox) { - int i; - for (i = 0; i < self->count; ++i) - if (self->boundingBoxes[i] == boundingBox) return self->polygons[i]; - return 0; +#include +#include +#include + +spPolygon* spPolygon_create (int capacity) { + spPolygon* self = NEW(spPolygon); + self->capacity = capacity; + CONST_CAST(float*, self->vertices) = MALLOC(float, capacity); + return self; +} + +void spPolygon_dispose (spPolygon* self) { + FREE(self->vertices); + FREE(self); +} + +int/*bool*/spPolygon_containsPoint (spPolygon* self, float x, float y) { + int prevIndex = self->count - 2; + int inside = 0; + int i; + for (i = 0; i < self->count; i += 2) { + float vertexY = self->vertices[i + 1]; + float prevY = self->vertices[prevIndex + 1]; + if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { + float vertexX = self->vertices[i]; + if (vertexX + (y - vertexY) / (prevY - vertexY) * (self->vertices[prevIndex] - vertexX) < x) inside = !inside; + } + prevIndex = i; + } + return inside; +} + +int/*bool*/spPolygon_intersectsSegment (spPolygon* self, float x1, float y1, float x2, float y2) { + float width12 = x1 - x2, height12 = y1 - y2; + float det1 = x1 * y2 - y1 * x2; + float x3 = self->vertices[self->count - 2], y3 = self->vertices[self->count - 1]; + int i; + for (i = 0; i < self->count; i += 2) { + float x4 = self->vertices[i], y4 = self->vertices[i + 1]; + float det2 = x3 * y4 - y3 * x4; + float width34 = x3 - x4, height34 = y3 - y4; + float det3 = width12 * height34 - height12 * width34; + float x = (det1 * width34 - width12 * det2) / det3; + if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { + float y = (det1 * height34 - height12 * det2) / det3; + if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return 1; + } + x3 = x4; + y3 = y4; + } + return 0; +} + +/**/ + +typedef struct { + spSkeletonBounds super; + int capacity; +} _spSkeletonBounds; + +spSkeletonBounds* spSkeletonBounds_create () { + return SUPER(NEW(_spSkeletonBounds)); +} + +void spSkeletonBounds_dispose (spSkeletonBounds* self) { + int i; + for (i = 0; i < SUB_CAST(_spSkeletonBounds, self)->capacity; ++i) + if (self->polygons[i]) spPolygon_dispose(self->polygons[i]); + FREE(self->polygons); + FREE(self->boundingBoxes); + FREE(self); +} + +void spSkeletonBounds_update (spSkeletonBounds* self, spSkeleton* skeleton, int/*bool*/updateAabb) { + int i; + + _spSkeletonBounds* internal = SUB_CAST(_spSkeletonBounds, self); + if (internal->capacity < skeleton->slotsCount) { + spPolygon** newPolygons; + + FREE(self->boundingBoxes); + self->boundingBoxes = MALLOC(spBoundingBoxAttachment*, skeleton->slotsCount); + + newPolygons = CALLOC(spPolygon*, skeleton->slotsCount); + memcpy(newPolygons, self->polygons, internal->capacity); + FREE(self->polygons); + self->polygons = newPolygons; + + internal->capacity = skeleton->slotsCount; + } + + self->minX = (float)INT_MAX; + self->minY = (float)INT_MAX; + self->maxX = (float)INT_MIN; + self->maxY = (float)INT_MIN; + + self->count = 0; + for (i = 0; i < skeleton->slotsCount; ++i) { + spPolygon* polygon; + spBoundingBoxAttachment* boundingBox; + + spSlot* slot = skeleton->slots[i]; + spAttachment* attachment = slot->attachment; + if (!attachment || attachment->type != SP_ATTACHMENT_BOUNDING_BOX) continue; + boundingBox = (spBoundingBoxAttachment*)attachment; + self->boundingBoxes[self->count] = boundingBox; + + polygon = self->polygons[self->count]; + if (!polygon || polygon->capacity < boundingBox->super.worldVerticesLength) { + if (polygon) spPolygon_dispose(polygon); + self->polygons[self->count] = polygon = spPolygon_create(boundingBox->super.worldVerticesLength); + } + polygon->count = boundingBox->super.worldVerticesLength; + spBoundingBoxAttachment_computeWorldVertices(boundingBox, slot, polygon->vertices); + + if (updateAabb) { + int ii = 0; + for (; ii < polygon->count; ii += 2) { + float x = polygon->vertices[ii]; + float y = polygon->vertices[ii + 1]; + if (x < self->minX) self->minX = x; + if (y < self->minY) self->minY = y; + if (x > self->maxX) self->maxX = x; + if (y > self->maxY) self->maxY = y; + } + } + + self->count++; + } +} + +int/*bool*/spSkeletonBounds_aabbContainsPoint (spSkeletonBounds* self, float x, float y) { + return x >= self->minX && x <= self->maxX && y >= self->minY && y <= self->maxY; +} + +int/*bool*/spSkeletonBounds_aabbIntersectsSegment (spSkeletonBounds* self, float x1, float y1, float x2, float y2) { + float m, x, y; + if ((x1 <= self->minX && x2 <= self->minX) || (y1 <= self->minY && y2 <= self->minY) || (x1 >= self->maxX && x2 >= self->maxX) + || (y1 >= self->maxY && y2 >= self->maxY)) return 0; + m = (y2 - y1) / (x2 - x1); + y = m * (self->minX - x1) + y1; + if (y > self->minY && y < self->maxY) return 1; + y = m * (self->maxX - x1) + y1; + if (y > self->minY && y < self->maxY) return 1; + x = (self->minY - y1) / m + x1; + if (x > self->minX && x < self->maxX) return 1; + x = (self->maxY - y1) / m + x1; + if (x > self->minX && x < self->maxX) return 1; + return 0; +} + +int/*bool*/spSkeletonBounds_aabbIntersectsSkeleton (spSkeletonBounds* self, spSkeletonBounds* bounds) { + return self->minX < bounds->maxX && self->maxX > bounds->minX && self->minY < bounds->maxY && self->maxY > bounds->minY; +} + +spBoundingBoxAttachment* spSkeletonBounds_containsPoint (spSkeletonBounds* self, float x, float y) { + int i; + for (i = 0; i < self->count; ++i) + if (spPolygon_containsPoint(self->polygons[i], x, y)) return self->boundingBoxes[i]; + return 0; +} + +spBoundingBoxAttachment* spSkeletonBounds_intersectsSegment (spSkeletonBounds* self, float x1, float y1, float x2, float y2) { + int i; + for (i = 0; i < self->count; ++i) + if (spPolygon_intersectsSegment(self->polygons[i], x1, y1, x2, y2)) return self->boundingBoxes[i]; + return 0; +} + +spPolygon* spSkeletonBounds_getPolygon (spSkeletonBounds* self, spBoundingBoxAttachment* boundingBox) { + int i; + for (i = 0; i < self->count; ++i) + if (self->boundingBoxes[i] == boundingBox) return self->polygons[i]; + return 0; } diff --git a/spine-c/src/spine/SkeletonData.c b/spine-c/src/spine/SkeletonData.c index a3e2fc7de3..c2467cd8ab 100644 --- a/spine-c/src/spine/SkeletonData.c +++ b/spine-c/src/spine/SkeletonData.c @@ -1,148 +1,147 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include - -spSkeletonData* spSkeletonData_create () { - return NEW(spSkeletonData); -} - -void spSkeletonData_dispose (spSkeletonData* self) { - int i; - for (i = 0; i < self->bonesCount; ++i) - spBoneData_dispose(self->bones[i]); - FREE(self->bones); - - for (i = 0; i < self->slotsCount; ++i) - spSlotData_dispose(self->slots[i]); - FREE(self->slots); - - for (i = 0; i < self->skinsCount; ++i) - spSkin_dispose(self->skins[i]); - FREE(self->skins); - - for (i = 0; i < self->eventsCount; ++i) - spEventData_dispose(self->events[i]); - FREE(self->events); - - for (i = 0; i < self->animationsCount; ++i) - spAnimation_dispose(self->animations[i]); - FREE(self->animations); - - for (i = 0; i < self->ikConstraintsCount; ++i) - spIkConstraintData_dispose(self->ikConstraints[i]); - FREE(self->ikConstraints); - - for (i = 0; i < self->transformConstraintsCount; ++i) - spTransformConstraintData_dispose(self->transformConstraints[i]); - FREE(self->transformConstraints); - - for (i = 0; i < self->pathConstraintsCount; i++) - spPathConstraintData_dispose(self->pathConstraints[i]); - FREE(self->pathConstraints); - - FREE(self->hash); - FREE(self->version); - - FREE(self); -} - -spBoneData* spSkeletonData_findBone (const spSkeletonData* self, const char* boneName) { - int i; - for (i = 0; i < self->bonesCount; ++i) - if (strcmp(self->bones[i]->name, boneName) == 0) return self->bones[i]; - return 0; -} - -int spSkeletonData_findBoneIndex (const spSkeletonData* self, const char* boneName) { - int i; - for (i = 0; i < self->bonesCount; ++i) - if (strcmp(self->bones[i]->name, boneName) == 0) return i; - return -1; -} - -spSlotData* spSkeletonData_findSlot (const spSkeletonData* self, const char* slotName) { - int i; - for (i = 0; i < self->slotsCount; ++i) - if (strcmp(self->slots[i]->name, slotName) == 0) return self->slots[i]; - return 0; -} - -int spSkeletonData_findSlotIndex (const spSkeletonData* self, const char* slotName) { - int i; - for (i = 0; i < self->slotsCount; ++i) - if (strcmp(self->slots[i]->name, slotName) == 0) return i; - return -1; -} - -spSkin* spSkeletonData_findSkin (const spSkeletonData* self, const char* skinName) { - int i; - for (i = 0; i < self->skinsCount; ++i) - if (strcmp(self->skins[i]->name, skinName) == 0) return self->skins[i]; - return 0; -} - -spEventData* spSkeletonData_findEvent (const spSkeletonData* self, const char* eventName) { - int i; - for (i = 0; i < self->eventsCount; ++i) - if (strcmp(self->events[i]->name, eventName) == 0) return self->events[i]; - return 0; -} - -spAnimation* spSkeletonData_findAnimation (const spSkeletonData* self, const char* animationName) { - int i; - for (i = 0; i < self->animationsCount; ++i) - if (strcmp(self->animations[i]->name, animationName) == 0) return self->animations[i]; - return 0; -} - -spIkConstraintData* spSkeletonData_findIkConstraint (const spSkeletonData* self, const char* constraintName) { - int i; - for (i = 0; i < self->ikConstraintsCount; ++i) - if (strcmp(self->ikConstraints[i]->name, constraintName) == 0) return self->ikConstraints[i]; - return 0; -} - -spTransformConstraintData* spSkeletonData_findTransformConstraint (const spSkeletonData* self, const char* constraintName) { - int i; - for (i = 0; i < self->transformConstraintsCount; ++i) - if (strcmp(self->transformConstraints[i]->name, constraintName) == 0) return self->transformConstraints[i]; - return 0; -} - -spPathConstraintData* spSkeletonData_findPathConstraint (const spSkeletonData* self, const char* constraintName) { - int i; - for (i = 0; i < self->pathConstraintsCount; ++i) - if (strcmp(self->pathConstraints[i]->name, constraintName) == 0) return self->pathConstraints[i]; - return 0; +#include +#include +#include + +spSkeletonData* spSkeletonData_create () { + return NEW(spSkeletonData); +} + +void spSkeletonData_dispose (spSkeletonData* self) { + int i; + for (i = 0; i < self->bonesCount; ++i) + spBoneData_dispose(self->bones[i]); + FREE(self->bones); + + for (i = 0; i < self->slotsCount; ++i) + spSlotData_dispose(self->slots[i]); + FREE(self->slots); + + for (i = 0; i < self->skinsCount; ++i) + spSkin_dispose(self->skins[i]); + FREE(self->skins); + + for (i = 0; i < self->eventsCount; ++i) + spEventData_dispose(self->events[i]); + FREE(self->events); + + for (i = 0; i < self->animationsCount; ++i) + spAnimation_dispose(self->animations[i]); + FREE(self->animations); + + for (i = 0; i < self->ikConstraintsCount; ++i) + spIkConstraintData_dispose(self->ikConstraints[i]); + FREE(self->ikConstraints); + + for (i = 0; i < self->transformConstraintsCount; ++i) + spTransformConstraintData_dispose(self->transformConstraints[i]); + FREE(self->transformConstraints); + + for (i = 0; i < self->pathConstraintsCount; i++) + spPathConstraintData_dispose(self->pathConstraints[i]); + FREE(self->pathConstraints); + + FREE(self->hash); + FREE(self->version); + + FREE(self); +} + +spBoneData* spSkeletonData_findBone (const spSkeletonData* self, const char* boneName) { + int i; + for (i = 0; i < self->bonesCount; ++i) + if (strcmp(self->bones[i]->name, boneName) == 0) return self->bones[i]; + return 0; +} + +int spSkeletonData_findBoneIndex (const spSkeletonData* self, const char* boneName) { + int i; + for (i = 0; i < self->bonesCount; ++i) + if (strcmp(self->bones[i]->name, boneName) == 0) return i; + return -1; +} + +spSlotData* spSkeletonData_findSlot (const spSkeletonData* self, const char* slotName) { + int i; + for (i = 0; i < self->slotsCount; ++i) + if (strcmp(self->slots[i]->name, slotName) == 0) return self->slots[i]; + return 0; +} + +int spSkeletonData_findSlotIndex (const spSkeletonData* self, const char* slotName) { + int i; + for (i = 0; i < self->slotsCount; ++i) + if (strcmp(self->slots[i]->name, slotName) == 0) return i; + return -1; +} + +spSkin* spSkeletonData_findSkin (const spSkeletonData* self, const char* skinName) { + int i; + for (i = 0; i < self->skinsCount; ++i) + if (strcmp(self->skins[i]->name, skinName) == 0) return self->skins[i]; + return 0; +} + +spEventData* spSkeletonData_findEvent (const spSkeletonData* self, const char* eventName) { + int i; + for (i = 0; i < self->eventsCount; ++i) + if (strcmp(self->events[i]->name, eventName) == 0) return self->events[i]; + return 0; +} + +spAnimation* spSkeletonData_findAnimation (const spSkeletonData* self, const char* animationName) { + int i; + for (i = 0; i < self->animationsCount; ++i) + if (strcmp(self->animations[i]->name, animationName) == 0) return self->animations[i]; + return 0; +} + +spIkConstraintData* spSkeletonData_findIkConstraint (const spSkeletonData* self, const char* constraintName) { + int i; + for (i = 0; i < self->ikConstraintsCount; ++i) + if (strcmp(self->ikConstraints[i]->name, constraintName) == 0) return self->ikConstraints[i]; + return 0; +} + +spTransformConstraintData* spSkeletonData_findTransformConstraint (const spSkeletonData* self, const char* constraintName) { + int i; + for (i = 0; i < self->transformConstraintsCount; ++i) + if (strcmp(self->transformConstraints[i]->name, constraintName) == 0) return self->transformConstraints[i]; + return 0; +} + +spPathConstraintData* spSkeletonData_findPathConstraint (const spSkeletonData* self, const char* constraintName) { + int i; + for (i = 0; i < self->pathConstraintsCount; ++i) + if (strcmp(self->pathConstraints[i]->name, constraintName) == 0) return self->pathConstraints[i]; + return 0; } diff --git a/spine-c/src/spine/SkeletonJson.c b/spine-c/src/spine/SkeletonJson.c index 0f87102a75..bd6f49c40b 100644 --- a/spine-c/src/spine/SkeletonJson.c +++ b/spine-c/src/spine/SkeletonJson.c @@ -1,1045 +1,1044 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include -#include "Json.h" -#include -#include -#include - -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) -#define strdup _strdup -#endif - -typedef struct { - const char* parent; - const char* skin; - int slotIndex; - spMeshAttachment* mesh; -} _spLinkedMesh; - -typedef struct { - spSkeletonJson super; - int ownsLoader; - - int linkedMeshCount; - int linkedMeshCapacity; - _spLinkedMesh* linkedMeshes; -} _spSkeletonJson; - -spSkeletonJson* spSkeletonJson_createWithLoader (spAttachmentLoader* attachmentLoader) { - spSkeletonJson* self = SUPER(NEW(_spSkeletonJson)); - self->scale = 1; - self->attachmentLoader = attachmentLoader; - return self; -} - -spSkeletonJson* spSkeletonJson_create (spAtlas* atlas) { - spAtlasAttachmentLoader* attachmentLoader = spAtlasAttachmentLoader_create(atlas); - spSkeletonJson* self = spSkeletonJson_createWithLoader(SUPER(attachmentLoader)); - SUB_CAST(_spSkeletonJson, self)->ownsLoader = 1; - return self; -} - -void spSkeletonJson_dispose (spSkeletonJson* self) { - _spSkeletonJson* internal = SUB_CAST(_spSkeletonJson, self); - if (internal->ownsLoader) spAttachmentLoader_dispose(self->attachmentLoader); - FREE(internal->linkedMeshes); - FREE(self->error); - FREE(self); -} - -void _spSkeletonJson_setError (spSkeletonJson* self, Json* root, const char* value1, const char* value2) { - char message[256]; - int length; - FREE(self->error); - strcpy(message, value1); - length = (int)strlen(value1); - if (value2) strncat(message + length, value2, 255 - length); - MALLOC_STR(self->error, message); - if (root) Json_dispose(root); -} - -static float toColor (const char* value, int index) { - char digits[3]; - char *error; - int color; - - if (strlen(value) != 8) return -1; - value += index * 2; - - digits[0] = *value; - digits[1] = *(value + 1); - digits[2] = '\0'; - color = (int)strtoul(digits, &error, 16); - if (*error != 0) return -1; - return color / (float)255; -} - -static void readCurve (Json* frame, spCurveTimeline* timeline, int frameIndex) { - Json* curve = Json_getItem(frame, "curve"); - if (!curve) return; - if (curve->type == Json_String && strcmp(curve->valueString, "stepped") == 0) - spCurveTimeline_setStepped(timeline, frameIndex); - else if (curve->type == Json_Array) { - Json* child0 = curve->child; - Json* child1 = child0->next; - Json* child2 = child1->next; - Json* child3 = child2->next; - spCurveTimeline_setCurve(timeline, frameIndex, child0->valueFloat, child1->valueFloat, child2->valueFloat, - child3->valueFloat); - } -} - -static void _spSkeletonJson_addLinkedMesh (spSkeletonJson* self, spMeshAttachment* mesh, const char* skin, int slotIndex, - const char* parent) { - _spLinkedMesh* linkedMesh; - _spSkeletonJson* internal = SUB_CAST(_spSkeletonJson, self); - - if (internal->linkedMeshCount == internal->linkedMeshCapacity) { - _spLinkedMesh* linkedMeshes; - internal->linkedMeshCapacity *= 2; - if (internal->linkedMeshCapacity < 8) internal->linkedMeshCapacity = 8; - linkedMeshes = MALLOC(_spLinkedMesh, internal->linkedMeshCapacity); - memcpy(linkedMeshes, internal->linkedMeshes, sizeof(_spLinkedMesh) * internal->linkedMeshCount); - FREE(internal->linkedMeshes); - internal->linkedMeshes = linkedMeshes; - } - - linkedMesh = internal->linkedMeshes + internal->linkedMeshCount++; - linkedMesh->mesh = mesh; - linkedMesh->skin = skin; - linkedMesh->slotIndex = slotIndex; - linkedMesh->parent = parent; -} - -static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* root, spSkeletonData *skeletonData) { - int frameIndex; - spAnimation* animation; - Json* valueMap; - int timelinesCount = 0; - - Json* bones = Json_getItem(root, "bones"); - Json* slots = Json_getItem(root, "slots"); - Json* ik = Json_getItem(root, "ik"); - Json* transform = Json_getItem(root, "transform"); - Json* paths = Json_getItem(root, "paths"); - Json* deform = Json_getItem(root, "deform"); - Json* drawOrder = Json_getItem(root, "drawOrder"); - Json* events = Json_getItem(root, "events"); - Json *boneMap, *slotMap, *constraintMap; - if (!drawOrder) drawOrder = Json_getItem(root, "draworder"); - - for (boneMap = bones ? bones->child : 0; boneMap; boneMap = boneMap->next) - timelinesCount += boneMap->size; - for (slotMap = slots ? slots->child : 0; slotMap; slotMap = slotMap->next) - timelinesCount += slotMap->size; - timelinesCount += ik ? ik->size : 0; - timelinesCount += transform ? transform->size : 0; - for (constraintMap = paths ? paths->child : 0; constraintMap; constraintMap = constraintMap->next) - timelinesCount += constraintMap->size; - for (constraintMap = deform ? deform->child : 0; constraintMap; constraintMap = constraintMap->next) - for (slotMap = constraintMap->child; slotMap; slotMap = slotMap->next) - timelinesCount += slotMap->size; - if (drawOrder) ++timelinesCount; - if (events) ++timelinesCount; - - animation = spAnimation_create(root->name, timelinesCount); - animation->timelinesCount = 0; - - /* Slot timelines. */ - for (slotMap = slots ? slots->child : 0; slotMap; slotMap = slotMap->next) { - Json *timelineMap; - - int slotIndex = spSkeletonData_findSlotIndex(skeletonData, slotMap->name); - if (slotIndex == -1) { - spAnimation_dispose(animation); - _spSkeletonJson_setError(self, root, "Slot not found: ", slotMap->name); - return 0; - } - - for (timelineMap = slotMap->child; timelineMap; timelineMap = timelineMap->next) { - if (strcmp(timelineMap->name, "color") == 0) { - spColorTimeline *timeline = spColorTimeline_create(timelineMap->size); - timeline->slotIndex = slotIndex; - - for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { - const char* s = Json_getString(valueMap, "color", 0); - spColorTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), toColor(s, 0), toColor(s, 1), toColor(s, 2), - toColor(s, 3)); - readCurve(valueMap, SUPER(timeline), frameIndex); - } - animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); - animation->duration = MAX(animation->duration, timeline->frames[(timelineMap->size - 1) * COLOR_ENTRIES]); - - } else if (strcmp(timelineMap->name, "attachment") == 0) { - spAttachmentTimeline *timeline = spAttachmentTimeline_create(timelineMap->size); - timeline->slotIndex = slotIndex; - - for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { - Json* name = Json_getItem(valueMap, "name"); - spAttachmentTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), - name->type == Json_NULL ? 0 : name->valueString); - } - animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); - animation->duration = MAX(animation->duration, timeline->frames[timelineMap->size - 1]); - - } else { - spAnimation_dispose(animation); - _spSkeletonJson_setError(self, 0, "Invalid timeline type for a slot: ", timelineMap->name); - return 0; - } - } - } - - /* Bone timelines. */ - for (boneMap = bones ? bones->child : 0; boneMap; boneMap = boneMap->next) { - Json *timelineMap; - - int boneIndex = spSkeletonData_findBoneIndex(skeletonData, boneMap->name); - if (boneIndex == -1) { - spAnimation_dispose(animation); - _spSkeletonJson_setError(self, root, "Bone not found: ", boneMap->name); - return 0; - } - - for (timelineMap = boneMap->child; timelineMap; timelineMap = timelineMap->next) { - if (strcmp(timelineMap->name, "rotate") == 0) { - spRotateTimeline *timeline = spRotateTimeline_create(timelineMap->size); - timeline->boneIndex = boneIndex; - - for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { - spRotateTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, "angle", 0)); - readCurve(valueMap, SUPER(timeline), frameIndex); - } - animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); - animation->duration = MAX(animation->duration, timeline->frames[(timelineMap->size - 1) * ROTATE_ENTRIES]); - - } else { - int isScale = strcmp(timelineMap->name, "scale") == 0; - int isTranslate = strcmp(timelineMap->name, "translate") == 0; - int isShear = strcmp(timelineMap->name, "shear") == 0; - if (isScale || isTranslate || isShear) { - float timelineScale = isTranslate ? self->scale: 1; - spTranslateTimeline *timeline = 0; - if (isScale) timeline = spScaleTimeline_create(timelineMap->size); - else if (isTranslate) timeline = spTranslateTimeline_create(timelineMap->size); - else if (isShear) timeline = spShearTimeline_create(timelineMap->size); - timeline->boneIndex = boneIndex; - - for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { - spTranslateTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, "x", 0) * timelineScale, - Json_getFloat(valueMap, "y", 0) * timelineScale); - readCurve(valueMap, SUPER(timeline), frameIndex); - } - animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); - animation->duration = MAX(animation->duration, timeline->frames[(timelineMap->size - 1) * TRANSLATE_ENTRIES]); - - } else { - spAnimation_dispose(animation); - _spSkeletonJson_setError(self, 0, "Invalid timeline type for a bone: ", timelineMap->name); - return 0; - } - } - } - } - - /* IK constraint timelines. */ - for (constraintMap = ik ? ik->child : 0; constraintMap; constraintMap = constraintMap->next) { - spIkConstraintData* constraint = spSkeletonData_findIkConstraint(skeletonData, constraintMap->name); - spIkConstraintTimeline* timeline = spIkConstraintTimeline_create(constraintMap->size); - for (frameIndex = 0; frameIndex < skeletonData->ikConstraintsCount; ++frameIndex) { - if (constraint == skeletonData->ikConstraints[frameIndex]) { - timeline->ikConstraintIndex = frameIndex; - break; - } - } - for (valueMap = constraintMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { - spIkConstraintTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, "mix", 1), - Json_getInt(valueMap, "bendPositive", 1) ? 1 : -1); - readCurve(valueMap, SUPER(timeline), frameIndex); - } - animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); - animation->duration = MAX(animation->duration, timeline->frames[(constraintMap->size - 1) * IKCONSTRAINT_ENTRIES]); - } - - /* Transform constraint timelines. */ - for (constraintMap = transform ? transform->child : 0; constraintMap; constraintMap = constraintMap->next) { - spTransformConstraintData* constraint = spSkeletonData_findTransformConstraint(skeletonData, constraintMap->name); - spTransformConstraintTimeline* timeline = spTransformConstraintTimeline_create(constraintMap->size); - for (frameIndex = 0; frameIndex < skeletonData->transformConstraintsCount; ++frameIndex) { - if (constraint == skeletonData->transformConstraints[frameIndex]) { - timeline->transformConstraintIndex = frameIndex; - break; - } - } - for (valueMap = constraintMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { - spTransformConstraintTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, "rotateMix", 1), - Json_getFloat(valueMap, "translateMix", 1), Json_getFloat(valueMap, "scaleMix", 1), Json_getFloat(valueMap, "shearMix", 1)); - readCurve(valueMap, SUPER(timeline), frameIndex); - } - animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); - animation->duration = MAX(animation->duration, timeline->frames[(constraintMap->size - 1) * TRANSFORMCONSTRAINT_ENTRIES]); - } - - /** Path constraint timelines. */ - for(constraintMap = paths ? paths->child : 0; constraintMap; constraintMap = constraintMap->next ) { - int constraintIndex, i; - Json* timelineMap; - - spPathConstraintData* data = spSkeletonData_findPathConstraint(skeletonData, constraintMap->name); - if (!data) { - spAnimation_dispose(animation); - _spSkeletonJson_setError(self, root, "Path constraint not found: ", constraintMap->name); - return 0; - } - for (i = 0; i < skeletonData->pathConstraintsCount; i++) { - if (skeletonData->pathConstraints[i] == data) { - constraintIndex = i; - break; - } - } - - for (timelineMap = constraintMap->child; timelineMap; timelineMap = timelineMap->next) { - const char* timelineName = timelineMap->name; - if (strcmp(timelineName, "position") == 0 || strcmp(timelineName, "spacing") == 0) { - spPathConstraintPositionTimeline* timeline; - float timelineScale = 1; - if (strcmp(timelineName, "spacing") == 0) { - timeline = (spPathConstraintPositionTimeline*)spPathConstraintSpacingTimeline_create(timelineMap->size); - if (data->spacingMode == SP_SPACING_MODE_LENGTH || data->spacingMode == SP_SPACING_MODE_FIXED) timelineScale = self->scale; - } else { - timeline = spPathConstraintPositionTimeline_create(timelineMap->size); - if (data->positionMode == SP_POSITION_MODE_FIXED) timelineScale = self->scale; - } - timeline->pathConstraintIndex = constraintIndex; - for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { - spPathConstraintPositionTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, timelineName, 0) * timelineScale); - readCurve(valueMap, SUPER(timeline), frameIndex); - } - animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); - animation->duration = MAX(animation->duration, timeline->frames[(timelineMap->size - 1) * PATHCONSTRAINTPOSITION_ENTRIES]); - } else if (strcmp(timelineName, "mix")) { - spPathConstraintMixTimeline* timeline = spPathConstraintMixTimeline_create(timelineMap->size); - timeline->pathConstraintIndex = constraintIndex; - for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { - spPathConstraintMixTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), - Json_getFloat(valueMap, "rotateMix", 1), Json_getFloat(valueMap, "translateMix", 1)); - readCurve(valueMap, SUPER(timeline), frameIndex); - } - animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); - animation->duration = MAX(animation->duration, timeline->frames[(timelineMap->size - 1) * PATHCONSTRAINTMIX_ENTRIES]); - } - } - } - - /* Deform timelines. */ - for (constraintMap = deform ? deform->child : 0; constraintMap; constraintMap = constraintMap->next) { - spSkin* skin = spSkeletonData_findSkin(skeletonData, constraintMap->name); - for (slotMap = constraintMap->child; slotMap; slotMap = slotMap->next) { - int slotIndex = spSkeletonData_findSlotIndex(skeletonData, slotMap->name); - Json* timelineMap; - for (timelineMap = slotMap->child; timelineMap; timelineMap = timelineMap->next) { - float* tempDeform; - spDeformTimeline *timeline; - int weighted, deformLength; - - spVertexAttachment* attachment = SUB_CAST(spVertexAttachment, spSkin_getAttachment(skin, slotIndex, timelineMap->name)); - if (!attachment) { - spAnimation_dispose(animation); - _spSkeletonJson_setError(self, 0, "Attachment not found: ", timelineMap->name); - return 0; - } - weighted = attachment->bones != 0; - deformLength = weighted ? attachment->verticesCount / 3 * 2 : attachment->verticesCount; - tempDeform = MALLOC(float, deformLength); - - timeline = spDeformTimeline_create(timelineMap->size, deformLength); - timeline->slotIndex = slotIndex; - timeline->attachment = SUPER(attachment); - - for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { - Json* vertices = Json_getItem(valueMap, "vertices"); - float* deform; - if (!vertices) { - if (weighted) { - deform = tempDeform; - memset(deform, 0, sizeof(float) * deformLength); - } else - deform = attachment->vertices; - } else { - int v, start = Json_getInt(valueMap, "offset", 0); - Json* vertex; - deform = tempDeform; - memset(deform, 0, sizeof(float) * start); - if (self->scale == 1) { - for (vertex = vertices->child, v = start; vertex; vertex = vertex->next, ++v) - deform[v] = vertex->valueFloat; - } else { - for (vertex = vertices->child, v = start; vertex; vertex = vertex->next, ++v) - deform[v] = vertex->valueFloat * self->scale; - } - memset(deform + v, 0, sizeof(float) * (deformLength - v)); - if (!weighted) { - float* vertices = attachment->vertices; - for (v = 0; v < deformLength; ++v) - deform[v] += vertices[v]; - } - } - spDeformTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), deform); - readCurve(valueMap, SUPER(timeline), frameIndex); - } - FREE(tempDeform); - - animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); - animation->duration = MAX(animation->duration, timeline->frames[timelineMap->size - 1]); - } - } - } - - /* Draw order timeline. */ - if (drawOrder) { - spDrawOrderTimeline* timeline = spDrawOrderTimeline_create(drawOrder->size, skeletonData->slotsCount); - for (valueMap = drawOrder->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { - int ii; - int* drawOrder = 0; - Json* offsets = Json_getItem(valueMap, "offsets"); - if (offsets) { - Json* offsetMap; - int* unchanged = MALLOC(int, skeletonData->slotsCount - offsets->size); - int originalIndex = 0, unchangedIndex = 0; - - drawOrder = MALLOC(int, skeletonData->slotsCount); - for (ii = skeletonData->slotsCount - 1; ii >= 0; --ii) - drawOrder[ii] = -1; - - for (offsetMap = offsets->child; offsetMap; offsetMap = offsetMap->next) { - int slotIndex = spSkeletonData_findSlotIndex(skeletonData, Json_getString(offsetMap, "slot", 0)); - if (slotIndex == -1) { - spAnimation_dispose(animation); - _spSkeletonJson_setError(self, 0, "Slot not found: ", Json_getString(offsetMap, "slot", 0)); - return 0; - } - /* Collect unchanged items. */ - while (originalIndex != slotIndex) - unchanged[unchangedIndex++] = originalIndex++; - /* Set changed items. */ - drawOrder[originalIndex + Json_getInt(offsetMap, "offset", 0)] = originalIndex; - originalIndex++; - } - /* Collect remaining unchanged items. */ - while (originalIndex < skeletonData->slotsCount) - unchanged[unchangedIndex++] = originalIndex++; - /* Fill in unchanged items. */ - for (ii = skeletonData->slotsCount - 1; ii >= 0; ii--) - if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex]; - FREE(unchanged); - } - spDrawOrderTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), drawOrder); - FREE(drawOrder); - } - animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); - animation->duration = MAX(animation->duration, timeline->frames[drawOrder->size - 1]); - } - - /* Event timeline. */ - if (events) { - spEventTimeline* timeline = spEventTimeline_create(events->size); - for (valueMap = events->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { - spEvent* event; - const char* stringValue; - spEventData* eventData = spSkeletonData_findEvent(skeletonData, Json_getString(valueMap, "name", 0)); - if (!eventData) { - spAnimation_dispose(animation); - _spSkeletonJson_setError(self, 0, "Event not found: ", Json_getString(valueMap, "name", 0)); - return 0; - } - event = spEvent_create(Json_getFloat(valueMap, "time", 0), eventData); - event->intValue = Json_getInt(valueMap, "int", eventData->intValue); - event->floatValue = Json_getFloat(valueMap, "float", eventData->floatValue); - stringValue = Json_getString(valueMap, "string", eventData->stringValue); - if (stringValue) MALLOC_STR(event->stringValue, stringValue); - spEventTimeline_setFrame(timeline, frameIndex, event); - } - animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); - animation->duration = MAX(animation->duration, timeline->frames[events->size - 1]); - } - - return animation; -} - -static void _readVertices (spSkeletonJson* self, Json* attachmentMap, spVertexAttachment* attachment, int verticesLength) { - Json* entry; - float* vertices; - int i, b, w, nn, entrySize; - - attachment->worldVerticesLength = verticesLength; - - entry = Json_getItem(attachmentMap, "vertices"); - entrySize = entry->size; - vertices = MALLOC(float, entrySize); - for (entry = entry->child, i = 0; entry; entry = entry->next, ++i) - vertices[i] = entry->valueFloat; - - if (verticesLength == entrySize) { - if (self->scale != 1) - for (i = 0; i < entrySize; ++i) - vertices[i] *= self->scale; - attachment->verticesCount = verticesLength; - attachment->vertices = vertices; - - attachment->bonesCount = 0; - attachment->bones = 0; - } else { - attachment->verticesCount = 0; - attachment->bonesCount = 0; - - for (i = 0; i < entrySize;) { - int bonesCount = (int)vertices[i]; - attachment->bonesCount += 1 + bonesCount; - attachment->verticesCount += 3 * bonesCount; - i += 1 + bonesCount * 4; - } - - attachment->vertices = MALLOC(float, attachment->verticesCount); - attachment->bones = MALLOC(int, attachment->bonesCount); - - for (i = 0, b = 0, w = 0; i < entrySize;) { - int bonesCount = (int)vertices[i++]; - attachment->bones[b++] = bonesCount; - for (nn = i + bonesCount * 4; i < nn;) { - attachment->bones[b++] = (int)vertices[i++]; - attachment->vertices[w++] = vertices[i++] * self->scale; - attachment->vertices[w++] = vertices[i++] * self->scale; - attachment->vertices[w++] = vertices[i++]; - } - } - - FREE(vertices); - } -} - -spSkeletonData* spSkeletonJson_readSkeletonDataFile (spSkeletonJson* self, const char* path) { - int length; - spSkeletonData* skeletonData; - const char* json = _spUtil_readFile(path, &length); - if (length == 0 || !json) { - _spSkeletonJson_setError(self, 0, "Unable to read skeleton file: ", path); - return 0; - } - skeletonData = spSkeletonJson_readSkeletonData(self, json); - FREE(json); - return skeletonData; -} - -spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const char* json) { - int i, ii; - spSkeletonData* skeletonData; - Json *root, *skeleton, *bones, *boneMap, *ik, *transform, *path, *slots, *skins, *animations, *events; - char* oldLocale; - _spSkeletonJson* internal = SUB_CAST(_spSkeletonJson, self); - - FREE(self->error); - CONST_CAST(char*, self->error) = 0; - internal->linkedMeshCount = 0; - -#ifndef __ANDROID__ - oldLocale = strdup(setlocale(LC_NUMERIC, NULL)); - setlocale(LC_NUMERIC, "C"); -#endif - - root = Json_create(json); - -#ifndef __ANDROID__ - setlocale(LC_NUMERIC, oldLocale); - free(oldLocale); -#endif - - if (!root) { - _spSkeletonJson_setError(self, 0, "Invalid skeleton JSON: ", Json_getError()); - return 0; - } - - skeletonData = spSkeletonData_create(); - - skeleton = Json_getItem(root, "skeleton"); - if (skeleton) { - MALLOC_STR(skeletonData->hash, Json_getString(skeleton, "hash", 0)); - MALLOC_STR(skeletonData->version, Json_getString(skeleton, "spine", 0)); - skeletonData->width = Json_getFloat(skeleton, "width", 0); - skeletonData->height = Json_getFloat(skeleton, "height", 0); - } - - /* Bones. */ - bones = Json_getItem(root, "bones"); - skeletonData->bones = MALLOC(spBoneData*, bones->size); - for (boneMap = bones->child, i = 0; boneMap; boneMap = boneMap->next, ++i) { - spBoneData* data; - - spBoneData* parent = 0; - const char* parentName = Json_getString(boneMap, "parent", 0); - if (parentName) { - parent = spSkeletonData_findBone(skeletonData, parentName); - if (!parent) { - spSkeletonData_dispose(skeletonData); - _spSkeletonJson_setError(self, root, "Parent bone not found: ", parentName); - return 0; - } - } - - data = spBoneData_create(skeletonData->bonesCount, Json_getString(boneMap, "name", 0), parent); - data->length = Json_getFloat(boneMap, "length", 0) * self->scale; - data->x = Json_getFloat(boneMap, "x", 0) * self->scale; - data->y = Json_getFloat(boneMap, "y", 0) * self->scale; - data->rotation = Json_getFloat(boneMap, "rotation", 0); - data->scaleX = Json_getFloat(boneMap, "scaleX", 1); - data->scaleY = Json_getFloat(boneMap, "scaleY", 1); - data->shearX = Json_getFloat(boneMap, "shearX", 0); - data->shearY = Json_getFloat(boneMap, "shearY", 0); - data->inheritRotation = Json_getInt(boneMap, "inheritRotation", 1); - data->inheritScale = Json_getInt(boneMap, "inheritScale", 1); - - skeletonData->bones[i] = data; - skeletonData->bonesCount++; - } - - /* Slots. */ - slots = Json_getItem(root, "slots"); - if (slots) { - Json *slotMap; - skeletonData->slotsCount = slots->size; - skeletonData->slots = MALLOC(spSlotData*, slots->size); - for (slotMap = slots->child, i = 0; slotMap; slotMap = slotMap->next, ++i) { - spSlotData* data; - const char* color; - Json *item; - - const char* boneName = Json_getString(slotMap, "bone", 0); - spBoneData* boneData = spSkeletonData_findBone(skeletonData, boneName); - if (!boneData) { - spSkeletonData_dispose(skeletonData); - _spSkeletonJson_setError(self, root, "Slot bone not found: ", boneName); - return 0; - } - - data = spSlotData_create(i, Json_getString(slotMap, "name", 0), boneData); - - color = Json_getString(slotMap, "color", 0); - if (color) { - data->r = toColor(color, 0); - data->g = toColor(color, 1); - data->b = toColor(color, 2); - data->a = toColor(color, 3); - } - - item = Json_getItem(slotMap, "attachment"); - if (item) spSlotData_setAttachmentName(data, item->valueString); - - item = Json_getItem(slotMap, "blend"); - if (item) { - if (strcmp(item->valueString, "additive") == 0) - data->blendMode = SP_BLEND_MODE_ADDITIVE; - else if (strcmp(item->valueString, "multiply") == 0) - data->blendMode = SP_BLEND_MODE_MULTIPLY; - else if (strcmp(item->valueString, "screen") == 0) - data->blendMode = SP_BLEND_MODE_SCREEN; - } - - skeletonData->slots[i] = data; - } - } - - /* IK constraints. */ - ik = Json_getItem(root, "ik"); - if (ik) { - Json *constraintMap; - skeletonData->ikConstraintsCount = ik->size; - skeletonData->ikConstraints = MALLOC(spIkConstraintData*, ik->size); - for (constraintMap = ik->child, i = 0; constraintMap; constraintMap = constraintMap->next, ++i) { - const char* targetName; - - spIkConstraintData* data = spIkConstraintData_create(Json_getString(constraintMap, "name", 0)); - - boneMap = Json_getItem(constraintMap, "bones"); - data->bonesCount = boneMap->size; - data->bones = MALLOC(spBoneData*, boneMap->size); - for (boneMap = boneMap->child, ii = 0; boneMap; boneMap = boneMap->next, ++ii) { - data->bones[ii] = spSkeletonData_findBone(skeletonData, boneMap->valueString); - if (!data->bones[ii]) { - spSkeletonData_dispose(skeletonData); - _spSkeletonJson_setError(self, root, "IK bone not found: ", boneMap->valueString); - return 0; - } - } - - targetName = Json_getString(constraintMap, "target", 0); - data->target = spSkeletonData_findBone(skeletonData, targetName); - if (!data->target) { - spSkeletonData_dispose(skeletonData); - _spSkeletonJson_setError(self, root, "Target bone not found: ", boneMap->name); - return 0; - } - - data->bendDirection = Json_getInt(constraintMap, "bendPositive", 1) ? 1 : -1; - data->mix = Json_getFloat(constraintMap, "mix", 1); - - skeletonData->ikConstraints[i] = data; - } - } - - /* Transform constraints. */ - transform = Json_getItem(root, "transform"); - if (transform) { - Json *constraintMap; - skeletonData->transformConstraintsCount = transform->size; - skeletonData->transformConstraints = MALLOC(spTransformConstraintData*, transform->size); - for (constraintMap = transform->child, i = 0; constraintMap; constraintMap = constraintMap->next, ++i) { - const char* name; - - spTransformConstraintData* data = spTransformConstraintData_create(Json_getString(constraintMap, "name", 0)); - - boneMap = Json_getItem(constraintMap, "bones"); - data->bonesCount = boneMap->size; - CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, boneMap->size); - for (boneMap = boneMap->child, ii = 0; boneMap; boneMap = boneMap->next, ++ii) { - data->bones[ii] = spSkeletonData_findBone(skeletonData, boneMap->valueString); - if (!data->bones[ii]) { - spSkeletonData_dispose(skeletonData); - _spSkeletonJson_setError(self, root, "Transform bone not found: ", boneMap->valueString); - return 0; - } - } - - name = Json_getString(constraintMap, "target", 0); - data->target = spSkeletonData_findBone(skeletonData, name); - if (!data->target) { - spSkeletonData_dispose(skeletonData); - _spSkeletonJson_setError(self, root, "Target bone not found: ", boneMap->name); - return 0; - } - - data->offsetRotation = Json_getFloat(constraintMap, "rotation", 0); - data->offsetX = Json_getFloat(constraintMap, "x", 0) * self->scale; - data->offsetY = Json_getFloat(constraintMap, "y", 0) * self->scale; - data->offsetScaleX = Json_getFloat(constraintMap, "scaleX", 0); - data->offsetScaleY = Json_getFloat(constraintMap, "scaleY", 0); - data->offsetShearY = Json_getFloat(constraintMap, "shearY", 0); - - data->rotateMix = Json_getFloat(constraintMap, "rotateMix", 1); - data->translateMix = Json_getFloat(constraintMap, "translateMix", 1); - data->scaleMix = Json_getFloat(constraintMap, "scaleMix", 1); - data->shearMix = Json_getFloat(constraintMap, "shearMix", 1); - - skeletonData->transformConstraints[i] = data; - } - } - - /* Path constraints */ - path = Json_getItem(root, "path"); - if (path) { - Json *constraintMap; - skeletonData->pathConstraintsCount = path->size; - skeletonData->pathConstraints = MALLOC(spPathConstraintData*, path->size); - for (constraintMap = path->child, i = 0; constraintMap; constraintMap = constraintMap->next, ++i) { - const char* name; - const char* item; - - spPathConstraintData* data = spPathConstraintData_create(Json_getString(constraintMap, "name", 0)); - - boneMap = Json_getItem(constraintMap, "bones"); - data->bonesCount = boneMap->size; - CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, boneMap->size); - for (boneMap = boneMap->child, ii = 0; boneMap; boneMap = boneMap->next, ++ii) { - data->bones[ii] = spSkeletonData_findBone(skeletonData, boneMap->valueString); - if (!data->bones[ii]) { - spSkeletonData_dispose(skeletonData); - _spSkeletonJson_setError(self, root, "Path bone not found: ", boneMap->valueString); - return 0; - } - } - - name = Json_getString(constraintMap, "target", 0); - data->target = spSkeletonData_findSlot(skeletonData, name); - if (!data->target) { - spSkeletonData_dispose(skeletonData); - _spSkeletonJson_setError(self, root, "Target slot not found: ", boneMap->name); - return 0; - } - - item = Json_getString(constraintMap, "positionMode", "percent"); - if (strcmp(item, "fixed") == 0) data->positionMode = SP_POSITION_MODE_FIXED; - else if (strcmp(item, "percent") == 0) data->positionMode = SP_POSITION_MODE_PERCENT; - - item = Json_getString(constraintMap, "spacingMode", "length"); - if (strcmp(item, "length") == 0) data->spacingMode = SP_SPACING_MODE_LENGTH; - else if (strcmp(item, "fixed") == 0) data->spacingMode = SP_SPACING_MODE_FIXED; - else if (strcmp(item, "percent") == 0) data->spacingMode = SP_SPACING_MODE_PERCENT; - - item = Json_getString(constraintMap, "rotateMode", "tangent"); - if (strcmp(item, "tangent") == 0) data->rotateMode = SP_ROTATE_MODE_TANGENT; - else if (strcmp(item, "chain") == 0) data->rotateMode = SP_ROTATE_MODE_CHAIN; - else if (strcmp(item, "chainScale") == 0) data->rotateMode = SP_ROTATE_MODE_CHAIN_SCALE; - - data->offsetRotation = Json_getFloat(constraintMap, "rotation", 0); - data->position = Json_getFloat(constraintMap, "position", 0); - if (data->positionMode == SP_POSITION_MODE_FIXED) data->position *= self->scale; - data->spacing = Json_getFloat(constraintMap, "spacing", 0); - if (data->spacingMode == SP_SPACING_MODE_LENGTH || data->spacingMode == SP_SPACING_MODE_FIXED) data->spacing *= self->scale; - data->rotateMix = Json_getFloat(constraintMap, "rotateMix", 1); - data->translateMix = Json_getFloat(constraintMap, "translateMix", 1); - - skeletonData->pathConstraints[i] = data; - } - } - - /* Skins. */ - skins = Json_getItem(root, "skins"); - if (skins) { - Json *skinMap; - skeletonData->skins = MALLOC(spSkin*, skins->size); - for (skinMap = skins->child, i = 0; skinMap; skinMap = skinMap->next, ++i) { - Json *attachmentsMap; - Json *curves; - spSkin *skin = spSkin_create(skinMap->name); - - skeletonData->skins[skeletonData->skinsCount++] = skin; - if (strcmp(skinMap->name, "default") == 0) skeletonData->defaultSkin = skin; - - for (attachmentsMap = skinMap->child; attachmentsMap; attachmentsMap = attachmentsMap->next) { - int slotIndex = spSkeletonData_findSlotIndex(skeletonData, attachmentsMap->name); - Json *attachmentMap; - - for (attachmentMap = attachmentsMap->child; attachmentMap; attachmentMap = attachmentMap->next) { - spAttachment* attachment; - const char* skinAttachmentName = attachmentMap->name; - const char* attachmentName = Json_getString(attachmentMap, "name", skinAttachmentName); - const char* path = Json_getString(attachmentMap, "path", attachmentName); - const char* color; - Json* entry; - - const char* typeString = Json_getString(attachmentMap, "type", "region"); - spAttachmentType type; - if (strcmp(typeString, "region") == 0) - type = SP_ATTACHMENT_REGION; - else if (strcmp(typeString, "mesh") == 0) - type = SP_ATTACHMENT_MESH; - else if (strcmp(typeString, "linkedmesh") == 0) - type = SP_ATTACHMENT_LINKED_MESH; - else if (strcmp(typeString, "boundingbox") == 0) - type = SP_ATTACHMENT_BOUNDING_BOX; - else if (strcmp(typeString, "path") == 0) - type = SP_ATTACHMENT_PATH; - else { - spSkeletonData_dispose(skeletonData); - _spSkeletonJson_setError(self, root, "Unknown attachment type: ", typeString); - return 0; - } - - attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, attachmentName, path); - if (!attachment) { - if (self->attachmentLoader->error1) { - spSkeletonData_dispose(skeletonData); - _spSkeletonJson_setError(self, root, self->attachmentLoader->error1, self->attachmentLoader->error2); - return 0; - } - continue; - } - - switch (attachment->type) { - case SP_ATTACHMENT_REGION: { - spRegionAttachment* region = SUB_CAST(spRegionAttachment, attachment); - if (path) MALLOC_STR(region->path, path); - region->x = Json_getFloat(attachmentMap, "x", 0) * self->scale; - region->y = Json_getFloat(attachmentMap, "y", 0) * self->scale; - region->scaleX = Json_getFloat(attachmentMap, "scaleX", 1); - region->scaleY = Json_getFloat(attachmentMap, "scaleY", 1); - region->rotation = Json_getFloat(attachmentMap, "rotation", 0); - region->width = Json_getFloat(attachmentMap, "width", 32) * self->scale; - region->height = Json_getFloat(attachmentMap, "height", 32) * self->scale; - - color = Json_getString(attachmentMap, "color", 0); - if (color) { - region->r = toColor(color, 0); - region->g = toColor(color, 1); - region->b = toColor(color, 2); - region->a = toColor(color, 3); - } - - spRegionAttachment_updateOffset(region); - - spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); - break; - } - case SP_ATTACHMENT_MESH: - case SP_ATTACHMENT_LINKED_MESH: { - spMeshAttachment* mesh = SUB_CAST(spMeshAttachment, attachment); - - MALLOC_STR(mesh->path, path); - - color = Json_getString(attachmentMap, "color", 0); - if (color) { - mesh->r = toColor(color, 0); - mesh->g = toColor(color, 1); - mesh->b = toColor(color, 2); - mesh->a = toColor(color, 3); - } - - mesh->width = Json_getFloat(attachmentMap, "width", 32) * self->scale; - mesh->height = Json_getFloat(attachmentMap, "height", 32) * self->scale; - - entry = Json_getItem(attachmentMap, "parent"); - if (!entry) { - int verticesLength; - entry = Json_getItem(attachmentMap, "triangles"); - mesh->trianglesCount = entry->size; - mesh->triangles = MALLOC(unsigned short, entry->size); - for (entry = entry->child, ii = 0; entry; entry = entry->next, ++ii) - mesh->triangles[ii] = (unsigned short)entry->valueInt; - - entry = Json_getItem(attachmentMap, "uvs"); - verticesLength = entry->size; - mesh->regionUVs = MALLOC(float, verticesLength); - for (entry = entry->child, ii = 0; entry; entry = entry->next, ++ii) - mesh->regionUVs[ii] = entry->valueFloat; - - _readVertices(self, attachmentMap, SUPER(mesh), verticesLength); - - spMeshAttachment_updateUVs(mesh); - - mesh->hullLength = Json_getInt(attachmentMap, "hull", 0); - - entry = Json_getItem(attachmentMap, "edges"); - if (entry) { - mesh->edgesCount = entry->size; - mesh->edges = MALLOC(int, entry->size); - for (entry = entry->child, ii = 0; entry; entry = entry->next, ++ii) - mesh->edges[ii] = entry->valueInt; - } - - spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); - } else { - mesh->inheritDeform = Json_getInt(attachmentMap, "deform", 1); - _spSkeletonJson_addLinkedMesh(self, SUB_CAST(spMeshAttachment, attachment), Json_getString(attachmentMap, "skin", 0), slotIndex, - entry->valueString); - } - break; - } - case SP_ATTACHMENT_BOUNDING_BOX: { - spBoundingBoxAttachment* box = SUB_CAST(spBoundingBoxAttachment, attachment); - int vertexCount = Json_getInt(attachmentMap, "vertexCount", 0) << 1; - _readVertices(self, attachmentMap, SUPER(box), vertexCount); - box->super.verticesCount = vertexCount; - spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); - break; - } - case SP_ATTACHMENT_PATH: { - spPathAttachment* path = SUB_CAST(spPathAttachment, attachment); - int vertexCount = 0; - path->closed = Json_getInt(attachmentMap, "closed", 0); - path->constantSpeed = Json_getInt(attachmentMap, "constantSpeed", 1); - vertexCount = Json_getInt(attachmentMap, "vertexCount", 0); - _readVertices(self, attachmentMap, SUPER(path), vertexCount << 1); - - path->lengthsLength = vertexCount / 3; - path->lengths = MALLOC(float, path->lengthsLength); - - curves = Json_getItem(attachmentMap, "lengths"); - for (curves = curves->child, ii = 0; curves; curves = curves->next, ++ii) { - path->lengths[ii] = curves->valueFloat * self->scale; - } - break; - } - } - - spSkin_addAttachment(skin, slotIndex, skinAttachmentName, attachment); - } - } - } - } - - /* Linked meshes. */ - for (i = 0; i < internal->linkedMeshCount; i++) { - spAttachment* parent; - _spLinkedMesh* linkedMesh = internal->linkedMeshes + i; - spSkin* skin = !linkedMesh->skin ? skeletonData->defaultSkin : spSkeletonData_findSkin(skeletonData, linkedMesh->skin); - if (!skin) { - spSkeletonData_dispose(skeletonData); - _spSkeletonJson_setError(self, 0, "Skin not found: ", linkedMesh->skin); - return 0; - } - parent = spSkin_getAttachment(skin, linkedMesh->slotIndex, linkedMesh->parent); - if (!parent) { - spSkeletonData_dispose(skeletonData); - _spSkeletonJson_setError(self, 0, "Parent mesh not found: ", linkedMesh->parent); - return 0; - } - spMeshAttachment_setParentMesh(linkedMesh->mesh, SUB_CAST(spMeshAttachment, parent)); - spMeshAttachment_updateUVs(linkedMesh->mesh); - spAttachmentLoader_configureAttachment(self->attachmentLoader, SUPER(SUPER(linkedMesh->mesh))); - } - - /* Events. */ - events = Json_getItem(root, "events"); - if (events) { - Json *eventMap; - const char* stringValue; - skeletonData->eventsCount = events->size; - skeletonData->events = MALLOC(spEventData*, events->size); - for (eventMap = events->child, i = 0; eventMap; eventMap = eventMap->next, ++i) { - spEventData* eventData = spEventData_create(eventMap->name); - eventData->intValue = Json_getInt(eventMap, "int", 0); - eventData->floatValue = Json_getFloat(eventMap, "float", 0); - stringValue = Json_getString(eventMap, "string", 0); - if (stringValue) MALLOC_STR(eventData->stringValue, stringValue); - skeletonData->events[i] = eventData; - } - } - - /* Animations. */ - animations = Json_getItem(root, "animations"); - if (animations) { - Json *animationMap; - skeletonData->animations = MALLOC(spAnimation*, animations->size); - for (animationMap = animations->child; animationMap; animationMap = animationMap->next) { - spAnimation* animation = _spSkeletonJson_readAnimation(self, animationMap, skeletonData); - if (!animation) { - spSkeletonData_dispose(skeletonData); - return 0; - } - skeletonData->animations[skeletonData->animationsCount++] = animation; - } - } - - Json_dispose(root); - return skeletonData; +#include +#include +#include +#include "Json.h" +#include +#include +#include + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__) +#define strdup _strdup +#endif + +typedef struct { + const char* parent; + const char* skin; + int slotIndex; + spMeshAttachment* mesh; +} _spLinkedMesh; + +typedef struct { + spSkeletonJson super; + int ownsLoader; + + int linkedMeshCount; + int linkedMeshCapacity; + _spLinkedMesh* linkedMeshes; +} _spSkeletonJson; + +spSkeletonJson* spSkeletonJson_createWithLoader (spAttachmentLoader* attachmentLoader) { + spSkeletonJson* self = SUPER(NEW(_spSkeletonJson)); + self->scale = 1; + self->attachmentLoader = attachmentLoader; + return self; +} + +spSkeletonJson* spSkeletonJson_create (spAtlas* atlas) { + spAtlasAttachmentLoader* attachmentLoader = spAtlasAttachmentLoader_create(atlas); + spSkeletonJson* self = spSkeletonJson_createWithLoader(SUPER(attachmentLoader)); + SUB_CAST(_spSkeletonJson, self)->ownsLoader = 1; + return self; +} + +void spSkeletonJson_dispose (spSkeletonJson* self) { + _spSkeletonJson* internal = SUB_CAST(_spSkeletonJson, self); + if (internal->ownsLoader) spAttachmentLoader_dispose(self->attachmentLoader); + FREE(internal->linkedMeshes); + FREE(self->error); + FREE(self); +} + +void _spSkeletonJson_setError (spSkeletonJson* self, Json* root, const char* value1, const char* value2) { + char message[256]; + int length; + FREE(self->error); + strcpy(message, value1); + length = (int)strlen(value1); + if (value2) strncat(message + length, value2, 255 - length); + MALLOC_STR(self->error, message); + if (root) Json_dispose(root); +} + +static float toColor (const char* value, int index) { + char digits[3]; + char *error; + int color; + + if (strlen(value) != 8) return -1; + value += index * 2; + + digits[0] = *value; + digits[1] = *(value + 1); + digits[2] = '\0'; + color = (int)strtoul(digits, &error, 16); + if (*error != 0) return -1; + return color / (float)255; +} + +static void readCurve (Json* frame, spCurveTimeline* timeline, int frameIndex) { + Json* curve = Json_getItem(frame, "curve"); + if (!curve) return; + if (curve->type == Json_String && strcmp(curve->valueString, "stepped") == 0) + spCurveTimeline_setStepped(timeline, frameIndex); + else if (curve->type == Json_Array) { + Json* child0 = curve->child; + Json* child1 = child0->next; + Json* child2 = child1->next; + Json* child3 = child2->next; + spCurveTimeline_setCurve(timeline, frameIndex, child0->valueFloat, child1->valueFloat, child2->valueFloat, + child3->valueFloat); + } +} + +static void _spSkeletonJson_addLinkedMesh (spSkeletonJson* self, spMeshAttachment* mesh, const char* skin, int slotIndex, + const char* parent) { + _spLinkedMesh* linkedMesh; + _spSkeletonJson* internal = SUB_CAST(_spSkeletonJson, self); + + if (internal->linkedMeshCount == internal->linkedMeshCapacity) { + _spLinkedMesh* linkedMeshes; + internal->linkedMeshCapacity *= 2; + if (internal->linkedMeshCapacity < 8) internal->linkedMeshCapacity = 8; + linkedMeshes = MALLOC(_spLinkedMesh, internal->linkedMeshCapacity); + memcpy(linkedMeshes, internal->linkedMeshes, sizeof(_spLinkedMesh) * internal->linkedMeshCount); + FREE(internal->linkedMeshes); + internal->linkedMeshes = linkedMeshes; + } + + linkedMesh = internal->linkedMeshes + internal->linkedMeshCount++; + linkedMesh->mesh = mesh; + linkedMesh->skin = skin; + linkedMesh->slotIndex = slotIndex; + linkedMesh->parent = parent; +} + +static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* root, spSkeletonData *skeletonData) { + int frameIndex; + spAnimation* animation; + Json* valueMap; + int timelinesCount = 0; + + Json* bones = Json_getItem(root, "bones"); + Json* slots = Json_getItem(root, "slots"); + Json* ik = Json_getItem(root, "ik"); + Json* transform = Json_getItem(root, "transform"); + Json* paths = Json_getItem(root, "paths"); + Json* deform = Json_getItem(root, "deform"); + Json* drawOrder = Json_getItem(root, "drawOrder"); + Json* events = Json_getItem(root, "events"); + Json *boneMap, *slotMap, *constraintMap; + if (!drawOrder) drawOrder = Json_getItem(root, "draworder"); + + for (boneMap = bones ? bones->child : 0; boneMap; boneMap = boneMap->next) + timelinesCount += boneMap->size; + for (slotMap = slots ? slots->child : 0; slotMap; slotMap = slotMap->next) + timelinesCount += slotMap->size; + timelinesCount += ik ? ik->size : 0; + timelinesCount += transform ? transform->size : 0; + for (constraintMap = paths ? paths->child : 0; constraintMap; constraintMap = constraintMap->next) + timelinesCount += constraintMap->size; + for (constraintMap = deform ? deform->child : 0; constraintMap; constraintMap = constraintMap->next) + for (slotMap = constraintMap->child; slotMap; slotMap = slotMap->next) + timelinesCount += slotMap->size; + if (drawOrder) ++timelinesCount; + if (events) ++timelinesCount; + + animation = spAnimation_create(root->name, timelinesCount); + animation->timelinesCount = 0; + + /* Slot timelines. */ + for (slotMap = slots ? slots->child : 0; slotMap; slotMap = slotMap->next) { + Json *timelineMap; + + int slotIndex = spSkeletonData_findSlotIndex(skeletonData, slotMap->name); + if (slotIndex == -1) { + spAnimation_dispose(animation); + _spSkeletonJson_setError(self, root, "Slot not found: ", slotMap->name); + return 0; + } + + for (timelineMap = slotMap->child; timelineMap; timelineMap = timelineMap->next) { + if (strcmp(timelineMap->name, "color") == 0) { + spColorTimeline *timeline = spColorTimeline_create(timelineMap->size); + timeline->slotIndex = slotIndex; + + for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { + const char* s = Json_getString(valueMap, "color", 0); + spColorTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), toColor(s, 0), toColor(s, 1), toColor(s, 2), + toColor(s, 3)); + readCurve(valueMap, SUPER(timeline), frameIndex); + } + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); + animation->duration = MAX(animation->duration, timeline->frames[(timelineMap->size - 1) * COLOR_ENTRIES]); + + } else if (strcmp(timelineMap->name, "attachment") == 0) { + spAttachmentTimeline *timeline = spAttachmentTimeline_create(timelineMap->size); + timeline->slotIndex = slotIndex; + + for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { + Json* name = Json_getItem(valueMap, "name"); + spAttachmentTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), + name->type == Json_NULL ? 0 : name->valueString); + } + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); + animation->duration = MAX(animation->duration, timeline->frames[timelineMap->size - 1]); + + } else { + spAnimation_dispose(animation); + _spSkeletonJson_setError(self, 0, "Invalid timeline type for a slot: ", timelineMap->name); + return 0; + } + } + } + + /* Bone timelines. */ + for (boneMap = bones ? bones->child : 0; boneMap; boneMap = boneMap->next) { + Json *timelineMap; + + int boneIndex = spSkeletonData_findBoneIndex(skeletonData, boneMap->name); + if (boneIndex == -1) { + spAnimation_dispose(animation); + _spSkeletonJson_setError(self, root, "Bone not found: ", boneMap->name); + return 0; + } + + for (timelineMap = boneMap->child; timelineMap; timelineMap = timelineMap->next) { + if (strcmp(timelineMap->name, "rotate") == 0) { + spRotateTimeline *timeline = spRotateTimeline_create(timelineMap->size); + timeline->boneIndex = boneIndex; + + for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { + spRotateTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, "angle", 0)); + readCurve(valueMap, SUPER(timeline), frameIndex); + } + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); + animation->duration = MAX(animation->duration, timeline->frames[(timelineMap->size - 1) * ROTATE_ENTRIES]); + + } else { + int isScale = strcmp(timelineMap->name, "scale") == 0; + int isTranslate = strcmp(timelineMap->name, "translate") == 0; + int isShear = strcmp(timelineMap->name, "shear") == 0; + if (isScale || isTranslate || isShear) { + float timelineScale = isTranslate ? self->scale: 1; + spTranslateTimeline *timeline = 0; + if (isScale) timeline = spScaleTimeline_create(timelineMap->size); + else if (isTranslate) timeline = spTranslateTimeline_create(timelineMap->size); + else if (isShear) timeline = spShearTimeline_create(timelineMap->size); + timeline->boneIndex = boneIndex; + + for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { + spTranslateTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, "x", 0) * timelineScale, + Json_getFloat(valueMap, "y", 0) * timelineScale); + readCurve(valueMap, SUPER(timeline), frameIndex); + } + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); + animation->duration = MAX(animation->duration, timeline->frames[(timelineMap->size - 1) * TRANSLATE_ENTRIES]); + + } else { + spAnimation_dispose(animation); + _spSkeletonJson_setError(self, 0, "Invalid timeline type for a bone: ", timelineMap->name); + return 0; + } + } + } + } + + /* IK constraint timelines. */ + for (constraintMap = ik ? ik->child : 0; constraintMap; constraintMap = constraintMap->next) { + spIkConstraintData* constraint = spSkeletonData_findIkConstraint(skeletonData, constraintMap->name); + spIkConstraintTimeline* timeline = spIkConstraintTimeline_create(constraintMap->size); + for (frameIndex = 0; frameIndex < skeletonData->ikConstraintsCount; ++frameIndex) { + if (constraint == skeletonData->ikConstraints[frameIndex]) { + timeline->ikConstraintIndex = frameIndex; + break; + } + } + for (valueMap = constraintMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { + spIkConstraintTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, "mix", 1), + Json_getInt(valueMap, "bendPositive", 1) ? 1 : -1); + readCurve(valueMap, SUPER(timeline), frameIndex); + } + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); + animation->duration = MAX(animation->duration, timeline->frames[(constraintMap->size - 1) * IKCONSTRAINT_ENTRIES]); + } + + /* Transform constraint timelines. */ + for (constraintMap = transform ? transform->child : 0; constraintMap; constraintMap = constraintMap->next) { + spTransformConstraintData* constraint = spSkeletonData_findTransformConstraint(skeletonData, constraintMap->name); + spTransformConstraintTimeline* timeline = spTransformConstraintTimeline_create(constraintMap->size); + for (frameIndex = 0; frameIndex < skeletonData->transformConstraintsCount; ++frameIndex) { + if (constraint == skeletonData->transformConstraints[frameIndex]) { + timeline->transformConstraintIndex = frameIndex; + break; + } + } + for (valueMap = constraintMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { + spTransformConstraintTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, "rotateMix", 1), + Json_getFloat(valueMap, "translateMix", 1), Json_getFloat(valueMap, "scaleMix", 1), Json_getFloat(valueMap, "shearMix", 1)); + readCurve(valueMap, SUPER(timeline), frameIndex); + } + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); + animation->duration = MAX(animation->duration, timeline->frames[(constraintMap->size - 1) * TRANSFORMCONSTRAINT_ENTRIES]); + } + + /** Path constraint timelines. */ + for(constraintMap = paths ? paths->child : 0; constraintMap; constraintMap = constraintMap->next ) { + int constraintIndex, i; + Json* timelineMap; + + spPathConstraintData* data = spSkeletonData_findPathConstraint(skeletonData, constraintMap->name); + if (!data) { + spAnimation_dispose(animation); + _spSkeletonJson_setError(self, root, "Path constraint not found: ", constraintMap->name); + return 0; + } + for (i = 0; i < skeletonData->pathConstraintsCount; i++) { + if (skeletonData->pathConstraints[i] == data) { + constraintIndex = i; + break; + } + } + + for (timelineMap = constraintMap->child; timelineMap; timelineMap = timelineMap->next) { + const char* timelineName = timelineMap->name; + if (strcmp(timelineName, "position") == 0 || strcmp(timelineName, "spacing") == 0) { + spPathConstraintPositionTimeline* timeline; + float timelineScale = 1; + if (strcmp(timelineName, "spacing") == 0) { + timeline = (spPathConstraintPositionTimeline*)spPathConstraintSpacingTimeline_create(timelineMap->size); + if (data->spacingMode == SP_SPACING_MODE_LENGTH || data->spacingMode == SP_SPACING_MODE_FIXED) timelineScale = self->scale; + } else { + timeline = spPathConstraintPositionTimeline_create(timelineMap->size); + if (data->positionMode == SP_POSITION_MODE_FIXED) timelineScale = self->scale; + } + timeline->pathConstraintIndex = constraintIndex; + for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { + spPathConstraintPositionTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, timelineName, 0) * timelineScale); + readCurve(valueMap, SUPER(timeline), frameIndex); + } + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); + animation->duration = MAX(animation->duration, timeline->frames[(timelineMap->size - 1) * PATHCONSTRAINTPOSITION_ENTRIES]); + } else if (strcmp(timelineName, "mix")) { + spPathConstraintMixTimeline* timeline = spPathConstraintMixTimeline_create(timelineMap->size); + timeline->pathConstraintIndex = constraintIndex; + for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { + spPathConstraintMixTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), + Json_getFloat(valueMap, "rotateMix", 1), Json_getFloat(valueMap, "translateMix", 1)); + readCurve(valueMap, SUPER(timeline), frameIndex); + } + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); + animation->duration = MAX(animation->duration, timeline->frames[(timelineMap->size - 1) * PATHCONSTRAINTMIX_ENTRIES]); + } + } + } + + /* Deform timelines. */ + for (constraintMap = deform ? deform->child : 0; constraintMap; constraintMap = constraintMap->next) { + spSkin* skin = spSkeletonData_findSkin(skeletonData, constraintMap->name); + for (slotMap = constraintMap->child; slotMap; slotMap = slotMap->next) { + int slotIndex = spSkeletonData_findSlotIndex(skeletonData, slotMap->name); + Json* timelineMap; + for (timelineMap = slotMap->child; timelineMap; timelineMap = timelineMap->next) { + float* tempDeform; + spDeformTimeline *timeline; + int weighted, deformLength; + + spVertexAttachment* attachment = SUB_CAST(spVertexAttachment, spSkin_getAttachment(skin, slotIndex, timelineMap->name)); + if (!attachment) { + spAnimation_dispose(animation); + _spSkeletonJson_setError(self, 0, "Attachment not found: ", timelineMap->name); + return 0; + } + weighted = attachment->bones != 0; + deformLength = weighted ? attachment->verticesCount / 3 * 2 : attachment->verticesCount; + tempDeform = MALLOC(float, deformLength); + + timeline = spDeformTimeline_create(timelineMap->size, deformLength); + timeline->slotIndex = slotIndex; + timeline->attachment = SUPER(attachment); + + for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { + Json* vertices = Json_getItem(valueMap, "vertices"); + float* deform; + if (!vertices) { + if (weighted) { + deform = tempDeform; + memset(deform, 0, sizeof(float) * deformLength); + } else + deform = attachment->vertices; + } else { + int v, start = Json_getInt(valueMap, "offset", 0); + Json* vertex; + deform = tempDeform; + memset(deform, 0, sizeof(float) * start); + if (self->scale == 1) { + for (vertex = vertices->child, v = start; vertex; vertex = vertex->next, ++v) + deform[v] = vertex->valueFloat; + } else { + for (vertex = vertices->child, v = start; vertex; vertex = vertex->next, ++v) + deform[v] = vertex->valueFloat * self->scale; + } + memset(deform + v, 0, sizeof(float) * (deformLength - v)); + if (!weighted) { + float* vertices = attachment->vertices; + for (v = 0; v < deformLength; ++v) + deform[v] += vertices[v]; + } + } + spDeformTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), deform); + readCurve(valueMap, SUPER(timeline), frameIndex); + } + FREE(tempDeform); + + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); + animation->duration = MAX(animation->duration, timeline->frames[timelineMap->size - 1]); + } + } + } + + /* Draw order timeline. */ + if (drawOrder) { + spDrawOrderTimeline* timeline = spDrawOrderTimeline_create(drawOrder->size, skeletonData->slotsCount); + for (valueMap = drawOrder->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { + int ii; + int* drawOrder = 0; + Json* offsets = Json_getItem(valueMap, "offsets"); + if (offsets) { + Json* offsetMap; + int* unchanged = MALLOC(int, skeletonData->slotsCount - offsets->size); + int originalIndex = 0, unchangedIndex = 0; + + drawOrder = MALLOC(int, skeletonData->slotsCount); + for (ii = skeletonData->slotsCount - 1; ii >= 0; --ii) + drawOrder[ii] = -1; + + for (offsetMap = offsets->child; offsetMap; offsetMap = offsetMap->next) { + int slotIndex = spSkeletonData_findSlotIndex(skeletonData, Json_getString(offsetMap, "slot", 0)); + if (slotIndex == -1) { + spAnimation_dispose(animation); + _spSkeletonJson_setError(self, 0, "Slot not found: ", Json_getString(offsetMap, "slot", 0)); + return 0; + } + /* Collect unchanged items. */ + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + /* Set changed items. */ + drawOrder[originalIndex + Json_getInt(offsetMap, "offset", 0)] = originalIndex; + originalIndex++; + } + /* Collect remaining unchanged items. */ + while (originalIndex < skeletonData->slotsCount) + unchanged[unchangedIndex++] = originalIndex++; + /* Fill in unchanged items. */ + for (ii = skeletonData->slotsCount - 1; ii >= 0; ii--) + if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex]; + FREE(unchanged); + } + spDrawOrderTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), drawOrder); + FREE(drawOrder); + } + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); + animation->duration = MAX(animation->duration, timeline->frames[drawOrder->size - 1]); + } + + /* Event timeline. */ + if (events) { + spEventTimeline* timeline = spEventTimeline_create(events->size); + for (valueMap = events->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) { + spEvent* event; + const char* stringValue; + spEventData* eventData = spSkeletonData_findEvent(skeletonData, Json_getString(valueMap, "name", 0)); + if (!eventData) { + spAnimation_dispose(animation); + _spSkeletonJson_setError(self, 0, "Event not found: ", Json_getString(valueMap, "name", 0)); + return 0; + } + event = spEvent_create(Json_getFloat(valueMap, "time", 0), eventData); + event->intValue = Json_getInt(valueMap, "int", eventData->intValue); + event->floatValue = Json_getFloat(valueMap, "float", eventData->floatValue); + stringValue = Json_getString(valueMap, "string", eventData->stringValue); + if (stringValue) MALLOC_STR(event->stringValue, stringValue); + spEventTimeline_setFrame(timeline, frameIndex, event); + } + animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline); + animation->duration = MAX(animation->duration, timeline->frames[events->size - 1]); + } + + return animation; +} + +static void _readVertices (spSkeletonJson* self, Json* attachmentMap, spVertexAttachment* attachment, int verticesLength) { + Json* entry; + float* vertices; + int i, b, w, nn, entrySize; + + attachment->worldVerticesLength = verticesLength; + + entry = Json_getItem(attachmentMap, "vertices"); + entrySize = entry->size; + vertices = MALLOC(float, entrySize); + for (entry = entry->child, i = 0; entry; entry = entry->next, ++i) + vertices[i] = entry->valueFloat; + + if (verticesLength == entrySize) { + if (self->scale != 1) + for (i = 0; i < entrySize; ++i) + vertices[i] *= self->scale; + attachment->verticesCount = verticesLength; + attachment->vertices = vertices; + + attachment->bonesCount = 0; + attachment->bones = 0; + } else { + attachment->verticesCount = 0; + attachment->bonesCount = 0; + + for (i = 0; i < entrySize;) { + int bonesCount = (int)vertices[i]; + attachment->bonesCount += 1 + bonesCount; + attachment->verticesCount += 3 * bonesCount; + i += 1 + bonesCount * 4; + } + + attachment->vertices = MALLOC(float, attachment->verticesCount); + attachment->bones = MALLOC(int, attachment->bonesCount); + + for (i = 0, b = 0, w = 0; i < entrySize;) { + int bonesCount = (int)vertices[i++]; + attachment->bones[b++] = bonesCount; + for (nn = i + bonesCount * 4; i < nn;) { + attachment->bones[b++] = (int)vertices[i++]; + attachment->vertices[w++] = vertices[i++] * self->scale; + attachment->vertices[w++] = vertices[i++] * self->scale; + attachment->vertices[w++] = vertices[i++]; + } + } + + FREE(vertices); + } +} + +spSkeletonData* spSkeletonJson_readSkeletonDataFile (spSkeletonJson* self, const char* path) { + int length; + spSkeletonData* skeletonData; + const char* json = _spUtil_readFile(path, &length); + if (length == 0 || !json) { + _spSkeletonJson_setError(self, 0, "Unable to read skeleton file: ", path); + return 0; + } + skeletonData = spSkeletonJson_readSkeletonData(self, json); + FREE(json); + return skeletonData; +} + +spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const char* json) { + int i, ii; + spSkeletonData* skeletonData; + Json *root, *skeleton, *bones, *boneMap, *ik, *transform, *path, *slots, *skins, *animations, *events; + char* oldLocale; + _spSkeletonJson* internal = SUB_CAST(_spSkeletonJson, self); + + FREE(self->error); + CONST_CAST(char*, self->error) = 0; + internal->linkedMeshCount = 0; + +#ifndef __ANDROID__ + oldLocale = strdup(setlocale(LC_NUMERIC, NULL)); + setlocale(LC_NUMERIC, "C"); +#endif + + root = Json_create(json); + +#ifndef __ANDROID__ + setlocale(LC_NUMERIC, oldLocale); + free(oldLocale); +#endif + + if (!root) { + _spSkeletonJson_setError(self, 0, "Invalid skeleton JSON: ", Json_getError()); + return 0; + } + + skeletonData = spSkeletonData_create(); + + skeleton = Json_getItem(root, "skeleton"); + if (skeleton) { + MALLOC_STR(skeletonData->hash, Json_getString(skeleton, "hash", 0)); + MALLOC_STR(skeletonData->version, Json_getString(skeleton, "spine", 0)); + skeletonData->width = Json_getFloat(skeleton, "width", 0); + skeletonData->height = Json_getFloat(skeleton, "height", 0); + } + + /* Bones. */ + bones = Json_getItem(root, "bones"); + skeletonData->bones = MALLOC(spBoneData*, bones->size); + for (boneMap = bones->child, i = 0; boneMap; boneMap = boneMap->next, ++i) { + spBoneData* data; + + spBoneData* parent = 0; + const char* parentName = Json_getString(boneMap, "parent", 0); + if (parentName) { + parent = spSkeletonData_findBone(skeletonData, parentName); + if (!parent) { + spSkeletonData_dispose(skeletonData); + _spSkeletonJson_setError(self, root, "Parent bone not found: ", parentName); + return 0; + } + } + + data = spBoneData_create(skeletonData->bonesCount, Json_getString(boneMap, "name", 0), parent); + data->length = Json_getFloat(boneMap, "length", 0) * self->scale; + data->x = Json_getFloat(boneMap, "x", 0) * self->scale; + data->y = Json_getFloat(boneMap, "y", 0) * self->scale; + data->rotation = Json_getFloat(boneMap, "rotation", 0); + data->scaleX = Json_getFloat(boneMap, "scaleX", 1); + data->scaleY = Json_getFloat(boneMap, "scaleY", 1); + data->shearX = Json_getFloat(boneMap, "shearX", 0); + data->shearY = Json_getFloat(boneMap, "shearY", 0); + data->inheritRotation = Json_getInt(boneMap, "inheritRotation", 1); + data->inheritScale = Json_getInt(boneMap, "inheritScale", 1); + + skeletonData->bones[i] = data; + skeletonData->bonesCount++; + } + + /* Slots. */ + slots = Json_getItem(root, "slots"); + if (slots) { + Json *slotMap; + skeletonData->slotsCount = slots->size; + skeletonData->slots = MALLOC(spSlotData*, slots->size); + for (slotMap = slots->child, i = 0; slotMap; slotMap = slotMap->next, ++i) { + spSlotData* data; + const char* color; + Json *item; + + const char* boneName = Json_getString(slotMap, "bone", 0); + spBoneData* boneData = spSkeletonData_findBone(skeletonData, boneName); + if (!boneData) { + spSkeletonData_dispose(skeletonData); + _spSkeletonJson_setError(self, root, "Slot bone not found: ", boneName); + return 0; + } + + data = spSlotData_create(i, Json_getString(slotMap, "name", 0), boneData); + + color = Json_getString(slotMap, "color", 0); + if (color) { + data->r = toColor(color, 0); + data->g = toColor(color, 1); + data->b = toColor(color, 2); + data->a = toColor(color, 3); + } + + item = Json_getItem(slotMap, "attachment"); + if (item) spSlotData_setAttachmentName(data, item->valueString); + + item = Json_getItem(slotMap, "blend"); + if (item) { + if (strcmp(item->valueString, "additive") == 0) + data->blendMode = SP_BLEND_MODE_ADDITIVE; + else if (strcmp(item->valueString, "multiply") == 0) + data->blendMode = SP_BLEND_MODE_MULTIPLY; + else if (strcmp(item->valueString, "screen") == 0) + data->blendMode = SP_BLEND_MODE_SCREEN; + } + + skeletonData->slots[i] = data; + } + } + + /* IK constraints. */ + ik = Json_getItem(root, "ik"); + if (ik) { + Json *constraintMap; + skeletonData->ikConstraintsCount = ik->size; + skeletonData->ikConstraints = MALLOC(spIkConstraintData*, ik->size); + for (constraintMap = ik->child, i = 0; constraintMap; constraintMap = constraintMap->next, ++i) { + const char* targetName; + + spIkConstraintData* data = spIkConstraintData_create(Json_getString(constraintMap, "name", 0)); + + boneMap = Json_getItem(constraintMap, "bones"); + data->bonesCount = boneMap->size; + data->bones = MALLOC(spBoneData*, boneMap->size); + for (boneMap = boneMap->child, ii = 0; boneMap; boneMap = boneMap->next, ++ii) { + data->bones[ii] = spSkeletonData_findBone(skeletonData, boneMap->valueString); + if (!data->bones[ii]) { + spSkeletonData_dispose(skeletonData); + _spSkeletonJson_setError(self, root, "IK bone not found: ", boneMap->valueString); + return 0; + } + } + + targetName = Json_getString(constraintMap, "target", 0); + data->target = spSkeletonData_findBone(skeletonData, targetName); + if (!data->target) { + spSkeletonData_dispose(skeletonData); + _spSkeletonJson_setError(self, root, "Target bone not found: ", boneMap->name); + return 0; + } + + data->bendDirection = Json_getInt(constraintMap, "bendPositive", 1) ? 1 : -1; + data->mix = Json_getFloat(constraintMap, "mix", 1); + + skeletonData->ikConstraints[i] = data; + } + } + + /* Transform constraints. */ + transform = Json_getItem(root, "transform"); + if (transform) { + Json *constraintMap; + skeletonData->transformConstraintsCount = transform->size; + skeletonData->transformConstraints = MALLOC(spTransformConstraintData*, transform->size); + for (constraintMap = transform->child, i = 0; constraintMap; constraintMap = constraintMap->next, ++i) { + const char* name; + + spTransformConstraintData* data = spTransformConstraintData_create(Json_getString(constraintMap, "name", 0)); + + boneMap = Json_getItem(constraintMap, "bones"); + data->bonesCount = boneMap->size; + CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, boneMap->size); + for (boneMap = boneMap->child, ii = 0; boneMap; boneMap = boneMap->next, ++ii) { + data->bones[ii] = spSkeletonData_findBone(skeletonData, boneMap->valueString); + if (!data->bones[ii]) { + spSkeletonData_dispose(skeletonData); + _spSkeletonJson_setError(self, root, "Transform bone not found: ", boneMap->valueString); + return 0; + } + } + + name = Json_getString(constraintMap, "target", 0); + data->target = spSkeletonData_findBone(skeletonData, name); + if (!data->target) { + spSkeletonData_dispose(skeletonData); + _spSkeletonJson_setError(self, root, "Target bone not found: ", boneMap->name); + return 0; + } + + data->offsetRotation = Json_getFloat(constraintMap, "rotation", 0); + data->offsetX = Json_getFloat(constraintMap, "x", 0) * self->scale; + data->offsetY = Json_getFloat(constraintMap, "y", 0) * self->scale; + data->offsetScaleX = Json_getFloat(constraintMap, "scaleX", 0); + data->offsetScaleY = Json_getFloat(constraintMap, "scaleY", 0); + data->offsetShearY = Json_getFloat(constraintMap, "shearY", 0); + + data->rotateMix = Json_getFloat(constraintMap, "rotateMix", 1); + data->translateMix = Json_getFloat(constraintMap, "translateMix", 1); + data->scaleMix = Json_getFloat(constraintMap, "scaleMix", 1); + data->shearMix = Json_getFloat(constraintMap, "shearMix", 1); + + skeletonData->transformConstraints[i] = data; + } + } + + /* Path constraints */ + path = Json_getItem(root, "path"); + if (path) { + Json *constraintMap; + skeletonData->pathConstraintsCount = path->size; + skeletonData->pathConstraints = MALLOC(spPathConstraintData*, path->size); + for (constraintMap = path->child, i = 0; constraintMap; constraintMap = constraintMap->next, ++i) { + const char* name; + const char* item; + + spPathConstraintData* data = spPathConstraintData_create(Json_getString(constraintMap, "name", 0)); + + boneMap = Json_getItem(constraintMap, "bones"); + data->bonesCount = boneMap->size; + CONST_CAST(spBoneData**, data->bones) = MALLOC(spBoneData*, boneMap->size); + for (boneMap = boneMap->child, ii = 0; boneMap; boneMap = boneMap->next, ++ii) { + data->bones[ii] = spSkeletonData_findBone(skeletonData, boneMap->valueString); + if (!data->bones[ii]) { + spSkeletonData_dispose(skeletonData); + _spSkeletonJson_setError(self, root, "Path bone not found: ", boneMap->valueString); + return 0; + } + } + + name = Json_getString(constraintMap, "target", 0); + data->target = spSkeletonData_findSlot(skeletonData, name); + if (!data->target) { + spSkeletonData_dispose(skeletonData); + _spSkeletonJson_setError(self, root, "Target slot not found: ", boneMap->name); + return 0; + } + + item = Json_getString(constraintMap, "positionMode", "percent"); + if (strcmp(item, "fixed") == 0) data->positionMode = SP_POSITION_MODE_FIXED; + else if (strcmp(item, "percent") == 0) data->positionMode = SP_POSITION_MODE_PERCENT; + + item = Json_getString(constraintMap, "spacingMode", "length"); + if (strcmp(item, "length") == 0) data->spacingMode = SP_SPACING_MODE_LENGTH; + else if (strcmp(item, "fixed") == 0) data->spacingMode = SP_SPACING_MODE_FIXED; + else if (strcmp(item, "percent") == 0) data->spacingMode = SP_SPACING_MODE_PERCENT; + + item = Json_getString(constraintMap, "rotateMode", "tangent"); + if (strcmp(item, "tangent") == 0) data->rotateMode = SP_ROTATE_MODE_TANGENT; + else if (strcmp(item, "chain") == 0) data->rotateMode = SP_ROTATE_MODE_CHAIN; + else if (strcmp(item, "chainScale") == 0) data->rotateMode = SP_ROTATE_MODE_CHAIN_SCALE; + + data->offsetRotation = Json_getFloat(constraintMap, "rotation", 0); + data->position = Json_getFloat(constraintMap, "position", 0); + if (data->positionMode == SP_POSITION_MODE_FIXED) data->position *= self->scale; + data->spacing = Json_getFloat(constraintMap, "spacing", 0); + if (data->spacingMode == SP_SPACING_MODE_LENGTH || data->spacingMode == SP_SPACING_MODE_FIXED) data->spacing *= self->scale; + data->rotateMix = Json_getFloat(constraintMap, "rotateMix", 1); + data->translateMix = Json_getFloat(constraintMap, "translateMix", 1); + + skeletonData->pathConstraints[i] = data; + } + } + + /* Skins. */ + skins = Json_getItem(root, "skins"); + if (skins) { + Json *skinMap; + skeletonData->skins = MALLOC(spSkin*, skins->size); + for (skinMap = skins->child, i = 0; skinMap; skinMap = skinMap->next, ++i) { + Json *attachmentsMap; + Json *curves; + spSkin *skin = spSkin_create(skinMap->name); + + skeletonData->skins[skeletonData->skinsCount++] = skin; + if (strcmp(skinMap->name, "default") == 0) skeletonData->defaultSkin = skin; + + for (attachmentsMap = skinMap->child; attachmentsMap; attachmentsMap = attachmentsMap->next) { + int slotIndex = spSkeletonData_findSlotIndex(skeletonData, attachmentsMap->name); + Json *attachmentMap; + + for (attachmentMap = attachmentsMap->child; attachmentMap; attachmentMap = attachmentMap->next) { + spAttachment* attachment; + const char* skinAttachmentName = attachmentMap->name; + const char* attachmentName = Json_getString(attachmentMap, "name", skinAttachmentName); + const char* path = Json_getString(attachmentMap, "path", attachmentName); + const char* color; + Json* entry; + + const char* typeString = Json_getString(attachmentMap, "type", "region"); + spAttachmentType type; + if (strcmp(typeString, "region") == 0) + type = SP_ATTACHMENT_REGION; + else if (strcmp(typeString, "mesh") == 0) + type = SP_ATTACHMENT_MESH; + else if (strcmp(typeString, "linkedmesh") == 0) + type = SP_ATTACHMENT_LINKED_MESH; + else if (strcmp(typeString, "boundingbox") == 0) + type = SP_ATTACHMENT_BOUNDING_BOX; + else if (strcmp(typeString, "path") == 0) + type = SP_ATTACHMENT_PATH; + else { + spSkeletonData_dispose(skeletonData); + _spSkeletonJson_setError(self, root, "Unknown attachment type: ", typeString); + return 0; + } + + attachment = spAttachmentLoader_createAttachment(self->attachmentLoader, skin, type, attachmentName, path); + if (!attachment) { + if (self->attachmentLoader->error1) { + spSkeletonData_dispose(skeletonData); + _spSkeletonJson_setError(self, root, self->attachmentLoader->error1, self->attachmentLoader->error2); + return 0; + } + continue; + } + + switch (attachment->type) { + case SP_ATTACHMENT_REGION: { + spRegionAttachment* region = SUB_CAST(spRegionAttachment, attachment); + if (path) MALLOC_STR(region->path, path); + region->x = Json_getFloat(attachmentMap, "x", 0) * self->scale; + region->y = Json_getFloat(attachmentMap, "y", 0) * self->scale; + region->scaleX = Json_getFloat(attachmentMap, "scaleX", 1); + region->scaleY = Json_getFloat(attachmentMap, "scaleY", 1); + region->rotation = Json_getFloat(attachmentMap, "rotation", 0); + region->width = Json_getFloat(attachmentMap, "width", 32) * self->scale; + region->height = Json_getFloat(attachmentMap, "height", 32) * self->scale; + + color = Json_getString(attachmentMap, "color", 0); + if (color) { + region->r = toColor(color, 0); + region->g = toColor(color, 1); + region->b = toColor(color, 2); + region->a = toColor(color, 3); + } + + spRegionAttachment_updateOffset(region); + + spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); + break; + } + case SP_ATTACHMENT_MESH: + case SP_ATTACHMENT_LINKED_MESH: { + spMeshAttachment* mesh = SUB_CAST(spMeshAttachment, attachment); + + MALLOC_STR(mesh->path, path); + + color = Json_getString(attachmentMap, "color", 0); + if (color) { + mesh->r = toColor(color, 0); + mesh->g = toColor(color, 1); + mesh->b = toColor(color, 2); + mesh->a = toColor(color, 3); + } + + mesh->width = Json_getFloat(attachmentMap, "width", 32) * self->scale; + mesh->height = Json_getFloat(attachmentMap, "height", 32) * self->scale; + + entry = Json_getItem(attachmentMap, "parent"); + if (!entry) { + int verticesLength; + entry = Json_getItem(attachmentMap, "triangles"); + mesh->trianglesCount = entry->size; + mesh->triangles = MALLOC(unsigned short, entry->size); + for (entry = entry->child, ii = 0; entry; entry = entry->next, ++ii) + mesh->triangles[ii] = (unsigned short)entry->valueInt; + + entry = Json_getItem(attachmentMap, "uvs"); + verticesLength = entry->size; + mesh->regionUVs = MALLOC(float, verticesLength); + for (entry = entry->child, ii = 0; entry; entry = entry->next, ++ii) + mesh->regionUVs[ii] = entry->valueFloat; + + _readVertices(self, attachmentMap, SUPER(mesh), verticesLength); + + spMeshAttachment_updateUVs(mesh); + + mesh->hullLength = Json_getInt(attachmentMap, "hull", 0); + + entry = Json_getItem(attachmentMap, "edges"); + if (entry) { + mesh->edgesCount = entry->size; + mesh->edges = MALLOC(int, entry->size); + for (entry = entry->child, ii = 0; entry; entry = entry->next, ++ii) + mesh->edges[ii] = entry->valueInt; + } + + spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); + } else { + mesh->inheritDeform = Json_getInt(attachmentMap, "deform", 1); + _spSkeletonJson_addLinkedMesh(self, SUB_CAST(spMeshAttachment, attachment), Json_getString(attachmentMap, "skin", 0), slotIndex, + entry->valueString); + } + break; + } + case SP_ATTACHMENT_BOUNDING_BOX: { + spBoundingBoxAttachment* box = SUB_CAST(spBoundingBoxAttachment, attachment); + int vertexCount = Json_getInt(attachmentMap, "vertexCount", 0) << 1; + _readVertices(self, attachmentMap, SUPER(box), vertexCount); + box->super.verticesCount = vertexCount; + spAttachmentLoader_configureAttachment(self->attachmentLoader, attachment); + break; + } + case SP_ATTACHMENT_PATH: { + spPathAttachment* path = SUB_CAST(spPathAttachment, attachment); + int vertexCount = 0; + path->closed = Json_getInt(attachmentMap, "closed", 0); + path->constantSpeed = Json_getInt(attachmentMap, "constantSpeed", 1); + vertexCount = Json_getInt(attachmentMap, "vertexCount", 0); + _readVertices(self, attachmentMap, SUPER(path), vertexCount << 1); + + path->lengthsLength = vertexCount / 3; + path->lengths = MALLOC(float, path->lengthsLength); + + curves = Json_getItem(attachmentMap, "lengths"); + for (curves = curves->child, ii = 0; curves; curves = curves->next, ++ii) { + path->lengths[ii] = curves->valueFloat * self->scale; + } + break; + } + } + + spSkin_addAttachment(skin, slotIndex, skinAttachmentName, attachment); + } + } + } + } + + /* Linked meshes. */ + for (i = 0; i < internal->linkedMeshCount; i++) { + spAttachment* parent; + _spLinkedMesh* linkedMesh = internal->linkedMeshes + i; + spSkin* skin = !linkedMesh->skin ? skeletonData->defaultSkin : spSkeletonData_findSkin(skeletonData, linkedMesh->skin); + if (!skin) { + spSkeletonData_dispose(skeletonData); + _spSkeletonJson_setError(self, 0, "Skin not found: ", linkedMesh->skin); + return 0; + } + parent = spSkin_getAttachment(skin, linkedMesh->slotIndex, linkedMesh->parent); + if (!parent) { + spSkeletonData_dispose(skeletonData); + _spSkeletonJson_setError(self, 0, "Parent mesh not found: ", linkedMesh->parent); + return 0; + } + spMeshAttachment_setParentMesh(linkedMesh->mesh, SUB_CAST(spMeshAttachment, parent)); + spMeshAttachment_updateUVs(linkedMesh->mesh); + spAttachmentLoader_configureAttachment(self->attachmentLoader, SUPER(SUPER(linkedMesh->mesh))); + } + + /* Events. */ + events = Json_getItem(root, "events"); + if (events) { + Json *eventMap; + const char* stringValue; + skeletonData->eventsCount = events->size; + skeletonData->events = MALLOC(spEventData*, events->size); + for (eventMap = events->child, i = 0; eventMap; eventMap = eventMap->next, ++i) { + spEventData* eventData = spEventData_create(eventMap->name); + eventData->intValue = Json_getInt(eventMap, "int", 0); + eventData->floatValue = Json_getFloat(eventMap, "float", 0); + stringValue = Json_getString(eventMap, "string", 0); + if (stringValue) MALLOC_STR(eventData->stringValue, stringValue); + skeletonData->events[i] = eventData; + } + } + + /* Animations. */ + animations = Json_getItem(root, "animations"); + if (animations) { + Json *animationMap; + skeletonData->animations = MALLOC(spAnimation*, animations->size); + for (animationMap = animations->child; animationMap; animationMap = animationMap->next) { + spAnimation* animation = _spSkeletonJson_readAnimation(self, animationMap, skeletonData); + if (!animation) { + spSkeletonData_dispose(skeletonData); + return 0; + } + skeletonData->animations[skeletonData->animationsCount++] = animation; + } + } + + Json_dispose(root); + return skeletonData; } diff --git a/spine-c/src/spine/Skin.c b/spine-c/src/spine/Skin.c index 2fb361ea4a..2772a5bb57 100644 --- a/spine-c/src/spine/Skin.c +++ b/spine-c/src/spine/Skin.c @@ -1,107 +1,106 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -_Entry* _Entry_create (int slotIndex, const char* name, spAttachment* attachment) { - _Entry* self = NEW(_Entry); - self->slotIndex = slotIndex; - MALLOC_STR(self->name, name); - self->attachment = attachment; - return self; -} - -void _Entry_dispose (_Entry* self) { - spAttachment_dispose(self->attachment); - FREE(self->name); - FREE(self); -} - -/**/ - -spSkin* spSkin_create (const char* name) { - spSkin* self = SUPER(NEW(_spSkin)); - MALLOC_STR(self->name, name); - return self; -} - -void spSkin_dispose (spSkin* self) { - _Entry* entry = SUB_CAST(_spSkin, self)->entries; - while (entry) { - _Entry* nextEntry = entry->next; - _Entry_dispose(entry); - entry = nextEntry; - } - - FREE(self->name); - FREE(self); -} - -void spSkin_addAttachment (spSkin* self, int slotIndex, const char* name, spAttachment* attachment) { - _Entry* newEntry = _Entry_create(slotIndex, name, attachment); - newEntry->next = SUB_CAST(_spSkin, self)->entries; - SUB_CAST(_spSkin, self)->entries = newEntry; -} - -spAttachment* spSkin_getAttachment (const spSkin* self, int slotIndex, const char* name) { - const _Entry* entry = SUB_CAST(_spSkin, self)->entries; - while (entry) { - if (entry->slotIndex == slotIndex && strcmp(entry->name, name) == 0) return entry->attachment; - entry = entry->next; - } - return 0; -} - -const char* spSkin_getAttachmentName (const spSkin* self, int slotIndex, int attachmentIndex) { - const _Entry* entry = SUB_CAST(_spSkin, self)->entries; - int i = 0; - while (entry) { - if (entry->slotIndex == slotIndex) { - if (i == attachmentIndex) return entry->name; - i++; - } - entry = entry->next; - } - return 0; -} - -void spSkin_attachAll (const spSkin* self, spSkeleton* skeleton, const spSkin* oldSkin) { - const _Entry *entry = SUB_CAST(_spSkin, oldSkin)->entries; - while (entry) { - spSlot *slot = skeleton->slots[entry->slotIndex]; - if (slot->attachment == entry->attachment) { - spAttachment *attachment = spSkin_getAttachment(self, entry->slotIndex, entry->name); - if (attachment) spSlot_setAttachment(slot, attachment); - } - entry = entry->next; - } +#include +#include + +_Entry* _Entry_create (int slotIndex, const char* name, spAttachment* attachment) { + _Entry* self = NEW(_Entry); + self->slotIndex = slotIndex; + MALLOC_STR(self->name, name); + self->attachment = attachment; + return self; +} + +void _Entry_dispose (_Entry* self) { + spAttachment_dispose(self->attachment); + FREE(self->name); + FREE(self); +} + +/**/ + +spSkin* spSkin_create (const char* name) { + spSkin* self = SUPER(NEW(_spSkin)); + MALLOC_STR(self->name, name); + return self; +} + +void spSkin_dispose (spSkin* self) { + _Entry* entry = SUB_CAST(_spSkin, self)->entries; + while (entry) { + _Entry* nextEntry = entry->next; + _Entry_dispose(entry); + entry = nextEntry; + } + + FREE(self->name); + FREE(self); +} + +void spSkin_addAttachment (spSkin* self, int slotIndex, const char* name, spAttachment* attachment) { + _Entry* newEntry = _Entry_create(slotIndex, name, attachment); + newEntry->next = SUB_CAST(_spSkin, self)->entries; + SUB_CAST(_spSkin, self)->entries = newEntry; +} + +spAttachment* spSkin_getAttachment (const spSkin* self, int slotIndex, const char* name) { + const _Entry* entry = SUB_CAST(_spSkin, self)->entries; + while (entry) { + if (entry->slotIndex == slotIndex && strcmp(entry->name, name) == 0) return entry->attachment; + entry = entry->next; + } + return 0; +} + +const char* spSkin_getAttachmentName (const spSkin* self, int slotIndex, int attachmentIndex) { + const _Entry* entry = SUB_CAST(_spSkin, self)->entries; + int i = 0; + while (entry) { + if (entry->slotIndex == slotIndex) { + if (i == attachmentIndex) return entry->name; + i++; + } + entry = entry->next; + } + return 0; +} + +void spSkin_attachAll (const spSkin* self, spSkeleton* skeleton, const spSkin* oldSkin) { + const _Entry *entry = SUB_CAST(_spSkin, oldSkin)->entries; + while (entry) { + spSlot *slot = skeleton->slots[entry->slotIndex]; + if (slot->attachment == entry->attachment) { + spAttachment *attachment = spSkin_getAttachment(self, entry->slotIndex, entry->name); + if (attachment) spSlot_setAttachment(slot, attachment); + } + entry = entry->next; + } } diff --git a/spine-c/src/spine/Slot.c b/spine-c/src/spine/Slot.c index a0df1c5b40..758326c1c1 100644 --- a/spine-c/src/spine/Slot.c +++ b/spine-c/src/spine/Slot.c @@ -1,82 +1,81 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -typedef struct { - spSlot super; - float attachmentTime; -} _spSlot; - -spSlot* spSlot_create (spSlotData* data, spBone* bone) { - spSlot* self = SUPER(NEW(_spSlot)); - CONST_CAST(spSlotData*, self->data) = data; - CONST_CAST(spBone*, self->bone) = bone; - spSlot_setToSetupPose(self); - return self; -} - -void spSlot_dispose (spSlot* self) { - FREE(self->attachmentVertices); - FREE(self); -} - -void spSlot_setAttachment (spSlot* self, spAttachment* attachment) { - if (attachment == self->attachment) return; - CONST_CAST(spAttachment*, self->attachment) = attachment; - SUB_CAST(_spSlot, self)->attachmentTime = self->bone->skeleton->time; - self->attachmentVerticesCount = 0; -} - -void spSlot_setAttachmentTime (spSlot* self, float time) { - SUB_CAST(_spSlot, self)->attachmentTime = self->bone->skeleton->time - time; -} - -float spSlot_getAttachmentTime (const spSlot* self) { - return self->bone->skeleton->time - SUB_CAST(_spSlot, self) ->attachmentTime; -} - -void spSlot_setToSetupPose (spSlot* self) { - self->r = self->data->r; - self->g = self->data->g; - self->b = self->data->b; - self->a = self->data->a; - - if (!self->data->attachmentName) - spSlot_setAttachment(self, 0); - else { - spAttachment* attachment = spSkeleton_getAttachmentForSlotIndex( - self->bone->skeleton, self->data->index, self->data->attachmentName); - CONST_CAST(spAttachment*, self->attachment) = 0; - spSlot_setAttachment(self, attachment); - } +#include +#include + +typedef struct { + spSlot super; + float attachmentTime; +} _spSlot; + +spSlot* spSlot_create (spSlotData* data, spBone* bone) { + spSlot* self = SUPER(NEW(_spSlot)); + CONST_CAST(spSlotData*, self->data) = data; + CONST_CAST(spBone*, self->bone) = bone; + spSlot_setToSetupPose(self); + return self; +} + +void spSlot_dispose (spSlot* self) { + FREE(self->attachmentVertices); + FREE(self); +} + +void spSlot_setAttachment (spSlot* self, spAttachment* attachment) { + if (attachment == self->attachment) return; + CONST_CAST(spAttachment*, self->attachment) = attachment; + SUB_CAST(_spSlot, self)->attachmentTime = self->bone->skeleton->time; + self->attachmentVerticesCount = 0; +} + +void spSlot_setAttachmentTime (spSlot* self, float time) { + SUB_CAST(_spSlot, self)->attachmentTime = self->bone->skeleton->time - time; +} + +float spSlot_getAttachmentTime (const spSlot* self) { + return self->bone->skeleton->time - SUB_CAST(_spSlot, self) ->attachmentTime; +} + +void spSlot_setToSetupPose (spSlot* self) { + self->r = self->data->r; + self->g = self->data->g; + self->b = self->data->b; + self->a = self->data->a; + + if (!self->data->attachmentName) + spSlot_setAttachment(self, 0); + else { + spAttachment* attachment = spSkeleton_getAttachmentForSlotIndex( + self->bone->skeleton, self->data->index, self->data->attachmentName); + CONST_CAST(spAttachment*, self->attachment) = 0; + spSlot_setAttachment(self, attachment); + } } diff --git a/spine-c/src/spine/SlotData.c b/spine-c/src/spine/SlotData.c index 833a03788d..4cc6f35842 100644 --- a/spine-c/src/spine/SlotData.c +++ b/spine-c/src/spine/SlotData.c @@ -1,59 +1,58 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -spSlotData* spSlotData_create (const int index, const char* name, spBoneData* boneData) { - spSlotData* self = NEW(spSlotData); - CONST_CAST(int, self->index) = index; - MALLOC_STR(self->name, name); - CONST_CAST(spBoneData*, self->boneData) = boneData; - self->r = 1; - self->g = 1; - self->b = 1; - self->a = 1; - return self; -} - -void spSlotData_dispose (spSlotData* self) { - FREE(self->name); - FREE(self->attachmentName); - FREE(self); -} - -void spSlotData_setAttachmentName (spSlotData* self, const char* attachmentName) { - FREE(self->attachmentName); - if (attachmentName) - MALLOC_STR(self->attachmentName, attachmentName); - else - CONST_CAST(char*, self->attachmentName) = 0; +#include +#include + +spSlotData* spSlotData_create (const int index, const char* name, spBoneData* boneData) { + spSlotData* self = NEW(spSlotData); + CONST_CAST(int, self->index) = index; + MALLOC_STR(self->name, name); + CONST_CAST(spBoneData*, self->boneData) = boneData; + self->r = 1; + self->g = 1; + self->b = 1; + self->a = 1; + return self; +} + +void spSlotData_dispose (spSlotData* self) { + FREE(self->name); + FREE(self->attachmentName); + FREE(self); +} + +void spSlotData_setAttachmentName (spSlotData* self, const char* attachmentName) { + FREE(self->attachmentName); + if (attachmentName) + MALLOC_STR(self->attachmentName, attachmentName); + else + CONST_CAST(char*, self->attachmentName) = 0; } diff --git a/spine-c/src/spine/TransformConstraint.c b/spine-c/src/spine/TransformConstraint.c index 8cdc974423..719a6c53ef 100644 --- a/spine-c/src/spine/TransformConstraint.c +++ b/spine-c/src/spine/TransformConstraint.c @@ -1,112 +1,111 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include - -spTransformConstraint* spTransformConstraint_create (spTransformConstraintData* data, const spSkeleton* skeleton) { - int i; - spTransformConstraint* self = NEW(spTransformConstraint); - CONST_CAST(spTransformConstraintData*, self->data) = data; - self->rotateMix = data->rotateMix; - self->translateMix = data->translateMix; - self->scaleMix = data->scaleMix; - self->shearMix = data->shearMix; - self->bonesCount = data->bonesCount; - CONST_CAST(spBone**, self->bones) = MALLOC(spBone*, self->bonesCount); - for (i = 0; i < self->bonesCount; ++i) - self->bones[i] = spSkeleton_findBone(skeleton, self->data->bones[i]->name); - self->target = spSkeleton_findBone(skeleton, self->data->target->name); - return self; -} - -void spTransformConstraint_dispose (spTransformConstraint* self) { - FREE(self->bones); - FREE(self); -} - -void spTransformConstraint_apply (spTransformConstraint* self) { - float rotateMix = self->rotateMix, translateMix = self->translateMix, scaleMix = self->scaleMix, shearMix = self->shearMix; - spBone* target = self->target; - float ta = target->a, tb = target->b, tc = target->c, td = target->d; - int i; - for (i = 0; i < self->bonesCount; ++i) { - spBone* bone = self->bones[i]; - - if (rotateMix > 0) { - float a = bone->a, b = bone->b, c = bone->c, d = bone->d; - float r = ATAN2(tc, ta) - ATAN2(c, a) + self->data->offsetRotation * DEG_RAD; - float cosine, sine; - if (r > PI) r -= PI2; - else if (r < -PI) r += PI2; - r *= rotateMix; - cosine = COS(r); - sine = SIN(r); - CONST_CAST(float, bone->a) = cosine * a - sine * c; - CONST_CAST(float, bone->b) = cosine * b - sine * d; - CONST_CAST(float, bone->c) = sine * a + cosine * c; - CONST_CAST(float, bone->d) = sine * b + cosine * d; - } - - if (translateMix > 0) { - float x, y; - spBone_localToWorld(target, self->data->offsetX, self->data->offsetY, &x, &y); - CONST_CAST(float, bone->worldX) += (x - bone->worldX) * translateMix; - CONST_CAST(float, bone->worldY) += (y - bone->worldY) * translateMix; - } - - if (scaleMix > 0) { - float bs = SQRT(bone->a * bone->a + bone->c * bone->c); - float ts = SQRT(ta * ta + tc * tc); - float s = bs > 0.00001f ? (bs + (ts - bs + self->data->offsetScaleX) * scaleMix) / bs : 0; - CONST_CAST(float, bone->a) *= s; - CONST_CAST(float, bone->c) *= s; - bs = SQRT(bone->b * bone->b + bone->d * bone->d); - ts = SQRT(tb * tb + td * td); - s = bs > 0.00001f ? (bs + (ts - bs + self->data->offsetScaleY) * scaleMix) / bs : 0; - CONST_CAST(float, bone->b) *= s; - CONST_CAST(float, bone->d) *= s; - } - - if (shearMix > 0) { - float b = bone->b, d = bone->d; - float by = ATAN2(d, b); - float r = ATAN2(td, tb) - ATAN2(tc, ta) - (by - ATAN2(bone->c, bone->a)); - float s = SQRT(b * b + d * d); - if (r > PI) r -= PI2; - else if (r < -PI) r += PI2; - r = by + (r + self->data->offsetShearY * DEG_RAD) * shearMix; - CONST_CAST(float, bone->b) = COS(r) * s; - CONST_CAST(float, bone->d) = SIN(r) * s; - } - } +#include +#include +#include + +spTransformConstraint* spTransformConstraint_create (spTransformConstraintData* data, const spSkeleton* skeleton) { + int i; + spTransformConstraint* self = NEW(spTransformConstraint); + CONST_CAST(spTransformConstraintData*, self->data) = data; + self->rotateMix = data->rotateMix; + self->translateMix = data->translateMix; + self->scaleMix = data->scaleMix; + self->shearMix = data->shearMix; + self->bonesCount = data->bonesCount; + CONST_CAST(spBone**, self->bones) = MALLOC(spBone*, self->bonesCount); + for (i = 0; i < self->bonesCount; ++i) + self->bones[i] = spSkeleton_findBone(skeleton, self->data->bones[i]->name); + self->target = spSkeleton_findBone(skeleton, self->data->target->name); + return self; +} + +void spTransformConstraint_dispose (spTransformConstraint* self) { + FREE(self->bones); + FREE(self); +} + +void spTransformConstraint_apply (spTransformConstraint* self) { + float rotateMix = self->rotateMix, translateMix = self->translateMix, scaleMix = self->scaleMix, shearMix = self->shearMix; + spBone* target = self->target; + float ta = target->a, tb = target->b, tc = target->c, td = target->d; + int i; + for (i = 0; i < self->bonesCount; ++i) { + spBone* bone = self->bones[i]; + + if (rotateMix > 0) { + float a = bone->a, b = bone->b, c = bone->c, d = bone->d; + float r = ATAN2(tc, ta) - ATAN2(c, a) + self->data->offsetRotation * DEG_RAD; + float cosine, sine; + if (r > PI) r -= PI2; + else if (r < -PI) r += PI2; + r *= rotateMix; + cosine = COS(r); + sine = SIN(r); + CONST_CAST(float, bone->a) = cosine * a - sine * c; + CONST_CAST(float, bone->b) = cosine * b - sine * d; + CONST_CAST(float, bone->c) = sine * a + cosine * c; + CONST_CAST(float, bone->d) = sine * b + cosine * d; + } + + if (translateMix > 0) { + float x, y; + spBone_localToWorld(target, self->data->offsetX, self->data->offsetY, &x, &y); + CONST_CAST(float, bone->worldX) += (x - bone->worldX) * translateMix; + CONST_CAST(float, bone->worldY) += (y - bone->worldY) * translateMix; + } + + if (scaleMix > 0) { + float bs = SQRT(bone->a * bone->a + bone->c * bone->c); + float ts = SQRT(ta * ta + tc * tc); + float s = bs > 0.00001f ? (bs + (ts - bs + self->data->offsetScaleX) * scaleMix) / bs : 0; + CONST_CAST(float, bone->a) *= s; + CONST_CAST(float, bone->c) *= s; + bs = SQRT(bone->b * bone->b + bone->d * bone->d); + ts = SQRT(tb * tb + td * td); + s = bs > 0.00001f ? (bs + (ts - bs + self->data->offsetScaleY) * scaleMix) / bs : 0; + CONST_CAST(float, bone->b) *= s; + CONST_CAST(float, bone->d) *= s; + } + + if (shearMix > 0) { + float b = bone->b, d = bone->d; + float by = ATAN2(d, b); + float r = ATAN2(td, tb) - ATAN2(tc, ta) - (by - ATAN2(bone->c, bone->a)); + float s = SQRT(b * b + d * d); + if (r > PI) r -= PI2; + else if (r < -PI) r += PI2; + r = by + (r + self->data->offsetShearY * DEG_RAD) * shearMix; + CONST_CAST(float, bone->b) = COS(r) * s; + CONST_CAST(float, bone->d) = SIN(r) * s; + } + } } diff --git a/spine-c/src/spine/TransformConstraintData.c b/spine-c/src/spine/TransformConstraintData.c index bc93d4e936..3b74a45264 100644 --- a/spine-c/src/spine/TransformConstraintData.c +++ b/spine-c/src/spine/TransformConstraintData.c @@ -1,45 +1,44 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -spTransformConstraintData* spTransformConstraintData_create (const char* name) { - spTransformConstraintData* self = NEW(spTransformConstraintData); - MALLOC_STR(self->name, name); - return self; -} - -void spTransformConstraintData_dispose (spTransformConstraintData* self) { - FREE(self->name); - FREE(self->bones); - FREE(self); +#include +#include + +spTransformConstraintData* spTransformConstraintData_create (const char* name) { + spTransformConstraintData* self = NEW(spTransformConstraintData); + MALLOC_STR(self->name, name); + return self; +} + +void spTransformConstraintData_dispose (spTransformConstraintData* self) { + FREE(self->name); + FREE(self->bones); + FREE(self); } diff --git a/spine-c/src/spine/VertexAttachment.c b/spine-c/src/spine/VertexAttachment.c index bf034820d2..5b3d5b3f8b 100644 --- a/spine-c/src/spine/VertexAttachment.c +++ b/spine-c/src/spine/VertexAttachment.c @@ -1,114 +1,113 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -void _spVertexAttachment_deinit (spVertexAttachment* attachment) { - _spAttachment_deinit(SUPER(attachment)); - FREE(attachment->bones); - FREE(attachment->vertices); -} - -void spVertexAttachment_computeWorldVertices (spVertexAttachment* self, spSlot* slot, float* worldVertices) { - spVertexAttachment_computeWorldVertices1(self, 0, self->worldVerticesLength, slot, worldVertices, 0); -} - -void spVertexAttachment_computeWorldVertices1 (spVertexAttachment* self, int start, int count, spSlot* slot, float* worldVertices, int offset) { - spSkeleton* skeleton; - float x, y; - int deformLength; - float* deform; - float* vertices; - int* bones; - - count += offset; - skeleton = slot->bone->skeleton; - x = skeleton->x; - y = skeleton->y; - deformLength = slot->attachmentVerticesCount; - deform = slot->attachmentVertices; - vertices = self->vertices; - bones = self->bones; - if (!bones) { - spBone* bone; - int v, w; - if (deformLength > 0) vertices = deform; - bone = slot->bone; - x += bone->worldX; - y += bone->worldY; - for (v = start, w = offset; w < count; v += 2, w += 2) { - float vx = vertices[v], vy = vertices[v + 1]; - worldVertices[w] = vx * bone->a + vy * bone->b + x; - worldVertices[w + 1] = vx * bone->c + vy * bone->d + y; - } - } else { - int v = 0, skip = 0, i; - spBone** skeletonBones; - for (i = 0; i < start; i += 2) { - int n = bones[v]; - v += n + 1; - skip += n; - } - skeletonBones = skeleton->bones; - if (deformLength == 0) { - int w, b; - for (w = offset, b = skip * 3; w < count; w += 2) { - float wx = x, wy = y; - int n = bones[v++]; - n += v; - for (; v < n; v++, b += 3) { - spBone* bone = skeletonBones[bones[v]]; - float vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; - wx += (vx * bone->a + vy * bone->b + bone->worldX) * weight; - wy += (vx * bone->c + vy * bone->d + bone->worldY) * weight; - } - worldVertices[w] = wx; - worldVertices[w + 1] = wy; - } - } else { - int w, b, f; - for (w = offset, b = skip * 3, f = skip << 1; w < count; w += 2) { - float wx = x, wy = y; - int n = bones[v++]; - n += v; - for (; v < n; v++, b += 3, f += 2) { - spBone* bone = skeletonBones[bones[v]]; - float vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; - wx += (vx * bone->a + vy * bone->b + bone->worldX) * weight; - wy += (vx * bone->c + vy * bone->d + bone->worldY) * weight; - } - worldVertices[w] = wx; - worldVertices[w + 1] = wy; - } - } - } +#include +#include + +void _spVertexAttachment_deinit (spVertexAttachment* attachment) { + _spAttachment_deinit(SUPER(attachment)); + FREE(attachment->bones); + FREE(attachment->vertices); +} + +void spVertexAttachment_computeWorldVertices (spVertexAttachment* self, spSlot* slot, float* worldVertices) { + spVertexAttachment_computeWorldVertices1(self, 0, self->worldVerticesLength, slot, worldVertices, 0); +} + +void spVertexAttachment_computeWorldVertices1 (spVertexAttachment* self, int start, int count, spSlot* slot, float* worldVertices, int offset) { + spSkeleton* skeleton; + float x, y; + int deformLength; + float* deform; + float* vertices; + int* bones; + + count += offset; + skeleton = slot->bone->skeleton; + x = skeleton->x; + y = skeleton->y; + deformLength = slot->attachmentVerticesCount; + deform = slot->attachmentVertices; + vertices = self->vertices; + bones = self->bones; + if (!bones) { + spBone* bone; + int v, w; + if (deformLength > 0) vertices = deform; + bone = slot->bone; + x += bone->worldX; + y += bone->worldY; + for (v = start, w = offset; w < count; v += 2, w += 2) { + float vx = vertices[v], vy = vertices[v + 1]; + worldVertices[w] = vx * bone->a + vy * bone->b + x; + worldVertices[w + 1] = vx * bone->c + vy * bone->d + y; + } + } else { + int v = 0, skip = 0, i; + spBone** skeletonBones; + for (i = 0; i < start; i += 2) { + int n = bones[v]; + v += n + 1; + skip += n; + } + skeletonBones = skeleton->bones; + if (deformLength == 0) { + int w, b; + for (w = offset, b = skip * 3; w < count; w += 2) { + float wx = x, wy = y; + int n = bones[v++]; + n += v; + for (; v < n; v++, b += 3) { + spBone* bone = skeletonBones[bones[v]]; + float vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; + wx += (vx * bone->a + vy * bone->b + bone->worldX) * weight; + wy += (vx * bone->c + vy * bone->d + bone->worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } else { + int w, b, f; + for (w = offset, b = skip * 3, f = skip << 1; w < count; w += 2) { + float wx = x, wy = y; + int n = bones[v++]; + n += v; + for (; v < n; v++, b += 3, f += 2) { + spBone* bone = skeletonBones[bones[v]]; + float vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; + wx += (vx * bone->a + vy * bone->b + bone->worldX) * weight; + wy += (vx * bone->c + vy * bone->d + bone->worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } + } } diff --git a/spine-c/src/spine/extension.c b/spine-c/src/spine/extension.c index 18c917928d..bff2df4c45 100644 --- a/spine-c/src/spine/extension.c +++ b/spine-c/src/spine/extension.c @@ -1,79 +1,78 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -static void* (*mallocFunc) (size_t size) = malloc; -static void* (*debugMallocFunc) (size_t size, const char* file, int line) = NULL; -static void (*freeFunc) (void* ptr) = free; - -void* _malloc (size_t size, const char* file, int line) { - if(debugMallocFunc) - return debugMallocFunc(size, file, line); - - return mallocFunc(size); -} -void* _calloc (size_t num, size_t size, const char* file, int line) { - void* ptr = _malloc(num * size, file, line); - if (ptr) memset(ptr, 0, num * size); - return ptr; -} -void _free (void* ptr) { - freeFunc(ptr); -} - -void _setDebugMalloc(void* (*malloc) (size_t size, const char* file, int line)) { - debugMallocFunc = malloc; -} - -void _setMalloc (void* (*malloc) (size_t size)) { - mallocFunc = malloc; -} -void _setFree (void (*free) (void* ptr)) { - freeFunc = free; -} - -char* _readFile (const char* path, int* length) { - char *data; - FILE *file = fopen(path, "rb"); - if (!file) return 0; - - fseek(file, 0, SEEK_END); - *length = (int)ftell(file); - fseek(file, 0, SEEK_SET); - - data = MALLOC(char, *length); - fread(data, 1, *length, file); - fclose(file); - - return data; +#include +#include + +static void* (*mallocFunc) (size_t size) = malloc; +static void* (*debugMallocFunc) (size_t size, const char* file, int line) = NULL; +static void (*freeFunc) (void* ptr) = free; + +void* _malloc (size_t size, const char* file, int line) { + if(debugMallocFunc) + return debugMallocFunc(size, file, line); + + return mallocFunc(size); +} +void* _calloc (size_t num, size_t size, const char* file, int line) { + void* ptr = _malloc(num * size, file, line); + if (ptr) memset(ptr, 0, num * size); + return ptr; +} +void _free (void* ptr) { + freeFunc(ptr); +} + +void _setDebugMalloc(void* (*malloc) (size_t size, const char* file, int line)) { + debugMallocFunc = malloc; +} + +void _setMalloc (void* (*malloc) (size_t size)) { + mallocFunc = malloc; +} +void _setFree (void (*free) (void* ptr)) { + freeFunc = free; +} + +char* _readFile (const char* path, int* length) { + char *data; + FILE *file = fopen(path, "rb"); + if (!file) return 0; + + fseek(file, 0, SEEK_END); + *length = (int)ftell(file); + fseek(file, 0, SEEK_SET); + + data = MALLOC(char, *length); + fread(data, 1, *length, file); + fclose(file); + + return data; } diff --git a/spine-cocos2d-objc/example/GoblinsExample.h b/spine-cocos2d-objc/example/GoblinsExample.h index 3b8bea4ae3..16c65e52eb 100644 --- a/spine-cocos2d-objc/example/GoblinsExample.h +++ b/spine-cocos2d-objc/example/GoblinsExample.h @@ -1,41 +1,40 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#import "cocos2d.h" -#import - -@interface GoblinsExample : CCNode { - SkeletonAnimation* skeletonNode; -} - -+ (CCScene*) scene; - +#import "cocos2d.h" +#import + +@interface GoblinsExample : CCNode { + SkeletonAnimation* skeletonNode; +} + ++ (CCScene*) scene; + @end diff --git a/spine-cocos2d-objc/example/GoblinsExample.m b/spine-cocos2d-objc/example/GoblinsExample.m index a2e9a1e849..dc6ec27f78 100644 --- a/spine-cocos2d-objc/example/GoblinsExample.m +++ b/spine-cocos2d-objc/example/GoblinsExample.m @@ -1,72 +1,71 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#import "GoblinsExample.h" -#import "RaptorExample.h" - -@implementation GoblinsExample - -+ (CCScene*) scene { - CCScene *scene = [CCScene node]; - [scene addChild:[GoblinsExample node]]; - return scene; -} - --(id) init { - self = [super init]; - if (!self) return nil; - - skeletonNode = [SkeletonAnimation skeletonWithFile:@"goblins-mesh.json" atlasFile:@"goblins-mesh.atlas" scale:1]; - [skeletonNode setSkin:@"goblin"]; - [skeletonNode setAnimationForTrack:0 name:@"walk" loop:YES]; - - CGSize windowSize = [[CCDirector sharedDirector] viewSize]; - [skeletonNode setPosition:ccp(windowSize.width / 2, 20)]; - [self addChild:skeletonNode]; - - self.userInteractionEnabled = YES; - self.contentSize = windowSize; - - return self; -} - -#if ( TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR ) -- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event { - if (!skeletonNode.debugBones) - skeletonNode.debugBones = true; - else if (skeletonNode.timeScale == 1) - skeletonNode.timeScale = 0.3f; - else - [[CCDirector sharedDirector] replaceScene:[RaptorExample scene]]; -} -#endif - +#import "GoblinsExample.h" +#import "RaptorExample.h" + +@implementation GoblinsExample + ++ (CCScene*) scene { + CCScene *scene = [CCScene node]; + [scene addChild:[GoblinsExample node]]; + return scene; +} + +-(id) init { + self = [super init]; + if (!self) return nil; + + skeletonNode = [SkeletonAnimation skeletonWithFile:@"goblins-mesh.json" atlasFile:@"goblins-mesh.atlas" scale:1]; + [skeletonNode setSkin:@"goblin"]; + [skeletonNode setAnimationForTrack:0 name:@"walk" loop:YES]; + + CGSize windowSize = [[CCDirector sharedDirector] viewSize]; + [skeletonNode setPosition:ccp(windowSize.width / 2, 20)]; + [self addChild:skeletonNode]; + + self.userInteractionEnabled = YES; + self.contentSize = windowSize; + + return self; +} + +#if ( TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR ) +- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event { + if (!skeletonNode.debugBones) + skeletonNode.debugBones = true; + else if (skeletonNode.timeScale == 1) + skeletonNode.timeScale = 0.3f; + else + [[CCDirector sharedDirector] replaceScene:[RaptorExample scene]]; +} +#endif + @end diff --git a/spine-cocos2d-objc/example/RaptorExample.h b/spine-cocos2d-objc/example/RaptorExample.h index 1951c6e8c0..993d3f783d 100644 --- a/spine-cocos2d-objc/example/RaptorExample.h +++ b/spine-cocos2d-objc/example/RaptorExample.h @@ -1,41 +1,40 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#import "cocos2d.h" -#import - -@interface RaptorExample : CCNode { - SkeletonAnimation* skeletonNode; -} - -+ (CCScene*) scene; - +#import "cocos2d.h" +#import + +@interface RaptorExample : CCNode { + SkeletonAnimation* skeletonNode; +} + ++ (CCScene*) scene; + @end diff --git a/spine-cocos2d-objc/example/RaptorExample.m b/spine-cocos2d-objc/example/RaptorExample.m index 983f4982ff..aebd3c2801 100644 --- a/spine-cocos2d-objc/example/RaptorExample.m +++ b/spine-cocos2d-objc/example/RaptorExample.m @@ -1,71 +1,70 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#import "RaptorExample.h" -#import "TankExample.h" - -@implementation RaptorExample - -+ (CCScene*) scene { - CCScene *scene = [CCScene node]; - [scene addChild:[RaptorExample node]]; - return scene; -} - --(id) init { - self = [super init]; - if (!self) return nil; - - skeletonNode = [SkeletonAnimation skeletonWithFile:@"raptor.json" atlasFile:@"raptor.atlas" scale:0.3f]; - [skeletonNode setAnimationForTrack:0 name:@"walk" loop:YES]; - - CGSize windowSize = [[CCDirector sharedDirector] viewSize]; - [skeletonNode setPosition:ccp(windowSize.width / 2, 20)]; - [self addChild:skeletonNode]; - - self.userInteractionEnabled = YES; - self.contentSize = windowSize; - - return self; -} - -#if ( TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR ) -- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event { - if (!skeletonNode.debugBones) - skeletonNode.debugBones = true; - else if (skeletonNode.timeScale == 1) - skeletonNode.timeScale = 0.3f; - else - [[CCDirector sharedDirector] replaceScene:[TankExample scene]]; -} -#endif - +#import "RaptorExample.h" +#import "TankExample.h" + +@implementation RaptorExample + ++ (CCScene*) scene { + CCScene *scene = [CCScene node]; + [scene addChild:[RaptorExample node]]; + return scene; +} + +-(id) init { + self = [super init]; + if (!self) return nil; + + skeletonNode = [SkeletonAnimation skeletonWithFile:@"raptor.json" atlasFile:@"raptor.atlas" scale:0.3f]; + [skeletonNode setAnimationForTrack:0 name:@"walk" loop:YES]; + + CGSize windowSize = [[CCDirector sharedDirector] viewSize]; + [skeletonNode setPosition:ccp(windowSize.width / 2, 20)]; + [self addChild:skeletonNode]; + + self.userInteractionEnabled = YES; + self.contentSize = windowSize; + + return self; +} + +#if ( TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR ) +- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event { + if (!skeletonNode.debugBones) + skeletonNode.debugBones = true; + else if (skeletonNode.timeScale == 1) + skeletonNode.timeScale = 0.3f; + else + [[CCDirector sharedDirector] replaceScene:[TankExample scene]]; +} +#endif + @end diff --git a/spine-cocos2d-objc/example/SpineboyExample.h b/spine-cocos2d-objc/example/SpineboyExample.h index 32810a67ca..57e876c6d6 100644 --- a/spine-cocos2d-objc/example/SpineboyExample.h +++ b/spine-cocos2d-objc/example/SpineboyExample.h @@ -1,41 +1,40 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#import "cocos2d.h" -#import - -@interface SpineboyExample : CCNode { - SkeletonAnimation* skeletonNode; -} - -+ (CCScene*) scene; - +#import "cocos2d.h" +#import + +@interface SpineboyExample : CCNode { + SkeletonAnimation* skeletonNode; +} + ++ (CCScene*) scene; + @end diff --git a/spine-cocos2d-objc/example/SpineboyExample.m b/spine-cocos2d-objc/example/SpineboyExample.m index 0d5636fc12..55f685202f 100644 --- a/spine-cocos2d-objc/example/SpineboyExample.m +++ b/spine-cocos2d-objc/example/SpineboyExample.m @@ -1,98 +1,97 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#import "SpineboyExample.h" -#import "GoblinsExample.h" - -@implementation SpineboyExample - -+ (CCScene*) scene { - CCScene *scene = [CCScene node]; - [scene addChild:[SpineboyExample node]]; - return scene; -} - --(id) init { - self = [super init]; - if (!self) return nil; - - skeletonNode = [SkeletonAnimation skeletonWithFile:@"spineboy.json" atlasFile:@"spineboy.atlas" scale:0.6]; - [skeletonNode setMixFrom:@"walk" to:@"jump" duration:0.2f]; - [skeletonNode setMixFrom:@"jump" to:@"run" duration:0.2f]; - - __weak SkeletonAnimation* node = skeletonNode; - skeletonNode.startListener = ^(int trackIndex) { - spTrackEntry* entry = spAnimationState_getCurrent(node.state, trackIndex); - const char* animationName = (entry && entry->animation) ? entry->animation->name : 0; - NSLog(@"%d start: %s", trackIndex, animationName); - }; - skeletonNode.endListener = ^(int trackIndex) { - NSLog(@"%d end", trackIndex); - }; - skeletonNode.completeListener = ^(int trackIndex, int loopCount) { - NSLog(@"%d complete: %d", trackIndex, loopCount); - }; - skeletonNode.eventListener = ^(int trackIndex, spEvent* event) { - NSLog(@"%d event: %s, %d, %f, %s", trackIndex, event->data->name, event->intValue, event->floatValue, event->stringValue); - }; - - [skeletonNode setAnimationForTrack:0 name:@"walk" loop:YES]; - spTrackEntry* jumpEntry = [skeletonNode addAnimationForTrack:0 name:@"jump" loop:NO afterDelay:3]; - [skeletonNode addAnimationForTrack:0 name:@"run" loop:YES afterDelay:0]; - - [skeletonNode setListenerForEntry:jumpEntry onStart:^(int trackIndex) { - CCLOG(@"jumped!"); - }]; - - // [skeletonNode setAnimationForTrack:1 name:@"test" loop:YES]; - - CGSize windowSize = [[CCDirector sharedDirector] viewSize]; - [skeletonNode setPosition:ccp(windowSize.width / 2, 20)]; - [self addChild:skeletonNode]; - - self.userInteractionEnabled = YES; - self.contentSize = windowSize; - - return self; -} - -#if ( TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR ) -- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event { - if (!skeletonNode.debugBones) - skeletonNode.debugBones = true; - else if (skeletonNode.timeScale == 1) - skeletonNode.timeScale = 0.3f; - else - [[CCDirector sharedDirector] replaceScene:[GoblinsExample scene]]; -} -#endif - +#import "SpineboyExample.h" +#import "GoblinsExample.h" + +@implementation SpineboyExample + ++ (CCScene*) scene { + CCScene *scene = [CCScene node]; + [scene addChild:[SpineboyExample node]]; + return scene; +} + +-(id) init { + self = [super init]; + if (!self) return nil; + + skeletonNode = [SkeletonAnimation skeletonWithFile:@"spineboy.json" atlasFile:@"spineboy.atlas" scale:0.6]; + [skeletonNode setMixFrom:@"walk" to:@"jump" duration:0.2f]; + [skeletonNode setMixFrom:@"jump" to:@"run" duration:0.2f]; + + __weak SkeletonAnimation* node = skeletonNode; + skeletonNode.startListener = ^(int trackIndex) { + spTrackEntry* entry = spAnimationState_getCurrent(node.state, trackIndex); + const char* animationName = (entry && entry->animation) ? entry->animation->name : 0; + NSLog(@"%d start: %s", trackIndex, animationName); + }; + skeletonNode.endListener = ^(int trackIndex) { + NSLog(@"%d end", trackIndex); + }; + skeletonNode.completeListener = ^(int trackIndex, int loopCount) { + NSLog(@"%d complete: %d", trackIndex, loopCount); + }; + skeletonNode.eventListener = ^(int trackIndex, spEvent* event) { + NSLog(@"%d event: %s, %d, %f, %s", trackIndex, event->data->name, event->intValue, event->floatValue, event->stringValue); + }; + + [skeletonNode setAnimationForTrack:0 name:@"walk" loop:YES]; + spTrackEntry* jumpEntry = [skeletonNode addAnimationForTrack:0 name:@"jump" loop:NO afterDelay:3]; + [skeletonNode addAnimationForTrack:0 name:@"run" loop:YES afterDelay:0]; + + [skeletonNode setListenerForEntry:jumpEntry onStart:^(int trackIndex) { + CCLOG(@"jumped!"); + }]; + + // [skeletonNode setAnimationForTrack:1 name:@"test" loop:YES]; + + CGSize windowSize = [[CCDirector sharedDirector] viewSize]; + [skeletonNode setPosition:ccp(windowSize.width / 2, 20)]; + [self addChild:skeletonNode]; + + self.userInteractionEnabled = YES; + self.contentSize = windowSize; + + return self; +} + +#if ( TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR ) +- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event { + if (!skeletonNode.debugBones) + skeletonNode.debugBones = true; + else if (skeletonNode.timeScale == 1) + skeletonNode.timeScale = 0.3f; + else + [[CCDirector sharedDirector] replaceScene:[GoblinsExample scene]]; +} +#endif + @end diff --git a/spine-cocos2d-objc/example/TankExample.h b/spine-cocos2d-objc/example/TankExample.h index ad0fbb0ff7..0e2b3ac3c0 100644 --- a/spine-cocos2d-objc/example/TankExample.h +++ b/spine-cocos2d-objc/example/TankExample.h @@ -1,41 +1,40 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#import "cocos2d.h" -#import - -@interface TankExample : CCNode { - SkeletonAnimation* skeletonNode; -} - -+ (CCScene*) scene; - +#import "cocos2d.h" +#import + +@interface TankExample : CCNode { + SkeletonAnimation* skeletonNode; +} + ++ (CCScene*) scene; + @end diff --git a/spine-cocos2d-objc/example/TankExample.m b/spine-cocos2d-objc/example/TankExample.m index 1c28908b4d..df08d06f11 100644 --- a/spine-cocos2d-objc/example/TankExample.m +++ b/spine-cocos2d-objc/example/TankExample.m @@ -1,71 +1,70 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#import "TankExample.h" -#import "SpineboyExample.h" - -@implementation TankExample - -+ (CCScene*) scene { - CCScene *scene = [CCScene node]; - [scene addChild:[TankExample node]]; - return scene; -} - --(id) init { - self = [super init]; - if (!self) return nil; - - skeletonNode = [SkeletonAnimation skeletonWithFile:@"tank.json" atlasFile:@"tank.atlas" scale:0.2f]; - [skeletonNode setAnimationForTrack:0 name:@"drive" loop:YES]; - - CGSize windowSize = [[CCDirector sharedDirector] viewSize]; - [skeletonNode setPosition:ccp(windowSize.width / 2, 20)]; - [self addChild:skeletonNode]; - - self.userInteractionEnabled = YES; - self.contentSize = windowSize; - - return self; -} - -#if ( TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR ) -- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event { - if (!skeletonNode.debugBones) - skeletonNode.debugBones = true; - else if (skeletonNode.timeScale == 1) - skeletonNode.timeScale = 0.3f; - else - [[CCDirector sharedDirector] replaceScene:[SpineboyExample scene]]; -} -#endif - +#import "TankExample.h" +#import "SpineboyExample.h" + +@implementation TankExample + ++ (CCScene*) scene { + CCScene *scene = [CCScene node]; + [scene addChild:[TankExample node]]; + return scene; +} + +-(id) init { + self = [super init]; + if (!self) return nil; + + skeletonNode = [SkeletonAnimation skeletonWithFile:@"tank.json" atlasFile:@"tank.atlas" scale:0.2f]; + [skeletonNode setAnimationForTrack:0 name:@"drive" loop:YES]; + + CGSize windowSize = [[CCDirector sharedDirector] viewSize]; + [skeletonNode setPosition:ccp(windowSize.width / 2, 20)]; + [self addChild:skeletonNode]; + + self.userInteractionEnabled = YES; + self.contentSize = windowSize; + + return self; +} + +#if ( TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR ) +- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event { + if (!skeletonNode.debugBones) + skeletonNode.debugBones = true; + else if (skeletonNode.timeScale == 1) + skeletonNode.timeScale = 0.3f; + else + [[CCDirector sharedDirector] replaceScene:[SpineboyExample scene]]; +} +#endif + @end diff --git a/spine-cocos2d-objc/src/spine/SkeletonAnimation.h b/spine-cocos2d-objc/src/spine/SkeletonAnimation.h index 22ee4f1dab..42bf58622e 100644 --- a/spine-cocos2d-objc/src/spine/SkeletonAnimation.h +++ b/spine-cocos2d-objc/src/spine/SkeletonAnimation.h @@ -1,88 +1,87 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#import -#import -#import "cocos2d.h" - -@class SkeletonAnimation; - -typedef void(^spStartListener)(int trackIndex); -typedef void(^spEndListener)(int trackIndex); -typedef void(^spCompleteListener)(int trackIndex, int loopCount); -typedef void(^spEventListener)(int trackIndex, spEvent* event); - -/** Draws an animated skeleton, providing an AnimationState for applying one or more animations and queuing animations to be - * played later. */ -@interface SkeletonAnimation : SkeletonRenderer { - spAnimationState* _state; - bool _ownsAnimationStateData; - float _timeScale; - - spStartListener _startListener; - spEndListener _endListener; - spCompleteListener _completeListener; - spEventListener _eventListener; -} - -+ (id) skeletonWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData; -+ (id) skeletonWithFile:(NSString*)skeletonDataFile atlas:(spAtlas*)atlas scale:(float)scale; -+ (id) skeletonWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale; - -- (id) initWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData; -- (id) initWithFile:(NSString*)skeletonDataFile atlas:(spAtlas*)atlas scale:(float)scale; -- (id) initWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale; - -- (void) setAnimationStateData:(spAnimationStateData*)stateData; -- (void) setMixFrom:(NSString*)fromAnimation to:(NSString*)toAnimation duration:(float)duration; - -- (spTrackEntry*) setAnimationForTrack:(int)trackIndex name:(NSString*)name loop:(bool)loop; -- (spTrackEntry*) addAnimationForTrack:(int)trackIndex name:(NSString*)name loop:(bool)loop afterDelay:(int)delay; -- (spTrackEntry*) getCurrentForTrack:(int)trackIndex; -- (void) clearTracks; -- (void) clearTrack:(int)trackIndex; - -- (void) setListenerForEntry:(spTrackEntry*)entry onStart:(spStartListener)listener; -- (void) setListenerForEntry:(spTrackEntry*)entry onEnd:(spEndListener)listener; -- (void) setListenerForEntry:(spTrackEntry*)entry onComplete:(spCompleteListener)listener; -- (void) setListenerForEntry:(spTrackEntry*)entry onEvent:(spEventListener)listener; - -- (void) onAnimationStateEvent:(int)trackIndex type:(spEventType)type event:(spEvent*)event loopCount:(int)loopCount; -- (void) onTrackEntryEvent:(int)trackIndex type:(spEventType)type event:(spEvent*)event loopCount:(int)loopCount; - -@property (nonatomic, readonly) spAnimationState* state; -@property (nonatomic) float timeScale; -@property (nonatomic, copy) spStartListener startListener; -@property (nonatomic, copy) spEndListener endListener; -@property (nonatomic, copy) spCompleteListener completeListener; -@property (nonatomic, copy) spEventListener eventListener; - +#import +#import +#import "cocos2d.h" + +@class SkeletonAnimation; + +typedef void(^spStartListener)(int trackIndex); +typedef void(^spEndListener)(int trackIndex); +typedef void(^spCompleteListener)(int trackIndex, int loopCount); +typedef void(^spEventListener)(int trackIndex, spEvent* event); + +/** Draws an animated skeleton, providing an AnimationState for applying one or more animations and queuing animations to be + * played later. */ +@interface SkeletonAnimation : SkeletonRenderer { + spAnimationState* _state; + bool _ownsAnimationStateData; + float _timeScale; + + spStartListener _startListener; + spEndListener _endListener; + spCompleteListener _completeListener; + spEventListener _eventListener; +} + ++ (id) skeletonWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData; ++ (id) skeletonWithFile:(NSString*)skeletonDataFile atlas:(spAtlas*)atlas scale:(float)scale; ++ (id) skeletonWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale; + +- (id) initWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData; +- (id) initWithFile:(NSString*)skeletonDataFile atlas:(spAtlas*)atlas scale:(float)scale; +- (id) initWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale; + +- (void) setAnimationStateData:(spAnimationStateData*)stateData; +- (void) setMixFrom:(NSString*)fromAnimation to:(NSString*)toAnimation duration:(float)duration; + +- (spTrackEntry*) setAnimationForTrack:(int)trackIndex name:(NSString*)name loop:(bool)loop; +- (spTrackEntry*) addAnimationForTrack:(int)trackIndex name:(NSString*)name loop:(bool)loop afterDelay:(int)delay; +- (spTrackEntry*) getCurrentForTrack:(int)trackIndex; +- (void) clearTracks; +- (void) clearTrack:(int)trackIndex; + +- (void) setListenerForEntry:(spTrackEntry*)entry onStart:(spStartListener)listener; +- (void) setListenerForEntry:(spTrackEntry*)entry onEnd:(spEndListener)listener; +- (void) setListenerForEntry:(spTrackEntry*)entry onComplete:(spCompleteListener)listener; +- (void) setListenerForEntry:(spTrackEntry*)entry onEvent:(spEventListener)listener; + +- (void) onAnimationStateEvent:(int)trackIndex type:(spEventType)type event:(spEvent*)event loopCount:(int)loopCount; +- (void) onTrackEntryEvent:(int)trackIndex type:(spEventType)type event:(spEvent*)event loopCount:(int)loopCount; + +@property (nonatomic, readonly) spAnimationState* state; +@property (nonatomic) float timeScale; +@property (nonatomic, copy) spStartListener startListener; +@property (nonatomic, copy) spEndListener endListener; +@property (nonatomic, copy) spCompleteListener completeListener; +@property (nonatomic, copy) spEventListener eventListener; + @end diff --git a/spine-cocos2d-objc/src/spine/SkeletonAnimation.m b/spine-cocos2d-objc/src/spine/SkeletonAnimation.m index c34dcf0734..70736c39ce 100644 --- a/spine-cocos2d-objc/src/spine/SkeletonAnimation.m +++ b/spine-cocos2d-objc/src/spine/SkeletonAnimation.m @@ -1,256 +1,255 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#import -#import -#import - -static void animationCallback (spAnimationState* state, int trackIndex, spEventType type, spEvent* event, int loopCount) { - [(SkeletonAnimation*)state->rendererObject onAnimationStateEvent:trackIndex type:type event:event loopCount:loopCount]; -} - -void trackEntryCallback (spAnimationState* state, int trackIndex, spEventType type, spEvent* event, int loopCount) { - [(SkeletonAnimation*)state->rendererObject onTrackEntryEvent:trackIndex type:type event:event loopCount:loopCount]; -} - -typedef struct _TrackEntryListeners { - spStartListener startListener; - spEndListener endListener; - spCompleteListener completeListener; - spEventListener eventListener; -} _TrackEntryListeners; - -static _TrackEntryListeners* getListeners (spTrackEntry* entry) { - if (!entry->rendererObject) { - entry->rendererObject = NEW(_TrackEntryListeners); - entry->listener = trackEntryCallback; - } - return (_TrackEntryListeners*)entry->rendererObject; -} - -void disposeTrackEntry (spTrackEntry* entry) { - if (entry->rendererObject) { - _TrackEntryListeners* listeners = (_TrackEntryListeners*)entry->rendererObject; - [listeners->startListener release]; - [listeners->endListener release]; - [listeners->completeListener release]; - [listeners->eventListener release]; - FREE(listeners); - } - _spTrackEntry_dispose(entry); -} - -// - -@interface SkeletonAnimation (Private) -- (void) initialize; -@end - -@implementation SkeletonAnimation - -@synthesize state = _state; -@synthesize timeScale = _timeScale; -@synthesize startListener = _startListener; -@synthesize endListener = _endListener; -@synthesize completeListener = _completeListener; -@synthesize eventListener = _eventListener; - -+ (id) skeletonWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData { - return [[[self alloc] initWithData:skeletonData ownsSkeletonData:ownsSkeletonData] autorelease]; -} - -+ (id) skeletonWithFile:(NSString*)skeletonDataFile atlas:(spAtlas*)atlas scale:(float)scale { - return [[[self alloc] initWithFile:skeletonDataFile atlas:atlas scale:scale] autorelease]; -} - -+ (id) skeletonWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale { - return [[[self alloc] initWithFile:skeletonDataFile atlasFile:atlasFile scale:scale] autorelease]; -} - -- (void) initialize { - _ownsAnimationStateData = true; - _timeScale = 1; - - _state = spAnimationState_create(spAnimationStateData_create(_skeleton->data)); - _state->rendererObject = self; - _state->listener = animationCallback; - - _spAnimationState* stateInternal = (_spAnimationState*)_state; - stateInternal->disposeTrackEntry = disposeTrackEntry; -} - -- (id) initWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData { - self = [super initWithData:skeletonData ownsSkeletonData:ownsSkeletonData]; - if (!self) return nil; - - [self initialize]; - - return self; -} - -- (id) initWithFile:(NSString*)skeletonDataFile atlas:(spAtlas*)atlas scale:(float)scale { - self = [super initWithFile:skeletonDataFile atlas:atlas scale:scale]; - if (!self) return nil; - - [self initialize]; - - return self; -} - -- (id) initWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale { - self = [super initWithFile:skeletonDataFile atlasFile:atlasFile scale:scale]; - if (!self) return nil; - - [self initialize]; - - return self; -} - -- (void) dealloc { - if (_ownsAnimationStateData) spAnimationStateData_dispose(_state->data); - spAnimationState_dispose(_state); - - [_startListener release]; - [_endListener release]; - [_completeListener release]; - [_eventListener release]; - - [super dealloc]; -} - -- (void) update:(CCTime)deltaTime { - deltaTime *= _timeScale; - spSkeleton_update(_skeleton, deltaTime); - spAnimationState_update(_state, deltaTime); - spAnimationState_apply(_state, _skeleton); - spSkeleton_updateWorldTransform(_skeleton); -} - -- (void) setAnimationStateData:(spAnimationStateData*)stateData { - NSAssert(stateData, @"stateData cannot be null."); - - if (_ownsAnimationStateData) spAnimationStateData_dispose(_state->data); - spAnimationState_dispose(_state); - - _ownsAnimationStateData = false; - _state = spAnimationState_create(stateData); - _state->rendererObject = self; - _state->listener = animationCallback; -} - -- (void) setMixFrom:(NSString*)fromAnimation to:(NSString*)toAnimation duration:(float)duration { - spAnimationStateData_setMixByName(_state->data, [fromAnimation UTF8String], [toAnimation UTF8String], duration); -} - -- (spTrackEntry*) setAnimationForTrack:(int)trackIndex name:(NSString*)name loop:(bool)loop { - spAnimation* animation = spSkeletonData_findAnimation(_skeleton->data, [name UTF8String]); - if (!animation) { - CCLOG(@"Spine: Animation not found: %@", name); - return 0; - } - return spAnimationState_setAnimation(_state, trackIndex, animation, loop); -} - -- (spTrackEntry*) addAnimationForTrack:(int)trackIndex name:(NSString*)name loop:(bool)loop afterDelay:(int)delay { - spAnimation* animation = spSkeletonData_findAnimation(_skeleton->data, [name UTF8String]); - if (!animation) { - CCLOG(@"Spine: Animation not found: %@", name); - return 0; - } - return spAnimationState_addAnimation(_state, trackIndex, animation, loop, delay); -} - -- (spTrackEntry*) getCurrentForTrack:(int)trackIndex { - return spAnimationState_getCurrent(_state, trackIndex); -} - -- (void) clearTracks { - spAnimationState_clearTracks(_state); -} - -- (void) clearTrack:(int)trackIndex { - spAnimationState_clearTrack(_state, trackIndex); -} - -- (void) onAnimationStateEvent:(int)trackIndex type:(spEventType)type event:(spEvent*)event loopCount:(int)loopCount { - switch (type) { - case SP_ANIMATION_START: - if (_startListener) _startListener(trackIndex); - break; - case SP_ANIMATION_END: - if (_endListener) _endListener(trackIndex); - break; - case SP_ANIMATION_COMPLETE: - if (_completeListener) _completeListener(trackIndex, loopCount); - break; - case SP_ANIMATION_EVENT: - if (_eventListener) _eventListener(trackIndex, event); - break; - } -} - -- (void) onTrackEntryEvent:(int)trackIndex type:(spEventType)type event:(spEvent*)event loopCount:(int)loopCount { - spTrackEntry* entry = spAnimationState_getCurrent(_state, trackIndex); - if (!entry->rendererObject) return; - _TrackEntryListeners* listeners = (_TrackEntryListeners*)entry->rendererObject; - switch (type) { - case SP_ANIMATION_START: - if (listeners->startListener) listeners->startListener(trackIndex); - break; - case SP_ANIMATION_END: - if (listeners->endListener) listeners->endListener(trackIndex); - break; - case SP_ANIMATION_COMPLETE: - if (listeners->completeListener) listeners->completeListener(trackIndex, loopCount); - break; - case SP_ANIMATION_EVENT: - if (listeners->eventListener) listeners->eventListener(trackIndex, event); - break; - } -} - -- (void) setListenerForEntry:(spTrackEntry*)entry onStart:(spStartListener)listener { - getListeners(entry)->startListener = [listener copy]; -} - -- (void) setListenerForEntry:(spTrackEntry*)entry onEnd:(spEndListener)listener { - getListeners(entry)->endListener = [listener copy]; -} - -- (void) setListenerForEntry:(spTrackEntry*)entry onComplete:(spCompleteListener)listener { - getListeners(entry)->completeListener = [listener copy]; -} - -- (void) setListenerForEntry:(spTrackEntry*)entry onEvent:(spEventListener)listener { - getListeners(entry)->eventListener = [listener copy]; -} - +#import +#import +#import + +static void animationCallback (spAnimationState* state, int trackIndex, spEventType type, spEvent* event, int loopCount) { + [(SkeletonAnimation*)state->rendererObject onAnimationStateEvent:trackIndex type:type event:event loopCount:loopCount]; +} + +void trackEntryCallback (spAnimationState* state, int trackIndex, spEventType type, spEvent* event, int loopCount) { + [(SkeletonAnimation*)state->rendererObject onTrackEntryEvent:trackIndex type:type event:event loopCount:loopCount]; +} + +typedef struct _TrackEntryListeners { + spStartListener startListener; + spEndListener endListener; + spCompleteListener completeListener; + spEventListener eventListener; +} _TrackEntryListeners; + +static _TrackEntryListeners* getListeners (spTrackEntry* entry) { + if (!entry->rendererObject) { + entry->rendererObject = NEW(_TrackEntryListeners); + entry->listener = trackEntryCallback; + } + return (_TrackEntryListeners*)entry->rendererObject; +} + +void disposeTrackEntry (spTrackEntry* entry) { + if (entry->rendererObject) { + _TrackEntryListeners* listeners = (_TrackEntryListeners*)entry->rendererObject; + [listeners->startListener release]; + [listeners->endListener release]; + [listeners->completeListener release]; + [listeners->eventListener release]; + FREE(listeners); + } + _spTrackEntry_dispose(entry); +} + +// + +@interface SkeletonAnimation (Private) +- (void) initialize; +@end + +@implementation SkeletonAnimation + +@synthesize state = _state; +@synthesize timeScale = _timeScale; +@synthesize startListener = _startListener; +@synthesize endListener = _endListener; +@synthesize completeListener = _completeListener; +@synthesize eventListener = _eventListener; + ++ (id) skeletonWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData { + return [[[self alloc] initWithData:skeletonData ownsSkeletonData:ownsSkeletonData] autorelease]; +} + ++ (id) skeletonWithFile:(NSString*)skeletonDataFile atlas:(spAtlas*)atlas scale:(float)scale { + return [[[self alloc] initWithFile:skeletonDataFile atlas:atlas scale:scale] autorelease]; +} + ++ (id) skeletonWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale { + return [[[self alloc] initWithFile:skeletonDataFile atlasFile:atlasFile scale:scale] autorelease]; +} + +- (void) initialize { + _ownsAnimationStateData = true; + _timeScale = 1; + + _state = spAnimationState_create(spAnimationStateData_create(_skeleton->data)); + _state->rendererObject = self; + _state->listener = animationCallback; + + _spAnimationState* stateInternal = (_spAnimationState*)_state; + stateInternal->disposeTrackEntry = disposeTrackEntry; +} + +- (id) initWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData { + self = [super initWithData:skeletonData ownsSkeletonData:ownsSkeletonData]; + if (!self) return nil; + + [self initialize]; + + return self; +} + +- (id) initWithFile:(NSString*)skeletonDataFile atlas:(spAtlas*)atlas scale:(float)scale { + self = [super initWithFile:skeletonDataFile atlas:atlas scale:scale]; + if (!self) return nil; + + [self initialize]; + + return self; +} + +- (id) initWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale { + self = [super initWithFile:skeletonDataFile atlasFile:atlasFile scale:scale]; + if (!self) return nil; + + [self initialize]; + + return self; +} + +- (void) dealloc { + if (_ownsAnimationStateData) spAnimationStateData_dispose(_state->data); + spAnimationState_dispose(_state); + + [_startListener release]; + [_endListener release]; + [_completeListener release]; + [_eventListener release]; + + [super dealloc]; +} + +- (void) update:(CCTime)deltaTime { + deltaTime *= _timeScale; + spSkeleton_update(_skeleton, deltaTime); + spAnimationState_update(_state, deltaTime); + spAnimationState_apply(_state, _skeleton); + spSkeleton_updateWorldTransform(_skeleton); +} + +- (void) setAnimationStateData:(spAnimationStateData*)stateData { + NSAssert(stateData, @"stateData cannot be null."); + + if (_ownsAnimationStateData) spAnimationStateData_dispose(_state->data); + spAnimationState_dispose(_state); + + _ownsAnimationStateData = false; + _state = spAnimationState_create(stateData); + _state->rendererObject = self; + _state->listener = animationCallback; +} + +- (void) setMixFrom:(NSString*)fromAnimation to:(NSString*)toAnimation duration:(float)duration { + spAnimationStateData_setMixByName(_state->data, [fromAnimation UTF8String], [toAnimation UTF8String], duration); +} + +- (spTrackEntry*) setAnimationForTrack:(int)trackIndex name:(NSString*)name loop:(bool)loop { + spAnimation* animation = spSkeletonData_findAnimation(_skeleton->data, [name UTF8String]); + if (!animation) { + CCLOG(@"Spine: Animation not found: %@", name); + return 0; + } + return spAnimationState_setAnimation(_state, trackIndex, animation, loop); +} + +- (spTrackEntry*) addAnimationForTrack:(int)trackIndex name:(NSString*)name loop:(bool)loop afterDelay:(int)delay { + spAnimation* animation = spSkeletonData_findAnimation(_skeleton->data, [name UTF8String]); + if (!animation) { + CCLOG(@"Spine: Animation not found: %@", name); + return 0; + } + return spAnimationState_addAnimation(_state, trackIndex, animation, loop, delay); +} + +- (spTrackEntry*) getCurrentForTrack:(int)trackIndex { + return spAnimationState_getCurrent(_state, trackIndex); +} + +- (void) clearTracks { + spAnimationState_clearTracks(_state); +} + +- (void) clearTrack:(int)trackIndex { + spAnimationState_clearTrack(_state, trackIndex); +} + +- (void) onAnimationStateEvent:(int)trackIndex type:(spEventType)type event:(spEvent*)event loopCount:(int)loopCount { + switch (type) { + case SP_ANIMATION_START: + if (_startListener) _startListener(trackIndex); + break; + case SP_ANIMATION_END: + if (_endListener) _endListener(trackIndex); + break; + case SP_ANIMATION_COMPLETE: + if (_completeListener) _completeListener(trackIndex, loopCount); + break; + case SP_ANIMATION_EVENT: + if (_eventListener) _eventListener(trackIndex, event); + break; + } +} + +- (void) onTrackEntryEvent:(int)trackIndex type:(spEventType)type event:(spEvent*)event loopCount:(int)loopCount { + spTrackEntry* entry = spAnimationState_getCurrent(_state, trackIndex); + if (!entry->rendererObject) return; + _TrackEntryListeners* listeners = (_TrackEntryListeners*)entry->rendererObject; + switch (type) { + case SP_ANIMATION_START: + if (listeners->startListener) listeners->startListener(trackIndex); + break; + case SP_ANIMATION_END: + if (listeners->endListener) listeners->endListener(trackIndex); + break; + case SP_ANIMATION_COMPLETE: + if (listeners->completeListener) listeners->completeListener(trackIndex, loopCount); + break; + case SP_ANIMATION_EVENT: + if (listeners->eventListener) listeners->eventListener(trackIndex, event); + break; + } +} + +- (void) setListenerForEntry:(spTrackEntry*)entry onStart:(spStartListener)listener { + getListeners(entry)->startListener = [listener copy]; +} + +- (void) setListenerForEntry:(spTrackEntry*)entry onEnd:(spEndListener)listener { + getListeners(entry)->endListener = [listener copy]; +} + +- (void) setListenerForEntry:(spTrackEntry*)entry onComplete:(spCompleteListener)listener { + getListeners(entry)->completeListener = [listener copy]; +} + +- (void) setListenerForEntry:(spTrackEntry*)entry onEvent:(spEventListener)listener { + getListeners(entry)->eventListener = [listener copy]; +} + @end diff --git a/spine-cocos2d-objc/src/spine/SkeletonRenderer.h b/spine-cocos2d-objc/src/spine/SkeletonRenderer.h index f35e94caef..123c97356a 100644 --- a/spine-cocos2d-objc/src/spine/SkeletonRenderer.h +++ b/spine-cocos2d-objc/src/spine/SkeletonRenderer.h @@ -1,92 +1,91 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#import -#import "cocos2d.h" - -/** Draws a skeleton. */ -@interface SkeletonRenderer : CCNode { - spSkeleton* _skeleton; - spBone* _rootBone; - bool _debugSlots; - bool _debugBones; - bool _premultipliedAlpha; - bool _skipVisibilityCheck; - ccBlendFunc _blendFunc; - CCDrawNode* _drawNode; - bool _ownsSkeletonData; - spAtlas* _atlas; - float* _worldVertices; - CCBlendMode* screenMode; -} - -+ (id) skeletonWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData; -+ (id) skeletonWithFile:(NSString*)skeletonDataFile atlas:(spAtlas*)atlas scale:(float)scale; -+ (id) skeletonWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale; - -- (id) initWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData; -- (id) initWithFile:(NSString*)skeletonDataFile atlas:(spAtlas*)atlas scale:(float)scale; -- (id) initWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale; - -- (CCTexture*) getTextureForRegion:(spRegionAttachment*)attachment; -- (CCTexture*) getTextureForMesh:(spMeshAttachment*)attachment; - -// --- Convenience methods for common Skeleton_* functions. -- (void) updateWorldTransform; - -- (void) setToSetupPose; -- (void) setBonesToSetupPose; -- (void) setSlotsToSetupPose; - -/* Returns 0 if the bone was not found. */ -- (spBone*) findBone:(NSString*)boneName; - -/* Returns 0 if the slot was not found. */ -- (spSlot*) findSlot:(NSString*)slotName; - -/* Sets the skin used to look up attachments not found in the SkeletonData defaultSkin. 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. Returns false if the skin was not found. - * @param skin May be 0.*/ -- (bool) setSkin:(NSString*)skinName; - -/* Returns 0 if the slot or attachment was not found. */ -- (spAttachment*) getAttachment:(NSString*)slotName attachmentName:(NSString*)attachmentName; -/* Returns false if the slot or attachment was not found. */ -- (bool) setAttachment:(NSString*)slotName attachmentName:(NSString*)attachmentName; - -@property (nonatomic, readonly) spSkeleton* skeleton; -@property (nonatomic) bool debugSlots; -@property (nonatomic) bool debugBones; -@property (nonatomic) bool skipVisibilityCheck; -@property (nonatomic) spBone* rootBone; - +#import +#import "cocos2d.h" + +/** Draws a skeleton. */ +@interface SkeletonRenderer : CCNode { + spSkeleton* _skeleton; + spBone* _rootBone; + bool _debugSlots; + bool _debugBones; + bool _premultipliedAlpha; + bool _skipVisibilityCheck; + ccBlendFunc _blendFunc; + CCDrawNode* _drawNode; + bool _ownsSkeletonData; + spAtlas* _atlas; + float* _worldVertices; + CCBlendMode* screenMode; +} + ++ (id) skeletonWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData; ++ (id) skeletonWithFile:(NSString*)skeletonDataFile atlas:(spAtlas*)atlas scale:(float)scale; ++ (id) skeletonWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale; + +- (id) initWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData; +- (id) initWithFile:(NSString*)skeletonDataFile atlas:(spAtlas*)atlas scale:(float)scale; +- (id) initWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale; + +- (CCTexture*) getTextureForRegion:(spRegionAttachment*)attachment; +- (CCTexture*) getTextureForMesh:(spMeshAttachment*)attachment; + +// --- Convenience methods for common Skeleton_* functions. +- (void) updateWorldTransform; + +- (void) setToSetupPose; +- (void) setBonesToSetupPose; +- (void) setSlotsToSetupPose; + +/* Returns 0 if the bone was not found. */ +- (spBone*) findBone:(NSString*)boneName; + +/* Returns 0 if the slot was not found. */ +- (spSlot*) findSlot:(NSString*)slotName; + +/* Sets the skin used to look up attachments not found in the SkeletonData defaultSkin. 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. Returns false if the skin was not found. + * @param skin May be 0.*/ +- (bool) setSkin:(NSString*)skinName; + +/* Returns 0 if the slot or attachment was not found. */ +- (spAttachment*) getAttachment:(NSString*)slotName attachmentName:(NSString*)attachmentName; +/* Returns false if the slot or attachment was not found. */ +- (bool) setAttachment:(NSString*)slotName attachmentName:(NSString*)attachmentName; + +@property (nonatomic, readonly) spSkeleton* skeleton; +@property (nonatomic) bool debugSlots; +@property (nonatomic) bool debugBones; +@property (nonatomic) bool skipVisibilityCheck; +@property (nonatomic) spBone* rootBone; + @end diff --git a/spine-cocos2d-objc/src/spine/SkeletonRenderer.m b/spine-cocos2d-objc/src/spine/SkeletonRenderer.m index 5d9f279f47..89f1a51bb0 100644 --- a/spine-cocos2d-objc/src/spine/SkeletonRenderer.m +++ b/spine-cocos2d-objc/src/spine/SkeletonRenderer.m @@ -1,372 +1,371 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#import -#import -#import -#import "CCDrawNode.h" - -static const unsigned short quadTriangles[6] = {0, 1, 2, 2, 3, 0}; - -@interface SkeletonRenderer (Private) -- (void) initialize:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData; -@end - -@implementation SkeletonRenderer - -@synthesize skeleton = _skeleton; -@synthesize rootBone = _rootBone; -@synthesize debugSlots = _debugSlots; -@synthesize debugBones = _debugBones; - -+ (id) skeletonWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData { - return [[[self alloc] initWithData:skeletonData ownsSkeletonData:ownsSkeletonData] autorelease]; -} - -+ (id) skeletonWithFile:(NSString*)skeletonDataFile atlas:(spAtlas*)atlas scale:(float)scale { - return [[[self alloc] initWithFile:skeletonDataFile atlas:atlas scale:scale] autorelease]; -} - -+ (id) skeletonWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale { - return [[[self alloc] initWithFile:skeletonDataFile atlasFile:atlasFile scale:scale] autorelease]; -} - -- (void) initialize:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData { - _ownsSkeletonData = ownsSkeletonData; - - _worldVertices = MALLOC(float, 1000); // Max number of vertices per mesh. - - _skeleton = spSkeleton_create(skeletonData); - _rootBone = _skeleton->bones[0]; - - _blendFunc.src = GL_ONE; - _blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; - _drawNode = [[CCDrawNode alloc] init]; - [_drawNode setBlendMode: [CCBlendMode premultipliedAlphaMode]]; - [self addChild:_drawNode]; - - [self setShader:[CCShader positionTextureColorShader]]; - - _premultipliedAlpha = true; - screenMode = [CCBlendMode blendModeWithOptions:@{ - CCBlendFuncSrcColor: @(GL_ONE), - CCBlendFuncDstColor: @(GL_ONE_MINUS_SRC_COLOR)} - ]; -} - -- (id) initWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData { - NSAssert(skeletonData, @"skeletonData cannot be null."); - - self = [super init]; - if (!self) return nil; - - [self initialize:skeletonData ownsSkeletonData:ownsSkeletonData]; - - return self; -} - -- (id) initWithFile:(NSString*)skeletonDataFile atlas:(spAtlas*)atlas scale:(float)scale { - self = [super init]; - if (!self) return nil; - - spSkeletonJson* json = spSkeletonJson_create(atlas); - json->scale = scale; - spSkeletonData* skeletonData = nil; - - @synchronized(self.class) { - spSkeletonJson_readSkeletonDataFile(json, [skeletonDataFile UTF8String]); - } - NSAssert(skeletonData, ([NSString stringWithFormat:@"Error reading skeleton data file: %@\nError: %s", skeletonDataFile, json->error])); - spSkeletonJson_dispose(json); - if (!skeletonData) return 0; - - [self initialize:skeletonData ownsSkeletonData:YES]; - - return self; -} - -- (id) initWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale { - self = [super init]; - if (!self) return nil; - - @synchronized(self.class) { - _atlas = spAtlas_createFromFile([atlasFile UTF8String], 0); - } - NSAssert(_atlas, ([NSString stringWithFormat:@"Error reading atlas file: %@", atlasFile])); - if (!_atlas) return 0; - - spSkeletonJson* json = spSkeletonJson_create(_atlas); - json->scale = scale; - spSkeletonData* skeletonData; - - @synchronized(self.class) { - skeletonData = spSkeletonJson_readSkeletonDataFile(json, [skeletonDataFile UTF8String]); - } - NSAssert(skeletonData, ([NSString stringWithFormat:@"Error reading skeleton data file: %@\nError: %s", skeletonDataFile, json->error])); - spSkeletonJson_dispose(json); - if (!skeletonData) return 0; - - [self initialize:skeletonData ownsSkeletonData:YES]; - - return self; -} - -- (void) dealloc { - if (_ownsSkeletonData) spSkeletonData_dispose(_skeleton->data); - if (_atlas) spAtlas_dispose(_atlas); - spSkeleton_dispose(_skeleton); - FREE(_worldVertices); - [super dealloc]; -} - --(void)draw:(CCRenderer *)renderer transform:(const GLKMatrix4 *)transform { - CCColor* nodeColor = self.color; - _skeleton->r = nodeColor.red; - _skeleton->g = nodeColor.green; - _skeleton->b = nodeColor.blue; - _skeleton->a = self.displayedOpacity; - - int blendMode = -1; - const float* uvs = 0; - int verticesCount = 0; - const unsigned short* triangles = 0; - int trianglesCount = 0; - float r = 0, g = 0, b = 0, a = 0; - for (int i = 0, n = _skeleton->slotsCount; i < n; i++) { - spSlot* slot = _skeleton->drawOrder[i]; - if (!slot->attachment) continue; - CCTexture *texture = 0; - switch (slot->attachment->type) { - case SP_ATTACHMENT_REGION: { - spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; - spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices); - texture = [self getTextureForRegion:attachment]; - uvs = attachment->uvs; - verticesCount = 8; - triangles = quadTriangles; - trianglesCount = 6; - r = attachment->r; - g = attachment->g; - b = attachment->b; - a = attachment->a; - break; - } - case SP_ATTACHMENT_MESH: { - spMeshAttachment* attachment = (spMeshAttachment*)slot->attachment; - spMeshAttachment_computeWorldVertices(attachment, slot, _worldVertices); - texture = [self getTextureForMesh:attachment]; - uvs = attachment->uvs; - verticesCount = attachment->super.worldVerticesLength; - triangles = attachment->triangles; - trianglesCount = attachment->trianglesCount; - r = attachment->r; - g = attachment->g; - b = attachment->b; - a = attachment->a; - break; - } - default: ; - } - if (texture) { - if (slot->data->blendMode != blendMode) { - blendMode = slot->data->blendMode; - switch (slot->data->blendMode) { - case SP_BLEND_MODE_ADDITIVE: - [self setBlendMode:[CCBlendMode addMode]]; - break; - case SP_BLEND_MODE_MULTIPLY: - [self setBlendMode:[CCBlendMode multiplyMode]]; - break; - case SP_BLEND_MODE_SCREEN: - [self setBlendMode:screenMode]; - break; - default: - [self setBlendMode:_premultipliedAlpha ? [CCBlendMode premultipliedAlphaMode] : [CCBlendMode alphaMode]]; - } - } - if (_premultipliedAlpha) { - a *= _skeleton->a * slot->a; - r *= _skeleton->r * slot->r * a; - g *= _skeleton->g * slot->g * a; - b *= _skeleton->b * slot->b * a; - } else { - a *= _skeleton->a * slot->a; - r *= _skeleton->r * slot->r; - g *= _skeleton->g * slot->g; - b *= _skeleton->b * slot->b; - } - self.texture = texture; - CGSize size = texture.contentSize; - GLKVector2 center = GLKVector2Make(size.width / 2.0, size.height / 2.0); - GLKVector2 extents = GLKVector2Make(size.width / 2.0, size.height / 2.0); - if (_skipVisibilityCheck || CCRenderCheckVisbility(transform, center, extents)) { - CCRenderBuffer buffer = [renderer enqueueTriangles:(trianglesCount / 3) andVertexes:verticesCount withState:self.renderState globalSortOrder:0]; - for (int i = 0; i * 2 < verticesCount; ++i) { - CCVertex vertex; - vertex.position = GLKVector4Make(_worldVertices[i * 2], _worldVertices[i * 2 + 1], 0.0, 1.0); - vertex.color = GLKVector4Make(r, g, b, a); - vertex.texCoord1 = GLKVector2Make(uvs[i * 2], 1 - uvs[i * 2 + 1]); - CCRenderBufferSetVertex(buffer, i, CCVertexApplyTransform(vertex, transform)); - } - for (int j = 0; j * 3 < trianglesCount; ++j) { - CCRenderBufferSetTriangle(buffer, j, triangles[j * 3], triangles[j * 3 + 1], triangles[j * 3 + 2]); - } - } - } - } - [_drawNode clear]; - if (_debugSlots) { - // Slots. - CGPoint points[4]; - for (int i = 0, n = _skeleton->slotsCount; i < n; i++) { - spSlot* slot = _skeleton->drawOrder[i]; - if (!slot->attachment || slot->attachment->type != SP_ATTACHMENT_REGION) continue; - spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; - spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices); - points[0] = ccp(_worldVertices[0], _worldVertices[1]); - points[1] = ccp(_worldVertices[2], _worldVertices[3]); - points[2] = ccp(_worldVertices[4], _worldVertices[5]); - points[3] = ccp(_worldVertices[6], _worldVertices[7]); - [_drawNode drawPolyWithVerts:points count:4 fillColor:[CCColor clearColor] borderWidth:1 borderColor:[CCColor blueColor]]; - } - } - if (_debugBones) { - // Bone lengths. - for (int i = 0, n = _skeleton->bonesCount; i < n; i++) { - spBone *bone = _skeleton->bones[i]; - float x = bone->data->length * bone->a + bone->worldX; - float y = bone->data->length * bone->c + bone->worldY; - [_drawNode drawSegmentFrom:ccp(bone->worldX, bone->worldY) to: ccp(x, y)radius:2 color:[CCColor redColor]]; - } - - // Bone origins. - for (int i = 0, n = _skeleton->bonesCount; i < n; i++) { - spBone *bone = _skeleton->bones[i]; - [_drawNode drawDot:ccp(bone->worldX, bone->worldY) radius:4 color:[CCColor greenColor]]; - if (i == 0) [_drawNode drawDot:ccp(bone->worldX, bone->worldY) radius:4 color:[CCColor blueColor]]; - } - } -} - -- (CCTexture*) getTextureForRegion:(spRegionAttachment*)attachment { - return (CCTexture*)((spAtlasRegion*)attachment->rendererObject)->page->rendererObject; -} - -- (CCTexture*) getTextureForMesh:(spMeshAttachment*)attachment { - return (CCTexture*)((spAtlasRegion*)attachment->rendererObject)->page->rendererObject; -} - -- (CGRect) boundingBox { - float minX = FLT_MAX, minY = FLT_MAX, maxX = FLT_MIN, maxY = FLT_MIN; - float scaleX = self.scaleX, scaleY = self.scaleY; - for (int i = 0; i < _skeleton->slotsCount; ++i) { - spSlot* slot = _skeleton->slots[i]; - if (!slot->attachment) continue; - int verticesCount; - if (slot->attachment->type == SP_ATTACHMENT_REGION) { - spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; - spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices); - verticesCount = 8; - } else if (slot->attachment->type == SP_ATTACHMENT_MESH) { - spMeshAttachment* mesh = (spMeshAttachment*)slot->attachment; - spMeshAttachment_computeWorldVertices(mesh, slot, _worldVertices); - verticesCount = mesh->super.worldVerticesLength; - } else - continue; - for (int ii = 0; ii < verticesCount; ii += 2) { - float x = _worldVertices[ii] * scaleX, y = _worldVertices[ii + 1] * scaleY; - minX = fmin(minX, x); - minY = fmin(minY, y); - maxX = fmax(maxX, x); - maxY = fmax(maxY, y); - } - } - minX = self.position.x + minX; - minY = self.position.y + minY; - maxX = self.position.x + maxX; - maxY = self.position.y + maxY; - return CGRectMake(minX, minY, maxX - minX, maxY - minY); -} - -// --- Convenience methods for Skeleton_* functions. - -- (void) updateWorldTransform { - spSkeleton_updateWorldTransform(_skeleton); -} - -- (void) setToSetupPose { - spSkeleton_setToSetupPose(_skeleton); -} -- (void) setBonesToSetupPose { - spSkeleton_setBonesToSetupPose(_skeleton); -} -- (void) setSlotsToSetupPose { - spSkeleton_setSlotsToSetupPose(_skeleton); -} - -- (spBone*) findBone:(NSString*)boneName { - return spSkeleton_findBone(_skeleton, [boneName UTF8String]); -} - -- (spSlot*) findSlot:(NSString*)slotName { - return spSkeleton_findSlot(_skeleton, [slotName UTF8String]); -} - -- (bool) setSkin:(NSString*)skinName { - return (bool)spSkeleton_setSkinByName(_skeleton, skinName ? [skinName UTF8String] : 0); -} - -- (spAttachment*) getAttachment:(NSString*)slotName attachmentName:(NSString*)attachmentName { - return spSkeleton_getAttachmentForSlotName(_skeleton, [slotName UTF8String], [attachmentName UTF8String]); -} -- (bool) setAttachment:(NSString*)slotName attachmentName:(NSString*)attachmentName { - return (bool)spSkeleton_setAttachment(_skeleton, [slotName UTF8String], [attachmentName UTF8String]); -} - -// --- CCBlendProtocol - -- (void) setBlendFunc:(ccBlendFunc)func { - self.blendFunc = func; -} - -- (ccBlendFunc) blendFunc { - return _blendFunc; -} - -- (void) setOpacityModifyRGB:(BOOL)value { - _premultipliedAlpha = value; -} - -- (BOOL) doesOpacityModifyRGB { - return _premultipliedAlpha; -} - +#import +#import +#import +#import "CCDrawNode.h" + +static const unsigned short quadTriangles[6] = {0, 1, 2, 2, 3, 0}; + +@interface SkeletonRenderer (Private) +- (void) initialize:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData; +@end + +@implementation SkeletonRenderer + +@synthesize skeleton = _skeleton; +@synthesize rootBone = _rootBone; +@synthesize debugSlots = _debugSlots; +@synthesize debugBones = _debugBones; + ++ (id) skeletonWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData { + return [[[self alloc] initWithData:skeletonData ownsSkeletonData:ownsSkeletonData] autorelease]; +} + ++ (id) skeletonWithFile:(NSString*)skeletonDataFile atlas:(spAtlas*)atlas scale:(float)scale { + return [[[self alloc] initWithFile:skeletonDataFile atlas:atlas scale:scale] autorelease]; +} + ++ (id) skeletonWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale { + return [[[self alloc] initWithFile:skeletonDataFile atlasFile:atlasFile scale:scale] autorelease]; +} + +- (void) initialize:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData { + _ownsSkeletonData = ownsSkeletonData; + + _worldVertices = MALLOC(float, 1000); // Max number of vertices per mesh. + + _skeleton = spSkeleton_create(skeletonData); + _rootBone = _skeleton->bones[0]; + + _blendFunc.src = GL_ONE; + _blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; + _drawNode = [[CCDrawNode alloc] init]; + [_drawNode setBlendMode: [CCBlendMode premultipliedAlphaMode]]; + [self addChild:_drawNode]; + + [self setShader:[CCShader positionTextureColorShader]]; + + _premultipliedAlpha = true; + screenMode = [CCBlendMode blendModeWithOptions:@{ + CCBlendFuncSrcColor: @(GL_ONE), + CCBlendFuncDstColor: @(GL_ONE_MINUS_SRC_COLOR)} + ]; +} + +- (id) initWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData { + NSAssert(skeletonData, @"skeletonData cannot be null."); + + self = [super init]; + if (!self) return nil; + + [self initialize:skeletonData ownsSkeletonData:ownsSkeletonData]; + + return self; +} + +- (id) initWithFile:(NSString*)skeletonDataFile atlas:(spAtlas*)atlas scale:(float)scale { + self = [super init]; + if (!self) return nil; + + spSkeletonJson* json = spSkeletonJson_create(atlas); + json->scale = scale; + spSkeletonData* skeletonData = nil; + + @synchronized(self.class) { + spSkeletonJson_readSkeletonDataFile(json, [skeletonDataFile UTF8String]); + } + NSAssert(skeletonData, ([NSString stringWithFormat:@"Error reading skeleton data file: %@\nError: %s", skeletonDataFile, json->error])); + spSkeletonJson_dispose(json); + if (!skeletonData) return 0; + + [self initialize:skeletonData ownsSkeletonData:YES]; + + return self; +} + +- (id) initWithFile:(NSString*)skeletonDataFile atlasFile:(NSString*)atlasFile scale:(float)scale { + self = [super init]; + if (!self) return nil; + + @synchronized(self.class) { + _atlas = spAtlas_createFromFile([atlasFile UTF8String], 0); + } + NSAssert(_atlas, ([NSString stringWithFormat:@"Error reading atlas file: %@", atlasFile])); + if (!_atlas) return 0; + + spSkeletonJson* json = spSkeletonJson_create(_atlas); + json->scale = scale; + spSkeletonData* skeletonData; + + @synchronized(self.class) { + skeletonData = spSkeletonJson_readSkeletonDataFile(json, [skeletonDataFile UTF8String]); + } + NSAssert(skeletonData, ([NSString stringWithFormat:@"Error reading skeleton data file: %@\nError: %s", skeletonDataFile, json->error])); + spSkeletonJson_dispose(json); + if (!skeletonData) return 0; + + [self initialize:skeletonData ownsSkeletonData:YES]; + + return self; +} + +- (void) dealloc { + if (_ownsSkeletonData) spSkeletonData_dispose(_skeleton->data); + if (_atlas) spAtlas_dispose(_atlas); + spSkeleton_dispose(_skeleton); + FREE(_worldVertices); + [super dealloc]; +} + +-(void)draw:(CCRenderer *)renderer transform:(const GLKMatrix4 *)transform { + CCColor* nodeColor = self.color; + _skeleton->r = nodeColor.red; + _skeleton->g = nodeColor.green; + _skeleton->b = nodeColor.blue; + _skeleton->a = self.displayedOpacity; + + int blendMode = -1; + const float* uvs = 0; + int verticesCount = 0; + const unsigned short* triangles = 0; + int trianglesCount = 0; + float r = 0, g = 0, b = 0, a = 0; + for (int i = 0, n = _skeleton->slotsCount; i < n; i++) { + spSlot* slot = _skeleton->drawOrder[i]; + if (!slot->attachment) continue; + CCTexture *texture = 0; + switch (slot->attachment->type) { + case SP_ATTACHMENT_REGION: { + spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; + spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices); + texture = [self getTextureForRegion:attachment]; + uvs = attachment->uvs; + verticesCount = 8; + triangles = quadTriangles; + trianglesCount = 6; + r = attachment->r; + g = attachment->g; + b = attachment->b; + a = attachment->a; + break; + } + case SP_ATTACHMENT_MESH: { + spMeshAttachment* attachment = (spMeshAttachment*)slot->attachment; + spMeshAttachment_computeWorldVertices(attachment, slot, _worldVertices); + texture = [self getTextureForMesh:attachment]; + uvs = attachment->uvs; + verticesCount = attachment->super.worldVerticesLength; + triangles = attachment->triangles; + trianglesCount = attachment->trianglesCount; + r = attachment->r; + g = attachment->g; + b = attachment->b; + a = attachment->a; + break; + } + default: ; + } + if (texture) { + if (slot->data->blendMode != blendMode) { + blendMode = slot->data->blendMode; + switch (slot->data->blendMode) { + case SP_BLEND_MODE_ADDITIVE: + [self setBlendMode:[CCBlendMode addMode]]; + break; + case SP_BLEND_MODE_MULTIPLY: + [self setBlendMode:[CCBlendMode multiplyMode]]; + break; + case SP_BLEND_MODE_SCREEN: + [self setBlendMode:screenMode]; + break; + default: + [self setBlendMode:_premultipliedAlpha ? [CCBlendMode premultipliedAlphaMode] : [CCBlendMode alphaMode]]; + } + } + if (_premultipliedAlpha) { + a *= _skeleton->a * slot->a; + r *= _skeleton->r * slot->r * a; + g *= _skeleton->g * slot->g * a; + b *= _skeleton->b * slot->b * a; + } else { + a *= _skeleton->a * slot->a; + r *= _skeleton->r * slot->r; + g *= _skeleton->g * slot->g; + b *= _skeleton->b * slot->b; + } + self.texture = texture; + CGSize size = texture.contentSize; + GLKVector2 center = GLKVector2Make(size.width / 2.0, size.height / 2.0); + GLKVector2 extents = GLKVector2Make(size.width / 2.0, size.height / 2.0); + if (_skipVisibilityCheck || CCRenderCheckVisbility(transform, center, extents)) { + CCRenderBuffer buffer = [renderer enqueueTriangles:(trianglesCount / 3) andVertexes:verticesCount withState:self.renderState globalSortOrder:0]; + for (int i = 0; i * 2 < verticesCount; ++i) { + CCVertex vertex; + vertex.position = GLKVector4Make(_worldVertices[i * 2], _worldVertices[i * 2 + 1], 0.0, 1.0); + vertex.color = GLKVector4Make(r, g, b, a); + vertex.texCoord1 = GLKVector2Make(uvs[i * 2], 1 - uvs[i * 2 + 1]); + CCRenderBufferSetVertex(buffer, i, CCVertexApplyTransform(vertex, transform)); + } + for (int j = 0; j * 3 < trianglesCount; ++j) { + CCRenderBufferSetTriangle(buffer, j, triangles[j * 3], triangles[j * 3 + 1], triangles[j * 3 + 2]); + } + } + } + } + [_drawNode clear]; + if (_debugSlots) { + // Slots. + CGPoint points[4]; + for (int i = 0, n = _skeleton->slotsCount; i < n; i++) { + spSlot* slot = _skeleton->drawOrder[i]; + if (!slot->attachment || slot->attachment->type != SP_ATTACHMENT_REGION) continue; + spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; + spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices); + points[0] = ccp(_worldVertices[0], _worldVertices[1]); + points[1] = ccp(_worldVertices[2], _worldVertices[3]); + points[2] = ccp(_worldVertices[4], _worldVertices[5]); + points[3] = ccp(_worldVertices[6], _worldVertices[7]); + [_drawNode drawPolyWithVerts:points count:4 fillColor:[CCColor clearColor] borderWidth:1 borderColor:[CCColor blueColor]]; + } + } + if (_debugBones) { + // Bone lengths. + for (int i = 0, n = _skeleton->bonesCount; i < n; i++) { + spBone *bone = _skeleton->bones[i]; + float x = bone->data->length * bone->a + bone->worldX; + float y = bone->data->length * bone->c + bone->worldY; + [_drawNode drawSegmentFrom:ccp(bone->worldX, bone->worldY) to: ccp(x, y)radius:2 color:[CCColor redColor]]; + } + + // Bone origins. + for (int i = 0, n = _skeleton->bonesCount; i < n; i++) { + spBone *bone = _skeleton->bones[i]; + [_drawNode drawDot:ccp(bone->worldX, bone->worldY) radius:4 color:[CCColor greenColor]]; + if (i == 0) [_drawNode drawDot:ccp(bone->worldX, bone->worldY) radius:4 color:[CCColor blueColor]]; + } + } +} + +- (CCTexture*) getTextureForRegion:(spRegionAttachment*)attachment { + return (CCTexture*)((spAtlasRegion*)attachment->rendererObject)->page->rendererObject; +} + +- (CCTexture*) getTextureForMesh:(spMeshAttachment*)attachment { + return (CCTexture*)((spAtlasRegion*)attachment->rendererObject)->page->rendererObject; +} + +- (CGRect) boundingBox { + float minX = FLT_MAX, minY = FLT_MAX, maxX = FLT_MIN, maxY = FLT_MIN; + float scaleX = self.scaleX, scaleY = self.scaleY; + for (int i = 0; i < _skeleton->slotsCount; ++i) { + spSlot* slot = _skeleton->slots[i]; + if (!slot->attachment) continue; + int verticesCount; + if (slot->attachment->type == SP_ATTACHMENT_REGION) { + spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; + spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices); + verticesCount = 8; + } else if (slot->attachment->type == SP_ATTACHMENT_MESH) { + spMeshAttachment* mesh = (spMeshAttachment*)slot->attachment; + spMeshAttachment_computeWorldVertices(mesh, slot, _worldVertices); + verticesCount = mesh->super.worldVerticesLength; + } else + continue; + for (int ii = 0; ii < verticesCount; ii += 2) { + float x = _worldVertices[ii] * scaleX, y = _worldVertices[ii + 1] * scaleY; + minX = fmin(minX, x); + minY = fmin(minY, y); + maxX = fmax(maxX, x); + maxY = fmax(maxY, y); + } + } + minX = self.position.x + minX; + minY = self.position.y + minY; + maxX = self.position.x + maxX; + maxY = self.position.y + maxY; + return CGRectMake(minX, minY, maxX - minX, maxY - minY); +} + +// --- Convenience methods for Skeleton_* functions. + +- (void) updateWorldTransform { + spSkeleton_updateWorldTransform(_skeleton); +} + +- (void) setToSetupPose { + spSkeleton_setToSetupPose(_skeleton); +} +- (void) setBonesToSetupPose { + spSkeleton_setBonesToSetupPose(_skeleton); +} +- (void) setSlotsToSetupPose { + spSkeleton_setSlotsToSetupPose(_skeleton); +} + +- (spBone*) findBone:(NSString*)boneName { + return spSkeleton_findBone(_skeleton, [boneName UTF8String]); +} + +- (spSlot*) findSlot:(NSString*)slotName { + return spSkeleton_findSlot(_skeleton, [slotName UTF8String]); +} + +- (bool) setSkin:(NSString*)skinName { + return (bool)spSkeleton_setSkinByName(_skeleton, skinName ? [skinName UTF8String] : 0); +} + +- (spAttachment*) getAttachment:(NSString*)slotName attachmentName:(NSString*)attachmentName { + return spSkeleton_getAttachmentForSlotName(_skeleton, [slotName UTF8String], [attachmentName UTF8String]); +} +- (bool) setAttachment:(NSString*)slotName attachmentName:(NSString*)attachmentName { + return (bool)spSkeleton_setAttachment(_skeleton, [slotName UTF8String], [attachmentName UTF8String]); +} + +// --- CCBlendProtocol + +- (void) setBlendFunc:(ccBlendFunc)func { + self.blendFunc = func; +} + +- (ccBlendFunc) blendFunc { + return _blendFunc; +} + +- (void) setOpacityModifyRGB:(BOOL)value { + _premultipliedAlpha = value; +} + +- (BOOL) doesOpacityModifyRGB { + return _premultipliedAlpha; +} + @end diff --git a/spine-cocos2d-objc/src/spine/spine-cocos2d-objc.h b/spine-cocos2d-objc/src/spine/spine-cocos2d-objc.h index 848a4043ba..505d1f0204 100644 --- a/spine-cocos2d-objc/src/spine/spine-cocos2d-objc.h +++ b/spine-cocos2d-objc/src/spine/spine-cocos2d-objc.h @@ -1,35 +1,34 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#import -#import "cocos2d.h" -#import +#import +#import "cocos2d.h" +#import #import diff --git a/spine-cocos2d-objc/src/spine/spine-cocos2d-objc.m b/spine-cocos2d-objc/src/spine/spine-cocos2d-objc.m index 9a4270502d..b2323346b3 100644 --- a/spine-cocos2d-objc/src/spine/spine-cocos2d-objc.m +++ b/spine-cocos2d-objc/src/spine/spine-cocos2d-objc.m @@ -1,49 +1,48 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#import -#import - -void _spAtlasPage_createTexture (spAtlasPage* self, const char* path) { - CCTexture* texture = [[CCTexture textureWithFile:@(path)] retain]; - self->rendererObject = texture; - CGSize size = texture.contentSizeInPixels; - self->width = size.width; - self->height = size.height; -} - -void _spAtlasPage_disposeTexture (spAtlasPage* self) { - [(CCTexture*)self->rendererObject release]; -} - -char* _spUtil_readFile (const char* path, int* length) { - return _readFile([[[CCFileUtils sharedFileUtils] fullPathForFilename:@(path)] UTF8String], length); +#import +#import + +void _spAtlasPage_createTexture (spAtlasPage* self, const char* path) { + CCTexture* texture = [[CCTexture textureWithFile:@(path)] retain]; + self->rendererObject = texture; + CGSize size = texture.contentSizeInPixels; + self->width = size.width; + self->height = size.height; +} + +void _spAtlasPage_disposeTexture (spAtlasPage* self) { + [(CCTexture*)self->rendererObject release]; +} + +char* _spUtil_readFile (const char* path, int* length) { + return _readFile([[[CCFileUtils sharedFileUtils] fullPathForFilename:@(path)] UTF8String], length); } diff --git a/spine-cocos2dx/example/Classes/AppDelegate.cpp b/spine-cocos2dx/example/Classes/AppDelegate.cpp index 252e465d39..1587e7655e 100644 --- a/spine-cocos2dx/example/Classes/AppDelegate.cpp +++ b/spine-cocos2dx/example/Classes/AppDelegate.cpp @@ -1,124 +1,123 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include "AppDelegate.h" - -#include -#include - -#include "RaptorExample.h" -#include "BatchingExample.h" -#include "AppMacros.h" - -USING_NS_CC; -using namespace std; - -AppDelegate::AppDelegate () { -} - -AppDelegate::~AppDelegate () { -} - -bool AppDelegate::applicationDidFinishLaunching () { - // initialize director - auto director = Director::getInstance(); - auto glview = director->getOpenGLView(); - if (!glview) { - glview = GLViewImpl::create("Spine Example"); - director->setOpenGLView(glview); - } - - // Set the design resolution -#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) - // a bug in DirectX 11 level9-x on the device prevents ResolutionPolicy::NO_BORDER from working correctly - glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::SHOW_ALL); -#else - glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER); -#endif - - Size frameSize = glview->getFrameSize(); - - vector searchPath; - - // In this demo, we select resource according to the frame's height. - // If the resource size is different from design resolution size, you need to set contentScaleFactor. - // We use the ratio of resource's height to the height of design resolution, - // this can make sure that the resource's height could fit for the height of design resolution. - if (frameSize.height > mediumResource.size.height) { - // if the frame's height is larger than the height of medium resource size, select large resource. - searchPath.push_back(largeResource.directory); - director->setContentScaleFactor(MIN(largeResource.size.height/designResolutionSize.height, largeResource.size.width/designResolutionSize.width)); - } else if (frameSize.height > smallResource.size.height) { - // if the frame's height is larger than the height of small resource size, select medium resource. - searchPath.push_back(mediumResource.directory); - director->setContentScaleFactor(MIN(mediumResource.size.height/designResolutionSize.height, mediumResource.size.width/designResolutionSize.width)); - } else { - // if the frame's height is smaller than the height of medium resource size, select small resource. - searchPath.push_back(smallResource.directory); - director->setContentScaleFactor(MIN(smallResource.size.height/designResolutionSize.height, smallResource.size.width/designResolutionSize.width)); - } - - searchPath.push_back("common"); - - // set search path - FileUtils::getInstance()->setSearchPaths(searchPath); - - // turn on display FPS - director->setDisplayStats(true); - - // set FPS. the default value is 1.0/60 if you don't call this - director->setAnimationInterval(1.0f / 60); - - // create a scene. it's an autorelease object - //auto scene = RaptorExample::scene(); - auto scene = BatchingExample::scene(); - - // run - director->runWithScene(scene); - - return true; -} - -// This function will be called when the app is inactive. When comes a phone call,it's be invoked too -void AppDelegate::applicationDidEnterBackground () { - Director::getInstance()->stopAnimation(); - - // if you use SimpleAudioEngine, it must be paused - // SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic(); -} - -// this function will be called when the app is active again -void AppDelegate::applicationWillEnterForeground () { - Director::getInstance()->startAnimation(); - - // if you use SimpleAudioEngine, it must resume here - // SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic(); +#include "AppDelegate.h" + +#include +#include + +#include "RaptorExample.h" +#include "BatchingExample.h" +#include "AppMacros.h" + +USING_NS_CC; +using namespace std; + +AppDelegate::AppDelegate () { +} + +AppDelegate::~AppDelegate () { +} + +bool AppDelegate::applicationDidFinishLaunching () { + // initialize director + auto director = Director::getInstance(); + auto glview = director->getOpenGLView(); + if (!glview) { + glview = GLViewImpl::create("Spine Example"); + director->setOpenGLView(glview); + } + + // Set the design resolution +#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) + // a bug in DirectX 11 level9-x on the device prevents ResolutionPolicy::NO_BORDER from working correctly + glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::SHOW_ALL); +#else + glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER); +#endif + + Size frameSize = glview->getFrameSize(); + + vector searchPath; + + // In this demo, we select resource according to the frame's height. + // If the resource size is different from design resolution size, you need to set contentScaleFactor. + // We use the ratio of resource's height to the height of design resolution, + // this can make sure that the resource's height could fit for the height of design resolution. + if (frameSize.height > mediumResource.size.height) { + // if the frame's height is larger than the height of medium resource size, select large resource. + searchPath.push_back(largeResource.directory); + director->setContentScaleFactor(MIN(largeResource.size.height/designResolutionSize.height, largeResource.size.width/designResolutionSize.width)); + } else if (frameSize.height > smallResource.size.height) { + // if the frame's height is larger than the height of small resource size, select medium resource. + searchPath.push_back(mediumResource.directory); + director->setContentScaleFactor(MIN(mediumResource.size.height/designResolutionSize.height, mediumResource.size.width/designResolutionSize.width)); + } else { + // if the frame's height is smaller than the height of medium resource size, select small resource. + searchPath.push_back(smallResource.directory); + director->setContentScaleFactor(MIN(smallResource.size.height/designResolutionSize.height, smallResource.size.width/designResolutionSize.width)); + } + + searchPath.push_back("common"); + + // set search path + FileUtils::getInstance()->setSearchPaths(searchPath); + + // turn on display FPS + director->setDisplayStats(true); + + // set FPS. the default value is 1.0/60 if you don't call this + director->setAnimationInterval(1.0f / 60); + + // create a scene. it's an autorelease object + //auto scene = RaptorExample::scene(); + auto scene = BatchingExample::scene(); + + // run + director->runWithScene(scene); + + return true; +} + +// This function will be called when the app is inactive. When comes a phone call,it's be invoked too +void AppDelegate::applicationDidEnterBackground () { + Director::getInstance()->stopAnimation(); + + // if you use SimpleAudioEngine, it must be paused + // SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic(); +} + +// this function will be called when the app is active again +void AppDelegate::applicationWillEnterForeground () { + Director::getInstance()->startAnimation(); + + // if you use SimpleAudioEngine, it must resume here + // SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic(); } diff --git a/spine-cocos2dx/example/Classes/AppDelegate.h b/spine-cocos2dx/example/Classes/AppDelegate.h index 2bc788a6fa..3acb630299 100644 --- a/spine-cocos2dx/example/Classes/AppDelegate.h +++ b/spine-cocos2dx/example/Classes/AppDelegate.h @@ -1,47 +1,46 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef _APPDELEGATE_H_ -#define _APPDELEGATE_H_ - -#include "cocos2d.h" - -class AppDelegate: private cocos2d::Application { -public: - AppDelegate (); - virtual ~AppDelegate (); - - virtual bool applicationDidFinishLaunching (); - virtual void applicationDidEnterBackground (); - virtual void applicationWillEnterForeground (); -}; - +#ifndef _APPDELEGATE_H_ +#define _APPDELEGATE_H_ + +#include "cocos2d.h" + +class AppDelegate: private cocos2d::Application { +public: + AppDelegate (); + virtual ~AppDelegate (); + + virtual bool applicationDidFinishLaunching (); + virtual void applicationDidEnterBackground (); + virtual void applicationWillEnterForeground (); +}; + #endif // _APPDELEGATE_H_ diff --git a/spine-cocos2dx/example/Classes/AppMacros.h b/spine-cocos2dx/example/Classes/AppMacros.h index 3b8deb4986..b0265cfa2c 100644 --- a/spine-cocos2dx/example/Classes/AppMacros.h +++ b/spine-cocos2dx/example/Classes/AppMacros.h @@ -1,90 +1,89 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef _APPMACROS_H_ -#define _APPMACROS_H_ - -#include "cocos2d.h" - -/* For demonstrating using one design resolution to match different resources, - or one resource to match different design resolutions. - - [Situation 1] Using one design resolution to match different resources. - Please look into Appdelegate::applicationDidFinishLaunching. - We check current device frame size to decide which resource need to be selected. - So if you want to test this situation which said in title '[Situation 1]', - you should change ios simulator to different device(e.g. iphone, iphone-retina3.5, iphone-retina4.0, ipad, ipad-retina), - or change the window size in "proj.XXX/main.cpp" by "CCEGLView::setFrameSize" if you are using win32 or linux plaform - and modify "proj.mac/AppController.mm" by changing the window rectangle. - - [Situation 2] Using one resource to match different design resolutions. - The coordinates in your codes is based on your current design resolution rather than resource size. - Therefore, your design resolution could be very large and your resource size could be small. - To test this, just define the marco 'TARGET_DESIGN_RESOLUTION_SIZE' to 'DESIGN_RESOLUTION_2048X1536' - and open iphone simulator or create a window of 480x320 size. - - [Note] Normally, developer just need to define one design resolution(e.g. 960x640) with one or more resources. - */ - -#define DESIGN_RESOLUTION_480X320 0 -#define DESIGN_RESOLUTION_960x640 1 -#define DESIGN_RESOLUTION_1024X768 2 -#define DESIGN_RESOLUTION_2048X1536 3 - -/* If you want to switch design resolution, change next line */ -#define TARGET_DESIGN_RESOLUTION_SIZE DESIGN_RESOLUTION_960x640 - -typedef struct tagResource { - cocos2d::Size size; - char directory[100]; -} Resource; - -static Resource smallResource = {cocos2d::Size(480, 320), "iphone"}; -static Resource mediumResource = {cocos2d::Size(960, 640), "iphone-retina"}; -static Resource largeResource = {cocos2d::Size(1024, 768), "ipad"}; -static Resource extralargeResource = {cocos2d::Size(2048, 1536), "ipad-retina"}; - -#if (TARGET_DESIGN_RESOLUTION_SIZE == DESIGN_RESOLUTION_480X320) -static cocos2d::Size designResolutionSize = cocos2d::Size(480, 320); -#elif (TARGET_DESIGN_RESOLUTION_SIZE == DESIGN_RESOLUTION_960x640) -static cocos2d::Size designResolutionSize = cocos2d::Size(960, 640); -#elif (TARGET_DESIGN_RESOLUTION_SIZE == DESIGN_RESOLUTION_1024X768) -static cocos2d::Size designResolutionSize = cocos2d::Size(1024, 768); -#elif (TARGET_DESIGN_RESOLUTION_SIZE == DESIGN_RESOLUTION_2048X1536) -static cocos2d::Size designResolutionSize = cocos2d::Size(2048, 1536); -#else -#error unknown target design resolution! -#endif - -// The font size 24 is designed for small resolution, so we should change it to fit for current design resolution -#define TITLE_FONT_SIZE (cocos2d::Director::getInstance()->getOpenGLView()->getDesignResolutionSize().width / smallResource.size.width * 24) - +#ifndef _APPMACROS_H_ +#define _APPMACROS_H_ + +#include "cocos2d.h" + +/* For demonstrating using one design resolution to match different resources, + or one resource to match different design resolutions. + + [Situation 1] Using one design resolution to match different resources. + Please look into Appdelegate::applicationDidFinishLaunching. + We check current device frame size to decide which resource need to be selected. + So if you want to test this situation which said in title '[Situation 1]', + you should change ios simulator to different device(e.g. iphone, iphone-retina3.5, iphone-retina4.0, ipad, ipad-retina), + or change the window size in "proj.XXX/main.cpp" by "CCEGLView::setFrameSize" if you are using win32 or linux plaform + and modify "proj.mac/AppController.mm" by changing the window rectangle. + + [Situation 2] Using one resource to match different design resolutions. + The coordinates in your codes is based on your current design resolution rather than resource size. + Therefore, your design resolution could be very large and your resource size could be small. + To test this, just define the marco 'TARGET_DESIGN_RESOLUTION_SIZE' to 'DESIGN_RESOLUTION_2048X1536' + and open iphone simulator or create a window of 480x320 size. + + [Note] Normally, developer just need to define one design resolution(e.g. 960x640) with one or more resources. + */ + +#define DESIGN_RESOLUTION_480X320 0 +#define DESIGN_RESOLUTION_960x640 1 +#define DESIGN_RESOLUTION_1024X768 2 +#define DESIGN_RESOLUTION_2048X1536 3 + +/* If you want to switch design resolution, change next line */ +#define TARGET_DESIGN_RESOLUTION_SIZE DESIGN_RESOLUTION_960x640 + +typedef struct tagResource { + cocos2d::Size size; + char directory[100]; +} Resource; + +static Resource smallResource = {cocos2d::Size(480, 320), "iphone"}; +static Resource mediumResource = {cocos2d::Size(960, 640), "iphone-retina"}; +static Resource largeResource = {cocos2d::Size(1024, 768), "ipad"}; +static Resource extralargeResource = {cocos2d::Size(2048, 1536), "ipad-retina"}; + +#if (TARGET_DESIGN_RESOLUTION_SIZE == DESIGN_RESOLUTION_480X320) +static cocos2d::Size designResolutionSize = cocos2d::Size(480, 320); +#elif (TARGET_DESIGN_RESOLUTION_SIZE == DESIGN_RESOLUTION_960x640) +static cocos2d::Size designResolutionSize = cocos2d::Size(960, 640); +#elif (TARGET_DESIGN_RESOLUTION_SIZE == DESIGN_RESOLUTION_1024X768) +static cocos2d::Size designResolutionSize = cocos2d::Size(1024, 768); +#elif (TARGET_DESIGN_RESOLUTION_SIZE == DESIGN_RESOLUTION_2048X1536) +static cocos2d::Size designResolutionSize = cocos2d::Size(2048, 1536); +#else +#error unknown target design resolution! +#endif + +// The font size 24 is designed for small resolution, so we should change it to fit for current design resolution +#define TITLE_FONT_SIZE (cocos2d::Director::getInstance()->getOpenGLView()->getDesignResolutionSize().width / smallResource.size.width * 24) + #endif /* _APPMACROS_H_ */ diff --git a/spine-cocos2dx/example/Classes/BatchingExample.cpp b/spine-cocos2dx/example/Classes/BatchingExample.cpp index 0577fd077d..7fea834b5c 100644 --- a/spine-cocos2dx/example/Classes/BatchingExample.cpp +++ b/spine-cocos2dx/example/Classes/BatchingExample.cpp @@ -1,104 +1,103 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include "BatchingExample.h" -#include "SpineboyExample.h" - -USING_NS_CC; -using namespace spine; - -Scene* BatchingExample::scene () { - Scene *scene = Scene::create(); - scene->addChild(BatchingExample::create()); - return scene; -} - -bool BatchingExample::init () { - if (!LayerColor::initWithColor(Color4B(128, 128, 128, 255))) return false; - - // Load the texture atlas. - _atlas = spAtlas_createFromFile("spineboy.atlas", 0); - CCASSERT(_atlas, "Error reading atlas file."); - - // This attachment loader configures attachments with data needed for cocos2d-x rendering. - // Do not dispose the attachment loader until the skeleton data is disposed! - _attachmentLoader = (spAttachmentLoader*)Cocos2dAttachmentLoader_create(_atlas); - - // Load the skeleton data. - spSkeletonJson* json = spSkeletonJson_createWithLoader(_attachmentLoader); - json->scale = 0.6f; // Resizes skeleton data to 60% of the size it was in Spine. - _skeletonData = spSkeletonJson_readSkeletonDataFile(json, "spineboy.json"); - CCASSERT(_skeletonData, json->error ? json->error : "Error reading skeleton data file."); - spSkeletonJson_dispose(json); - - // Setup mix times. - _stateData = spAnimationStateData_create(_skeletonData); - spAnimationStateData_setMixByName(_stateData, "walk", "jump", 0.2f); - spAnimationStateData_setMixByName(_stateData, "jump", "run", 0.2f); - - int xMin = _contentSize.width * 0.10f, xMax = _contentSize.width * 0.90f; - int yMin = 0, yMax = _contentSize.height * 0.7f; - for (int i = 0; i < 50; i++) { - // Each skeleton node shares the same atlas, skeleton data, and mix times. - SkeletonAnimation* skeletonNode = SkeletonAnimation::createWithData(_skeletonData, false); - skeletonNode->setAnimationStateData(_stateData); - - skeletonNode->setAnimation(0, "walk", true); - skeletonNode->addAnimation(0, "jump", false, 3); - skeletonNode->addAnimation(0, "run", true); - - skeletonNode->setPosition(Vec2( - RandomHelper::random_int(xMin, xMax), - RandomHelper::random_int(yMin, yMax) - )); - addChild(skeletonNode); - } - - scheduleUpdate(); - - EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create(); - listener->onTouchBegan = [this] (Touch* touch, Event* event) -> bool { - Director::getInstance()->replaceScene(SpineboyExample::scene()); - return true; - }; - _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); - - return true; -} - -BatchingExample::~BatchingExample () { - // SkeletonAnimation instances are cocos2d-x nodes and are disposed of automatically as normal, but the data created - // manually to be shared across multiple SkeletonAnimations needs to be disposed of manually. - spSkeletonData_dispose(_skeletonData); - spAnimationStateData_dispose(_stateData); - spAttachmentLoader_dispose(_attachmentLoader); - spAtlas_dispose(_atlas); +#include "BatchingExample.h" +#include "SpineboyExample.h" + +USING_NS_CC; +using namespace spine; + +Scene* BatchingExample::scene () { + Scene *scene = Scene::create(); + scene->addChild(BatchingExample::create()); + return scene; +} + +bool BatchingExample::init () { + if (!LayerColor::initWithColor(Color4B(128, 128, 128, 255))) return false; + + // Load the texture atlas. + _atlas = spAtlas_createFromFile("spineboy.atlas", 0); + CCASSERT(_atlas, "Error reading atlas file."); + + // This attachment loader configures attachments with data needed for cocos2d-x rendering. + // Do not dispose the attachment loader until the skeleton data is disposed! + _attachmentLoader = (spAttachmentLoader*)Cocos2dAttachmentLoader_create(_atlas); + + // Load the skeleton data. + spSkeletonJson* json = spSkeletonJson_createWithLoader(_attachmentLoader); + json->scale = 0.6f; // Resizes skeleton data to 60% of the size it was in Spine. + _skeletonData = spSkeletonJson_readSkeletonDataFile(json, "spineboy.json"); + CCASSERT(_skeletonData, json->error ? json->error : "Error reading skeleton data file."); + spSkeletonJson_dispose(json); + + // Setup mix times. + _stateData = spAnimationStateData_create(_skeletonData); + spAnimationStateData_setMixByName(_stateData, "walk", "jump", 0.2f); + spAnimationStateData_setMixByName(_stateData, "jump", "run", 0.2f); + + int xMin = _contentSize.width * 0.10f, xMax = _contentSize.width * 0.90f; + int yMin = 0, yMax = _contentSize.height * 0.7f; + for (int i = 0; i < 50; i++) { + // Each skeleton node shares the same atlas, skeleton data, and mix times. + SkeletonAnimation* skeletonNode = SkeletonAnimation::createWithData(_skeletonData, false); + skeletonNode->setAnimationStateData(_stateData); + + skeletonNode->setAnimation(0, "walk", true); + skeletonNode->addAnimation(0, "jump", false, 3); + skeletonNode->addAnimation(0, "run", true); + + skeletonNode->setPosition(Vec2( + RandomHelper::random_int(xMin, xMax), + RandomHelper::random_int(yMin, yMax) + )); + addChild(skeletonNode); + } + + scheduleUpdate(); + + EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create(); + listener->onTouchBegan = [this] (Touch* touch, Event* event) -> bool { + Director::getInstance()->replaceScene(SpineboyExample::scene()); + return true; + }; + _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); + + return true; +} + +BatchingExample::~BatchingExample () { + // SkeletonAnimation instances are cocos2d-x nodes and are disposed of automatically as normal, but the data created + // manually to be shared across multiple SkeletonAnimations needs to be disposed of manually. + spSkeletonData_dispose(_skeletonData); + spAnimationStateData_dispose(_stateData); + spAttachmentLoader_dispose(_attachmentLoader); + spAtlas_dispose(_atlas); } diff --git a/spine-cocos2dx/example/Classes/BatchingExample.h b/spine-cocos2dx/example/Classes/BatchingExample.h index 763e786a85..76e5c5f541 100644 --- a/spine-cocos2dx/example/Classes/BatchingExample.h +++ b/spine-cocos2dx/example/Classes/BatchingExample.h @@ -1,54 +1,53 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef _BATCHINGEXAMPLE_H_ -#define _BATCHINGEXAMPLE_H_ - -#include "cocos2d.h" -#include - -class BatchingExample : public cocos2d::LayerColor { -public: - static cocos2d::Scene* scene (); - - CREATE_FUNC(BatchingExample); - ~BatchingExample (); - - virtual bool init (); - -protected: - spAtlas* _atlas; - spAttachmentLoader* _attachmentLoader; - spSkeletonData* _skeletonData; - spAnimationStateData* _stateData; -}; - +#ifndef _BATCHINGEXAMPLE_H_ +#define _BATCHINGEXAMPLE_H_ + +#include "cocos2d.h" +#include + +class BatchingExample : public cocos2d::LayerColor { +public: + static cocos2d::Scene* scene (); + + CREATE_FUNC(BatchingExample); + ~BatchingExample (); + + virtual bool init (); + +protected: + spAtlas* _atlas; + spAttachmentLoader* _attachmentLoader; + spSkeletonData* _skeletonData; + spAnimationStateData* _stateData; +}; + #endif // _BATCHINGEXAMPLE_H_ diff --git a/spine-cocos2dx/example/Classes/GoblinsExample.cpp b/spine-cocos2dx/example/Classes/GoblinsExample.cpp index b2332d8e03..10f93c7601 100644 --- a/spine-cocos2dx/example/Classes/GoblinsExample.cpp +++ b/spine-cocos2dx/example/Classes/GoblinsExample.cpp @@ -1,69 +1,68 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include "GoblinsExample.h" -#include "RaptorExample.h" - -USING_NS_CC; -using namespace spine; - -Scene* GoblinsExample::scene () { - Scene *scene = Scene::create(); - scene->addChild(GoblinsExample::create()); - return scene; -} - -bool GoblinsExample::init () { - if (!LayerColor::initWithColor(Color4B(128, 128, 128, 255))) return false; - - skeletonNode = SkeletonAnimation::createWithJsonFile("goblins-mesh.json", "goblins.atlas", 1.5f); - skeletonNode->setAnimation(0, "walk", true); - skeletonNode->setSkin("goblin"); - - skeletonNode->setPosition(Vec2(_contentSize.width / 2, 20)); - addChild(skeletonNode); - - scheduleUpdate(); - - EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create(); - listener->onTouchBegan = [this] (Touch* touch, Event* event) -> bool { - if (!skeletonNode->getDebugBonesEnabled()) - skeletonNode->setDebugBonesEnabled(true); - else if (skeletonNode->getTimeScale() == 1) - skeletonNode->setTimeScale(0.3f); - else - Director::getInstance()->replaceScene(RaptorExample::scene()); - return true; - }; - _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); - - return true; +#include "GoblinsExample.h" +#include "RaptorExample.h" + +USING_NS_CC; +using namespace spine; + +Scene* GoblinsExample::scene () { + Scene *scene = Scene::create(); + scene->addChild(GoblinsExample::create()); + return scene; +} + +bool GoblinsExample::init () { + if (!LayerColor::initWithColor(Color4B(128, 128, 128, 255))) return false; + + skeletonNode = SkeletonAnimation::createWithJsonFile("goblins-mesh.json", "goblins.atlas", 1.5f); + skeletonNode->setAnimation(0, "walk", true); + skeletonNode->setSkin("goblin"); + + skeletonNode->setPosition(Vec2(_contentSize.width / 2, 20)); + addChild(skeletonNode); + + scheduleUpdate(); + + EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create(); + listener->onTouchBegan = [this] (Touch* touch, Event* event) -> bool { + if (!skeletonNode->getDebugBonesEnabled()) + skeletonNode->setDebugBonesEnabled(true); + else if (skeletonNode->getTimeScale() == 1) + skeletonNode->setTimeScale(0.3f); + else + Director::getInstance()->replaceScene(RaptorExample::scene()); + return true; + }; + _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); + + return true; } diff --git a/spine-cocos2dx/example/Classes/GoblinsExample.h b/spine-cocos2dx/example/Classes/GoblinsExample.h index 9139a9f963..3c9d633181 100644 --- a/spine-cocos2dx/example/Classes/GoblinsExample.h +++ b/spine-cocos2dx/example/Classes/GoblinsExample.h @@ -1,50 +1,49 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef _GOBLINSEXAMPLE_H_ -#define _GOBLINSEXAMPLE_H_ - -#include "cocos2d.h" -#include - -class GoblinsExample : public cocos2d::LayerColor { -public: - static cocos2d::Scene* scene (); - - CREATE_FUNC(GoblinsExample); - - virtual bool init (); - -private: - spine::SkeletonAnimation* skeletonNode; -}; - +#ifndef _GOBLINSEXAMPLE_H_ +#define _GOBLINSEXAMPLE_H_ + +#include "cocos2d.h" +#include + +class GoblinsExample : public cocos2d::LayerColor { +public: + static cocos2d::Scene* scene (); + + CREATE_FUNC(GoblinsExample); + + virtual bool init (); + +private: + spine::SkeletonAnimation* skeletonNode; +}; + #endif // _GOBLINSEXAMPLE_H_ diff --git a/spine-cocos2dx/example/Classes/RaptorExample.cpp b/spine-cocos2dx/example/Classes/RaptorExample.cpp index 6eb57c9643..2293fc25b3 100644 --- a/spine-cocos2dx/example/Classes/RaptorExample.cpp +++ b/spine-cocos2dx/example/Classes/RaptorExample.cpp @@ -1,70 +1,69 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include "RaptorExample.h" -#include "TankExample.h" - -USING_NS_CC; -using namespace spine; - -Scene* RaptorExample::scene () { - Scene *scene = Scene::create(); - scene->addChild(RaptorExample::create()); - return scene; -} - -bool RaptorExample::init () { - if (!LayerColor::initWithColor(Color4B(128, 128, 128, 255))) return false; - - skeletonNode = SkeletonAnimation::createWithJsonFile("raptor.json", "raptor.atlas", 0.5f); - skeletonNode->setAnimation(0, "walk", true); - skeletonNode->setAnimation(1, "empty", false); - skeletonNode->addAnimation(1, "gungrab", false, 2); - - skeletonNode->setPosition(Vec2(_contentSize.width / 2, 20)); - addChild(skeletonNode); - - scheduleUpdate(); - - EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create(); - listener->onTouchBegan = [this] (Touch* touch, Event* event) -> bool { - if (!skeletonNode->getDebugBonesEnabled()) - skeletonNode->setDebugBonesEnabled(true); - else if (skeletonNode->getTimeScale() == 1) - skeletonNode->setTimeScale(0.3f); - else - Director::getInstance()->replaceScene(TankExample::scene()); - return true; - }; - _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); - - return true; +#include "RaptorExample.h" +#include "TankExample.h" + +USING_NS_CC; +using namespace spine; + +Scene* RaptorExample::scene () { + Scene *scene = Scene::create(); + scene->addChild(RaptorExample::create()); + return scene; +} + +bool RaptorExample::init () { + if (!LayerColor::initWithColor(Color4B(128, 128, 128, 255))) return false; + + skeletonNode = SkeletonAnimation::createWithJsonFile("raptor.json", "raptor.atlas", 0.5f); + skeletonNode->setAnimation(0, "walk", true); + skeletonNode->setAnimation(1, "empty", false); + skeletonNode->addAnimation(1, "gungrab", false, 2); + + skeletonNode->setPosition(Vec2(_contentSize.width / 2, 20)); + addChild(skeletonNode); + + scheduleUpdate(); + + EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create(); + listener->onTouchBegan = [this] (Touch* touch, Event* event) -> bool { + if (!skeletonNode->getDebugBonesEnabled()) + skeletonNode->setDebugBonesEnabled(true); + else if (skeletonNode->getTimeScale() == 1) + skeletonNode->setTimeScale(0.3f); + else + Director::getInstance()->replaceScene(TankExample::scene()); + return true; + }; + _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); + + return true; } diff --git a/spine-cocos2dx/example/Classes/RaptorExample.h b/spine-cocos2dx/example/Classes/RaptorExample.h index 3a48181652..84637b128f 100644 --- a/spine-cocos2dx/example/Classes/RaptorExample.h +++ b/spine-cocos2dx/example/Classes/RaptorExample.h @@ -1,50 +1,49 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef _RAPTOREXAMPLE_H_ -#define _RAPTOREXAMPLE_H_ - -#include "cocos2d.h" -#include - -class RaptorExample : public cocos2d::LayerColor { -public: - static cocos2d::Scene* scene (); - - CREATE_FUNC(RaptorExample); - - virtual bool init (); - -private: - spine::SkeletonAnimation* skeletonNode; -}; - +#ifndef _RAPTOREXAMPLE_H_ +#define _RAPTOREXAMPLE_H_ + +#include "cocos2d.h" +#include + +class RaptorExample : public cocos2d::LayerColor { +public: + static cocos2d::Scene* scene (); + + CREATE_FUNC(RaptorExample); + + virtual bool init (); + +private: + spine::SkeletonAnimation* skeletonNode; +}; + #endif // _RAPTOREXAMPLE_H_ diff --git a/spine-cocos2dx/example/Classes/SimpleCommand.cpp b/spine-cocos2dx/example/Classes/SimpleCommand.cpp index 238794b2e9..4b8d43b0ca 100644 --- a/spine-cocos2dx/example/Classes/SimpleCommand.cpp +++ b/spine-cocos2dx/example/Classes/SimpleCommand.cpp @@ -1,103 +1,102 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include "SimpleCommand.h" - -USING_NS_CC; -using namespace std; - -Scene* SimpleCommand::scene () { - Scene *scene = Scene::create(); - scene->addChild(SimpleCommand::create()); - return scene; -} - -bool SimpleCommand::init () { - if (!Node::init()) return false; - - setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP)); - - _texture = _director->getTextureCache()->addImage("sprite.png"); - - setPosition(100, 100); - - return true; -} - -void SimpleCommand::draw (Renderer* renderer, const Mat4& transform, uint32_t transformFlags) { - TrianglesCommand::Triangles* triangles = new TrianglesCommand::Triangles(); - - float x = 0, y = 0; - float w = 80, h = 80; - - triangles->vertCount = 4; - triangles->verts = new V3F_C4B_T2F[4]; - triangles->verts[0].colors = Color4B::WHITE; - triangles->verts[0].texCoords.u = 0; - triangles->verts[0].texCoords.v = 1; - triangles->verts[0].vertices.x = 0; - triangles->verts[0].vertices.y = 0; - triangles->verts[0].vertices.z = 0; - - triangles->verts[1].colors = Color4B::WHITE; - triangles->verts[1].texCoords.u = 0; - triangles->verts[1].texCoords.v = 0; - triangles->verts[1].vertices.x = 0; - triangles->verts[1].vertices.y = h; - triangles->verts[1].vertices.z = 0; - - triangles->verts[2].colors = Color4B::WHITE; - triangles->verts[2].texCoords.u = 1; - triangles->verts[2].texCoords.v = 1; - triangles->verts[2].vertices.x = w; - triangles->verts[2].vertices.y = 0; - triangles->verts[2].vertices.z = 0; - - triangles->verts[3].colors = Color4B::WHITE; - triangles->verts[3].texCoords.u = 1; - triangles->verts[3].texCoords.v = 0; - triangles->verts[3].vertices.x = w; - triangles->verts[3].vertices.y = h; - triangles->verts[3].vertices.z = 0; - - triangles->indexCount = 6; - triangles->indices = new GLushort[6]; - triangles->indices[0] = 0; - triangles->indices[1] = 1; - triangles->indices[2] = 2; - triangles->indices[3] = 3; - triangles->indices[4] = 2; - triangles->indices[5] = 1; - - TrianglesCommand* trianglesCommand = new TrianglesCommand(); - trianglesCommand->init(_globalZOrder, _texture->getName(), getGLProgramState(), BlendFunc::ALPHA_PREMULTIPLIED, *triangles, transform, transformFlags); - renderer->addCommand(trianglesCommand); +#include "SimpleCommand.h" + +USING_NS_CC; +using namespace std; + +Scene* SimpleCommand::scene () { + Scene *scene = Scene::create(); + scene->addChild(SimpleCommand::create()); + return scene; +} + +bool SimpleCommand::init () { + if (!Node::init()) return false; + + setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP)); + + _texture = _director->getTextureCache()->addImage("sprite.png"); + + setPosition(100, 100); + + return true; +} + +void SimpleCommand::draw (Renderer* renderer, const Mat4& transform, uint32_t transformFlags) { + TrianglesCommand::Triangles* triangles = new TrianglesCommand::Triangles(); + + float x = 0, y = 0; + float w = 80, h = 80; + + triangles->vertCount = 4; + triangles->verts = new V3F_C4B_T2F[4]; + triangles->verts[0].colors = Color4B::WHITE; + triangles->verts[0].texCoords.u = 0; + triangles->verts[0].texCoords.v = 1; + triangles->verts[0].vertices.x = 0; + triangles->verts[0].vertices.y = 0; + triangles->verts[0].vertices.z = 0; + + triangles->verts[1].colors = Color4B::WHITE; + triangles->verts[1].texCoords.u = 0; + triangles->verts[1].texCoords.v = 0; + triangles->verts[1].vertices.x = 0; + triangles->verts[1].vertices.y = h; + triangles->verts[1].vertices.z = 0; + + triangles->verts[2].colors = Color4B::WHITE; + triangles->verts[2].texCoords.u = 1; + triangles->verts[2].texCoords.v = 1; + triangles->verts[2].vertices.x = w; + triangles->verts[2].vertices.y = 0; + triangles->verts[2].vertices.z = 0; + + triangles->verts[3].colors = Color4B::WHITE; + triangles->verts[3].texCoords.u = 1; + triangles->verts[3].texCoords.v = 0; + triangles->verts[3].vertices.x = w; + triangles->verts[3].vertices.y = h; + triangles->verts[3].vertices.z = 0; + + triangles->indexCount = 6; + triangles->indices = new GLushort[6]; + triangles->indices[0] = 0; + triangles->indices[1] = 1; + triangles->indices[2] = 2; + triangles->indices[3] = 3; + triangles->indices[4] = 2; + triangles->indices[5] = 1; + + TrianglesCommand* trianglesCommand = new TrianglesCommand(); + trianglesCommand->init(_globalZOrder, _texture->getName(), getGLProgramState(), BlendFunc::ALPHA_PREMULTIPLIED, *triangles, transform, transformFlags); + renderer->addCommand(trianglesCommand); } diff --git a/spine-cocos2dx/example/Classes/SimpleCommand.h b/spine-cocos2dx/example/Classes/SimpleCommand.h index 328eb92ca4..94df6f8208 100644 --- a/spine-cocos2dx/example/Classes/SimpleCommand.h +++ b/spine-cocos2dx/example/Classes/SimpleCommand.h @@ -1,51 +1,50 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef _SIMPLECOMMAND_H_ -#define _SIMPLECOMMAND_H_ - -#include "cocos2d.h" - - -class SimpleCommand : public cocos2d::Node { -public: - static cocos2d::Scene* scene (); - - virtual bool init (); - virtual void draw (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags) override; - - CREATE_FUNC (SimpleCommand); - -protected: - cocos2d::Texture2D* _texture; -}; - +#ifndef _SIMPLECOMMAND_H_ +#define _SIMPLECOMMAND_H_ + +#include "cocos2d.h" + + +class SimpleCommand : public cocos2d::Node { +public: + static cocos2d::Scene* scene (); + + virtual bool init (); + virtual void draw (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags) override; + + CREATE_FUNC (SimpleCommand); + +protected: + cocos2d::Texture2D* _texture; +}; + #endif // _SIMPLECOMMAND_H_ diff --git a/spine-cocos2dx/example/Classes/SpineboyExample.cpp b/spine-cocos2dx/example/Classes/SpineboyExample.cpp index a89ff54975..bff00eaf86 100644 --- a/spine-cocos2dx/example/Classes/SpineboyExample.cpp +++ b/spine-cocos2dx/example/Classes/SpineboyExample.cpp @@ -1,100 +1,99 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include "SpineboyExample.h" -#include "GoblinsExample.h" - -USING_NS_CC; -using namespace spine; - -Scene* SpineboyExample::scene () { - Scene *scene = Scene::create(); - scene->addChild(SpineboyExample::create()); - return scene; -} - -bool SpineboyExample::init () { - if (!LayerColor::initWithColor(Color4B(128, 128, 128, 255))) return false; - - skeletonNode = SkeletonAnimation::createWithJsonFile("spineboy.json", "spineboy.atlas", 0.6f); - - skeletonNode->setStartListener( [this] (int trackIndex) { - spTrackEntry* entry = spAnimationState_getCurrent(skeletonNode->getState(), trackIndex); - const char* animationName = (entry && entry->animation) ? entry->animation->name : 0; - log("%d start: %s", trackIndex, animationName); - }); - skeletonNode->setEndListener( [] (int trackIndex) { - log("%d end", trackIndex); - }); - skeletonNode->setCompleteListener( [] (int trackIndex, int loopCount) { - log("%d complete: %d", trackIndex, loopCount); - }); - skeletonNode->setEventListener( [] (int trackIndex, spEvent* event) { - log("%d event: %s, %d, %f, %s", trackIndex, event->data->name, event->intValue, event->floatValue, event->stringValue); - }); - - skeletonNode->setMix("walk", "jump", 0.2f); - skeletonNode->setMix("jump", "run", 0.2f); - skeletonNode->setAnimation(0, "walk", true); - spTrackEntry* jumpEntry = skeletonNode->addAnimation(0, "jump", false, 3); - skeletonNode->addAnimation(0, "run", true); - - skeletonNode->setTrackStartListener(jumpEntry, [] (int trackIndex) { - log("jumped!"); - }); - - // skeletonNode->addAnimation(1, "test", true); - // skeletonNode->runAction(RepeatForever::create(Sequence::create(FadeOut::create(1), FadeIn::create(1), DelayTime::create(5), NULL))); - - skeletonNode->setPosition(Vec2(_contentSize.width / 2, 20)); - addChild(skeletonNode); - - scheduleUpdate(); - - EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create(); - listener->onTouchBegan = [this] (Touch* touch, Event* event) -> bool { - if (!skeletonNode->getDebugBonesEnabled()) - skeletonNode->setDebugBonesEnabled(true); - else if (skeletonNode->getTimeScale() == 1) - skeletonNode->setTimeScale(0.3f); - else - Director::getInstance()->replaceScene(GoblinsExample::scene()); - return true; - }; - _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); - - return true; -} - -void SpineboyExample::update (float deltaTime) { - // Test releasing memory. - // Director::getInstance()->replaceScene(SpineboyExample::scene()); +#include "SpineboyExample.h" +#include "GoblinsExample.h" + +USING_NS_CC; +using namespace spine; + +Scene* SpineboyExample::scene () { + Scene *scene = Scene::create(); + scene->addChild(SpineboyExample::create()); + return scene; +} + +bool SpineboyExample::init () { + if (!LayerColor::initWithColor(Color4B(128, 128, 128, 255))) return false; + + skeletonNode = SkeletonAnimation::createWithJsonFile("spineboy.json", "spineboy.atlas", 0.6f); + + skeletonNode->setStartListener( [this] (int trackIndex) { + spTrackEntry* entry = spAnimationState_getCurrent(skeletonNode->getState(), trackIndex); + const char* animationName = (entry && entry->animation) ? entry->animation->name : 0; + log("%d start: %s", trackIndex, animationName); + }); + skeletonNode->setEndListener( [] (int trackIndex) { + log("%d end", trackIndex); + }); + skeletonNode->setCompleteListener( [] (int trackIndex, int loopCount) { + log("%d complete: %d", trackIndex, loopCount); + }); + skeletonNode->setEventListener( [] (int trackIndex, spEvent* event) { + log("%d event: %s, %d, %f, %s", trackIndex, event->data->name, event->intValue, event->floatValue, event->stringValue); + }); + + skeletonNode->setMix("walk", "jump", 0.2f); + skeletonNode->setMix("jump", "run", 0.2f); + skeletonNode->setAnimation(0, "walk", true); + spTrackEntry* jumpEntry = skeletonNode->addAnimation(0, "jump", false, 3); + skeletonNode->addAnimation(0, "run", true); + + skeletonNode->setTrackStartListener(jumpEntry, [] (int trackIndex) { + log("jumped!"); + }); + + // skeletonNode->addAnimation(1, "test", true); + // skeletonNode->runAction(RepeatForever::create(Sequence::create(FadeOut::create(1), FadeIn::create(1), DelayTime::create(5), NULL))); + + skeletonNode->setPosition(Vec2(_contentSize.width / 2, 20)); + addChild(skeletonNode); + + scheduleUpdate(); + + EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create(); + listener->onTouchBegan = [this] (Touch* touch, Event* event) -> bool { + if (!skeletonNode->getDebugBonesEnabled()) + skeletonNode->setDebugBonesEnabled(true); + else if (skeletonNode->getTimeScale() == 1) + skeletonNode->setTimeScale(0.3f); + else + Director::getInstance()->replaceScene(GoblinsExample::scene()); + return true; + }; + _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); + + return true; +} + +void SpineboyExample::update (float deltaTime) { + // Test releasing memory. + // Director::getInstance()->replaceScene(SpineboyExample::scene()); } diff --git a/spine-cocos2dx/example/Classes/SpineboyExample.h b/spine-cocos2dx/example/Classes/SpineboyExample.h index 4a5245c324..b94eba3eab 100644 --- a/spine-cocos2dx/example/Classes/SpineboyExample.h +++ b/spine-cocos2dx/example/Classes/SpineboyExample.h @@ -1,52 +1,51 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef _SPINEBOYEXAMPLE_H_ -#define _SPINEBOYEXAMPLE_H_ - -#include "cocos2d.h" -#include - -class SpineboyExample : public cocos2d::LayerColor { -public: - static cocos2d::Scene* scene (); - - CREATE_FUNC (SpineboyExample); - - virtual bool init (); - - virtual void update (float deltaTime); - -private: - spine::SkeletonAnimation* skeletonNode; -}; - +#ifndef _SPINEBOYEXAMPLE_H_ +#define _SPINEBOYEXAMPLE_H_ + +#include "cocos2d.h" +#include + +class SpineboyExample : public cocos2d::LayerColor { +public: + static cocos2d::Scene* scene (); + + CREATE_FUNC (SpineboyExample); + + virtual bool init (); + + virtual void update (float deltaTime); + +private: + spine::SkeletonAnimation* skeletonNode; +}; + #endif // _SPINEBOYEXAMPLE_H_ diff --git a/spine-cocos2dx/example/Classes/TankExample.cpp b/spine-cocos2dx/example/Classes/TankExample.cpp index 059ca56a12..c3898bde25 100644 --- a/spine-cocos2dx/example/Classes/TankExample.cpp +++ b/spine-cocos2dx/example/Classes/TankExample.cpp @@ -1,68 +1,67 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include "TankExample.h" -#include "BatchingExample.h" - -USING_NS_CC; -using namespace spine; - -Scene* TankExample::scene () { - Scene *scene = Scene::create(); - scene->addChild(TankExample::create()); - return scene; -} - -bool TankExample::init () { - if (!LayerColor::initWithColor(Color4B(128, 128, 128, 255))) return false; - - skeletonNode = SkeletonAnimation::createWithJsonFile("tank.json", "tank.atlas", 0.5f); - skeletonNode->setAnimation(0, "drive", true); - - skeletonNode->setPosition(Vec2(_contentSize.width / 2 + 400, 20)); - addChild(skeletonNode); - - scheduleUpdate(); - - EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create(); - listener->onTouchBegan = [this] (Touch* touch, Event* event) -> bool { - if (!skeletonNode->getDebugBonesEnabled()) - skeletonNode->setDebugBonesEnabled(true); - else if (skeletonNode->getTimeScale() == 1) - skeletonNode->setTimeScale(0.3f); - else - Director::getInstance()->replaceScene(BatchingExample::scene()); - return true; - }; - _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); - - return true; +#include "TankExample.h" +#include "BatchingExample.h" + +USING_NS_CC; +using namespace spine; + +Scene* TankExample::scene () { + Scene *scene = Scene::create(); + scene->addChild(TankExample::create()); + return scene; +} + +bool TankExample::init () { + if (!LayerColor::initWithColor(Color4B(128, 128, 128, 255))) return false; + + skeletonNode = SkeletonAnimation::createWithJsonFile("tank.json", "tank.atlas", 0.5f); + skeletonNode->setAnimation(0, "drive", true); + + skeletonNode->setPosition(Vec2(_contentSize.width / 2 + 400, 20)); + addChild(skeletonNode); + + scheduleUpdate(); + + EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create(); + listener->onTouchBegan = [this] (Touch* touch, Event* event) -> bool { + if (!skeletonNode->getDebugBonesEnabled()) + skeletonNode->setDebugBonesEnabled(true); + else if (skeletonNode->getTimeScale() == 1) + skeletonNode->setTimeScale(0.3f); + else + Director::getInstance()->replaceScene(BatchingExample::scene()); + return true; + }; + _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this); + + return true; } diff --git a/spine-cocos2dx/example/Classes/TankExample.h b/spine-cocos2dx/example/Classes/TankExample.h index eccbb413d8..eb114030ee 100644 --- a/spine-cocos2dx/example/Classes/TankExample.h +++ b/spine-cocos2dx/example/Classes/TankExample.h @@ -1,50 +1,49 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef _TANKEXAMPLE_H_ -#define _TANKEXAMPLE_H_ - -#include "cocos2d.h" -#include - -class TankExample : public cocos2d::LayerColor { -public: - static cocos2d::Scene* scene (); - - CREATE_FUNC(TankExample); - - virtual bool init (); - -private: - spine::SkeletonAnimation* skeletonNode; -}; - +#ifndef _TANKEXAMPLE_H_ +#define _TANKEXAMPLE_H_ + +#include "cocos2d.h" +#include + +class TankExample : public cocos2d::LayerColor { +public: + static cocos2d::Scene* scene (); + + CREATE_FUNC(TankExample); + + virtual bool init (); + +private: + spine::SkeletonAnimation* skeletonNode; +}; + #endif // _TANKEXAMPLE_H_ diff --git a/spine-cocos2dx/src/spine/AttachmentVertices.cpp b/spine-cocos2dx/src/spine/AttachmentVertices.cpp index b45320f34a..ebd9407dc9 100644 --- a/spine-cocos2dx/src/spine/AttachmentVertices.cpp +++ b/spine-cocos2dx/src/spine/AttachmentVertices.cpp @@ -1,53 +1,52 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include - -USING_NS_CC; - -namespace spine { - -AttachmentVertices::AttachmentVertices (Texture2D* texture, int verticesCount, unsigned short* triangles, int trianglesCount) { - _texture = texture; - - _triangles = new TrianglesCommand::Triangles(); - _triangles->verts = new V3F_C4B_T2F[verticesCount]; - _triangles->vertCount = verticesCount; - _triangles->indices = triangles; - _triangles->indexCount = trianglesCount; -} - -AttachmentVertices::~AttachmentVertices () { - delete [] _triangles->verts; - delete _triangles; -} - +#include + +USING_NS_CC; + +namespace spine { + +AttachmentVertices::AttachmentVertices (Texture2D* texture, int verticesCount, unsigned short* triangles, int trianglesCount) { + _texture = texture; + + _triangles = new TrianglesCommand::Triangles(); + _triangles->verts = new V3F_C4B_T2F[verticesCount]; + _triangles->vertCount = verticesCount; + _triangles->indices = triangles; + _triangles->indexCount = trianglesCount; +} + +AttachmentVertices::~AttachmentVertices () { + delete [] _triangles->verts; + delete _triangles; +} + } diff --git a/spine-cocos2dx/src/spine/AttachmentVertices.h b/spine-cocos2dx/src/spine/AttachmentVertices.h index 72ff827e9e..b7d39c4a63 100644 --- a/spine-cocos2dx/src/spine/AttachmentVertices.h +++ b/spine-cocos2dx/src/spine/AttachmentVertices.h @@ -1,50 +1,49 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_ATTACHMENTVERTICES_H_ -#define SPINE_ATTACHMENTVERTICES_H_ - -#include "cocos2d.h" - -namespace spine { - -class AttachmentVertices { -public: - AttachmentVertices (cocos2d::Texture2D* texture, int verticesCount, unsigned short* triangles, int trianglesCount); - virtual ~AttachmentVertices (); - - cocos2d::Texture2D* _texture; - cocos2d::TrianglesCommand::Triangles* _triangles; -}; - -} - +#ifndef SPINE_ATTACHMENTVERTICES_H_ +#define SPINE_ATTACHMENTVERTICES_H_ + +#include "cocos2d.h" + +namespace spine { + +class AttachmentVertices { +public: + AttachmentVertices (cocos2d::Texture2D* texture, int verticesCount, unsigned short* triangles, int trianglesCount); + virtual ~AttachmentVertices (); + + cocos2d::Texture2D* _texture; + cocos2d::TrianglesCommand::Triangles* _triangles; +}; + +} + #endif /* SPINE_ATTACHMENTVERTICES_H_ */ diff --git a/spine-cocos2dx/src/spine/Cocos2dAttachmentLoader.cpp b/spine-cocos2dx/src/spine/Cocos2dAttachmentLoader.cpp index fe719d6699..c1d662cada 100644 --- a/spine-cocos2dx/src/spine/Cocos2dAttachmentLoader.cpp +++ b/spine-cocos2dx/src/spine/Cocos2dAttachmentLoader.cpp @@ -1,108 +1,107 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include - -USING_NS_CC; -using namespace spine; - -static unsigned short quadTriangles[6] = {0, 1, 2, 2, 3, 0}; - -spAttachment* _Cocos2dAttachmentLoader_createAttachment (spAttachmentLoader* loader, spSkin* skin, spAttachmentType type, - const char* name, const char* path) { - Cocos2dAttachmentLoader* self = SUB_CAST(Cocos2dAttachmentLoader, loader); - return spAttachmentLoader_createAttachment(SUPER(self->atlasAttachmentLoader), skin, type, name, path); -} - -void _Cocos2dAttachmentLoader_configureAttachment (spAttachmentLoader* loader, spAttachment* attachment) { - attachment->attachmentLoader = loader; - - switch (attachment->type) { - case SP_ATTACHMENT_REGION: { - spRegionAttachment* regionAttachment = SUB_CAST(spRegionAttachment, attachment); - spAtlasRegion* region = (spAtlasRegion*)regionAttachment->rendererObject; - AttachmentVertices* attachmentVertices = new AttachmentVertices((Texture2D*)region->page->rendererObject, 4, quadTriangles, 6); - V3F_C4B_T2F* vertices = attachmentVertices->_triangles->verts; - for (int i = 0, ii = 0; i < 4; ++i, ii += 2) { - vertices[i].texCoords.u = regionAttachment->uvs[ii]; - vertices[i].texCoords.v = regionAttachment->uvs[ii + 1]; - } - regionAttachment->rendererObject = attachmentVertices; - break; - } - case SP_ATTACHMENT_MESH: { - spMeshAttachment* meshAttachment = SUB_CAST(spMeshAttachment, attachment); - spAtlasRegion* region = (spAtlasRegion*)meshAttachment->rendererObject; - AttachmentVertices* attachmentVertices = new AttachmentVertices((Texture2D*)region->page->rendererObject, - meshAttachment->super.worldVerticesLength >> 1, meshAttachment->triangles, meshAttachment->trianglesCount); - V3F_C4B_T2F* vertices = attachmentVertices->_triangles->verts; - for (int i = 0, ii = 0, nn = meshAttachment->super.worldVerticesLength; ii < nn; ++i, ii += 2) { - vertices[i].texCoords.u = meshAttachment->uvs[ii]; - vertices[i].texCoords.v = meshAttachment->uvs[ii + 1]; - } - meshAttachment->rendererObject = attachmentVertices; - break; - } - default: ; - } -} - -void _Cocos2dAttachmentLoader_disposeAttachment (spAttachmentLoader* loader, spAttachment* attachment) { - switch (attachment->type) { - case SP_ATTACHMENT_REGION: { - spRegionAttachment* regionAttachment = SUB_CAST(spRegionAttachment, attachment); - delete (AttachmentVertices*)regionAttachment->rendererObject; - break; - } - case SP_ATTACHMENT_MESH: { - spMeshAttachment* meshAttachment = SUB_CAST(spMeshAttachment, attachment); - delete (AttachmentVertices*)meshAttachment->rendererObject; - break; - } - default: ; - } -} - -void _Cocos2dAttachmentLoader_dispose (spAttachmentLoader* loader) { - Cocos2dAttachmentLoader* self = SUB_CAST(Cocos2dAttachmentLoader, loader); - spAttachmentLoader_dispose(SUPER_CAST(spAttachmentLoader, self->atlasAttachmentLoader)); - _spAttachmentLoader_deinit(loader); -} - -Cocos2dAttachmentLoader* Cocos2dAttachmentLoader_create (spAtlas* atlas) { - Cocos2dAttachmentLoader* self = NEW(Cocos2dAttachmentLoader); - _spAttachmentLoader_init(SUPER(self), _Cocos2dAttachmentLoader_dispose, _Cocos2dAttachmentLoader_createAttachment, - _Cocos2dAttachmentLoader_configureAttachment, _Cocos2dAttachmentLoader_disposeAttachment); - self->atlasAttachmentLoader = spAtlasAttachmentLoader_create(atlas); - return self; +#include +#include +#include + +USING_NS_CC; +using namespace spine; + +static unsigned short quadTriangles[6] = {0, 1, 2, 2, 3, 0}; + +spAttachment* _Cocos2dAttachmentLoader_createAttachment (spAttachmentLoader* loader, spSkin* skin, spAttachmentType type, + const char* name, const char* path) { + Cocos2dAttachmentLoader* self = SUB_CAST(Cocos2dAttachmentLoader, loader); + return spAttachmentLoader_createAttachment(SUPER(self->atlasAttachmentLoader), skin, type, name, path); +} + +void _Cocos2dAttachmentLoader_configureAttachment (spAttachmentLoader* loader, spAttachment* attachment) { + attachment->attachmentLoader = loader; + + switch (attachment->type) { + case SP_ATTACHMENT_REGION: { + spRegionAttachment* regionAttachment = SUB_CAST(spRegionAttachment, attachment); + spAtlasRegion* region = (spAtlasRegion*)regionAttachment->rendererObject; + AttachmentVertices* attachmentVertices = new AttachmentVertices((Texture2D*)region->page->rendererObject, 4, quadTriangles, 6); + V3F_C4B_T2F* vertices = attachmentVertices->_triangles->verts; + for (int i = 0, ii = 0; i < 4; ++i, ii += 2) { + vertices[i].texCoords.u = regionAttachment->uvs[ii]; + vertices[i].texCoords.v = regionAttachment->uvs[ii + 1]; + } + regionAttachment->rendererObject = attachmentVertices; + break; + } + case SP_ATTACHMENT_MESH: { + spMeshAttachment* meshAttachment = SUB_CAST(spMeshAttachment, attachment); + spAtlasRegion* region = (spAtlasRegion*)meshAttachment->rendererObject; + AttachmentVertices* attachmentVertices = new AttachmentVertices((Texture2D*)region->page->rendererObject, + meshAttachment->super.worldVerticesLength >> 1, meshAttachment->triangles, meshAttachment->trianglesCount); + V3F_C4B_T2F* vertices = attachmentVertices->_triangles->verts; + for (int i = 0, ii = 0, nn = meshAttachment->super.worldVerticesLength; ii < nn; ++i, ii += 2) { + vertices[i].texCoords.u = meshAttachment->uvs[ii]; + vertices[i].texCoords.v = meshAttachment->uvs[ii + 1]; + } + meshAttachment->rendererObject = attachmentVertices; + break; + } + default: ; + } +} + +void _Cocos2dAttachmentLoader_disposeAttachment (spAttachmentLoader* loader, spAttachment* attachment) { + switch (attachment->type) { + case SP_ATTACHMENT_REGION: { + spRegionAttachment* regionAttachment = SUB_CAST(spRegionAttachment, attachment); + delete (AttachmentVertices*)regionAttachment->rendererObject; + break; + } + case SP_ATTACHMENT_MESH: { + spMeshAttachment* meshAttachment = SUB_CAST(spMeshAttachment, attachment); + delete (AttachmentVertices*)meshAttachment->rendererObject; + break; + } + default: ; + } +} + +void _Cocos2dAttachmentLoader_dispose (spAttachmentLoader* loader) { + Cocos2dAttachmentLoader* self = SUB_CAST(Cocos2dAttachmentLoader, loader); + spAttachmentLoader_dispose(SUPER_CAST(spAttachmentLoader, self->atlasAttachmentLoader)); + _spAttachmentLoader_deinit(loader); +} + +Cocos2dAttachmentLoader* Cocos2dAttachmentLoader_create (spAtlas* atlas) { + Cocos2dAttachmentLoader* self = NEW(Cocos2dAttachmentLoader); + _spAttachmentLoader_init(SUPER(self), _Cocos2dAttachmentLoader_dispose, _Cocos2dAttachmentLoader_createAttachment, + _Cocos2dAttachmentLoader_configureAttachment, _Cocos2dAttachmentLoader_disposeAttachment); + self->atlasAttachmentLoader = spAtlasAttachmentLoader_create(atlas); + return self; } diff --git a/spine-cocos2dx/src/spine/Cocos2dAttachmentLoader.h b/spine-cocos2dx/src/spine/Cocos2dAttachmentLoader.h index fe15375e08..bca500917d 100644 --- a/spine-cocos2dx/src/spine/Cocos2dAttachmentLoader.h +++ b/spine-cocos2dx/src/spine/Cocos2dAttachmentLoader.h @@ -1,49 +1,48 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_COCOS2DATTACHMENTLOADER_H_ -#define SPINE_COCOS2DATTACHMENTLOADER_H_ - -#include - -extern "C" { - -typedef struct Cocos2dAttachmentLoader { - spAttachmentLoader super; - spAtlasAttachmentLoader* atlasAttachmentLoader; -} Cocos2dAttachmentLoader; - -/* The Cocos2dAttachmentLoader must not be disposed until after the skeleton data has been disposed. */ -Cocos2dAttachmentLoader* Cocos2dAttachmentLoader_create (spAtlas* atlas); - -} - +#ifndef SPINE_COCOS2DATTACHMENTLOADER_H_ +#define SPINE_COCOS2DATTACHMENTLOADER_H_ + +#include + +extern "C" { + +typedef struct Cocos2dAttachmentLoader { + spAttachmentLoader super; + spAtlasAttachmentLoader* atlasAttachmentLoader; +} Cocos2dAttachmentLoader; + +/* The Cocos2dAttachmentLoader must not be disposed until after the skeleton data has been disposed. */ +Cocos2dAttachmentLoader* Cocos2dAttachmentLoader_create (spAtlas* atlas); + +} + #endif /* SPINE_COCOS2DATTACHMENTLOADER_H_ */ diff --git a/spine-cocos2dx/src/spine/SkeletonAnimation.cpp b/spine-cocos2dx/src/spine/SkeletonAnimation.cpp index 2af2d9a829..e9f8a1008b 100644 --- a/spine-cocos2dx/src/spine/SkeletonAnimation.cpp +++ b/spine-cocos2dx/src/spine/SkeletonAnimation.cpp @@ -1,265 +1,264 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include -#include - -USING_NS_CC; -using std::min; -using std::max; -using std::vector; - -namespace spine { - -void animationCallback (spAnimationState* state, int trackIndex, spEventType type, spEvent* event, int loopCount) { - ((SkeletonAnimation*)state->rendererObject)->onAnimationStateEvent(trackIndex, type, event, loopCount); -} - -void trackEntryCallback (spAnimationState* state, int trackIndex, spEventType type, spEvent* event, int loopCount) { - ((SkeletonAnimation*)state->rendererObject)->onTrackEntryEvent(trackIndex, type, event, loopCount); -} - -typedef struct _TrackEntryListeners { - StartListener startListener; - EndListener endListener; - CompleteListener completeListener; - EventListener eventListener; -} _TrackEntryListeners; - -static _TrackEntryListeners* getListeners (spTrackEntry* entry) { - if (!entry->rendererObject) { - entry->rendererObject = new spine::_TrackEntryListeners(); - entry->listener = trackEntryCallback; - } - return (_TrackEntryListeners*)entry->rendererObject; -} - -void disposeTrackEntry (spTrackEntry* entry) { - if (entry->rendererObject) delete (spine::_TrackEntryListeners*)entry->rendererObject; - _spTrackEntry_dispose(entry); -} - -// - -SkeletonAnimation* SkeletonAnimation::createWithData (spSkeletonData* skeletonData, bool ownsSkeletonData) { - SkeletonAnimation* node = new SkeletonAnimation(); - node->initWithData(skeletonData, ownsSkeletonData); - node->autorelease(); - return node; -} - -SkeletonAnimation* SkeletonAnimation::createWithJsonFile (const std::string& skeletonJsonFile, spAtlas* atlas, float scale) { - SkeletonAnimation* node = new SkeletonAnimation(); - node->initWithJsonFile(skeletonJsonFile, atlas, scale); - node->autorelease(); - return node; -} - -SkeletonAnimation* SkeletonAnimation::createWithJsonFile (const std::string& skeletonJsonFile, const std::string& atlasFile, float scale) { - SkeletonAnimation* node = new SkeletonAnimation(); - spAtlas* atlas = spAtlas_createFromFile(atlasFile.c_str(), 0); - node->initWithJsonFile(skeletonJsonFile, atlas, scale); - node->autorelease(); - return node; -} - -SkeletonAnimation* SkeletonAnimation::createWithBinaryFile (const std::string& skeletonBinaryFile, spAtlas* atlas, float scale) { - SkeletonAnimation* node = new SkeletonAnimation(); - node->initWithBinaryFile(skeletonBinaryFile, atlas, scale); - node->autorelease(); - return node; -} - -SkeletonAnimation* SkeletonAnimation::createWithBinaryFile (const std::string& skeletonBinaryFile, const std::string& atlasFile, float scale) { - SkeletonAnimation* node = new SkeletonAnimation(); - spAtlas* atlas = spAtlas_createFromFile(atlasFile.c_str(), 0); - node->initWithBinaryFile(skeletonBinaryFile, atlas, scale); - node->autorelease(); - return node; -} - - -void SkeletonAnimation::initialize () { - super::initialize(); - - _ownsAnimationStateData = true; - _state = spAnimationState_create(spAnimationStateData_create(_skeleton->data)); - _state->rendererObject = this; - _state->listener = animationCallback; - - _spAnimationState* stateInternal = (_spAnimationState*)_state; - stateInternal->disposeTrackEntry = disposeTrackEntry; -} - -SkeletonAnimation::SkeletonAnimation () - : SkeletonRenderer() { -} - -SkeletonAnimation::~SkeletonAnimation () { - if (_ownsAnimationStateData) spAnimationStateData_dispose(_state->data); - spAnimationState_dispose(_state); -} - -void SkeletonAnimation::update (float deltaTime) { - super::update(deltaTime); - - deltaTime *= _timeScale; - spAnimationState_update(_state, deltaTime); - spAnimationState_apply(_state, _skeleton); - spSkeleton_updateWorldTransform(_skeleton); -} - -void SkeletonAnimation::setAnimationStateData (spAnimationStateData* stateData) { - CCASSERT(stateData, "stateData cannot be null."); - - if (_ownsAnimationStateData) spAnimationStateData_dispose(_state->data); - spAnimationState_dispose(_state); - - _ownsAnimationStateData = false; - _state = spAnimationState_create(stateData); - _state->rendererObject = this; - _state->listener = animationCallback; -} - -void SkeletonAnimation::setMix (const std::string& fromAnimation, const std::string& toAnimation, float duration) { - spAnimationStateData_setMixByName(_state->data, fromAnimation.c_str(), toAnimation.c_str(), duration); -} - -spTrackEntry* SkeletonAnimation::setAnimation (int trackIndex, const std::string& name, bool loop) { - spAnimation* animation = spSkeletonData_findAnimation(_skeleton->data, name.c_str()); - if (!animation) { - log("Spine: Animation not found: %s", name.c_str()); - return 0; - } - return spAnimationState_setAnimation(_state, trackIndex, animation, loop); -} - -spTrackEntry* SkeletonAnimation::addAnimation (int trackIndex, const std::string& name, bool loop, float delay) { - spAnimation* animation = spSkeletonData_findAnimation(_skeleton->data, name.c_str()); - if (!animation) { - log("Spine: Animation not found: %s", name.c_str()); - return 0; - } - return spAnimationState_addAnimation(_state, trackIndex, animation, loop, delay); -} - -spAnimation* SkeletonAnimation::findAnimation(const std::string& name) const { - return spSkeletonData_findAnimation(_skeleton->data, name.c_str()); -} - -spTrackEntry* SkeletonAnimation::getCurrent (int trackIndex) { - return spAnimationState_getCurrent(_state, trackIndex); -} - -void SkeletonAnimation::clearTracks () { - spAnimationState_clearTracks(_state); -} - -void SkeletonAnimation::clearTrack (int trackIndex) { - spAnimationState_clearTrack(_state, trackIndex); -} - -void SkeletonAnimation::onAnimationStateEvent (int trackIndex, spEventType type, spEvent* event, int loopCount) { - switch (type) { - case SP_ANIMATION_START: - if (_startListener) _startListener(trackIndex); - break; - case SP_ANIMATION_END: - if (_endListener) _endListener(trackIndex); - break; - case SP_ANIMATION_COMPLETE: - if (_completeListener) _completeListener(trackIndex, loopCount); - break; - case SP_ANIMATION_EVENT: - if (_eventListener) _eventListener(trackIndex, event); - break; - } -} - -void SkeletonAnimation::onTrackEntryEvent (int trackIndex, spEventType type, spEvent* event, int loopCount) { - spTrackEntry* entry = spAnimationState_getCurrent(_state, trackIndex); - if (!entry->rendererObject) return; - _TrackEntryListeners* listeners = (_TrackEntryListeners*)entry->rendererObject; - switch (type) { - case SP_ANIMATION_START: - if (listeners->startListener) listeners->startListener(trackIndex); - break; - case SP_ANIMATION_END: - if (listeners->endListener) listeners->endListener(trackIndex); - break; - case SP_ANIMATION_COMPLETE: - if (listeners->completeListener) listeners->completeListener(trackIndex, loopCount); - break; - case SP_ANIMATION_EVENT: - if (listeners->eventListener) listeners->eventListener(trackIndex, event); - break; - } -} - -void SkeletonAnimation::setStartListener (const StartListener& listener) { - _startListener = listener; -} - -void SkeletonAnimation::setEndListener (const EndListener& listener) { - _endListener = listener; -} - -void SkeletonAnimation::setCompleteListener (const CompleteListener& listener) { - _completeListener = listener; -} - -void SkeletonAnimation::setEventListener (const EventListener& listener) { - _eventListener = listener; -} - -void SkeletonAnimation::setTrackStartListener (spTrackEntry* entry, const StartListener& listener) { - getListeners(entry)->startListener = listener; -} - -void SkeletonAnimation::setTrackEndListener (spTrackEntry* entry, const EndListener& listener) { - getListeners(entry)->endListener = listener; -} - -void SkeletonAnimation::setTrackCompleteListener (spTrackEntry* entry, const CompleteListener& listener) { - getListeners(entry)->completeListener = listener; -} - -void SkeletonAnimation::setTrackEventListener (spTrackEntry* entry, const EventListener& listener) { - getListeners(entry)->eventListener = listener; -} - -spAnimationState* SkeletonAnimation::getState() const { - return _state; -} - +#include +#include +#include +#include + +USING_NS_CC; +using std::min; +using std::max; +using std::vector; + +namespace spine { + +void animationCallback (spAnimationState* state, int trackIndex, spEventType type, spEvent* event, int loopCount) { + ((SkeletonAnimation*)state->rendererObject)->onAnimationStateEvent(trackIndex, type, event, loopCount); +} + +void trackEntryCallback (spAnimationState* state, int trackIndex, spEventType type, spEvent* event, int loopCount) { + ((SkeletonAnimation*)state->rendererObject)->onTrackEntryEvent(trackIndex, type, event, loopCount); +} + +typedef struct _TrackEntryListeners { + StartListener startListener; + EndListener endListener; + CompleteListener completeListener; + EventListener eventListener; +} _TrackEntryListeners; + +static _TrackEntryListeners* getListeners (spTrackEntry* entry) { + if (!entry->rendererObject) { + entry->rendererObject = new spine::_TrackEntryListeners(); + entry->listener = trackEntryCallback; + } + return (_TrackEntryListeners*)entry->rendererObject; +} + +void disposeTrackEntry (spTrackEntry* entry) { + if (entry->rendererObject) delete (spine::_TrackEntryListeners*)entry->rendererObject; + _spTrackEntry_dispose(entry); +} + +// + +SkeletonAnimation* SkeletonAnimation::createWithData (spSkeletonData* skeletonData, bool ownsSkeletonData) { + SkeletonAnimation* node = new SkeletonAnimation(); + node->initWithData(skeletonData, ownsSkeletonData); + node->autorelease(); + return node; +} + +SkeletonAnimation* SkeletonAnimation::createWithJsonFile (const std::string& skeletonJsonFile, spAtlas* atlas, float scale) { + SkeletonAnimation* node = new SkeletonAnimation(); + node->initWithJsonFile(skeletonJsonFile, atlas, scale); + node->autorelease(); + return node; +} + +SkeletonAnimation* SkeletonAnimation::createWithJsonFile (const std::string& skeletonJsonFile, const std::string& atlasFile, float scale) { + SkeletonAnimation* node = new SkeletonAnimation(); + spAtlas* atlas = spAtlas_createFromFile(atlasFile.c_str(), 0); + node->initWithJsonFile(skeletonJsonFile, atlas, scale); + node->autorelease(); + return node; +} + +SkeletonAnimation* SkeletonAnimation::createWithBinaryFile (const std::string& skeletonBinaryFile, spAtlas* atlas, float scale) { + SkeletonAnimation* node = new SkeletonAnimation(); + node->initWithBinaryFile(skeletonBinaryFile, atlas, scale); + node->autorelease(); + return node; +} + +SkeletonAnimation* SkeletonAnimation::createWithBinaryFile (const std::string& skeletonBinaryFile, const std::string& atlasFile, float scale) { + SkeletonAnimation* node = new SkeletonAnimation(); + spAtlas* atlas = spAtlas_createFromFile(atlasFile.c_str(), 0); + node->initWithBinaryFile(skeletonBinaryFile, atlas, scale); + node->autorelease(); + return node; +} + + +void SkeletonAnimation::initialize () { + super::initialize(); + + _ownsAnimationStateData = true; + _state = spAnimationState_create(spAnimationStateData_create(_skeleton->data)); + _state->rendererObject = this; + _state->listener = animationCallback; + + _spAnimationState* stateInternal = (_spAnimationState*)_state; + stateInternal->disposeTrackEntry = disposeTrackEntry; +} + +SkeletonAnimation::SkeletonAnimation () + : SkeletonRenderer() { +} + +SkeletonAnimation::~SkeletonAnimation () { + if (_ownsAnimationStateData) spAnimationStateData_dispose(_state->data); + spAnimationState_dispose(_state); +} + +void SkeletonAnimation::update (float deltaTime) { + super::update(deltaTime); + + deltaTime *= _timeScale; + spAnimationState_update(_state, deltaTime); + spAnimationState_apply(_state, _skeleton); + spSkeleton_updateWorldTransform(_skeleton); +} + +void SkeletonAnimation::setAnimationStateData (spAnimationStateData* stateData) { + CCASSERT(stateData, "stateData cannot be null."); + + if (_ownsAnimationStateData) spAnimationStateData_dispose(_state->data); + spAnimationState_dispose(_state); + + _ownsAnimationStateData = false; + _state = spAnimationState_create(stateData); + _state->rendererObject = this; + _state->listener = animationCallback; +} + +void SkeletonAnimation::setMix (const std::string& fromAnimation, const std::string& toAnimation, float duration) { + spAnimationStateData_setMixByName(_state->data, fromAnimation.c_str(), toAnimation.c_str(), duration); +} + +spTrackEntry* SkeletonAnimation::setAnimation (int trackIndex, const std::string& name, bool loop) { + spAnimation* animation = spSkeletonData_findAnimation(_skeleton->data, name.c_str()); + if (!animation) { + log("Spine: Animation not found: %s", name.c_str()); + return 0; + } + return spAnimationState_setAnimation(_state, trackIndex, animation, loop); +} + +spTrackEntry* SkeletonAnimation::addAnimation (int trackIndex, const std::string& name, bool loop, float delay) { + spAnimation* animation = spSkeletonData_findAnimation(_skeleton->data, name.c_str()); + if (!animation) { + log("Spine: Animation not found: %s", name.c_str()); + return 0; + } + return spAnimationState_addAnimation(_state, trackIndex, animation, loop, delay); +} + +spAnimation* SkeletonAnimation::findAnimation(const std::string& name) const { + return spSkeletonData_findAnimation(_skeleton->data, name.c_str()); +} + +spTrackEntry* SkeletonAnimation::getCurrent (int trackIndex) { + return spAnimationState_getCurrent(_state, trackIndex); +} + +void SkeletonAnimation::clearTracks () { + spAnimationState_clearTracks(_state); +} + +void SkeletonAnimation::clearTrack (int trackIndex) { + spAnimationState_clearTrack(_state, trackIndex); +} + +void SkeletonAnimation::onAnimationStateEvent (int trackIndex, spEventType type, spEvent* event, int loopCount) { + switch (type) { + case SP_ANIMATION_START: + if (_startListener) _startListener(trackIndex); + break; + case SP_ANIMATION_END: + if (_endListener) _endListener(trackIndex); + break; + case SP_ANIMATION_COMPLETE: + if (_completeListener) _completeListener(trackIndex, loopCount); + break; + case SP_ANIMATION_EVENT: + if (_eventListener) _eventListener(trackIndex, event); + break; + } +} + +void SkeletonAnimation::onTrackEntryEvent (int trackIndex, spEventType type, spEvent* event, int loopCount) { + spTrackEntry* entry = spAnimationState_getCurrent(_state, trackIndex); + if (!entry->rendererObject) return; + _TrackEntryListeners* listeners = (_TrackEntryListeners*)entry->rendererObject; + switch (type) { + case SP_ANIMATION_START: + if (listeners->startListener) listeners->startListener(trackIndex); + break; + case SP_ANIMATION_END: + if (listeners->endListener) listeners->endListener(trackIndex); + break; + case SP_ANIMATION_COMPLETE: + if (listeners->completeListener) listeners->completeListener(trackIndex, loopCount); + break; + case SP_ANIMATION_EVENT: + if (listeners->eventListener) listeners->eventListener(trackIndex, event); + break; + } +} + +void SkeletonAnimation::setStartListener (const StartListener& listener) { + _startListener = listener; +} + +void SkeletonAnimation::setEndListener (const EndListener& listener) { + _endListener = listener; +} + +void SkeletonAnimation::setCompleteListener (const CompleteListener& listener) { + _completeListener = listener; +} + +void SkeletonAnimation::setEventListener (const EventListener& listener) { + _eventListener = listener; +} + +void SkeletonAnimation::setTrackStartListener (spTrackEntry* entry, const StartListener& listener) { + getListeners(entry)->startListener = listener; +} + +void SkeletonAnimation::setTrackEndListener (spTrackEntry* entry, const EndListener& listener) { + getListeners(entry)->endListener = listener; +} + +void SkeletonAnimation::setTrackCompleteListener (spTrackEntry* entry, const CompleteListener& listener) { + getListeners(entry)->completeListener = listener; +} + +void SkeletonAnimation::setTrackEventListener (spTrackEntry* entry, const EventListener& listener) { + getListeners(entry)->eventListener = listener; +} + +spAnimationState* SkeletonAnimation::getState() const { + return _state; +} + } diff --git a/spine-cocos2dx/src/spine/SkeletonAnimation.h b/spine-cocos2dx/src/spine/SkeletonAnimation.h index 8bf5c257de..be8e7866ee 100644 --- a/spine-cocos2dx/src/spine/SkeletonAnimation.h +++ b/spine-cocos2dx/src/spine/SkeletonAnimation.h @@ -1,116 +1,115 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_SKELETONANIMATION_H_ -#define SPINE_SKELETONANIMATION_H_ - -#include -#include -#include "cocos2d.h" - -namespace spine { - -typedef std::function StartListener; -typedef std::function EndListener; -typedef std::function CompleteListener; -typedef std::function EventListener; - -/** Draws an animated skeleton, providing an AnimationState for applying one or more animations and queuing animations to be - * played later. */ -class SkeletonAnimation: public SkeletonRenderer { -public: - CREATE_FUNC(SkeletonAnimation); - static SkeletonAnimation* createWithData (spSkeletonData* skeletonData, bool ownsSkeletonData = false); - static SkeletonAnimation* createWithJsonFile (const std::string& skeletonJsonFile, spAtlas* atlas, float scale = 1); - static SkeletonAnimation* createWithJsonFile (const std::string& skeletonJsonFile, const std::string& atlasFile, float scale = 1); - static SkeletonAnimation* createWithBinaryFile (const std::string& skeletonBinaryFile, spAtlas* atlas, float scale = 1); - static SkeletonAnimation* createWithBinaryFile (const std::string& skeletonBinaryFile, const std::string& atlasFile, float scale = 1); - - // Use createWithJsonFile instead - CC_DEPRECATED_ATTRIBUTE static SkeletonAnimation* createWithFile (const std::string& skeletonJsonFile, spAtlas* atlas, float scale = 1) - { - return SkeletonAnimation::createWithJsonFile(skeletonJsonFile, atlas, scale); - } - // Use createWithJsonFile instead - CC_DEPRECATED_ATTRIBUTE static SkeletonAnimation* createWithile (const std::string& skeletonJsonFile, const std::string& atlasFile, float scale = 1) - { - return SkeletonAnimation::createWithJsonFile(skeletonJsonFile, atlasFile, scale); - } - - virtual void update (float deltaTime) override; - - void setAnimationStateData (spAnimationStateData* stateData); - void setMix (const std::string& fromAnimation, const std::string& toAnimation, float duration); - - spTrackEntry* setAnimation (int trackIndex, const std::string& name, bool loop); - spTrackEntry* addAnimation (int trackIndex, const std::string& name, bool loop, float delay = 0); - spAnimation* findAnimation(const std::string& name) const; - spTrackEntry* getCurrent (int trackIndex = 0); - void clearTracks (); - void clearTrack (int trackIndex = 0); - - void setStartListener (const StartListener& listener); - void setEndListener (const EndListener& listener); - void setCompleteListener (const CompleteListener& listener); - void setEventListener (const EventListener& listener); - - void setTrackStartListener (spTrackEntry* entry, const StartListener& listener); - void setTrackEndListener (spTrackEntry* entry, const EndListener& listener); - void setTrackCompleteListener (spTrackEntry* entry, const CompleteListener& listener); - void setTrackEventListener (spTrackEntry* entry, const EventListener& listener); - - virtual void onAnimationStateEvent (int trackIndex, spEventType type, spEvent* event, int loopCount); - virtual void onTrackEntryEvent (int trackIndex, spEventType type, spEvent* event, int loopCount); - - spAnimationState* getState() const; - -CC_CONSTRUCTOR_ACCESS: - SkeletonAnimation (); - virtual ~SkeletonAnimation (); - virtual void initialize () override; - -protected: - spAnimationState* _state; - - bool _ownsAnimationStateData; - - StartListener _startListener; - EndListener _endListener; - CompleteListener _completeListener; - EventListener _eventListener; - -private: - typedef SkeletonRenderer super; -}; - -} - +#ifndef SPINE_SKELETONANIMATION_H_ +#define SPINE_SKELETONANIMATION_H_ + +#include +#include +#include "cocos2d.h" + +namespace spine { + +typedef std::function StartListener; +typedef std::function EndListener; +typedef std::function CompleteListener; +typedef std::function EventListener; + +/** Draws an animated skeleton, providing an AnimationState for applying one or more animations and queuing animations to be + * played later. */ +class SkeletonAnimation: public SkeletonRenderer { +public: + CREATE_FUNC(SkeletonAnimation); + static SkeletonAnimation* createWithData (spSkeletonData* skeletonData, bool ownsSkeletonData = false); + static SkeletonAnimation* createWithJsonFile (const std::string& skeletonJsonFile, spAtlas* atlas, float scale = 1); + static SkeletonAnimation* createWithJsonFile (const std::string& skeletonJsonFile, const std::string& atlasFile, float scale = 1); + static SkeletonAnimation* createWithBinaryFile (const std::string& skeletonBinaryFile, spAtlas* atlas, float scale = 1); + static SkeletonAnimation* createWithBinaryFile (const std::string& skeletonBinaryFile, const std::string& atlasFile, float scale = 1); + + // Use createWithJsonFile instead + CC_DEPRECATED_ATTRIBUTE static SkeletonAnimation* createWithFile (const std::string& skeletonJsonFile, spAtlas* atlas, float scale = 1) + { + return SkeletonAnimation::createWithJsonFile(skeletonJsonFile, atlas, scale); + } + // Use createWithJsonFile instead + CC_DEPRECATED_ATTRIBUTE static SkeletonAnimation* createWithile (const std::string& skeletonJsonFile, const std::string& atlasFile, float scale = 1) + { + return SkeletonAnimation::createWithJsonFile(skeletonJsonFile, atlasFile, scale); + } + + virtual void update (float deltaTime) override; + + void setAnimationStateData (spAnimationStateData* stateData); + void setMix (const std::string& fromAnimation, const std::string& toAnimation, float duration); + + spTrackEntry* setAnimation (int trackIndex, const std::string& name, bool loop); + spTrackEntry* addAnimation (int trackIndex, const std::string& name, bool loop, float delay = 0); + spAnimation* findAnimation(const std::string& name) const; + spTrackEntry* getCurrent (int trackIndex = 0); + void clearTracks (); + void clearTrack (int trackIndex = 0); + + void setStartListener (const StartListener& listener); + void setEndListener (const EndListener& listener); + void setCompleteListener (const CompleteListener& listener); + void setEventListener (const EventListener& listener); + + void setTrackStartListener (spTrackEntry* entry, const StartListener& listener); + void setTrackEndListener (spTrackEntry* entry, const EndListener& listener); + void setTrackCompleteListener (spTrackEntry* entry, const CompleteListener& listener); + void setTrackEventListener (spTrackEntry* entry, const EventListener& listener); + + virtual void onAnimationStateEvent (int trackIndex, spEventType type, spEvent* event, int loopCount); + virtual void onTrackEntryEvent (int trackIndex, spEventType type, spEvent* event, int loopCount); + + spAnimationState* getState() const; + +CC_CONSTRUCTOR_ACCESS: + SkeletonAnimation (); + virtual ~SkeletonAnimation (); + virtual void initialize () override; + +protected: + spAnimationState* _state; + + bool _ownsAnimationStateData; + + StartListener _startListener; + EndListener _endListener; + CompleteListener _completeListener; + EventListener _eventListener; + +private: + typedef SkeletonRenderer super; +}; + +} + #endif /* SPINE_SKELETONANIMATION_H_ */ diff --git a/spine-cocos2dx/src/spine/SkeletonBatch.cpp b/spine-cocos2dx/src/spine/SkeletonBatch.cpp index 974dc15e06..37ac51fb70 100644 --- a/spine-cocos2dx/src/spine/SkeletonBatch.cpp +++ b/spine-cocos2dx/src/spine/SkeletonBatch.cpp @@ -1,118 +1,117 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include - -USING_NS_CC; -#define EVENT_AFTER_DRAW_RESET_POSITION "director_after_draw" -using std::max; - -namespace spine { - - static SkeletonBatch* instance = nullptr; - - SkeletonBatch* SkeletonBatch::getInstance () { - if (!instance) instance = new SkeletonBatch(); - return instance; - } - - void SkeletonBatch::destroyInstance () { - if (instance) { - delete instance; - instance = nullptr; - } - } - - SkeletonBatch::SkeletonBatch () - { - _firstCommand = new Command(); - _command = _firstCommand; - - Director::getInstance()->getEventDispatcher()->addCustomEventListener(EVENT_AFTER_DRAW_RESET_POSITION, [this](EventCustom* eventCustom){ - this->update(0); - });; - } - - SkeletonBatch::~SkeletonBatch () { - Director::getInstance()->getEventDispatcher()->removeCustomEventListeners(EVENT_AFTER_DRAW_RESET_POSITION); - - Command* command = _firstCommand; - while (command) { - Command* next = command->next; - delete command; - command = next; - } - } - - void SkeletonBatch::update (float delta) { - _command = _firstCommand; - } - - void SkeletonBatch::addCommand (cocos2d::Renderer* renderer, float globalZOrder, GLuint textureID, GLProgramState* glProgramState, - BlendFunc blendFunc, const TrianglesCommand::Triangles& triangles, const Mat4& transform, uint32_t transformFlags - ) { - if (_command->triangles->verts) { - free(_command->triangles->verts); - _command->triangles->verts = NULL; - } - - _command->triangles->verts = (V3F_C4B_T2F *)malloc(sizeof(V3F_C4B_T2F) * triangles.vertCount); - memcpy(_command->triangles->verts, triangles.verts, sizeof(V3F_C4B_T2F) * triangles.vertCount); - - _command->triangles->vertCount = triangles.vertCount; - _command->triangles->indexCount = triangles.indexCount; - _command->triangles->indices = triangles.indices; - - _command->trianglesCommand->init(globalZOrder, textureID, glProgramState, blendFunc, *_command->triangles, transform); - renderer->addCommand(_command->trianglesCommand); - - if (!_command->next) _command->next = new Command(); - _command = _command->next; - } - - SkeletonBatch::Command::Command () : - next(nullptr) - { - trianglesCommand = new TrianglesCommand(); - triangles = new TrianglesCommand::Triangles(); - } - - SkeletonBatch::Command::~Command () { - if (triangles->verts) { - free(triangles->verts); - } - delete triangles; - delete trianglesCommand; - } - +#include +#include +#include + +USING_NS_CC; +#define EVENT_AFTER_DRAW_RESET_POSITION "director_after_draw" +using std::max; + +namespace spine { + + static SkeletonBatch* instance = nullptr; + + SkeletonBatch* SkeletonBatch::getInstance () { + if (!instance) instance = new SkeletonBatch(); + return instance; + } + + void SkeletonBatch::destroyInstance () { + if (instance) { + delete instance; + instance = nullptr; + } + } + + SkeletonBatch::SkeletonBatch () + { + _firstCommand = new Command(); + _command = _firstCommand; + + Director::getInstance()->getEventDispatcher()->addCustomEventListener(EVENT_AFTER_DRAW_RESET_POSITION, [this](EventCustom* eventCustom){ + this->update(0); + });; + } + + SkeletonBatch::~SkeletonBatch () { + Director::getInstance()->getEventDispatcher()->removeCustomEventListeners(EVENT_AFTER_DRAW_RESET_POSITION); + + Command* command = _firstCommand; + while (command) { + Command* next = command->next; + delete command; + command = next; + } + } + + void SkeletonBatch::update (float delta) { + _command = _firstCommand; + } + + void SkeletonBatch::addCommand (cocos2d::Renderer* renderer, float globalZOrder, GLuint textureID, GLProgramState* glProgramState, + BlendFunc blendFunc, const TrianglesCommand::Triangles& triangles, const Mat4& transform, uint32_t transformFlags + ) { + if (_command->triangles->verts) { + free(_command->triangles->verts); + _command->triangles->verts = NULL; + } + + _command->triangles->verts = (V3F_C4B_T2F *)malloc(sizeof(V3F_C4B_T2F) * triangles.vertCount); + memcpy(_command->triangles->verts, triangles.verts, sizeof(V3F_C4B_T2F) * triangles.vertCount); + + _command->triangles->vertCount = triangles.vertCount; + _command->triangles->indexCount = triangles.indexCount; + _command->triangles->indices = triangles.indices; + + _command->trianglesCommand->init(globalZOrder, textureID, glProgramState, blendFunc, *_command->triangles, transform); + renderer->addCommand(_command->trianglesCommand); + + if (!_command->next) _command->next = new Command(); + _command = _command->next; + } + + SkeletonBatch::Command::Command () : + next(nullptr) + { + trianglesCommand = new TrianglesCommand(); + triangles = new TrianglesCommand::Triangles(); + } + + SkeletonBatch::Command::~Command () { + if (triangles->verts) { + free(triangles->verts); + } + delete triangles; + delete trianglesCommand; + } + } diff --git a/spine-cocos2dx/src/spine/SkeletonBatch.h b/spine-cocos2dx/src/spine/SkeletonBatch.h index 6c2069ce48..13cba2df3d 100644 --- a/spine-cocos2dx/src/spine/SkeletonBatch.h +++ b/spine-cocos2dx/src/spine/SkeletonBatch.h @@ -1,71 +1,70 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_SKELETONBATCH_H_ -#define SPINE_SKELETONBATCH_H_ - -#include -#include "cocos2d.h" - -namespace spine { - - class SkeletonBatch { - public: - static SkeletonBatch* getInstance (); - - static void destroyInstance (); - - void update (float delta); - - void addCommand (cocos2d::Renderer* renderer, float globalOrder, GLuint textureID, cocos2d::GLProgramState* glProgramState, - cocos2d::BlendFunc blendType, const cocos2d::TrianglesCommand:: Triangles& triangles, const cocos2d::Mat4& mv, uint32_t flags); - - protected: - SkeletonBatch (); - virtual ~SkeletonBatch (); - - class Command { - public: - Command (); - virtual ~Command (); - - cocos2d::TrianglesCommand* trianglesCommand; - cocos2d::TrianglesCommand::Triangles* triangles; - Command* next; - }; - - Command* _firstCommand; - Command* _command; - }; - -} - -#endif // SPINE_SKELETONBATCH_H_ \ No newline at end of file +#ifndef SPINE_SKELETONBATCH_H_ +#define SPINE_SKELETONBATCH_H_ + +#include +#include "cocos2d.h" + +namespace spine { + + class SkeletonBatch { + public: + static SkeletonBatch* getInstance (); + + static void destroyInstance (); + + void update (float delta); + + void addCommand (cocos2d::Renderer* renderer, float globalOrder, GLuint textureID, cocos2d::GLProgramState* glProgramState, + cocos2d::BlendFunc blendType, const cocos2d::TrianglesCommand:: Triangles& triangles, const cocos2d::Mat4& mv, uint32_t flags); + + protected: + SkeletonBatch (); + virtual ~SkeletonBatch (); + + class Command { + public: + Command (); + virtual ~Command (); + + cocos2d::TrianglesCommand* trianglesCommand; + cocos2d::TrianglesCommand::Triangles* triangles; + Command* next; + }; + + Command* _firstCommand; + Command* _command; + }; + +} + +#endif // SPINE_SKELETONBATCH_H_ diff --git a/spine-cocos2dx/src/spine/SkeletonRenderer.cpp b/spine-cocos2dx/src/spine/SkeletonRenderer.cpp index 3dc5d30058..e05d638816 100644 --- a/spine-cocos2dx/src/spine/SkeletonRenderer.cpp +++ b/spine-cocos2dx/src/spine/SkeletonRenderer.cpp @@ -1,451 +1,450 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include -#include -#include -#include - -USING_NS_CC; -using std::min; -using std::max; - -namespace spine { - -SkeletonRenderer* SkeletonRenderer::createWithData (spSkeletonData* skeletonData, bool ownsSkeletonData) { - SkeletonRenderer* node = new SkeletonRenderer(skeletonData, ownsSkeletonData); - node->autorelease(); - return node; -} - -SkeletonRenderer* SkeletonRenderer::createWithFile (const std::string& skeletonDataFile, spAtlas* atlas, float scale) { - SkeletonRenderer* node = new SkeletonRenderer(skeletonDataFile, atlas, scale); - node->autorelease(); - return node; -} - -SkeletonRenderer* SkeletonRenderer::createWithFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) { - SkeletonRenderer* node = new SkeletonRenderer(skeletonDataFile, atlasFile, scale); - node->autorelease(); - return node; -} - -void SkeletonRenderer::initialize () { - _worldVertices = new float[1000]; // Max number of vertices per mesh. - - _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED; - setOpacityModifyRGB(true); - - setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP)); -} - -void SkeletonRenderer::setSkeletonData (spSkeletonData *skeletonData, bool ownsSkeletonData) { - _skeleton = spSkeleton_create(skeletonData); - _ownsSkeletonData = ownsSkeletonData; -} - -SkeletonRenderer::SkeletonRenderer () - : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _timeScale(1) { -} - -SkeletonRenderer::SkeletonRenderer (spSkeletonData *skeletonData, bool ownsSkeletonData) - : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _timeScale(1) { - initWithData(skeletonData, ownsSkeletonData); -} - -SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, spAtlas* atlas, float scale) - : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _timeScale(1) { - initWithJsonFile(skeletonDataFile, atlas, scale); -} - -SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) - : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _timeScale(1) { - initWithJsonFile(skeletonDataFile, atlasFile, scale); -} - -SkeletonRenderer::~SkeletonRenderer () { - if (_ownsSkeletonData) spSkeletonData_dispose(_skeleton->data); - spSkeleton_dispose(_skeleton); - if (_atlas) spAtlas_dispose(_atlas); - if (_attachmentLoader) spAttachmentLoader_dispose(_attachmentLoader); - delete [] _worldVertices; -} - -void SkeletonRenderer::initWithData (spSkeletonData* skeletonData, bool ownsSkeletonData) { - setSkeletonData(skeletonData, ownsSkeletonData); - - initialize(); -} - -void SkeletonRenderer::initWithJsonFile (const std::string& skeletonDataFile, spAtlas* atlas, float scale) { - _atlas = atlas; - _attachmentLoader = SUPER(Cocos2dAttachmentLoader_create(_atlas)); - - spSkeletonJson* json = spSkeletonJson_createWithLoader(_attachmentLoader); - json->scale = scale; - spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, skeletonDataFile.c_str()); - CCASSERT(skeletonData, json->error ? json->error : "Error reading skeleton data."); - spSkeletonJson_dispose(json); - - setSkeletonData(skeletonData, true); - - initialize(); -} - -void SkeletonRenderer::initWithJsonFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) { - _atlas = spAtlas_createFromFile(atlasFile.c_str(), 0); - CCASSERT(_atlas, "Error reading atlas file."); - - _attachmentLoader = SUPER(Cocos2dAttachmentLoader_create(_atlas)); - - spSkeletonJson* json = spSkeletonJson_createWithLoader(_attachmentLoader); - json->scale = scale; - spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, skeletonDataFile.c_str()); - CCASSERT(skeletonData, json->error ? json->error : "Error reading skeleton data file."); - spSkeletonJson_dispose(json); - - setSkeletonData(skeletonData, true); - - initialize(); -} - -void SkeletonRenderer::initWithBinaryFile (const std::string& skeletonDataFile, spAtlas* atlas, float scale) { - _atlas = atlas; - _attachmentLoader = SUPER(Cocos2dAttachmentLoader_create(_atlas)); - - spSkeletonBinary* binary = spSkeletonBinary_createWithLoader(_attachmentLoader); - binary->scale = scale; - spSkeletonData* skeletonData = spSkeletonBinary_readSkeletonDataFile(binary, skeletonDataFile.c_str()); - CCASSERT(skeletonData, binary->error ? binary->error : "Error reading skeleton data file."); - spSkeletonBinary_dispose(binary); - - setSkeletonData(skeletonData, true); - - initialize(); -} - -void SkeletonRenderer::initWithBinaryFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) { - _atlas = spAtlas_createFromFile(atlasFile.c_str(), 0); - CCASSERT(_atlas, "Error reading atlas file."); - - _attachmentLoader = SUPER(Cocos2dAttachmentLoader_create(_atlas)); - - spSkeletonBinary* binary = spSkeletonBinary_createWithLoader(_attachmentLoader); - binary->scale = scale; - spSkeletonData* skeletonData = spSkeletonBinary_readSkeletonDataFile(binary, skeletonDataFile.c_str()); - CCASSERT(skeletonData, binary->error ? binary->error : "Error reading skeleton data file."); - spSkeletonBinary_dispose(binary); - - setSkeletonData(skeletonData, true); - - initialize(); -} - - -void SkeletonRenderer::update (float deltaTime) { - spSkeleton_update(_skeleton, deltaTime * _timeScale); -} - -void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t transformFlags) { - SkeletonBatch* batch = SkeletonBatch::getInstance(); - - Color3B nodeColor = getColor(); - _skeleton->r = nodeColor.r / (float)255; - _skeleton->g = nodeColor.g / (float)255; - _skeleton->b = nodeColor.b / (float)255; - _skeleton->a = getDisplayedOpacity() / (float)255; - - Color4F color; - AttachmentVertices* attachmentVertices = nullptr; - for (int i = 0, n = _skeleton->slotsCount; i < n; ++i) { - spSlot* slot = _skeleton->drawOrder[i]; - if (!slot->attachment) continue; - - switch (slot->attachment->type) { - case SP_ATTACHMENT_REGION: { - spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; - spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices); - attachmentVertices = getAttachmentVertices(attachment); - color.r = attachment->r; - color.g = attachment->g; - color.b = attachment->b; - color.a = attachment->a; - break; - } - case SP_ATTACHMENT_MESH: { - spMeshAttachment* attachment = (spMeshAttachment*)slot->attachment; - spMeshAttachment_computeWorldVertices(attachment, slot, _worldVertices); - attachmentVertices = getAttachmentVertices(attachment); - color.r = attachment->r; - color.g = attachment->g; - color.b = attachment->b; - color.a = attachment->a; - break; - } - default: - continue; - } - - color.a *= _skeleton->a * slot->a * 255; - float multiplier = _premultipliedAlpha ? color.a : 255; - color.r *= _skeleton->r * slot->r * multiplier; - color.g *= _skeleton->g * slot->g * multiplier; - color.b *= _skeleton->b * slot->b * multiplier; - - - - for (int v = 0, w = 0, vn = attachmentVertices->_triangles->vertCount; v < vn; ++v, w += 2) { - V3F_C4B_T2F* vertex = attachmentVertices->_triangles->verts + v; - vertex->vertices.x = _worldVertices[w]; - vertex->vertices.y = _worldVertices[w + 1]; - vertex->colors.r = (GLubyte)color.r; - vertex->colors.g = (GLubyte)color.g; - vertex->colors.b = (GLubyte)color.b; - vertex->colors.a = (GLubyte)color.a; - } - - BlendFunc blendFunc; - switch (slot->data->blendMode) { - case SP_BLEND_MODE_ADDITIVE: - blendFunc.src = _premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; - blendFunc.dst = GL_ONE; - break; - case SP_BLEND_MODE_MULTIPLY: - blendFunc.src = GL_DST_COLOR; - blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; - break; - case SP_BLEND_MODE_SCREEN: - blendFunc.src = GL_ONE; - blendFunc.dst = GL_ONE_MINUS_SRC_COLOR; - break; - default: - blendFunc.src = _premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; - blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; - } - - batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, - *attachmentVertices->_triangles, transform, transformFlags); - } - - if (_debugSlots || _debugBones) { - drawDebug(renderer, transform, transformFlags); - } -} - -void SkeletonRenderer::drawDebug (Renderer* renderer, const Mat4 &transform, uint32_t transformFlags) { - - Director* director = Director::getInstance(); - director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); - director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, transform); - - DrawNode* drawNode = DrawNode::create(); - - if (_debugSlots) { - // Slots. - // DrawPrimitives::setDrawColor4B(0, 0, 255, 255); - glLineWidth(1); - Vec2 points[4]; - V3F_C4B_T2F_Quad quad; - for (int i = 0, n = _skeleton->slotsCount; i < n; i++) { - spSlot* slot = _skeleton->drawOrder[i]; - if (!slot->attachment || slot->attachment->type != SP_ATTACHMENT_REGION) continue; - spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; - spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices); - points[0] = Vec2(_worldVertices[0], _worldVertices[1]); - points[1] = Vec2(_worldVertices[2], _worldVertices[3]); - points[2] = Vec2(_worldVertices[4], _worldVertices[5]); - points[3] = Vec2(_worldVertices[6], _worldVertices[7]); - drawNode->drawPoly(points, 4, true, Color4F::BLUE); - } - } - if (_debugBones) { - // Bone lengths. - glLineWidth(2); - for (int i = 0, n = _skeleton->bonesCount; i < n; i++) { - spBone *bone = _skeleton->bones[i]; - float x = bone->data->length * bone->a + bone->worldX; - float y = bone->data->length * bone->c + bone->worldY; - drawNode->drawLine(Vec2(bone->worldX, bone->worldY), Vec2(x, y), Color4F::RED); - } - // Bone origins. - auto color = Color4F::BLUE; // Root bone is blue. - for (int i = 0, n = _skeleton->bonesCount; i < n; i++) { - spBone *bone = _skeleton->bones[i]; - drawNode->drawPoint(Vec2(bone->worldX, bone->worldY), 4, color); - if (i == 0) color = Color4F::GREEN; - } - } - - drawNode->draw(renderer, transform, transformFlags); - director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); -} - -AttachmentVertices* SkeletonRenderer::getAttachmentVertices (spRegionAttachment* attachment) const { - return (AttachmentVertices*)attachment->rendererObject; -} - -AttachmentVertices* SkeletonRenderer::getAttachmentVertices (spMeshAttachment* attachment) const { - return (AttachmentVertices*)attachment->rendererObject; -} - -Rect SkeletonRenderer::getBoundingBox () const { - float minX = FLT_MAX, minY = FLT_MAX, maxX = -FLT_MAX, maxY = -FLT_MAX; - float scaleX = getScaleX(), scaleY = getScaleY(); - for (int i = 0; i < _skeleton->slotsCount; ++i) { - spSlot* slot = _skeleton->slots[i]; - if (!slot->attachment) continue; - int verticesCount; - if (slot->attachment->type == SP_ATTACHMENT_REGION) { - spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; - spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices); - verticesCount = 8; - } else if (slot->attachment->type == SP_ATTACHMENT_MESH) { - spMeshAttachment* mesh = (spMeshAttachment*)slot->attachment; - spMeshAttachment_computeWorldVertices(mesh, slot, _worldVertices); - verticesCount = mesh->super.worldVerticesLength; - } else - continue; - for (int ii = 0; ii < verticesCount; ii += 2) { - float x = _worldVertices[ii] * scaleX, y = _worldVertices[ii + 1] * scaleY; - minX = min(minX, x); - minY = min(minY, y); - maxX = max(maxX, x); - maxY = max(maxY, y); - } - } - Vec2 position = getPosition(); - if (minX == FLT_MAX) minX = minY = maxX = maxY = 0; - return Rect(position.x + minX, position.y + minY, maxX - minX, maxY - minY); -} - -// --- Convenience methods for Skeleton_* functions. - -void SkeletonRenderer::updateWorldTransform () { - spSkeleton_updateWorldTransform(_skeleton); -} - -void SkeletonRenderer::setToSetupPose () { - spSkeleton_setToSetupPose(_skeleton); -} -void SkeletonRenderer::setBonesToSetupPose () { - spSkeleton_setBonesToSetupPose(_skeleton); -} -void SkeletonRenderer::setSlotsToSetupPose () { - spSkeleton_setSlotsToSetupPose(_skeleton); -} - -spBone* SkeletonRenderer::findBone (const std::string& boneName) const { - return spSkeleton_findBone(_skeleton, boneName.c_str()); -} - -spSlot* SkeletonRenderer::findSlot (const std::string& slotName) const { - return spSkeleton_findSlot(_skeleton, slotName.c_str()); -} - -bool SkeletonRenderer::setSkin (const std::string& skinName) { - return spSkeleton_setSkinByName(_skeleton, skinName.empty() ? 0 : skinName.c_str()) ? true : false; -} -bool SkeletonRenderer::setSkin (const char* skinName) { - return spSkeleton_setSkinByName(_skeleton, skinName) ? true : false; -} - -spAttachment* SkeletonRenderer::getAttachment (const std::string& slotName, const std::string& attachmentName) const { - return spSkeleton_getAttachmentForSlotName(_skeleton, slotName.c_str(), attachmentName.c_str()); -} -bool SkeletonRenderer::setAttachment (const std::string& slotName, const std::string& attachmentName) { - return spSkeleton_setAttachment(_skeleton, slotName.c_str(), attachmentName.empty() ? 0 : attachmentName.c_str()) ? true : false; -} -bool SkeletonRenderer::setAttachment (const std::string& slotName, const char* attachmentName) { - return spSkeleton_setAttachment(_skeleton, slotName.c_str(), attachmentName) ? true : false; -} - -spSkeleton* SkeletonRenderer::getSkeleton () { - return _skeleton; -} - -void SkeletonRenderer::setTimeScale (float scale) { - _timeScale = scale; -} -float SkeletonRenderer::getTimeScale () const { - return _timeScale; -} - -void SkeletonRenderer::setDebugSlotsEnabled (bool enabled) { - _debugSlots = enabled; -} -bool SkeletonRenderer::getDebugSlotsEnabled () const { - return _debugSlots; -} - -void SkeletonRenderer::setDebugBonesEnabled (bool enabled) { - _debugBones = enabled; -} -bool SkeletonRenderer::getDebugBonesEnabled () const { - return _debugBones; -} - -void SkeletonRenderer::onEnter () { -#if CC_ENABLE_SCRIPT_BINDING - if (_scriptType == kScriptTypeJavascript && ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnEnter)) return; -#endif - Node::onEnter(); - scheduleUpdate(); -} - -void SkeletonRenderer::onExit () { -#if CC_ENABLE_SCRIPT_BINDING - if (_scriptType == kScriptTypeJavascript && ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnExit)) return; -#endif - Node::onExit(); - unscheduleUpdate(); -} - -// --- CCBlendProtocol - -const BlendFunc& SkeletonRenderer::getBlendFunc () const { - return _blendFunc; -} - -void SkeletonRenderer::setBlendFunc (const BlendFunc &blendFunc) { - _blendFunc = blendFunc; -} - -void SkeletonRenderer::setOpacityModifyRGB (bool value) { - _premultipliedAlpha = value; -} - -bool SkeletonRenderer::isOpacityModifyRGB () const { - return _premultipliedAlpha; -} - +#include +#include +#include +#include +#include +#include + +USING_NS_CC; +using std::min; +using std::max; + +namespace spine { + +SkeletonRenderer* SkeletonRenderer::createWithData (spSkeletonData* skeletonData, bool ownsSkeletonData) { + SkeletonRenderer* node = new SkeletonRenderer(skeletonData, ownsSkeletonData); + node->autorelease(); + return node; +} + +SkeletonRenderer* SkeletonRenderer::createWithFile (const std::string& skeletonDataFile, spAtlas* atlas, float scale) { + SkeletonRenderer* node = new SkeletonRenderer(skeletonDataFile, atlas, scale); + node->autorelease(); + return node; +} + +SkeletonRenderer* SkeletonRenderer::createWithFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) { + SkeletonRenderer* node = new SkeletonRenderer(skeletonDataFile, atlasFile, scale); + node->autorelease(); + return node; +} + +void SkeletonRenderer::initialize () { + _worldVertices = new float[1000]; // Max number of vertices per mesh. + + _blendFunc = BlendFunc::ALPHA_PREMULTIPLIED; + setOpacityModifyRGB(true); + + setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP)); +} + +void SkeletonRenderer::setSkeletonData (spSkeletonData *skeletonData, bool ownsSkeletonData) { + _skeleton = spSkeleton_create(skeletonData); + _ownsSkeletonData = ownsSkeletonData; +} + +SkeletonRenderer::SkeletonRenderer () + : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _timeScale(1) { +} + +SkeletonRenderer::SkeletonRenderer (spSkeletonData *skeletonData, bool ownsSkeletonData) + : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _timeScale(1) { + initWithData(skeletonData, ownsSkeletonData); +} + +SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, spAtlas* atlas, float scale) + : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _timeScale(1) { + initWithJsonFile(skeletonDataFile, atlas, scale); +} + +SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) + : _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _timeScale(1) { + initWithJsonFile(skeletonDataFile, atlasFile, scale); +} + +SkeletonRenderer::~SkeletonRenderer () { + if (_ownsSkeletonData) spSkeletonData_dispose(_skeleton->data); + spSkeleton_dispose(_skeleton); + if (_atlas) spAtlas_dispose(_atlas); + if (_attachmentLoader) spAttachmentLoader_dispose(_attachmentLoader); + delete [] _worldVertices; +} + +void SkeletonRenderer::initWithData (spSkeletonData* skeletonData, bool ownsSkeletonData) { + setSkeletonData(skeletonData, ownsSkeletonData); + + initialize(); +} + +void SkeletonRenderer::initWithJsonFile (const std::string& skeletonDataFile, spAtlas* atlas, float scale) { + _atlas = atlas; + _attachmentLoader = SUPER(Cocos2dAttachmentLoader_create(_atlas)); + + spSkeletonJson* json = spSkeletonJson_createWithLoader(_attachmentLoader); + json->scale = scale; + spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, skeletonDataFile.c_str()); + CCASSERT(skeletonData, json->error ? json->error : "Error reading skeleton data."); + spSkeletonJson_dispose(json); + + setSkeletonData(skeletonData, true); + + initialize(); +} + +void SkeletonRenderer::initWithJsonFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) { + _atlas = spAtlas_createFromFile(atlasFile.c_str(), 0); + CCASSERT(_atlas, "Error reading atlas file."); + + _attachmentLoader = SUPER(Cocos2dAttachmentLoader_create(_atlas)); + + spSkeletonJson* json = spSkeletonJson_createWithLoader(_attachmentLoader); + json->scale = scale; + spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, skeletonDataFile.c_str()); + CCASSERT(skeletonData, json->error ? json->error : "Error reading skeleton data file."); + spSkeletonJson_dispose(json); + + setSkeletonData(skeletonData, true); + + initialize(); +} + +void SkeletonRenderer::initWithBinaryFile (const std::string& skeletonDataFile, spAtlas* atlas, float scale) { + _atlas = atlas; + _attachmentLoader = SUPER(Cocos2dAttachmentLoader_create(_atlas)); + + spSkeletonBinary* binary = spSkeletonBinary_createWithLoader(_attachmentLoader); + binary->scale = scale; + spSkeletonData* skeletonData = spSkeletonBinary_readSkeletonDataFile(binary, skeletonDataFile.c_str()); + CCASSERT(skeletonData, binary->error ? binary->error : "Error reading skeleton data file."); + spSkeletonBinary_dispose(binary); + + setSkeletonData(skeletonData, true); + + initialize(); +} + +void SkeletonRenderer::initWithBinaryFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale) { + _atlas = spAtlas_createFromFile(atlasFile.c_str(), 0); + CCASSERT(_atlas, "Error reading atlas file."); + + _attachmentLoader = SUPER(Cocos2dAttachmentLoader_create(_atlas)); + + spSkeletonBinary* binary = spSkeletonBinary_createWithLoader(_attachmentLoader); + binary->scale = scale; + spSkeletonData* skeletonData = spSkeletonBinary_readSkeletonDataFile(binary, skeletonDataFile.c_str()); + CCASSERT(skeletonData, binary->error ? binary->error : "Error reading skeleton data file."); + spSkeletonBinary_dispose(binary); + + setSkeletonData(skeletonData, true); + + initialize(); +} + + +void SkeletonRenderer::update (float deltaTime) { + spSkeleton_update(_skeleton, deltaTime * _timeScale); +} + +void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t transformFlags) { + SkeletonBatch* batch = SkeletonBatch::getInstance(); + + Color3B nodeColor = getColor(); + _skeleton->r = nodeColor.r / (float)255; + _skeleton->g = nodeColor.g / (float)255; + _skeleton->b = nodeColor.b / (float)255; + _skeleton->a = getDisplayedOpacity() / (float)255; + + Color4F color; + AttachmentVertices* attachmentVertices = nullptr; + for (int i = 0, n = _skeleton->slotsCount; i < n; ++i) { + spSlot* slot = _skeleton->drawOrder[i]; + if (!slot->attachment) continue; + + switch (slot->attachment->type) { + case SP_ATTACHMENT_REGION: { + spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; + spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices); + attachmentVertices = getAttachmentVertices(attachment); + color.r = attachment->r; + color.g = attachment->g; + color.b = attachment->b; + color.a = attachment->a; + break; + } + case SP_ATTACHMENT_MESH: { + spMeshAttachment* attachment = (spMeshAttachment*)slot->attachment; + spMeshAttachment_computeWorldVertices(attachment, slot, _worldVertices); + attachmentVertices = getAttachmentVertices(attachment); + color.r = attachment->r; + color.g = attachment->g; + color.b = attachment->b; + color.a = attachment->a; + break; + } + default: + continue; + } + + color.a *= _skeleton->a * slot->a * 255; + float multiplier = _premultipliedAlpha ? color.a : 255; + color.r *= _skeleton->r * slot->r * multiplier; + color.g *= _skeleton->g * slot->g * multiplier; + color.b *= _skeleton->b * slot->b * multiplier; + + + + for (int v = 0, w = 0, vn = attachmentVertices->_triangles->vertCount; v < vn; ++v, w += 2) { + V3F_C4B_T2F* vertex = attachmentVertices->_triangles->verts + v; + vertex->vertices.x = _worldVertices[w]; + vertex->vertices.y = _worldVertices[w + 1]; + vertex->colors.r = (GLubyte)color.r; + vertex->colors.g = (GLubyte)color.g; + vertex->colors.b = (GLubyte)color.b; + vertex->colors.a = (GLubyte)color.a; + } + + BlendFunc blendFunc; + switch (slot->data->blendMode) { + case SP_BLEND_MODE_ADDITIVE: + blendFunc.src = _premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; + blendFunc.dst = GL_ONE; + break; + case SP_BLEND_MODE_MULTIPLY: + blendFunc.src = GL_DST_COLOR; + blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; + break; + case SP_BLEND_MODE_SCREEN: + blendFunc.src = GL_ONE; + blendFunc.dst = GL_ONE_MINUS_SRC_COLOR; + break; + default: + blendFunc.src = _premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; + blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA; + } + + batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, + *attachmentVertices->_triangles, transform, transformFlags); + } + + if (_debugSlots || _debugBones) { + drawDebug(renderer, transform, transformFlags); + } +} + +void SkeletonRenderer::drawDebug (Renderer* renderer, const Mat4 &transform, uint32_t transformFlags) { + + Director* director = Director::getInstance(); + director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); + director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, transform); + + DrawNode* drawNode = DrawNode::create(); + + if (_debugSlots) { + // Slots. + // DrawPrimitives::setDrawColor4B(0, 0, 255, 255); + glLineWidth(1); + Vec2 points[4]; + V3F_C4B_T2F_Quad quad; + for (int i = 0, n = _skeleton->slotsCount; i < n; i++) { + spSlot* slot = _skeleton->drawOrder[i]; + if (!slot->attachment || slot->attachment->type != SP_ATTACHMENT_REGION) continue; + spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; + spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices); + points[0] = Vec2(_worldVertices[0], _worldVertices[1]); + points[1] = Vec2(_worldVertices[2], _worldVertices[3]); + points[2] = Vec2(_worldVertices[4], _worldVertices[5]); + points[3] = Vec2(_worldVertices[6], _worldVertices[7]); + drawNode->drawPoly(points, 4, true, Color4F::BLUE); + } + } + if (_debugBones) { + // Bone lengths. + glLineWidth(2); + for (int i = 0, n = _skeleton->bonesCount; i < n; i++) { + spBone *bone = _skeleton->bones[i]; + float x = bone->data->length * bone->a + bone->worldX; + float y = bone->data->length * bone->c + bone->worldY; + drawNode->drawLine(Vec2(bone->worldX, bone->worldY), Vec2(x, y), Color4F::RED); + } + // Bone origins. + auto color = Color4F::BLUE; // Root bone is blue. + for (int i = 0, n = _skeleton->bonesCount; i < n; i++) { + spBone *bone = _skeleton->bones[i]; + drawNode->drawPoint(Vec2(bone->worldX, bone->worldY), 4, color); + if (i == 0) color = Color4F::GREEN; + } + } + + drawNode->draw(renderer, transform, transformFlags); + director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); +} + +AttachmentVertices* SkeletonRenderer::getAttachmentVertices (spRegionAttachment* attachment) const { + return (AttachmentVertices*)attachment->rendererObject; +} + +AttachmentVertices* SkeletonRenderer::getAttachmentVertices (spMeshAttachment* attachment) const { + return (AttachmentVertices*)attachment->rendererObject; +} + +Rect SkeletonRenderer::getBoundingBox () const { + float minX = FLT_MAX, minY = FLT_MAX, maxX = -FLT_MAX, maxY = -FLT_MAX; + float scaleX = getScaleX(), scaleY = getScaleY(); + for (int i = 0; i < _skeleton->slotsCount; ++i) { + spSlot* slot = _skeleton->slots[i]; + if (!slot->attachment) continue; + int verticesCount; + if (slot->attachment->type == SP_ATTACHMENT_REGION) { + spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; + spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices); + verticesCount = 8; + } else if (slot->attachment->type == SP_ATTACHMENT_MESH) { + spMeshAttachment* mesh = (spMeshAttachment*)slot->attachment; + spMeshAttachment_computeWorldVertices(mesh, slot, _worldVertices); + verticesCount = mesh->super.worldVerticesLength; + } else + continue; + for (int ii = 0; ii < verticesCount; ii += 2) { + float x = _worldVertices[ii] * scaleX, y = _worldVertices[ii + 1] * scaleY; + minX = min(minX, x); + minY = min(minY, y); + maxX = max(maxX, x); + maxY = max(maxY, y); + } + } + Vec2 position = getPosition(); + if (minX == FLT_MAX) minX = minY = maxX = maxY = 0; + return Rect(position.x + minX, position.y + minY, maxX - minX, maxY - minY); +} + +// --- Convenience methods for Skeleton_* functions. + +void SkeletonRenderer::updateWorldTransform () { + spSkeleton_updateWorldTransform(_skeleton); +} + +void SkeletonRenderer::setToSetupPose () { + spSkeleton_setToSetupPose(_skeleton); +} +void SkeletonRenderer::setBonesToSetupPose () { + spSkeleton_setBonesToSetupPose(_skeleton); +} +void SkeletonRenderer::setSlotsToSetupPose () { + spSkeleton_setSlotsToSetupPose(_skeleton); +} + +spBone* SkeletonRenderer::findBone (const std::string& boneName) const { + return spSkeleton_findBone(_skeleton, boneName.c_str()); +} + +spSlot* SkeletonRenderer::findSlot (const std::string& slotName) const { + return spSkeleton_findSlot(_skeleton, slotName.c_str()); +} + +bool SkeletonRenderer::setSkin (const std::string& skinName) { + return spSkeleton_setSkinByName(_skeleton, skinName.empty() ? 0 : skinName.c_str()) ? true : false; +} +bool SkeletonRenderer::setSkin (const char* skinName) { + return spSkeleton_setSkinByName(_skeleton, skinName) ? true : false; +} + +spAttachment* SkeletonRenderer::getAttachment (const std::string& slotName, const std::string& attachmentName) const { + return spSkeleton_getAttachmentForSlotName(_skeleton, slotName.c_str(), attachmentName.c_str()); +} +bool SkeletonRenderer::setAttachment (const std::string& slotName, const std::string& attachmentName) { + return spSkeleton_setAttachment(_skeleton, slotName.c_str(), attachmentName.empty() ? 0 : attachmentName.c_str()) ? true : false; +} +bool SkeletonRenderer::setAttachment (const std::string& slotName, const char* attachmentName) { + return spSkeleton_setAttachment(_skeleton, slotName.c_str(), attachmentName) ? true : false; +} + +spSkeleton* SkeletonRenderer::getSkeleton () { + return _skeleton; +} + +void SkeletonRenderer::setTimeScale (float scale) { + _timeScale = scale; +} +float SkeletonRenderer::getTimeScale () const { + return _timeScale; +} + +void SkeletonRenderer::setDebugSlotsEnabled (bool enabled) { + _debugSlots = enabled; +} +bool SkeletonRenderer::getDebugSlotsEnabled () const { + return _debugSlots; +} + +void SkeletonRenderer::setDebugBonesEnabled (bool enabled) { + _debugBones = enabled; +} +bool SkeletonRenderer::getDebugBonesEnabled () const { + return _debugBones; +} + +void SkeletonRenderer::onEnter () { +#if CC_ENABLE_SCRIPT_BINDING + if (_scriptType == kScriptTypeJavascript && ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnEnter)) return; +#endif + Node::onEnter(); + scheduleUpdate(); +} + +void SkeletonRenderer::onExit () { +#if CC_ENABLE_SCRIPT_BINDING + if (_scriptType == kScriptTypeJavascript && ScriptEngineManager::sendNodeEventToJSExtended(this, kNodeOnExit)) return; +#endif + Node::onExit(); + unscheduleUpdate(); +} + +// --- CCBlendProtocol + +const BlendFunc& SkeletonRenderer::getBlendFunc () const { + return _blendFunc; +} + +void SkeletonRenderer::setBlendFunc (const BlendFunc &blendFunc) { + _blendFunc = blendFunc; +} + +void SkeletonRenderer::setOpacityModifyRGB (bool value) { + _premultipliedAlpha = value; +} + +bool SkeletonRenderer::isOpacityModifyRGB () const { + return _premultipliedAlpha; +} + } diff --git a/spine-cocos2dx/src/spine/SkeletonRenderer.h b/spine-cocos2dx/src/spine/SkeletonRenderer.h index 2d33451026..ac1efac5cd 100644 --- a/spine-cocos2dx/src/spine/SkeletonRenderer.h +++ b/spine-cocos2dx/src/spine/SkeletonRenderer.h @@ -1,138 +1,137 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_SKELETONRENDERER_H_ -#define SPINE_SKELETONRENDERER_H_ - -#include -#include "cocos2d.h" - -namespace spine { - -class AttachmentVertices; - -/* Draws a skeleton. */ -class SkeletonRenderer: public cocos2d::Node, public cocos2d::BlendProtocol { -public: - CREATE_FUNC(SkeletonRenderer); - static SkeletonRenderer* createWithData (spSkeletonData* skeletonData, bool ownsSkeletonData = false); - static SkeletonRenderer* createWithFile (const std::string& skeletonDataFile, spAtlas* atlas, float scale = 1); - static SkeletonRenderer* createWithFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1); - - virtual void update (float deltaTime) override; - virtual void draw (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags) override; - virtual void drawDebug (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags); - virtual cocos2d::Rect getBoundingBox () const override; - virtual void onEnter () override; - virtual void onExit () override; - - spSkeleton* getSkeleton(); - - void setTimeScale(float scale); - float getTimeScale() const; - - /* */ - void setDebugSlotsEnabled(bool enabled); - bool getDebugSlotsEnabled() const; - - void setDebugBonesEnabled(bool enabled); - bool getDebugBonesEnabled() const; - - // --- Convenience methods for common Skeleton_* functions. - void updateWorldTransform (); - - void setToSetupPose (); - void setBonesToSetupPose (); - void setSlotsToSetupPose (); - - /* Returns 0 if the bone was not found. */ - spBone* findBone (const std::string& boneName) const; - /* Returns 0 if the slot was not found. */ - spSlot* findSlot (const std::string& slotName) const; - - /* Sets the skin used to look up attachments not found in the SkeletonData defaultSkin. Attachments from the new skin are - * attached if the corresponding attachment from the old skin was attached. Returns false if the skin was not found. - * @param skin May be empty string ("") for no skin.*/ - bool setSkin (const std::string& skinName); - /** @param skin May be 0 for no skin.*/ - bool setSkin (const char* skinName); - - /* Returns 0 if the slot or attachment was not found. */ - spAttachment* getAttachment (const std::string& slotName, const std::string& attachmentName) const; - /* Returns false if the slot or attachment was not found. - * @param attachmentName May be empty string ("") for no attachment. */ - bool setAttachment (const std::string& slotName, const std::string& attachmentName); - /* @param attachmentName May be 0 for no attachment. */ - bool setAttachment (const std::string& slotName, const char* attachmentName); - - // --- BlendProtocol - virtual void setBlendFunc (const cocos2d::BlendFunc& blendFunc)override; - virtual const cocos2d::BlendFunc& getBlendFunc () const override; - virtual void setOpacityModifyRGB (bool value) override; - virtual bool isOpacityModifyRGB () const override; - -CC_CONSTRUCTOR_ACCESS: - SkeletonRenderer (); - SkeletonRenderer (spSkeletonData* skeletonData, bool ownsSkeletonData = false); - SkeletonRenderer (const std::string& skeletonDataFile, spAtlas* atlas, float scale = 1); - SkeletonRenderer (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1); - - virtual ~SkeletonRenderer (); - - void initWithData (spSkeletonData* skeletonData, bool ownsSkeletonData = false); - void initWithJsonFile (const std::string& skeletonDataFile, spAtlas* atlas, float scale = 1); - void initWithJsonFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1); - void initWithBinaryFile (const std::string& skeletonDataFile, spAtlas* atlas, float scale = 1); - void initWithBinaryFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1); - - virtual void initialize (); - -protected: - void setSkeletonData (spSkeletonData* skeletonData, bool ownsSkeletonData); - virtual AttachmentVertices* getAttachmentVertices (spRegionAttachment* attachment) const; - virtual AttachmentVertices* getAttachmentVertices (spMeshAttachment* attachment) const; - - bool _ownsSkeletonData; - spAtlas* _atlas; - spAttachmentLoader* _attachmentLoader; - cocos2d::CustomCommand _debugCommand; - cocos2d::BlendFunc _blendFunc; - float* _worldVertices; - bool _premultipliedAlpha; - spSkeleton* _skeleton; - float _timeScale; - bool _debugSlots; - bool _debugBones; -}; - -} - +#ifndef SPINE_SKELETONRENDERER_H_ +#define SPINE_SKELETONRENDERER_H_ + +#include +#include "cocos2d.h" + +namespace spine { + +class AttachmentVertices; + +/* Draws a skeleton. */ +class SkeletonRenderer: public cocos2d::Node, public cocos2d::BlendProtocol { +public: + CREATE_FUNC(SkeletonRenderer); + static SkeletonRenderer* createWithData (spSkeletonData* skeletonData, bool ownsSkeletonData = false); + static SkeletonRenderer* createWithFile (const std::string& skeletonDataFile, spAtlas* atlas, float scale = 1); + static SkeletonRenderer* createWithFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1); + + virtual void update (float deltaTime) override; + virtual void draw (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags) override; + virtual void drawDebug (cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t transformFlags); + virtual cocos2d::Rect getBoundingBox () const override; + virtual void onEnter () override; + virtual void onExit () override; + + spSkeleton* getSkeleton(); + + void setTimeScale(float scale); + float getTimeScale() const; + + /* */ + void setDebugSlotsEnabled(bool enabled); + bool getDebugSlotsEnabled() const; + + void setDebugBonesEnabled(bool enabled); + bool getDebugBonesEnabled() const; + + // --- Convenience methods for common Skeleton_* functions. + void updateWorldTransform (); + + void setToSetupPose (); + void setBonesToSetupPose (); + void setSlotsToSetupPose (); + + /* Returns 0 if the bone was not found. */ + spBone* findBone (const std::string& boneName) const; + /* Returns 0 if the slot was not found. */ + spSlot* findSlot (const std::string& slotName) const; + + /* Sets the skin used to look up attachments not found in the SkeletonData defaultSkin. Attachments from the new skin are + * attached if the corresponding attachment from the old skin was attached. Returns false if the skin was not found. + * @param skin May be empty string ("") for no skin.*/ + bool setSkin (const std::string& skinName); + /** @param skin May be 0 for no skin.*/ + bool setSkin (const char* skinName); + + /* Returns 0 if the slot or attachment was not found. */ + spAttachment* getAttachment (const std::string& slotName, const std::string& attachmentName) const; + /* Returns false if the slot or attachment was not found. + * @param attachmentName May be empty string ("") for no attachment. */ + bool setAttachment (const std::string& slotName, const std::string& attachmentName); + /* @param attachmentName May be 0 for no attachment. */ + bool setAttachment (const std::string& slotName, const char* attachmentName); + + // --- BlendProtocol + virtual void setBlendFunc (const cocos2d::BlendFunc& blendFunc)override; + virtual const cocos2d::BlendFunc& getBlendFunc () const override; + virtual void setOpacityModifyRGB (bool value) override; + virtual bool isOpacityModifyRGB () const override; + +CC_CONSTRUCTOR_ACCESS: + SkeletonRenderer (); + SkeletonRenderer (spSkeletonData* skeletonData, bool ownsSkeletonData = false); + SkeletonRenderer (const std::string& skeletonDataFile, spAtlas* atlas, float scale = 1); + SkeletonRenderer (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1); + + virtual ~SkeletonRenderer (); + + void initWithData (spSkeletonData* skeletonData, bool ownsSkeletonData = false); + void initWithJsonFile (const std::string& skeletonDataFile, spAtlas* atlas, float scale = 1); + void initWithJsonFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1); + void initWithBinaryFile (const std::string& skeletonDataFile, spAtlas* atlas, float scale = 1); + void initWithBinaryFile (const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1); + + virtual void initialize (); + +protected: + void setSkeletonData (spSkeletonData* skeletonData, bool ownsSkeletonData); + virtual AttachmentVertices* getAttachmentVertices (spRegionAttachment* attachment) const; + virtual AttachmentVertices* getAttachmentVertices (spMeshAttachment* attachment) const; + + bool _ownsSkeletonData; + spAtlas* _atlas; + spAttachmentLoader* _attachmentLoader; + cocos2d::CustomCommand _debugCommand; + cocos2d::BlendFunc _blendFunc; + float* _worldVertices; + bool _premultipliedAlpha; + spSkeleton* _skeleton; + float _timeScale; + bool _debugSlots; + bool _debugBones; +}; + +} + #endif /* SPINE_SKELETONRENDERER_H_ */ diff --git a/spine-cocos2dx/src/spine/spine-cocos2dx.cpp b/spine-cocos2dx/src/spine/spine-cocos2dx.cpp index da7d3fa6d2..44c4f9e9f4 100644 --- a/spine-cocos2dx/src/spine/spine-cocos2dx.cpp +++ b/spine-cocos2dx/src/spine/spine-cocos2dx.cpp @@ -1,96 +1,95 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include - -USING_NS_CC; - -GLuint wrap (spAtlasWrap wrap) { - return wrap == SP_ATLAS_CLAMPTOEDGE ? GL_CLAMP_TO_EDGE : GL_REPEAT; -} - -GLuint filter (spAtlasFilter filter) { - switch (filter) { - case SP_ATLAS_UNKNOWN_FILTER: - break; - case SP_ATLAS_NEAREST: - return GL_NEAREST; - case SP_ATLAS_LINEAR: - return GL_LINEAR; - case SP_ATLAS_MIPMAP: - return GL_LINEAR_MIPMAP_LINEAR; - case SP_ATLAS_MIPMAP_NEAREST_NEAREST: - return GL_NEAREST_MIPMAP_NEAREST; - case SP_ATLAS_MIPMAP_LINEAR_NEAREST: - return GL_LINEAR_MIPMAP_NEAREST; - case SP_ATLAS_MIPMAP_NEAREST_LINEAR: - return GL_NEAREST_MIPMAP_LINEAR; - case SP_ATLAS_MIPMAP_LINEAR_LINEAR: - return GL_LINEAR_MIPMAP_LINEAR; - } - return GL_LINEAR; -} - -void _spAtlasPage_createTexture (spAtlasPage* self, const char* path) { - Texture2D* texture = Director::getInstance()->getTextureCache()->addImage(path); - CCASSERT(texture != nullptr, "Invalid image"); - texture->retain(); - - Texture2D::TexParams textureParams = {filter(self->minFilter), filter(self->magFilter), wrap(self->uWrap), wrap(self->vWrap)}; - texture->setTexParameters(textureParams); - - self->rendererObject = texture; - self->width = texture->getPixelsWide(); - self->height = texture->getPixelsHigh(); -} - -void _spAtlasPage_disposeTexture (spAtlasPage* self) { - ((Texture2D*)self->rendererObject)->release(); -} - -char* _spUtil_readFile (const char* path, int* length) { - Data data = FileUtils::getInstance()->getDataFromFile(FileUtils::getInstance()->fullPathForFilename(path)); - if (data.isNull()) return 0; - - // avoid buffer overflow (int is shorter than ssize_t in certain platforms) -#if COCOS2D_VERSION >= 0x00031200 - ssize_t tmpLen; - char *ret = (char*)data.takeBuffer(&tmpLen); - *length = static_cast(tmpLen); - return ret; -#else - *length = static_cast(data.getSize()); - char* bytes = MALLOC(char, *length); - memcpy(bytes, data.getBytes(), *length); - return bytes; -#endif +#include +#include + +USING_NS_CC; + +GLuint wrap (spAtlasWrap wrap) { + return wrap == SP_ATLAS_CLAMPTOEDGE ? GL_CLAMP_TO_EDGE : GL_REPEAT; +} + +GLuint filter (spAtlasFilter filter) { + switch (filter) { + case SP_ATLAS_UNKNOWN_FILTER: + break; + case SP_ATLAS_NEAREST: + return GL_NEAREST; + case SP_ATLAS_LINEAR: + return GL_LINEAR; + case SP_ATLAS_MIPMAP: + return GL_LINEAR_MIPMAP_LINEAR; + case SP_ATLAS_MIPMAP_NEAREST_NEAREST: + return GL_NEAREST_MIPMAP_NEAREST; + case SP_ATLAS_MIPMAP_LINEAR_NEAREST: + return GL_LINEAR_MIPMAP_NEAREST; + case SP_ATLAS_MIPMAP_NEAREST_LINEAR: + return GL_NEAREST_MIPMAP_LINEAR; + case SP_ATLAS_MIPMAP_LINEAR_LINEAR: + return GL_LINEAR_MIPMAP_LINEAR; + } + return GL_LINEAR; +} + +void _spAtlasPage_createTexture (spAtlasPage* self, const char* path) { + Texture2D* texture = Director::getInstance()->getTextureCache()->addImage(path); + CCASSERT(texture != nullptr, "Invalid image"); + texture->retain(); + + Texture2D::TexParams textureParams = {filter(self->minFilter), filter(self->magFilter), wrap(self->uWrap), wrap(self->vWrap)}; + texture->setTexParameters(textureParams); + + self->rendererObject = texture; + self->width = texture->getPixelsWide(); + self->height = texture->getPixelsHigh(); +} + +void _spAtlasPage_disposeTexture (spAtlasPage* self) { + ((Texture2D*)self->rendererObject)->release(); +} + +char* _spUtil_readFile (const char* path, int* length) { + Data data = FileUtils::getInstance()->getDataFromFile(FileUtils::getInstance()->fullPathForFilename(path)); + if (data.isNull()) return 0; + + // avoid buffer overflow (int is shorter than ssize_t in certain platforms) +#if COCOS2D_VERSION >= 0x00031200 + ssize_t tmpLen; + char *ret = (char*)data.takeBuffer(&tmpLen); + *length = static_cast(tmpLen); + return ret; +#else + *length = static_cast(data.getSize()); + char* bytes = MALLOC(char, *length); + memcpy(bytes, data.getBytes(), *length); + return bytes; +#endif } diff --git a/spine-cocos2dx/src/spine/spine-cocos2dx.h b/spine-cocos2dx/src/spine/spine-cocos2dx.h index 447c0b84af..88a4388c57 100644 --- a/spine-cocos2dx/src/spine/spine-cocos2dx.h +++ b/spine-cocos2dx/src/spine/spine-cocos2dx.h @@ -1,42 +1,41 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_COCOS2DX_H_ -#define SPINE_COCOS2DX_H_ - -#include -#include "cocos2d.h" -#include -#include -#include -#include - +#ifndef SPINE_COCOS2DX_H_ +#define SPINE_COCOS2DX_H_ + +#include +#include "cocos2d.h" +#include +#include +#include +#include + #endif /* SPINE_COCOS2DX_H_ */ diff --git a/spine-corona/spine-corona/spine.lua b/spine-corona/spine-corona/spine.lua index 0d68cf1b28..11dd486067 100644 --- a/spine-corona/spine-corona/spine.lua +++ b/spine-corona/spine-corona/spine.lua @@ -1,221 +1,220 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -spine = {} - -spine.utils = require "spine-lua.utils" -spine.SkeletonJson = require "spine-lua.SkeletonJson" -spine.SkeletonData = require "spine-lua.SkeletonData" -spine.BoneData = require "spine-lua.BoneData" -spine.SlotData = require "spine-lua.SlotData" -spine.IkConstraintData = require "spine-lua.IkConstraintData" -spine.Skin = require "spine-lua.Skin" -spine.Attachment = require "spine-lua.attachments.Attachment" -spine.BoundingBoxAttachment = require "spine-lua.attachments.BoundingBoxAttachment" -spine.RegionAttachment = require "spine-lua.attachments.RegionAttachment" -spine.MeshAttachment = require "spine-lua.attachments.MeshAttachment" -spine.VertexAttachment = require "spine-lua.attachments.VertexAttachment" -spine.PathAttachment = require "spine-lua.attachments.PathAttachment" -spine.Skeleton = require "spine-lua.Skeleton" -spine.Bone = require "spine-lua.Bone" -spine.Slot = require "spine-lua.Slot" -spine.IkConstraint = require "spine-lua.IkConstraint" -spine.AttachmentType = require "spine-lua.attachments.AttachmentType" -spine.AttachmentLoader = require "spine-lua.AttachmentLoader" -spine.Animation = require "spine-lua.Animation" -spine.AnimationStateData = require "spine-lua.AnimationStateData" -spine.AnimationState = require "spine-lua.AnimationState" -spine.EventData = require "spine-lua.EventData" -spine.Event = require "spine-lua.Event" -spine.SkeletonBounds = require "spine-lua.SkeletonBounds" -spine.BlendMode = require "spine-lua.BlendMode" -spine.TextureAtlas = require "spine-lua.TextureAtlas" -spine.TextureRegion = require "spine-lua.TextureRegion" -spine.TextureAtlasRegion = require "spine-lua.TextureAtlasRegion" -spine.TextureAtlasAttachmentLoader = require "spine-lua.TextureAtlasAttachmentLoader" -spine.Color = require "spine-lua.Color" - -spine.utils.readFile = function (fileName, base) - if not base then base = system.ResourceDirectory end - local path = system.pathForFile(fileName, base) - local file = io.open(path, "r") - if not file then return nil end - local contents = file:read("*a") - io.close(file) - return contents -end - -local json = require "json" -spine.utils.readJSON = function (text) - return json.decode(text) -end - -local QUAD_TRIANGLES = { 1, 2, 3, 3, 4, 1 } -spine.Skeleton.new_super = spine.Skeleton.new -spine.Skeleton.updateWorldTransform_super = spine.Skeleton.updateWorldTransform -spine.Skeleton.new = function(skeletonData, group) - self = spine.Skeleton.new_super(skeletonData) - self.group = group or display.newGroup() - self.drawingGroup = nil - self.premultipliedAlpha = false - self.batches = 0 - return self -end - -local function colorEquals(color1, color2) - if not color1 and not color2 then return true end - if not color1 and color2 then return false end - if color1 and not color2 then return false end - return color1[1] == color2[1] and color1[2] == color2[2] and color1[3] == color2[3] and color1[4] == color2[4] -end - -local function toCoronaBlendMode(blendMode) - if blendMode == spine.BlendMode.normal then - return "normal" - elseif blendMode == spine.BlendMode.additive then - return "add" - elseif blendMode == spine.BlendMode.multiply then - return "multiply" - elseif blendMode == spine.BlendMode.screen then - return "screen" - end -end - -function spine.Skeleton:updateWorldTransform() - spine.Skeleton.updateWorldTransform_super(self) - local premultipliedAlpha = self.premultipliedAlpha - - self.batches = 0 - - -- Remove old drawing group, we will start anew - if self.drawingGroup then self.drawingGroup:removeSelf() end - local drawingGroup = display.newGroup() - self.drawingGroup = drawingGroup - self.group:insert(drawingGroup) - - local drawOrder = self.drawOrder - local currentGroup = nil - local groupVertices = {} - local groupIndices = {} - local groupUvs = {} - local color = nil - local lastColor = nil - local texture = nil - local lastTexture = nil - local blendMode = nil - local lastBlendMode = nil - for i,slot in ipairs(drawOrder) do - local attachment = slot.attachment - local vertices = nil - local indices = nil - if attachment then - if attachment.type == spine.AttachmentType.region then - vertices = attachment:updateWorldVertices(slot, premultipliedAlpha) - indices = QUAD_TRIANGLES - texture = attachment.region.renderObject.texture - color = { vertices[5], vertices[6], vertices[7], vertices[8]} - blendMode = toCoronaBlendMode(slot.data.blendMode) - elseif attachment.type == spine.AttachmentType.mesh then - vertices = attachment:updateWorldVertices(slot, premultipliedAlpha) - indices = attachment.triangles - texture = attachment.region.renderObject.texture - color = { vertices[5], vertices[6], vertices[7], vertices[8] } - blendMode = toCoronaBlendMode(slot.data.blendMode) - end - - if texture and vertices and indices then - if not lastTexture then lastTexture = texture end - if not lastColor then lastColor = color end - if not lastBlendMode then lastBlendMode = blendMode end - - if (texture ~= lastTexture or not colorEquals(color, lastColor) or blendMode ~= lastBlendMode) then - self:flush(groupVertices, groupUvs, groupIndices, lastTexture, lastColor, lastBlendMode, drawingGroup) - lastTexture = texture - lastColor = color - lastBlendMode = blendMode - groupVertices = {} - groupUvs = {} - groupIndices = {} - end - - self:batch(vertices, indices, groupVertices, groupUvs, groupIndices) - end - end - end - - if #groupVertices > 0 then - self:flush(groupVertices, groupUvs, groupIndices, texture, color, blendMode, drawingGroup) - end -end - -function spine.Skeleton:flush(groupVertices, groupUvs, groupIndices, texture, color, blendMode, drawingGroup) - mesh = display.newMesh(drawingGroup, 0, 0, { - mode = "indexed", - vertices = groupVertices, - uvs = groupUvs, - indices = groupIndices - }) - mesh.fill = texture - mesh:setFillColor(color[1], color[2], color[3]) - mesh.alpha = color[4] - mesh.blendMode = blendMode - mesh:translate(mesh.path:getVertexOffset()) - self.batches = self.batches + 1 -end - -function spine.Skeleton:batch(vertices, indices, groupVertices, groupUvs, groupIndices) - local numIndices = #indices - local i = 1 - local indexStart = #groupIndices + 1 - local offset = #groupVertices / 2 - local indexEnd = indexStart + numIndices - - while indexStart < indexEnd do - groupIndices[indexStart] = indices[i] + offset - indexStart = indexStart + 1 - i = i + 1 - end - - i = 1 - local numVertices = #vertices - local vertexStart = #groupVertices + 1 - local vertexEnd = vertexStart + numVertices / 4 - while vertexStart < vertexEnd do - groupVertices[vertexStart] = vertices[i] - groupVertices[vertexStart+1] = vertices[i+1] - groupUvs[vertexStart] = vertices[i+2] - groupUvs[vertexStart+1] = vertices[i+3] - vertexStart = vertexStart + 2 - i = i + 8 - end -end -return spine \ No newline at end of file +spine = {} + +spine.utils = require "spine-lua.utils" +spine.SkeletonJson = require "spine-lua.SkeletonJson" +spine.SkeletonData = require "spine-lua.SkeletonData" +spine.BoneData = require "spine-lua.BoneData" +spine.SlotData = require "spine-lua.SlotData" +spine.IkConstraintData = require "spine-lua.IkConstraintData" +spine.Skin = require "spine-lua.Skin" +spine.Attachment = require "spine-lua.attachments.Attachment" +spine.BoundingBoxAttachment = require "spine-lua.attachments.BoundingBoxAttachment" +spine.RegionAttachment = require "spine-lua.attachments.RegionAttachment" +spine.MeshAttachment = require "spine-lua.attachments.MeshAttachment" +spine.VertexAttachment = require "spine-lua.attachments.VertexAttachment" +spine.PathAttachment = require "spine-lua.attachments.PathAttachment" +spine.Skeleton = require "spine-lua.Skeleton" +spine.Bone = require "spine-lua.Bone" +spine.Slot = require "spine-lua.Slot" +spine.IkConstraint = require "spine-lua.IkConstraint" +spine.AttachmentType = require "spine-lua.attachments.AttachmentType" +spine.AttachmentLoader = require "spine-lua.AttachmentLoader" +spine.Animation = require "spine-lua.Animation" +spine.AnimationStateData = require "spine-lua.AnimationStateData" +spine.AnimationState = require "spine-lua.AnimationState" +spine.EventData = require "spine-lua.EventData" +spine.Event = require "spine-lua.Event" +spine.SkeletonBounds = require "spine-lua.SkeletonBounds" +spine.BlendMode = require "spine-lua.BlendMode" +spine.TextureAtlas = require "spine-lua.TextureAtlas" +spine.TextureRegion = require "spine-lua.TextureRegion" +spine.TextureAtlasRegion = require "spine-lua.TextureAtlasRegion" +spine.TextureAtlasAttachmentLoader = require "spine-lua.TextureAtlasAttachmentLoader" +spine.Color = require "spine-lua.Color" + +spine.utils.readFile = function (fileName, base) + if not base then base = system.ResourceDirectory end + local path = system.pathForFile(fileName, base) + local file = io.open(path, "r") + if not file then return nil end + local contents = file:read("*a") + io.close(file) + return contents +end + +local json = require "json" +spine.utils.readJSON = function (text) + return json.decode(text) +end + +local QUAD_TRIANGLES = { 1, 2, 3, 3, 4, 1 } +spine.Skeleton.new_super = spine.Skeleton.new +spine.Skeleton.updateWorldTransform_super = spine.Skeleton.updateWorldTransform +spine.Skeleton.new = function(skeletonData, group) + self = spine.Skeleton.new_super(skeletonData) + self.group = group or display.newGroup() + self.drawingGroup = nil + self.premultipliedAlpha = false + self.batches = 0 + return self +end + +local function colorEquals(color1, color2) + if not color1 and not color2 then return true end + if not color1 and color2 then return false end + if color1 and not color2 then return false end + return color1[1] == color2[1] and color1[2] == color2[2] and color1[3] == color2[3] and color1[4] == color2[4] +end + +local function toCoronaBlendMode(blendMode) + if blendMode == spine.BlendMode.normal then + return "normal" + elseif blendMode == spine.BlendMode.additive then + return "add" + elseif blendMode == spine.BlendMode.multiply then + return "multiply" + elseif blendMode == spine.BlendMode.screen then + return "screen" + end +end + +function spine.Skeleton:updateWorldTransform() + spine.Skeleton.updateWorldTransform_super(self) + local premultipliedAlpha = self.premultipliedAlpha + + self.batches = 0 + + -- Remove old drawing group, we will start anew + if self.drawingGroup then self.drawingGroup:removeSelf() end + local drawingGroup = display.newGroup() + self.drawingGroup = drawingGroup + self.group:insert(drawingGroup) + + local drawOrder = self.drawOrder + local currentGroup = nil + local groupVertices = {} + local groupIndices = {} + local groupUvs = {} + local color = nil + local lastColor = nil + local texture = nil + local lastTexture = nil + local blendMode = nil + local lastBlendMode = nil + for i,slot in ipairs(drawOrder) do + local attachment = slot.attachment + local vertices = nil + local indices = nil + if attachment then + if attachment.type == spine.AttachmentType.region then + vertices = attachment:updateWorldVertices(slot, premultipliedAlpha) + indices = QUAD_TRIANGLES + texture = attachment.region.renderObject.texture + color = { vertices[5], vertices[6], vertices[7], vertices[8]} + blendMode = toCoronaBlendMode(slot.data.blendMode) + elseif attachment.type == spine.AttachmentType.mesh then + vertices = attachment:updateWorldVertices(slot, premultipliedAlpha) + indices = attachment.triangles + texture = attachment.region.renderObject.texture + color = { vertices[5], vertices[6], vertices[7], vertices[8] } + blendMode = toCoronaBlendMode(slot.data.blendMode) + end + + if texture and vertices and indices then + if not lastTexture then lastTexture = texture end + if not lastColor then lastColor = color end + if not lastBlendMode then lastBlendMode = blendMode end + + if (texture ~= lastTexture or not colorEquals(color, lastColor) or blendMode ~= lastBlendMode) then + self:flush(groupVertices, groupUvs, groupIndices, lastTexture, lastColor, lastBlendMode, drawingGroup) + lastTexture = texture + lastColor = color + lastBlendMode = blendMode + groupVertices = {} + groupUvs = {} + groupIndices = {} + end + + self:batch(vertices, indices, groupVertices, groupUvs, groupIndices) + end + end + end + + if #groupVertices > 0 then + self:flush(groupVertices, groupUvs, groupIndices, texture, color, blendMode, drawingGroup) + end +end + +function spine.Skeleton:flush(groupVertices, groupUvs, groupIndices, texture, color, blendMode, drawingGroup) + mesh = display.newMesh(drawingGroup, 0, 0, { + mode = "indexed", + vertices = groupVertices, + uvs = groupUvs, + indices = groupIndices + }) + mesh.fill = texture + mesh:setFillColor(color[1], color[2], color[3]) + mesh.alpha = color[4] + mesh.blendMode = blendMode + mesh:translate(mesh.path:getVertexOffset()) + self.batches = self.batches + 1 +end + +function spine.Skeleton:batch(vertices, indices, groupVertices, groupUvs, groupIndices) + local numIndices = #indices + local i = 1 + local indexStart = #groupIndices + 1 + local offset = #groupVertices / 2 + local indexEnd = indexStart + numIndices + + while indexStart < indexEnd do + groupIndices[indexStart] = indices[i] + offset + indexStart = indexStart + 1 + i = i + 1 + end + + i = 1 + local numVertices = #vertices + local vertexStart = #groupVertices + 1 + local vertexEnd = vertexStart + numVertices / 4 + while vertexStart < vertexEnd do + groupVertices[vertexStart] = vertices[i] + groupVertices[vertexStart+1] = vertices[i+1] + groupUvs[vertexStart] = vertices[i+2] + groupUvs[vertexStart+1] = vertices[i+3] + vertexStart = vertexStart + 2 + i = i + 8 + end +end + +return spine diff --git a/spine-csharp/src/Animation.cs b/spine-csharp/src/Animation.cs index e56e4ae33c..dc9315b8ed 100644 --- a/spine-csharp/src/Animation.cs +++ b/spine-csharp/src/Animation.cs @@ -1,875 +1,874 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using System.Collections.Generic; - -namespace Spine { - public class Animation { - internal ExposedList timelines; - internal float duration; - internal String name; - - public String Name { get { return name; } } - public ExposedList Timelines { get { return timelines; } set { timelines = value; } } - public float Duration { get { return duration; } set { duration = value; } } - - public Animation (String name, ExposedList timelines, float duration) { - if (name == null) throw new ArgumentNullException("name", "name cannot be null."); - if (timelines == null) throw new ArgumentNullException("timelines", "timelines cannot be null."); - this.name = name; - this.timelines = timelines; - this.duration = duration; - } - - ///

Poses the skeleton at the specified time for this animation. - /// The last time the animation was applied. - /// Any triggered events are added. May be null. - public void Apply (Skeleton skeleton, float lastTime, float time, bool loop, ExposedList events) { - if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null."); - - if (loop && duration != 0) { - time %= duration; - if (lastTime > 0) lastTime %= duration; - } - - ExposedList timelines = this.timelines; - for (int i = 0, n = timelines.Count; i < n; i++) - timelines.Items[i].Apply(skeleton, lastTime, time, events, 1); - } - - /// Poses the skeleton at the specified time for this animation mixed with the current pose. - /// The last time the animation was applied. - /// Any triggered events are added. May be null. - /// The amount of this animation that affects the current pose. - public void Mix (Skeleton skeleton, float lastTime, float time, bool loop, ExposedList events, float alpha) { - if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null."); - - if (loop && duration != 0) { - time %= duration; - if (lastTime > 0) lastTime %= duration; - } - - ExposedList timelines = this.timelines; - for (int i = 0, n = timelines.Count; i < n; i++) - timelines.Items[i].Apply(skeleton, lastTime, time, events, alpha); - } - - /// After the first and before the last entry. - internal static int binarySearch (float[] values, float target, int step) { - int low = 0; - int high = values.Length / step - 2; - if (high == 0) return step; - int current = (int)((uint)high >> 1); - while (true) { - if (values[(current + 1) * step] <= target) - low = current + 1; - else - high = current; - if (low == high) return (low + 1) * step; - current = (int)((uint)(low + high) >> 1); - } - } - - /// After the first and before the last entry. - internal static int binarySearch (float[] values, float target) { - int low = 0; - int high = values.Length - 2; - if (high == 0) return 1; - int current = (int)((uint)high >> 1); - while (true) { - if (values[(current + 1)] <= target) - low = current + 1; - else - high = current; - if (low == high) return (low + 1); - current = (int)((uint)(low + high) >> 1); - } - } - - internal static int linearSearch (float[] values, float target, int step) { - for (int i = 0, last = values.Length - step; i <= last; i += step) - if (values[i] > target) return i; - return -1; - } - } - - public interface Timeline { - /// Sets the value(s) for the specified time. - /// May be null to not collect fired events. - void Apply (Skeleton skeleton, float lastTime, float time, ExposedList events, float alpha); - } - - /// Base class for frames that use an interpolation bezier curve. - abstract public class CurveTimeline : Timeline { - protected const float LINEAR = 0, STEPPED = 1, BEZIER = 2; - protected const int BEZIER_SIZE = 10 * 2 - 1; - - private float[] curves; // type, x, y, ... - public int FrameCount { get { return curves.Length / BEZIER_SIZE + 1; } } - - public CurveTimeline (int frameCount) { - if (frameCount <= 0) throw new ArgumentException("frameCount must be > 0: " + frameCount, "frameCount"); - curves = new float[(frameCount - 1) * BEZIER_SIZE]; - } - - abstract public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha); - - public void SetLinear (int frameIndex) { - curves[frameIndex * BEZIER_SIZE] = LINEAR; - } - - public void SetStepped (int frameIndex) { - curves[frameIndex * BEZIER_SIZE] = STEPPED; - } - - /// Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. - /// cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of - /// the difference between the keyframe's values. - public void SetCurve (int frameIndex, float cx1, float cy1, float cx2, float cy2) { - float tmpx = (-cx1 * 2 + cx2) * 0.03f, tmpy = (-cy1 * 2 + cy2) * 0.03f; - float dddfx = ((cx1 - cx2) * 3 + 1) * 0.006f, dddfy = ((cy1 - cy2) * 3 + 1) * 0.006f; - float ddfx = tmpx * 2 + dddfx, ddfy = tmpy * 2 + dddfy; - float dfx = cx1 * 0.3f + tmpx + dddfx * 0.16666667f, dfy = cy1 * 0.3f + tmpy + dddfy * 0.16666667f; - - int i = frameIndex * BEZIER_SIZE; - float[] curves = this.curves; - curves[i++] = BEZIER; - - float x = dfx, y = dfy; - for (int n = i + BEZIER_SIZE - 1; i < n; i += 2) { - curves[i] = x; - curves[i + 1] = y; - dfx += ddfx; - dfy += ddfy; - ddfx += dddfx; - ddfy += dddfy; - x += dfx; - y += dfy; - } - } - - public float GetCurvePercent (int frameIndex, float percent) { - percent = MathUtils.Clamp (percent, 0, 1); - float[] curves = this.curves; - int i = frameIndex * BEZIER_SIZE; - float type = curves[i]; - if (type == LINEAR) return percent; - if (type == STEPPED) return 0; - i++; - float x = 0; - for (int start = i, n = i + BEZIER_SIZE - 1; i < n; i += 2) { - x = curves[i]; - if (x >= percent) { - float prevX, prevY; - if (i == start) { - prevX = 0; - prevY = 0; - } else { - prevX = curves[i - 2]; - prevY = curves[i - 1]; - } - return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX); - } - } - float y = curves[i - 1]; - return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. - } - public float GetCurveType (int frameIndex) { - return curves[frameIndex * BEZIER_SIZE]; - } - } - - public class RotateTimeline : CurveTimeline { - public const int ENTRIES = 2; - internal const int PREV_TIME = -2, PREV_ROTATION = -1; - internal const int ROTATION = 1; - - internal int boneIndex; - internal float[] frames; - - public int BoneIndex { get { return boneIndex; } set { boneIndex = value; } } - public float[] Frames { get { return frames; } set { frames = value; } } // time, angle, ... - - public RotateTimeline (int frameCount) - : base(frameCount) { - frames = new float[frameCount << 1]; - } - - /// Sets the time and value of the specified keyframe. - public void SetFrame (int frameIndex, float time, float degrees) { - frameIndex <<= 1; - frames[frameIndex] = time; - frames[frameIndex + ROTATION] = degrees; - } - - override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - Bone bone = skeleton.bones.Items[boneIndex]; - - float amount; - - if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. - amount = bone.data.rotation + frames[frames.Length + PREV_ROTATION] - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = Animation.binarySearch(frames, time, ENTRIES); - float prevRotation = frames[frame + PREV_ROTATION]; - float frameTime = frames[frame]; - float percent = GetCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - amount = frames[frame + ROTATION] - prevRotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - amount = bone.data.rotation + (prevRotation + amount * percent) - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - } - } - - public class TranslateTimeline : CurveTimeline { - public const int ENTRIES = 3; - protected const int PREV_TIME = -3, PREV_X = -2, PREV_Y = -1; - protected const int X = 1, Y = 2; - - internal int boneIndex; - internal float[] frames; - - public int BoneIndex { get { return boneIndex; } set { boneIndex = value; } } - public float[] Frames { get { return frames; } set { frames = value; } } // time, value, value, ... - - public TranslateTimeline (int frameCount) - : base(frameCount) { - frames = new float[frameCount * ENTRIES]; - } - - /// Sets the time and value of the specified keyframe. - public void SetFrame (int frameIndex, float time, float x, float y) { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[frameIndex + X] = x; - frames[frameIndex + Y] = y; - } - - override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - Bone bone = skeleton.bones.Items[boneIndex]; - - if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. - bone.x += (bone.data.x + frames[frames.Length + PREV_X] - bone.x) * alpha; - bone.y += (bone.data.y + frames[frames.Length + PREV_Y] - bone.y) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = Animation.binarySearch(frames, time, ENTRIES); - float prevX = frames[frame + PREV_X]; - float prevY = frames[frame + PREV_Y]; - float frameTime = frames[frame]; - float percent = GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - bone.x += (bone.data.x + prevX + (frames[frame + X] - prevX) * percent - bone.x) * alpha; - bone.y += (bone.data.y + prevY + (frames[frame + Y] - prevY) * percent - bone.y) * alpha; - } - } - - public class ScaleTimeline : TranslateTimeline { - public ScaleTimeline (int frameCount) - : base(frameCount) { - } - - override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - Bone bone = skeleton.bones.Items[boneIndex]; - if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. - bone.scaleX += (bone.data.scaleX * frames[frames.Length + PREV_X] - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY * frames[frames.Length + PREV_Y] - bone.scaleY) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = Animation.binarySearch(frames, time, ENTRIES); - float prevX = frames[frame + PREV_X]; - float prevY = frames[frame + PREV_Y]; - float frameTime = frames[frame]; - float percent = GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - bone.scaleX += (bone.data.scaleX * (prevX + (frames[frame + X] - prevX) * percent) - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY * (prevY + (frames[frame + Y] - prevY) * percent) - bone.scaleY) * alpha; - } - } - - public class ShearTimeline : TranslateTimeline { - public ShearTimeline (int frameCount) - : base(frameCount) { - } - - override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - Bone bone = skeleton.bones.Items[boneIndex]; - if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. - bone.shearX += (bone.data.shearX + frames[frames.Length + PREV_X] - bone.shearX) * alpha; - bone.shearY += (bone.data.shearY + frames[frames.Length + PREV_Y] - bone.shearY) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = Animation.binarySearch(frames, time, ENTRIES); - float prevX = frames[frame + PREV_X]; - float prevY = frames[frame + PREV_Y]; - float frameTime = frames[frame]; - float percent = GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - bone.shearX += (bone.data.shearX + (prevX + (frames[frame + X] - prevX) * percent) - bone.shearX) * alpha; - bone.shearY += (bone.data.shearY + (prevY + (frames[frame + Y] - prevY) * percent) - bone.shearY) * alpha; - } - } - - public class ColorTimeline : CurveTimeline { - public const int ENTRIES = 5; - protected const int PREV_TIME = -5, PREV_R = -4, PREV_G = -3, PREV_B = -2, PREV_A = -1; - protected const int R = 1, G = 2, B = 3, A = 4; - - internal int slotIndex; - internal float[] frames; - - public int SlotIndex { get { return slotIndex; } set { slotIndex = value; } } - public float[] Frames { get { return frames; } set { frames = value; } } // time, r, g, b, a, ... - - public ColorTimeline (int frameCount) - : base(frameCount) { - frames = new float[frameCount * ENTRIES]; - } - - /// Sets the time and value of the specified keyframe. - public void SetFrame (int frameIndex, float time, float r, float g, float b, float a) { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[frameIndex + R] = r; - frames[frameIndex + G] = g; - frames[frameIndex + B] = b; - frames[frameIndex + A] = a; - } - - override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - float r, g, b, a; - if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. - int i = frames.Length; - r = frames[i + PREV_R]; - g = frames[i + PREV_G]; - b = frames[i + PREV_B]; - a = frames[i + PREV_A]; - } else { - // Interpolate between the previous frame and the current frame. - int frame = Animation.binarySearch(frames, time, ENTRIES); - r = frames[frame + PREV_R]; - g = frames[frame + PREV_G]; - b = frames[frame + PREV_B]; - a = frames[frame + PREV_A]; - float frameTime = frames[frame]; - float percent = GetCurvePercent(frame / ENTRIES - 1, - 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - r += (frames[frame + R] - r) * percent; - g += (frames[frame + G] - g) * percent; - b += (frames[frame + B] - b) * percent; - a += (frames[frame + A] - a) * percent; - } - Slot slot = skeleton.slots.Items[slotIndex]; - if (alpha < 1) { - slot.r += (r - slot.r) * alpha; - slot.g += (g - slot.g) * alpha; - slot.b += (b - slot.b) * alpha; - slot.a += (a - slot.a) * alpha; - } else { - slot.r = r; - slot.g = g; - slot.b = b; - slot.a = a; - } - } - } - - public class AttachmentTimeline : Timeline { - internal int slotIndex; - internal float[] frames; - private String[] attachmentNames; - - public int SlotIndex { get { return slotIndex; } set { slotIndex = value; } } - public float[] Frames { get { return frames; } set { frames = value; } } // time, ... - public String[] AttachmentNames { get { return attachmentNames; } set { attachmentNames = value; } } - public int FrameCount { get { return frames.Length; } } - - public AttachmentTimeline (int frameCount) { - frames = new float[frameCount]; - attachmentNames = new String[frameCount]; - } - - /// Sets the time and value of the specified keyframe. - public void SetFrame (int frameIndex, float time, String attachmentName) { - frames[frameIndex] = time; - attachmentNames[frameIndex] = attachmentName; - } - - public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - int frameIndex; - if (time >= frames[frames.Length - 1]) // Time is after last frame. - frameIndex = frames.Length - 1; - else - frameIndex = Animation.binarySearch(frames, time, 1) - 1; - - String attachmentName = attachmentNames[frameIndex]; - skeleton.slots.Items[slotIndex] - .Attachment = attachmentName == null ? null : skeleton.GetAttachment(slotIndex, attachmentName); - } - } - - public class EventTimeline : Timeline { - internal float[] frames; - private Event[] events; - - public float[] Frames { get { return frames; } set { frames = value; } } // time, ... - public Event[] Events { get { return events; } set { events = value; } } - public int FrameCount { get { return frames.Length; } } - - public EventTimeline (int frameCount) { - frames = new float[frameCount]; - events = new Event[frameCount]; - } - - /// Sets the time and value of the specified keyframe. - public void SetFrame (int frameIndex, Event e) { - frames[frameIndex] = e.Time; - events[frameIndex] = e; - } - - /// Fires events for frames > lastTime and <= time. - public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { - if (firedEvents == null) return; - float[] frames = this.frames; - int frameCount = frames.Length; - - if (lastTime > time) { // Fire events after last time for looped animations. - Apply(skeleton, lastTime, int.MaxValue, firedEvents, alpha); - lastTime = -1f; - } else if (lastTime >= frames[frameCount - 1]) // Last time is after last frame. - return; - if (time < frames[0]) return; // Time is before first frame. - - int frame; - if (lastTime < frames[0]) - frame = 0; - else { - frame = Animation.binarySearch(frames, lastTime); - float frameTime = frames[frame]; - while (frame > 0) { // Fire multiple events with the same frame. - if (frames[frame - 1] != frameTime) break; - frame--; - } - } - for (; frame < frameCount && time >= frames[frame]; frame++) - firedEvents.Add(events[frame]); - } - } - - public class DrawOrderTimeline : Timeline { - internal float[] frames; - private int[][] drawOrders; - - public float[] Frames { get { return frames; } set { frames = value; } } // time, ... - public int[][] DrawOrders { get { return drawOrders; } set { drawOrders = value; } } - public int FrameCount { get { return frames.Length; } } - - public DrawOrderTimeline (int frameCount) { - frames = new float[frameCount]; - drawOrders = new int[frameCount][]; - } - - /// Sets the time and value of the specified keyframe. - /// May be null to use bind pose draw order. - public void SetFrame (int frameIndex, float time, int[] drawOrder) { - frames[frameIndex] = time; - drawOrders[frameIndex] = drawOrder; - } - - public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - int frame; - if (time >= frames[frames.Length - 1]) // Time is after last frame. - frame = frames.Length - 1; - else - frame = Animation.binarySearch(frames, time) - 1; - - ExposedList drawOrder = skeleton.drawOrder; - ExposedList slots = skeleton.slots; - int[] drawOrderToSetupIndex = drawOrders[frame]; - if (drawOrderToSetupIndex == null) { - drawOrder.Clear(); - for (int i = 0, n = slots.Count; i < n; i++) - drawOrder.Add(slots.Items[i]); - } else { - var drawOrderItems = drawOrder.Items; - var slotsItems = slots.Items; - for (int i = 0, n = drawOrderToSetupIndex.Length; i < n; i++) - drawOrderItems[i] = slotsItems[drawOrderToSetupIndex[i]]; - } - } - } - - public class DeformTimeline : CurveTimeline { - internal int slotIndex; - internal float[] frames; - private float[][] frameVertices; - internal VertexAttachment attachment; - - public int SlotIndex { get { return slotIndex; } set { slotIndex = value; } } - public float[] Frames { get { return frames; } set { frames = value; } } // time, ... - public float[][] Vertices { get { return frameVertices; } set { frameVertices = value; } } - public VertexAttachment Attachment { get { return attachment; } set { attachment = value; } } - - public DeformTimeline (int frameCount) - : base(frameCount) { - frames = new float[frameCount]; - frameVertices = new float[frameCount][]; - } - - /// Sets the time and value of the specified keyframe. - public void SetFrame (int frameIndex, float time, float[] vertices) { - frames[frameIndex] = time; - frameVertices[frameIndex] = vertices; - } - - override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { - Slot slot = skeleton.slots.Items[slotIndex]; - VertexAttachment slotAttachment = slot.attachment as VertexAttachment; - if (slotAttachment == null || !slotAttachment.ApplyDeform(attachment)) return; - - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - float[][] frameVertices = this.frameVertices; - int vertexCount = frameVertices[0].Length; - - var verticesArray = slot.attachmentVertices; - if (verticesArray.Count != vertexCount) alpha = 1; // Don't mix from uninitialized slot vertices. - // verticesArray.SetSize(vertexCount) // Ensure size and preemptively set count. - if (verticesArray.Capacity < vertexCount) verticesArray.Capacity = vertexCount; - verticesArray.Count = vertexCount; - float[] vertices = verticesArray.Items; - - if (time >= frames[frames.Length - 1]) { // Time is after last frame. - float[] lastVertices = frameVertices[frames.Length - 1]; - if (alpha < 1) { - for (int i = 0; i < vertexCount; i++) { - float vertex = vertices[i]; - vertices[i] = vertex + (lastVertices[i] - vertex) * alpha; - } - } else - Array.Copy(lastVertices, 0, vertices, 0, vertexCount); - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = Animation.binarySearch(frames, time); - float[] prevVertices = frameVertices[frame - 1]; - float[] nextVertices = frameVertices[frame]; - float frameTime = frames[frame]; - float percent = GetCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime)); - - if (alpha < 1) { - for (int i = 0; i < vertexCount; i++) { - float prev = prevVertices[i]; - float vertex = vertices[i]; - vertices[i] = vertex + (prev + (nextVertices[i] - prev) * percent - vertex) * alpha; - } - } else { - for (int i = 0; i < vertexCount; i++) { - float prev = prevVertices[i]; - vertices[i] = prev + (nextVertices[i] - prev) * percent; - } - } - } - } - - public class IkConstraintTimeline : CurveTimeline { - public const int ENTRIES = 3; - private const int PREV_TIME = -3, PREV_MIX = -2, PREV_BEND_DIRECTION = -1; - private const int MIX = 1, BEND_DIRECTION = 2; - - internal int ikConstraintIndex; - internal float[] frames; - - public int IkConstraintIndex { get { return ikConstraintIndex; } set { ikConstraintIndex = value; } } - public float[] Frames { get { return frames; } set { frames = value; } } // time, mix, bendDirection, ... - - public IkConstraintTimeline (int frameCount) - : base(frameCount) { - frames = new float[frameCount * ENTRIES]; - } - - /// Sets the time, mix and bend direction of the specified keyframe. - public void SetFrame (int frameIndex, float time, float mix, int bendDirection) { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[frameIndex + MIX] = mix; - frames[frameIndex + BEND_DIRECTION] = bendDirection; - } - - override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - IkConstraint constraint = skeleton.ikConstraints.Items[ikConstraintIndex]; - - if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. - constraint.mix += (frames[frames.Length + PREV_MIX] - constraint.mix) * alpha; - constraint.bendDirection = (int)frames[frames.Length + PREV_BEND_DIRECTION]; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = Animation.binarySearch(frames, time, ENTRIES); - float mix = frames[frame + PREV_MIX]; - float frameTime = frames[frame]; - float percent = GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - constraint.mix += (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha; - constraint.bendDirection = (int)frames[frame + PREV_BEND_DIRECTION]; - } - } - - public class TransformConstraintTimeline : CurveTimeline { - public const int ENTRIES = 5; - private const int PREV_TIME = -5, PREV_ROTATE = -4, PREV_TRANSLATE = -3, PREV_SCALE = -2, PREV_SHEAR = -1; - private const int ROTATE = 1, TRANSLATE = 2, SCALE = 3, SHEAR = 4; - - internal int transformConstraintIndex; - internal float[] frames; - - public int TransformConstraintIndex { get { return transformConstraintIndex; } set { transformConstraintIndex = value; } } - public float[] Frames { get { return frames; } set { frames = value; } } // time, rotate mix, translate mix, scale mix, shear mix, ... - - public TransformConstraintTimeline (int frameCount) - : base(frameCount) { - frames = new float[frameCount * ENTRIES]; - } - - public void SetFrame (int frameIndex, float time, float rotateMix, float translateMix, float scaleMix, float shearMix) { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[frameIndex + ROTATE] = rotateMix; - frames[frameIndex + TRANSLATE] = translateMix; - frames[frameIndex + SCALE] = scaleMix; - frames[frameIndex + SHEAR] = shearMix; - } - - override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - TransformConstraint constraint = skeleton.transformConstraints.Items[transformConstraintIndex]; - - if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. - int i = frames.Length; - constraint.rotateMix += (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha; - constraint.translateMix += (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha; - constraint.scaleMix += (frames[i + PREV_SCALE] - constraint.scaleMix) * alpha; - constraint.shearMix += (frames[i + PREV_SHEAR] - constraint.shearMix) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = Animation.binarySearch(frames, time, ENTRIES); - float frameTime = frames[frame]; - float percent = GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - float rotate = frames[frame + PREV_ROTATE]; - float translate = frames[frame + PREV_TRANSLATE]; - float scale = frames[frame + PREV_SCALE]; - float shear = frames[frame + PREV_SHEAR]; - constraint.rotateMix += (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha; - constraint.translateMix += (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix) - * alpha; - constraint.scaleMix += (scale + (frames[frame + SCALE] - scale) * percent - constraint.scaleMix) * alpha; - constraint.shearMix += (shear + (frames[frame + SHEAR] - shear) * percent - constraint.shearMix) * alpha; - } - } - - public class PathConstraintPositionTimeline : CurveTimeline { - public const int ENTRIES = 2; - protected const int PREV_TIME = -2, PREV_VALUE = -1; - protected const int VALUE = 1; - - internal int pathConstraintIndex; - internal float[] frames; - - public PathConstraintPositionTimeline (int frameCount) - : base(frameCount) { - frames = new float[frameCount * ENTRIES]; - } - - public int PathConstraintIndex { get { return pathConstraintIndex; } set { pathConstraintIndex = value; } } - public float[] Frames { get { return frames; } set { frames = value; } } // time, position, ... - - /// Sets the time and value of the specified keyframe. - public void SetFrame (int frameIndex, float time, float value) { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[frameIndex + VALUE] = value; - } - - override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList events, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - PathConstraint constraint = skeleton.pathConstraints.Items[pathConstraintIndex]; - - if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. - int i = frames.Length; - constraint.position += (frames[i + PREV_VALUE] - constraint.position) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = Animation.binarySearch(frames, time, ENTRIES); - float position = frames[frame + PREV_VALUE]; - float frameTime = frames[frame]; - float percent = GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - constraint.position += (position + (frames[frame + VALUE] - position) * percent - constraint.position) * alpha; - } - } - - public class PathConstraintSpacingTimeline : PathConstraintPositionTimeline { - public PathConstraintSpacingTimeline (int frameCount) - : base(frameCount) { - } - - override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList events, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - PathConstraint constraint = skeleton.pathConstraints.Items[pathConstraintIndex]; - - if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. - int i = frames.Length; - constraint.spacing += (frames[i + PREV_VALUE] - constraint.spacing) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = Animation.binarySearch(frames, time, ENTRIES); - float spacing = frames[frame + PREV_VALUE]; - float frameTime = frames[frame]; - float percent = GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - constraint.spacing += (spacing + (frames[frame + VALUE] - spacing) * percent - constraint.spacing) * alpha; - } - } - - public class PathConstraintMixTimeline : CurveTimeline { - public const int ENTRIES = 3; - private const int PREV_TIME = -3, PREV_ROTATE = -2, PREV_TRANSLATE = -1; - private const int ROTATE = 1, TRANSLATE = 2; - - internal int pathConstraintIndex; - internal float[] frames; - - public int PathConstraintIndex { get { return pathConstraintIndex; } set { pathConstraintIndex = value; } } - public float[] Frames { get { return frames; } set { frames = value; } } // time, rotate mix, translate mix, ... - - public PathConstraintMixTimeline (int frameCount) - : base(frameCount) { - frames = new float[frameCount * ENTRIES]; - } - - /** Sets the time and mixes of the specified keyframe. */ - public void SetFrame (int frameIndex, float time, float rotateMix, float translateMix) { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[frameIndex + ROTATE] = rotateMix; - frames[frameIndex + TRANSLATE] = translateMix; - } - - override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList events, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - PathConstraint constraint = skeleton.pathConstraints.Items[pathConstraintIndex]; - - if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. - int i = frames.Length; - constraint.rotateMix += (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha; - constraint.translateMix += (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = Animation.binarySearch(frames, time, ENTRIES); - float rotate = frames[frame + PREV_ROTATE]; - float translate = frames[frame + PREV_TRANSLATE]; - float frameTime = frames[frame]; - float percent = GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - constraint.rotateMix += (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha; - constraint.translateMix += (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix) - * alpha; - } - } +using System; +using System.Collections.Generic; + +namespace Spine { + public class Animation { + internal ExposedList timelines; + internal float duration; + internal String name; + + public String Name { get { return name; } } + public ExposedList Timelines { get { return timelines; } set { timelines = value; } } + public float Duration { get { return duration; } set { duration = value; } } + + public Animation (String name, ExposedList timelines, float duration) { + if (name == null) throw new ArgumentNullException("name", "name cannot be null."); + if (timelines == null) throw new ArgumentNullException("timelines", "timelines cannot be null."); + this.name = name; + this.timelines = timelines; + this.duration = duration; + } + + /// Poses the skeleton at the specified time for this animation. + /// The last time the animation was applied. + /// Any triggered events are added. May be null. + public void Apply (Skeleton skeleton, float lastTime, float time, bool loop, ExposedList events) { + if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null."); + + if (loop && duration != 0) { + time %= duration; + if (lastTime > 0) lastTime %= duration; + } + + ExposedList timelines = this.timelines; + for (int i = 0, n = timelines.Count; i < n; i++) + timelines.Items[i].Apply(skeleton, lastTime, time, events, 1); + } + + /// Poses the skeleton at the specified time for this animation mixed with the current pose. + /// The last time the animation was applied. + /// Any triggered events are added. May be null. + /// The amount of this animation that affects the current pose. + public void Mix (Skeleton skeleton, float lastTime, float time, bool loop, ExposedList events, float alpha) { + if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null."); + + if (loop && duration != 0) { + time %= duration; + if (lastTime > 0) lastTime %= duration; + } + + ExposedList timelines = this.timelines; + for (int i = 0, n = timelines.Count; i < n; i++) + timelines.Items[i].Apply(skeleton, lastTime, time, events, alpha); + } + + /// After the first and before the last entry. + internal static int binarySearch (float[] values, float target, int step) { + int low = 0; + int high = values.Length / step - 2; + if (high == 0) return step; + int current = (int)((uint)high >> 1); + while (true) { + if (values[(current + 1) * step] <= target) + low = current + 1; + else + high = current; + if (low == high) return (low + 1) * step; + current = (int)((uint)(low + high) >> 1); + } + } + + /// After the first and before the last entry. + internal static int binarySearch (float[] values, float target) { + int low = 0; + int high = values.Length - 2; + if (high == 0) return 1; + int current = (int)((uint)high >> 1); + while (true) { + if (values[(current + 1)] <= target) + low = current + 1; + else + high = current; + if (low == high) return (low + 1); + current = (int)((uint)(low + high) >> 1); + } + } + + internal static int linearSearch (float[] values, float target, int step) { + for (int i = 0, last = values.Length - step; i <= last; i += step) + if (values[i] > target) return i; + return -1; + } + } + + public interface Timeline { + /// Sets the value(s) for the specified time. + /// May be null to not collect fired events. + void Apply (Skeleton skeleton, float lastTime, float time, ExposedList events, float alpha); + } + + /// Base class for frames that use an interpolation bezier curve. + abstract public class CurveTimeline : Timeline { + protected const float LINEAR = 0, STEPPED = 1, BEZIER = 2; + protected const int BEZIER_SIZE = 10 * 2 - 1; + + private float[] curves; // type, x, y, ... + public int FrameCount { get { return curves.Length / BEZIER_SIZE + 1; } } + + public CurveTimeline (int frameCount) { + if (frameCount <= 0) throw new ArgumentException("frameCount must be > 0: " + frameCount, "frameCount"); + curves = new float[(frameCount - 1) * BEZIER_SIZE]; + } + + abstract public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha); + + public void SetLinear (int frameIndex) { + curves[frameIndex * BEZIER_SIZE] = LINEAR; + } + + public void SetStepped (int frameIndex) { + curves[frameIndex * BEZIER_SIZE] = STEPPED; + } + + /// Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. + /// cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of + /// the difference between the keyframe's values. + public void SetCurve (int frameIndex, float cx1, float cy1, float cx2, float cy2) { + float tmpx = (-cx1 * 2 + cx2) * 0.03f, tmpy = (-cy1 * 2 + cy2) * 0.03f; + float dddfx = ((cx1 - cx2) * 3 + 1) * 0.006f, dddfy = ((cy1 - cy2) * 3 + 1) * 0.006f; + float ddfx = tmpx * 2 + dddfx, ddfy = tmpy * 2 + dddfy; + float dfx = cx1 * 0.3f + tmpx + dddfx * 0.16666667f, dfy = cy1 * 0.3f + tmpy + dddfy * 0.16666667f; + + int i = frameIndex * BEZIER_SIZE; + float[] curves = this.curves; + curves[i++] = BEZIER; + + float x = dfx, y = dfy; + for (int n = i + BEZIER_SIZE - 1; i < n; i += 2) { + curves[i] = x; + curves[i + 1] = y; + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + x += dfx; + y += dfy; + } + } + + public float GetCurvePercent (int frameIndex, float percent) { + percent = MathUtils.Clamp (percent, 0, 1); + float[] curves = this.curves; + int i = frameIndex * BEZIER_SIZE; + float type = curves[i]; + if (type == LINEAR) return percent; + if (type == STEPPED) return 0; + i++; + float x = 0; + for (int start = i, n = i + BEZIER_SIZE - 1; i < n; i += 2) { + x = curves[i]; + if (x >= percent) { + float prevX, prevY; + if (i == start) { + prevX = 0; + prevY = 0; + } else { + prevX = curves[i - 2]; + prevY = curves[i - 1]; + } + return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX); + } + } + float y = curves[i - 1]; + return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. + } + public float GetCurveType (int frameIndex) { + return curves[frameIndex * BEZIER_SIZE]; + } + } + + public class RotateTimeline : CurveTimeline { + public const int ENTRIES = 2; + internal const int PREV_TIME = -2, PREV_ROTATION = -1; + internal const int ROTATION = 1; + + internal int boneIndex; + internal float[] frames; + + public int BoneIndex { get { return boneIndex; } set { boneIndex = value; } } + public float[] Frames { get { return frames; } set { frames = value; } } // time, angle, ... + + public RotateTimeline (int frameCount) + : base(frameCount) { + frames = new float[frameCount << 1]; + } + + /// Sets the time and value of the specified keyframe. + public void SetFrame (int frameIndex, float time, float degrees) { + frameIndex <<= 1; + frames[frameIndex] = time; + frames[frameIndex + ROTATION] = degrees; + } + + override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + Bone bone = skeleton.bones.Items[boneIndex]; + + float amount; + + if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. + amount = bone.data.rotation + frames[frames.Length + PREV_ROTATION] - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = Animation.binarySearch(frames, time, ENTRIES); + float prevRotation = frames[frame + PREV_ROTATION]; + float frameTime = frames[frame]; + float percent = GetCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + amount = frames[frame + ROTATION] - prevRotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + amount = bone.data.rotation + (prevRotation + amount * percent) - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + } + } + + public class TranslateTimeline : CurveTimeline { + public const int ENTRIES = 3; + protected const int PREV_TIME = -3, PREV_X = -2, PREV_Y = -1; + protected const int X = 1, Y = 2; + + internal int boneIndex; + internal float[] frames; + + public int BoneIndex { get { return boneIndex; } set { boneIndex = value; } } + public float[] Frames { get { return frames; } set { frames = value; } } // time, value, value, ... + + public TranslateTimeline (int frameCount) + : base(frameCount) { + frames = new float[frameCount * ENTRIES]; + } + + /// Sets the time and value of the specified keyframe. + public void SetFrame (int frameIndex, float time, float x, float y) { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[frameIndex + X] = x; + frames[frameIndex + Y] = y; + } + + override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + Bone bone = skeleton.bones.Items[boneIndex]; + + if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. + bone.x += (bone.data.x + frames[frames.Length + PREV_X] - bone.x) * alpha; + bone.y += (bone.data.y + frames[frames.Length + PREV_Y] - bone.y) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = Animation.binarySearch(frames, time, ENTRIES); + float prevX = frames[frame + PREV_X]; + float prevY = frames[frame + PREV_Y]; + float frameTime = frames[frame]; + float percent = GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + bone.x += (bone.data.x + prevX + (frames[frame + X] - prevX) * percent - bone.x) * alpha; + bone.y += (bone.data.y + prevY + (frames[frame + Y] - prevY) * percent - bone.y) * alpha; + } + } + + public class ScaleTimeline : TranslateTimeline { + public ScaleTimeline (int frameCount) + : base(frameCount) { + } + + override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + Bone bone = skeleton.bones.Items[boneIndex]; + if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. + bone.scaleX += (bone.data.scaleX * frames[frames.Length + PREV_X] - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY * frames[frames.Length + PREV_Y] - bone.scaleY) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = Animation.binarySearch(frames, time, ENTRIES); + float prevX = frames[frame + PREV_X]; + float prevY = frames[frame + PREV_Y]; + float frameTime = frames[frame]; + float percent = GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + bone.scaleX += (bone.data.scaleX * (prevX + (frames[frame + X] - prevX) * percent) - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY * (prevY + (frames[frame + Y] - prevY) * percent) - bone.scaleY) * alpha; + } + } + + public class ShearTimeline : TranslateTimeline { + public ShearTimeline (int frameCount) + : base(frameCount) { + } + + override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + Bone bone = skeleton.bones.Items[boneIndex]; + if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. + bone.shearX += (bone.data.shearX + frames[frames.Length + PREV_X] - bone.shearX) * alpha; + bone.shearY += (bone.data.shearY + frames[frames.Length + PREV_Y] - bone.shearY) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = Animation.binarySearch(frames, time, ENTRIES); + float prevX = frames[frame + PREV_X]; + float prevY = frames[frame + PREV_Y]; + float frameTime = frames[frame]; + float percent = GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + bone.shearX += (bone.data.shearX + (prevX + (frames[frame + X] - prevX) * percent) - bone.shearX) * alpha; + bone.shearY += (bone.data.shearY + (prevY + (frames[frame + Y] - prevY) * percent) - bone.shearY) * alpha; + } + } + + public class ColorTimeline : CurveTimeline { + public const int ENTRIES = 5; + protected const int PREV_TIME = -5, PREV_R = -4, PREV_G = -3, PREV_B = -2, PREV_A = -1; + protected const int R = 1, G = 2, B = 3, A = 4; + + internal int slotIndex; + internal float[] frames; + + public int SlotIndex { get { return slotIndex; } set { slotIndex = value; } } + public float[] Frames { get { return frames; } set { frames = value; } } // time, r, g, b, a, ... + + public ColorTimeline (int frameCount) + : base(frameCount) { + frames = new float[frameCount * ENTRIES]; + } + + /// Sets the time and value of the specified keyframe. + public void SetFrame (int frameIndex, float time, float r, float g, float b, float a) { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[frameIndex + R] = r; + frames[frameIndex + G] = g; + frames[frameIndex + B] = b; + frames[frameIndex + A] = a; + } + + override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + float r, g, b, a; + if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. + int i = frames.Length; + r = frames[i + PREV_R]; + g = frames[i + PREV_G]; + b = frames[i + PREV_B]; + a = frames[i + PREV_A]; + } else { + // Interpolate between the previous frame and the current frame. + int frame = Animation.binarySearch(frames, time, ENTRIES); + r = frames[frame + PREV_R]; + g = frames[frame + PREV_G]; + b = frames[frame + PREV_B]; + a = frames[frame + PREV_A]; + float frameTime = frames[frame]; + float percent = GetCurvePercent(frame / ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + r += (frames[frame + R] - r) * percent; + g += (frames[frame + G] - g) * percent; + b += (frames[frame + B] - b) * percent; + a += (frames[frame + A] - a) * percent; + } + Slot slot = skeleton.slots.Items[slotIndex]; + if (alpha < 1) { + slot.r += (r - slot.r) * alpha; + slot.g += (g - slot.g) * alpha; + slot.b += (b - slot.b) * alpha; + slot.a += (a - slot.a) * alpha; + } else { + slot.r = r; + slot.g = g; + slot.b = b; + slot.a = a; + } + } + } + + public class AttachmentTimeline : Timeline { + internal int slotIndex; + internal float[] frames; + private String[] attachmentNames; + + public int SlotIndex { get { return slotIndex; } set { slotIndex = value; } } + public float[] Frames { get { return frames; } set { frames = value; } } // time, ... + public String[] AttachmentNames { get { return attachmentNames; } set { attachmentNames = value; } } + public int FrameCount { get { return frames.Length; } } + + public AttachmentTimeline (int frameCount) { + frames = new float[frameCount]; + attachmentNames = new String[frameCount]; + } + + /// Sets the time and value of the specified keyframe. + public void SetFrame (int frameIndex, float time, String attachmentName) { + frames[frameIndex] = time; + attachmentNames[frameIndex] = attachmentName; + } + + public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + int frameIndex; + if (time >= frames[frames.Length - 1]) // Time is after last frame. + frameIndex = frames.Length - 1; + else + frameIndex = Animation.binarySearch(frames, time, 1) - 1; + + String attachmentName = attachmentNames[frameIndex]; + skeleton.slots.Items[slotIndex] + .Attachment = attachmentName == null ? null : skeleton.GetAttachment(slotIndex, attachmentName); + } + } + + public class EventTimeline : Timeline { + internal float[] frames; + private Event[] events; + + public float[] Frames { get { return frames; } set { frames = value; } } // time, ... + public Event[] Events { get { return events; } set { events = value; } } + public int FrameCount { get { return frames.Length; } } + + public EventTimeline (int frameCount) { + frames = new float[frameCount]; + events = new Event[frameCount]; + } + + /// Sets the time and value of the specified keyframe. + public void SetFrame (int frameIndex, Event e) { + frames[frameIndex] = e.Time; + events[frameIndex] = e; + } + + /// Fires events for frames > lastTime and <= time. + public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { + if (firedEvents == null) return; + float[] frames = this.frames; + int frameCount = frames.Length; + + if (lastTime > time) { // Fire events after last time for looped animations. + Apply(skeleton, lastTime, int.MaxValue, firedEvents, alpha); + lastTime = -1f; + } else if (lastTime >= frames[frameCount - 1]) // Last time is after last frame. + return; + if (time < frames[0]) return; // Time is before first frame. + + int frame; + if (lastTime < frames[0]) + frame = 0; + else { + frame = Animation.binarySearch(frames, lastTime); + float frameTime = frames[frame]; + while (frame > 0) { // Fire multiple events with the same frame. + if (frames[frame - 1] != frameTime) break; + frame--; + } + } + for (; frame < frameCount && time >= frames[frame]; frame++) + firedEvents.Add(events[frame]); + } + } + + public class DrawOrderTimeline : Timeline { + internal float[] frames; + private int[][] drawOrders; + + public float[] Frames { get { return frames; } set { frames = value; } } // time, ... + public int[][] DrawOrders { get { return drawOrders; } set { drawOrders = value; } } + public int FrameCount { get { return frames.Length; } } + + public DrawOrderTimeline (int frameCount) { + frames = new float[frameCount]; + drawOrders = new int[frameCount][]; + } + + /// Sets the time and value of the specified keyframe. + /// May be null to use bind pose draw order. + public void SetFrame (int frameIndex, float time, int[] drawOrder) { + frames[frameIndex] = time; + drawOrders[frameIndex] = drawOrder; + } + + public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + int frame; + if (time >= frames[frames.Length - 1]) // Time is after last frame. + frame = frames.Length - 1; + else + frame = Animation.binarySearch(frames, time) - 1; + + ExposedList drawOrder = skeleton.drawOrder; + ExposedList slots = skeleton.slots; + int[] drawOrderToSetupIndex = drawOrders[frame]; + if (drawOrderToSetupIndex == null) { + drawOrder.Clear(); + for (int i = 0, n = slots.Count; i < n; i++) + drawOrder.Add(slots.Items[i]); + } else { + var drawOrderItems = drawOrder.Items; + var slotsItems = slots.Items; + for (int i = 0, n = drawOrderToSetupIndex.Length; i < n; i++) + drawOrderItems[i] = slotsItems[drawOrderToSetupIndex[i]]; + } + } + } + + public class DeformTimeline : CurveTimeline { + internal int slotIndex; + internal float[] frames; + private float[][] frameVertices; + internal VertexAttachment attachment; + + public int SlotIndex { get { return slotIndex; } set { slotIndex = value; } } + public float[] Frames { get { return frames; } set { frames = value; } } // time, ... + public float[][] Vertices { get { return frameVertices; } set { frameVertices = value; } } + public VertexAttachment Attachment { get { return attachment; } set { attachment = value; } } + + public DeformTimeline (int frameCount) + : base(frameCount) { + frames = new float[frameCount]; + frameVertices = new float[frameCount][]; + } + + /// Sets the time and value of the specified keyframe. + public void SetFrame (int frameIndex, float time, float[] vertices) { + frames[frameIndex] = time; + frameVertices[frameIndex] = vertices; + } + + override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { + Slot slot = skeleton.slots.Items[slotIndex]; + VertexAttachment slotAttachment = slot.attachment as VertexAttachment; + if (slotAttachment == null || !slotAttachment.ApplyDeform(attachment)) return; + + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + float[][] frameVertices = this.frameVertices; + int vertexCount = frameVertices[0].Length; + + var verticesArray = slot.attachmentVertices; + if (verticesArray.Count != vertexCount) alpha = 1; // Don't mix from uninitialized slot vertices. + // verticesArray.SetSize(vertexCount) // Ensure size and preemptively set count. + if (verticesArray.Capacity < vertexCount) verticesArray.Capacity = vertexCount; + verticesArray.Count = vertexCount; + float[] vertices = verticesArray.Items; + + if (time >= frames[frames.Length - 1]) { // Time is after last frame. + float[] lastVertices = frameVertices[frames.Length - 1]; + if (alpha < 1) { + for (int i = 0; i < vertexCount; i++) { + float vertex = vertices[i]; + vertices[i] = vertex + (lastVertices[i] - vertex) * alpha; + } + } else + Array.Copy(lastVertices, 0, vertices, 0, vertexCount); + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = Animation.binarySearch(frames, time); + float[] prevVertices = frameVertices[frame - 1]; + float[] nextVertices = frameVertices[frame]; + float frameTime = frames[frame]; + float percent = GetCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime)); + + if (alpha < 1) { + for (int i = 0; i < vertexCount; i++) { + float prev = prevVertices[i]; + float vertex = vertices[i]; + vertices[i] = vertex + (prev + (nextVertices[i] - prev) * percent - vertex) * alpha; + } + } else { + for (int i = 0; i < vertexCount; i++) { + float prev = prevVertices[i]; + vertices[i] = prev + (nextVertices[i] - prev) * percent; + } + } + } + } + + public class IkConstraintTimeline : CurveTimeline { + public const int ENTRIES = 3; + private const int PREV_TIME = -3, PREV_MIX = -2, PREV_BEND_DIRECTION = -1; + private const int MIX = 1, BEND_DIRECTION = 2; + + internal int ikConstraintIndex; + internal float[] frames; + + public int IkConstraintIndex { get { return ikConstraintIndex; } set { ikConstraintIndex = value; } } + public float[] Frames { get { return frames; } set { frames = value; } } // time, mix, bendDirection, ... + + public IkConstraintTimeline (int frameCount) + : base(frameCount) { + frames = new float[frameCount * ENTRIES]; + } + + /// Sets the time, mix and bend direction of the specified keyframe. + public void SetFrame (int frameIndex, float time, float mix, int bendDirection) { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[frameIndex + MIX] = mix; + frames[frameIndex + BEND_DIRECTION] = bendDirection; + } + + override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + IkConstraint constraint = skeleton.ikConstraints.Items[ikConstraintIndex]; + + if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. + constraint.mix += (frames[frames.Length + PREV_MIX] - constraint.mix) * alpha; + constraint.bendDirection = (int)frames[frames.Length + PREV_BEND_DIRECTION]; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = Animation.binarySearch(frames, time, ENTRIES); + float mix = frames[frame + PREV_MIX]; + float frameTime = frames[frame]; + float percent = GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + constraint.mix += (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha; + constraint.bendDirection = (int)frames[frame + PREV_BEND_DIRECTION]; + } + } + + public class TransformConstraintTimeline : CurveTimeline { + public const int ENTRIES = 5; + private const int PREV_TIME = -5, PREV_ROTATE = -4, PREV_TRANSLATE = -3, PREV_SCALE = -2, PREV_SHEAR = -1; + private const int ROTATE = 1, TRANSLATE = 2, SCALE = 3, SHEAR = 4; + + internal int transformConstraintIndex; + internal float[] frames; + + public int TransformConstraintIndex { get { return transformConstraintIndex; } set { transformConstraintIndex = value; } } + public float[] Frames { get { return frames; } set { frames = value; } } // time, rotate mix, translate mix, scale mix, shear mix, ... + + public TransformConstraintTimeline (int frameCount) + : base(frameCount) { + frames = new float[frameCount * ENTRIES]; + } + + public void SetFrame (int frameIndex, float time, float rotateMix, float translateMix, float scaleMix, float shearMix) { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[frameIndex + ROTATE] = rotateMix; + frames[frameIndex + TRANSLATE] = translateMix; + frames[frameIndex + SCALE] = scaleMix; + frames[frameIndex + SHEAR] = shearMix; + } + + override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList firedEvents, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + TransformConstraint constraint = skeleton.transformConstraints.Items[transformConstraintIndex]; + + if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. + int i = frames.Length; + constraint.rotateMix += (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha; + constraint.translateMix += (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha; + constraint.scaleMix += (frames[i + PREV_SCALE] - constraint.scaleMix) * alpha; + constraint.shearMix += (frames[i + PREV_SHEAR] - constraint.shearMix) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = Animation.binarySearch(frames, time, ENTRIES); + float frameTime = frames[frame]; + float percent = GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + float rotate = frames[frame + PREV_ROTATE]; + float translate = frames[frame + PREV_TRANSLATE]; + float scale = frames[frame + PREV_SCALE]; + float shear = frames[frame + PREV_SHEAR]; + constraint.rotateMix += (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha; + constraint.translateMix += (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix) + * alpha; + constraint.scaleMix += (scale + (frames[frame + SCALE] - scale) * percent - constraint.scaleMix) * alpha; + constraint.shearMix += (shear + (frames[frame + SHEAR] - shear) * percent - constraint.shearMix) * alpha; + } + } + + public class PathConstraintPositionTimeline : CurveTimeline { + public const int ENTRIES = 2; + protected const int PREV_TIME = -2, PREV_VALUE = -1; + protected const int VALUE = 1; + + internal int pathConstraintIndex; + internal float[] frames; + + public PathConstraintPositionTimeline (int frameCount) + : base(frameCount) { + frames = new float[frameCount * ENTRIES]; + } + + public int PathConstraintIndex { get { return pathConstraintIndex; } set { pathConstraintIndex = value; } } + public float[] Frames { get { return frames; } set { frames = value; } } // time, position, ... + + /// Sets the time and value of the specified keyframe. + public void SetFrame (int frameIndex, float time, float value) { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[frameIndex + VALUE] = value; + } + + override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList events, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + PathConstraint constraint = skeleton.pathConstraints.Items[pathConstraintIndex]; + + if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. + int i = frames.Length; + constraint.position += (frames[i + PREV_VALUE] - constraint.position) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = Animation.binarySearch(frames, time, ENTRIES); + float position = frames[frame + PREV_VALUE]; + float frameTime = frames[frame]; + float percent = GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + constraint.position += (position + (frames[frame + VALUE] - position) * percent - constraint.position) * alpha; + } + } + + public class PathConstraintSpacingTimeline : PathConstraintPositionTimeline { + public PathConstraintSpacingTimeline (int frameCount) + : base(frameCount) { + } + + override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList events, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + PathConstraint constraint = skeleton.pathConstraints.Items[pathConstraintIndex]; + + if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. + int i = frames.Length; + constraint.spacing += (frames[i + PREV_VALUE] - constraint.spacing) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = Animation.binarySearch(frames, time, ENTRIES); + float spacing = frames[frame + PREV_VALUE]; + float frameTime = frames[frame]; + float percent = GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + constraint.spacing += (spacing + (frames[frame + VALUE] - spacing) * percent - constraint.spacing) * alpha; + } + } + + public class PathConstraintMixTimeline : CurveTimeline { + public const int ENTRIES = 3; + private const int PREV_TIME = -3, PREV_ROTATE = -2, PREV_TRANSLATE = -1; + private const int ROTATE = 1, TRANSLATE = 2; + + internal int pathConstraintIndex; + internal float[] frames; + + public int PathConstraintIndex { get { return pathConstraintIndex; } set { pathConstraintIndex = value; } } + public float[] Frames { get { return frames; } set { frames = value; } } // time, rotate mix, translate mix, ... + + public PathConstraintMixTimeline (int frameCount) + : base(frameCount) { + frames = new float[frameCount * ENTRIES]; + } + + /** Sets the time and mixes of the specified keyframe. */ + public void SetFrame (int frameIndex, float time, float rotateMix, float translateMix) { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[frameIndex + ROTATE] = rotateMix; + frames[frameIndex + TRANSLATE] = translateMix; + } + + override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList events, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + PathConstraint constraint = skeleton.pathConstraints.Items[pathConstraintIndex]; + + if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame. + int i = frames.Length; + constraint.rotateMix += (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha; + constraint.translateMix += (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = Animation.binarySearch(frames, time, ENTRIES); + float rotate = frames[frame + PREV_ROTATE]; + float translate = frames[frame + PREV_TRANSLATE]; + float frameTime = frames[frame]; + float percent = GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + constraint.rotateMix += (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha; + constraint.translateMix += (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix) + * alpha; + } + } } diff --git a/spine-csharp/src/AnimationState.cs b/spine-csharp/src/AnimationState.cs index 1d438efde7..9d0e65944a 100644 --- a/spine-csharp/src/AnimationState.cs +++ b/spine-csharp/src/AnimationState.cs @@ -1,307 +1,306 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Spine { - public class AnimationState { - private AnimationStateData data; - private ExposedList tracks = new ExposedList(); - private ExposedList events = new ExposedList(); - private float timeScale = 1; - - public AnimationStateData Data { get { return data; } } - /// A list of tracks that have animations, which may contain nulls. - public ExposedList Tracks { get { return tracks; } } - public float TimeScale { get { return timeScale; } set { timeScale = value; } } - - public delegate void StartEndDelegate (AnimationState state, int trackIndex); - public event StartEndDelegate Start; - public event StartEndDelegate End; - - public delegate void EventDelegate (AnimationState state, int trackIndex, Event e); - public event EventDelegate Event; - - public delegate void CompleteDelegate (AnimationState state, int trackIndex, int loopCount); - public event CompleteDelegate Complete; - - public AnimationState (AnimationStateData data) { - if (data == null) throw new ArgumentNullException("data", "data cannot be null."); - this.data = data; - } - - public void Update (float delta) { - delta *= timeScale; - for (int i = 0; i < tracks.Count; i++) { - TrackEntry current = tracks.Items[i]; - if (current == null) continue; - - float trackDelta = delta * current.timeScale; - float time = current.time + trackDelta; - float endTime = current.endTime; - - current.time = time; - if (current.previous != null) { - current.previous.time += trackDelta; - current.mixTime += trackDelta; - } - - // Check if completed the animation or a loop iteration. - if (current.loop ? (current.lastTime % endTime > time % endTime) : (current.lastTime < endTime && time >= endTime)) { - int count = (int)(time / endTime); - current.OnComplete(this, i, count); - if (Complete != null) Complete(this, i, count); - } - - TrackEntry next = current.next; - if (next != null) { - next.time = current.lastTime - next.delay; - if (next.time >= 0) SetCurrent(i, next); - } else { - // End non-looping animation when it reaches its end time and there is no next entry. - if (!current.loop && current.lastTime >= current.endTime) ClearTrack(i); - } - } - } - - public void Apply (Skeleton skeleton) { - ExposedList events = this.events; - - for (int i = 0; i < tracks.Count; i++) { - TrackEntry current = tracks.Items[i]; - if (current == null) continue; - - events.Clear(); - - float time = current.time; - bool loop = current.loop; - if (!loop && time > current.endTime) time = current.endTime; - - TrackEntry previous = current.previous; - if (previous == null) { - if (current.mix == 1) - current.animation.Apply(skeleton, current.lastTime, time, loop, events); - else - current.animation.Mix(skeleton, current.lastTime, time, loop, events, current.mix); - } else { - float previousTime = previous.time; - if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; - previous.animation.Apply(skeleton, previous.lastTime, previousTime, previous.loop, null); - // Remove the line above, and uncomment the line below, to allow previous animations to fire events during mixing. - //previous.animation.Apply(skeleton, previous.lastTime, previousTime, previous.loop, events); - previous.lastTime = previousTime; - - float alpha = current.mixTime / current.mixDuration * current.mix; - if (alpha >= 1) { - alpha = 1; - current.previous = null; - } - current.animation.Mix(skeleton, current.lastTime, time, loop, events, alpha); - } - - for (int ii = 0, nn = events.Count; ii < nn; ii++) { - Event e = events.Items[ii]; - current.OnEvent(this, i, e); - if (Event != null) Event(this, i, e); - } - - current.lastTime = current.time; - } - } - - public void ClearTracks () { - for (int i = 0, n = tracks.Count; i < n; i++) - ClearTrack(i); - tracks.Clear(); - } - - public void ClearTrack (int trackIndex) { - if (trackIndex >= tracks.Count) return; - TrackEntry current = tracks.Items[trackIndex]; - if (current == null) return; - - current.OnEnd(this, trackIndex); - if (End != null) End(this, trackIndex); - - tracks.Items[trackIndex] = null; - } - - private TrackEntry ExpandToIndex (int index) { - if (index < tracks.Count) return tracks.Items[index]; - while (index >= tracks.Count) - tracks.Add(null); - return null; - } - - private void SetCurrent (int index, TrackEntry entry) { - TrackEntry current = ExpandToIndex(index); - if (current != null) { - TrackEntry previous = current.previous; - current.previous = null; - - current.OnEnd(this, index); - if (End != null) End(this, index); - - entry.mixDuration = data.GetMix(current.animation, entry.animation); - if (entry.mixDuration > 0) { - entry.mixTime = 0; - // If a mix is in progress, mix from the closest animation. - if (previous != null && current.mixTime / current.mixDuration < 0.5f) - entry.previous = previous; - else - entry.previous = current; - } - } - - tracks.Items[index] = entry; - - entry.OnStart(this, index); - if (Start != null) Start(this, index); - } - - /// - public TrackEntry SetAnimation (int trackIndex, String animationName, bool loop) { - Animation animation = data.skeletonData.FindAnimation(animationName); - if (animation == null) throw new ArgumentException("Animation not found: " + animationName, "animationName"); - return SetAnimation(trackIndex, animation, loop); - } - - /// Set the current animation. Any queued animations are cleared. - public TrackEntry SetAnimation (int trackIndex, Animation animation, bool loop) { - if (animation == null) throw new ArgumentNullException("animation", "animation cannot be null."); - TrackEntry entry = new TrackEntry(); - entry.animation = animation; - entry.loop = loop; - entry.time = 0; - entry.endTime = animation.Duration; - SetCurrent(trackIndex, entry); - return entry; - } - - /// - public TrackEntry AddAnimation (int trackIndex, String animationName, bool loop, float delay) { - Animation animation = data.skeletonData.FindAnimation(animationName); - if (animation == null) throw new ArgumentException("Animation not found: " + animationName, "animationName"); - return AddAnimation(trackIndex, animation, loop, delay); - } - - /// Adds an animation to be played delay seconds after the current or last queued animation. - /// May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. - public TrackEntry AddAnimation (int trackIndex, Animation animation, bool loop, float delay) { - if (animation == null) throw new ArgumentNullException("animation", "animation cannot be null."); - TrackEntry entry = new TrackEntry(); - entry.animation = animation; - entry.loop = loop; - entry.time = 0; - entry.endTime = animation.Duration; - - TrackEntry last = ExpandToIndex(trackIndex); - if (last != null) { - while (last.next != null) - last = last.next; - last.next = entry; - } else - tracks.Items[trackIndex] = entry; - - if (delay <= 0) { - if (last != null) - delay += last.endTime - data.GetMix(last.animation, animation); - else - delay = 0; - } - entry.delay = delay; - - return entry; - } - - /// May be null. - public TrackEntry GetCurrent (int trackIndex) { - if (trackIndex >= tracks.Count) return null; - return tracks.Items[trackIndex]; - } - - override public String ToString () { - StringBuilder buffer = new StringBuilder(); - for (int i = 0, n = tracks.Count; i < n; i++) { - TrackEntry entry = tracks.Items[i]; - if (entry == null) continue; - if (buffer.Length > 0) buffer.Append(", "); - buffer.Append(entry.ToString()); - } - if (buffer.Length == 0) return ""; - return buffer.ToString(); - } - } - - public class TrackEntry { - internal TrackEntry next, previous; - internal Animation animation; - internal bool loop; - internal float delay, time, lastTime = -1, endTime, timeScale = 1; - internal float mixTime, mixDuration, mix = 1; - - public Animation Animation { get { return animation; } } - public float Delay { get { return delay; } set { delay = value; } } - public float Time { get { return time; } set { time = value; } } - public float LastTime { get { return lastTime; } set { lastTime = value; } } - public float EndTime { get { return endTime; } set { endTime = value; } } - public float TimeScale { get { return timeScale; } set { timeScale = value; } } - public float Mix { get { return mix; } set { mix = value; } } - public bool Loop { get { return loop; } set { loop = value; } } - - public event AnimationState.StartEndDelegate Start; - public event AnimationState.StartEndDelegate End; - public event AnimationState.EventDelegate Event; - public event AnimationState.CompleteDelegate Complete; - - internal void OnStart (AnimationState state, int index) { - if (Start != null) Start(state, index); - } - - internal void OnEnd (AnimationState state, int index) { - if (End != null) End(state, index); - } - - internal void OnEvent (AnimationState state, int index, Event e) { - if (Event != null) Event(state, index, e); - } - - internal void OnComplete (AnimationState state, int index, int loopCount) { - if (Complete != null) Complete(state, index, loopCount); - } - - override public String ToString () { - return animation == null ? "" : animation.name; - } - } +using System; +using System.Collections.Generic; +using System.Text; + +namespace Spine { + public class AnimationState { + private AnimationStateData data; + private ExposedList tracks = new ExposedList(); + private ExposedList events = new ExposedList(); + private float timeScale = 1; + + public AnimationStateData Data { get { return data; } } + /// A list of tracks that have animations, which may contain nulls. + public ExposedList Tracks { get { return tracks; } } + public float TimeScale { get { return timeScale; } set { timeScale = value; } } + + public delegate void StartEndDelegate (AnimationState state, int trackIndex); + public event StartEndDelegate Start; + public event StartEndDelegate End; + + public delegate void EventDelegate (AnimationState state, int trackIndex, Event e); + public event EventDelegate Event; + + public delegate void CompleteDelegate (AnimationState state, int trackIndex, int loopCount); + public event CompleteDelegate Complete; + + public AnimationState (AnimationStateData data) { + if (data == null) throw new ArgumentNullException("data", "data cannot be null."); + this.data = data; + } + + public void Update (float delta) { + delta *= timeScale; + for (int i = 0; i < tracks.Count; i++) { + TrackEntry current = tracks.Items[i]; + if (current == null) continue; + + float trackDelta = delta * current.timeScale; + float time = current.time + trackDelta; + float endTime = current.endTime; + + current.time = time; + if (current.previous != null) { + current.previous.time += trackDelta; + current.mixTime += trackDelta; + } + + // Check if completed the animation or a loop iteration. + if (current.loop ? (current.lastTime % endTime > time % endTime) : (current.lastTime < endTime && time >= endTime)) { + int count = (int)(time / endTime); + current.OnComplete(this, i, count); + if (Complete != null) Complete(this, i, count); + } + + TrackEntry next = current.next; + if (next != null) { + next.time = current.lastTime - next.delay; + if (next.time >= 0) SetCurrent(i, next); + } else { + // End non-looping animation when it reaches its end time and there is no next entry. + if (!current.loop && current.lastTime >= current.endTime) ClearTrack(i); + } + } + } + + public void Apply (Skeleton skeleton) { + ExposedList events = this.events; + + for (int i = 0; i < tracks.Count; i++) { + TrackEntry current = tracks.Items[i]; + if (current == null) continue; + + events.Clear(); + + float time = current.time; + bool loop = current.loop; + if (!loop && time > current.endTime) time = current.endTime; + + TrackEntry previous = current.previous; + if (previous == null) { + if (current.mix == 1) + current.animation.Apply(skeleton, current.lastTime, time, loop, events); + else + current.animation.Mix(skeleton, current.lastTime, time, loop, events, current.mix); + } else { + float previousTime = previous.time; + if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; + previous.animation.Apply(skeleton, previous.lastTime, previousTime, previous.loop, null); + // Remove the line above, and uncomment the line below, to allow previous animations to fire events during mixing. + //previous.animation.Apply(skeleton, previous.lastTime, previousTime, previous.loop, events); + previous.lastTime = previousTime; + + float alpha = current.mixTime / current.mixDuration * current.mix; + if (alpha >= 1) { + alpha = 1; + current.previous = null; + } + current.animation.Mix(skeleton, current.lastTime, time, loop, events, alpha); + } + + for (int ii = 0, nn = events.Count; ii < nn; ii++) { + Event e = events.Items[ii]; + current.OnEvent(this, i, e); + if (Event != null) Event(this, i, e); + } + + current.lastTime = current.time; + } + } + + public void ClearTracks () { + for (int i = 0, n = tracks.Count; i < n; i++) + ClearTrack(i); + tracks.Clear(); + } + + public void ClearTrack (int trackIndex) { + if (trackIndex >= tracks.Count) return; + TrackEntry current = tracks.Items[trackIndex]; + if (current == null) return; + + current.OnEnd(this, trackIndex); + if (End != null) End(this, trackIndex); + + tracks.Items[trackIndex] = null; + } + + private TrackEntry ExpandToIndex (int index) { + if (index < tracks.Count) return tracks.Items[index]; + while (index >= tracks.Count) + tracks.Add(null); + return null; + } + + private void SetCurrent (int index, TrackEntry entry) { + TrackEntry current = ExpandToIndex(index); + if (current != null) { + TrackEntry previous = current.previous; + current.previous = null; + + current.OnEnd(this, index); + if (End != null) End(this, index); + + entry.mixDuration = data.GetMix(current.animation, entry.animation); + if (entry.mixDuration > 0) { + entry.mixTime = 0; + // If a mix is in progress, mix from the closest animation. + if (previous != null && current.mixTime / current.mixDuration < 0.5f) + entry.previous = previous; + else + entry.previous = current; + } + } + + tracks.Items[index] = entry; + + entry.OnStart(this, index); + if (Start != null) Start(this, index); + } + + /// + public TrackEntry SetAnimation (int trackIndex, String animationName, bool loop) { + Animation animation = data.skeletonData.FindAnimation(animationName); + if (animation == null) throw new ArgumentException("Animation not found: " + animationName, "animationName"); + return SetAnimation(trackIndex, animation, loop); + } + + /// Set the current animation. Any queued animations are cleared. + public TrackEntry SetAnimation (int trackIndex, Animation animation, bool loop) { + if (animation == null) throw new ArgumentNullException("animation", "animation cannot be null."); + TrackEntry entry = new TrackEntry(); + entry.animation = animation; + entry.loop = loop; + entry.time = 0; + entry.endTime = animation.Duration; + SetCurrent(trackIndex, entry); + return entry; + } + + /// + public TrackEntry AddAnimation (int trackIndex, String animationName, bool loop, float delay) { + Animation animation = data.skeletonData.FindAnimation(animationName); + if (animation == null) throw new ArgumentException("Animation not found: " + animationName, "animationName"); + return AddAnimation(trackIndex, animation, loop, delay); + } + + /// Adds an animation to be played delay seconds after the current or last queued animation. + /// May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. + public TrackEntry AddAnimation (int trackIndex, Animation animation, bool loop, float delay) { + if (animation == null) throw new ArgumentNullException("animation", "animation cannot be null."); + TrackEntry entry = new TrackEntry(); + entry.animation = animation; + entry.loop = loop; + entry.time = 0; + entry.endTime = animation.Duration; + + TrackEntry last = ExpandToIndex(trackIndex); + if (last != null) { + while (last.next != null) + last = last.next; + last.next = entry; + } else + tracks.Items[trackIndex] = entry; + + if (delay <= 0) { + if (last != null) + delay += last.endTime - data.GetMix(last.animation, animation); + else + delay = 0; + } + entry.delay = delay; + + return entry; + } + + /// May be null. + public TrackEntry GetCurrent (int trackIndex) { + if (trackIndex >= tracks.Count) return null; + return tracks.Items[trackIndex]; + } + + override public String ToString () { + StringBuilder buffer = new StringBuilder(); + for (int i = 0, n = tracks.Count; i < n; i++) { + TrackEntry entry = tracks.Items[i]; + if (entry == null) continue; + if (buffer.Length > 0) buffer.Append(", "); + buffer.Append(entry.ToString()); + } + if (buffer.Length == 0) return ""; + return buffer.ToString(); + } + } + + public class TrackEntry { + internal TrackEntry next, previous; + internal Animation animation; + internal bool loop; + internal float delay, time, lastTime = -1, endTime, timeScale = 1; + internal float mixTime, mixDuration, mix = 1; + + public Animation Animation { get { return animation; } } + public float Delay { get { return delay; } set { delay = value; } } + public float Time { get { return time; } set { time = value; } } + public float LastTime { get { return lastTime; } set { lastTime = value; } } + public float EndTime { get { return endTime; } set { endTime = value; } } + public float TimeScale { get { return timeScale; } set { timeScale = value; } } + public float Mix { get { return mix; } set { mix = value; } } + public bool Loop { get { return loop; } set { loop = value; } } + + public event AnimationState.StartEndDelegate Start; + public event AnimationState.StartEndDelegate End; + public event AnimationState.EventDelegate Event; + public event AnimationState.CompleteDelegate Complete; + + internal void OnStart (AnimationState state, int index) { + if (Start != null) Start(state, index); + } + + internal void OnEnd (AnimationState state, int index) { + if (End != null) End(state, index); + } + + internal void OnEvent (AnimationState state, int index, Event e) { + if (Event != null) Event(state, index, e); + } + + internal void OnComplete (AnimationState state, int index, int loopCount) { + if (Complete != null) Complete(state, index, loopCount); + } + + override public String ToString () { + return animation == null ? "" : animation.name; + } + } } diff --git a/spine-csharp/src/AnimationStateData.cs b/spine-csharp/src/AnimationStateData.cs index 408cdfabfa..c868cfd84e 100644 --- a/spine-csharp/src/AnimationStateData.cs +++ b/spine-csharp/src/AnimationStateData.cs @@ -1,97 +1,96 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using System.Collections.Generic; - -namespace Spine { - public class AnimationStateData { - internal SkeletonData skeletonData; - private Dictionary animationToMixTime = new Dictionary(AnimationPairComparer.Instance); - internal float defaultMix; - - public SkeletonData SkeletonData { get { return skeletonData; } } - public float DefaultMix { get { return defaultMix; } set { defaultMix = value; } } - - public AnimationStateData (SkeletonData skeletonData) { - if (skeletonData == null) throw new ArgumentException ("skeletonData cannot be null."); - this.skeletonData = skeletonData; - } - - public void SetMix (String fromName, String toName, float duration) { - Animation from = skeletonData.FindAnimation(fromName); - if (from == null) throw new ArgumentException("Animation not found: " + fromName); - Animation to = skeletonData.FindAnimation(toName); - if (to == null) throw new ArgumentException("Animation not found: " + toName); - SetMix(from, to, duration); - } - - public void SetMix (Animation from, Animation to, float duration) { - if (from == null) throw new ArgumentNullException("from", "from cannot be null."); - if (to == null) throw new ArgumentNullException("to", "to cannot be null."); - AnimationPair key = new AnimationPair(from, to); - animationToMixTime.Remove(key); - animationToMixTime.Add(key, duration); - } - - public float GetMix (Animation from, Animation to) { - AnimationPair key = new AnimationPair(from, to); - float duration; - if (animationToMixTime.TryGetValue(key, out duration)) return duration; - return defaultMix; - } - - struct AnimationPair { - public readonly Animation a1; - public readonly Animation a2; - - public AnimationPair (Animation a1, Animation a2) { - this.a1 = a1; - this.a2 = a2; - } - } - - // Avoids boxing in the dictionary. - class AnimationPairComparer : IEqualityComparer { - internal static readonly AnimationPairComparer Instance = new AnimationPairComparer(); - - bool IEqualityComparer.Equals (AnimationPair x, AnimationPair y) { - return ReferenceEquals(x.a1, y.a1) && ReferenceEquals(x.a2, y.a2); - } - - int IEqualityComparer.GetHashCode (AnimationPair obj) { - // from Tuple.CombineHashCodes // return (((h1 << 5) + h1) ^ h2); - int h1 = obj.a1.GetHashCode(); - return (((h1 << 5) + h1) ^ obj.a2.GetHashCode()); - } - } - } +using System; +using System.Collections.Generic; + +namespace Spine { + public class AnimationStateData { + internal SkeletonData skeletonData; + private Dictionary animationToMixTime = new Dictionary(AnimationPairComparer.Instance); + internal float defaultMix; + + public SkeletonData SkeletonData { get { return skeletonData; } } + public float DefaultMix { get { return defaultMix; } set { defaultMix = value; } } + + public AnimationStateData (SkeletonData skeletonData) { + if (skeletonData == null) throw new ArgumentException ("skeletonData cannot be null."); + this.skeletonData = skeletonData; + } + + public void SetMix (String fromName, String toName, float duration) { + Animation from = skeletonData.FindAnimation(fromName); + if (from == null) throw new ArgumentException("Animation not found: " + fromName); + Animation to = skeletonData.FindAnimation(toName); + if (to == null) throw new ArgumentException("Animation not found: " + toName); + SetMix(from, to, duration); + } + + public void SetMix (Animation from, Animation to, float duration) { + if (from == null) throw new ArgumentNullException("from", "from cannot be null."); + if (to == null) throw new ArgumentNullException("to", "to cannot be null."); + AnimationPair key = new AnimationPair(from, to); + animationToMixTime.Remove(key); + animationToMixTime.Add(key, duration); + } + + public float GetMix (Animation from, Animation to) { + AnimationPair key = new AnimationPair(from, to); + float duration; + if (animationToMixTime.TryGetValue(key, out duration)) return duration; + return defaultMix; + } + + struct AnimationPair { + public readonly Animation a1; + public readonly Animation a2; + + public AnimationPair (Animation a1, Animation a2) { + this.a1 = a1; + this.a2 = a2; + } + } + + // Avoids boxing in the dictionary. + class AnimationPairComparer : IEqualityComparer { + internal static readonly AnimationPairComparer Instance = new AnimationPairComparer(); + + bool IEqualityComparer.Equals (AnimationPair x, AnimationPair y) { + return ReferenceEquals(x.a1, y.a1) && ReferenceEquals(x.a2, y.a2); + } + + int IEqualityComparer.GetHashCode (AnimationPair obj) { + // from Tuple.CombineHashCodes // return (((h1 << 5) + h1) ^ h2); + int h1 = obj.a1.GetHashCode(); + return (((h1 << 5) + h1) ^ obj.a2.GetHashCode()); + } + } + } } diff --git a/spine-csharp/src/Atlas.cs b/spine-csharp/src/Atlas.cs index c3aeb43bd6..b3f7b96ae2 100644 --- a/spine-csharp/src/Atlas.cs +++ b/spine-csharp/src/Atlas.cs @@ -1,294 +1,293 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; - -#if WINDOWS_STOREAPP -using System.Threading.Tasks; -using Windows.Storage; -#endif - -namespace Spine { - public class Atlas { - List pages = new List(); - List regions = new List(); - TextureLoader textureLoader; - - #if !(UNITY_5 || UNITY_4 || UNITY_WSA || UNITY_WP8 || UNITY_WP8_1) // !UNITY - #if WINDOWS_STOREAPP - private async Task ReadFile(string path, TextureLoader textureLoader) { - var folder = Windows.ApplicationModel.Package.Current.InstalledLocation; - var file = await folder.GetFileAsync(path).AsTask().ConfigureAwait(false); - using (var reader = new StreamReader(await file.OpenStreamForReadAsync().ConfigureAwait(false))) { - try { - Load(reader, Path.GetDirectoryName(path), textureLoader); - } catch (Exception ex) { - throw new Exception("Error reading atlas file: " + path, ex); - } - } - } - - public Atlas(String path, TextureLoader textureLoader) { - this.ReadFile(path, textureLoader).Wait(); - } - #else - - public Atlas (String path, TextureLoader textureLoader) { - - #if WINDOWS_PHONE - Stream stream = Microsoft.Xna.Framework.TitleContainer.OpenStream(path); - using (StreamReader reader = new StreamReader(stream)) { - #else - using (StreamReader reader = new StreamReader(path)) { - #endif // WINDOWS_PHONE - - try { - Load(reader, Path.GetDirectoryName(path), textureLoader); - } catch (Exception ex) { - throw new Exception("Error reading atlas file: " + path, ex); - } - - } - } - #endif // WINDOWS_STOREAPP - - #endif // !(UNITY) - - public Atlas (TextReader reader, String dir, TextureLoader textureLoader) { - Load(reader, dir, textureLoader); - } - - public Atlas (List pages, List regions) { - this.pages = pages; - this.regions = regions; - this.textureLoader = null; - } - - private void Load (TextReader reader, String imagesDir, TextureLoader textureLoader) { - if (textureLoader == null) throw new ArgumentNullException("textureLoader cannot be null."); - this.textureLoader = textureLoader; - - String[] tuple = new String[4]; - AtlasPage page = null; - while (true) { - String line = reader.ReadLine(); - if (line == null) break; - if (line.Trim().Length == 0) - page = null; - else if (page == null) { - page = new AtlasPage(); - page.name = line; - - if (ReadTuple(reader, tuple) == 2) { // size is only optional for an atlas packed with an old TexturePacker. - page.width = int.Parse(tuple[0]); - page.height = int.Parse(tuple[1]); - ReadTuple(reader, tuple); - } - page.format = (Format)Enum.Parse(typeof(Format), tuple[0], false); - - ReadTuple(reader, tuple); - page.minFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[0], false); - page.magFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[1], false); - - String direction = ReadValue(reader); - page.uWrap = TextureWrap.ClampToEdge; - page.vWrap = TextureWrap.ClampToEdge; - if (direction == "x") - page.uWrap = TextureWrap.Repeat; - else if (direction == "y") - page.vWrap = TextureWrap.Repeat; - else if (direction == "xy") - page.uWrap = page.vWrap = TextureWrap.Repeat; - - textureLoader.Load(page, Path.Combine(imagesDir, line)); - - pages.Add(page); - - } else { - AtlasRegion region = new AtlasRegion(); - region.name = line; - region.page = page; - - region.rotate = Boolean.Parse(ReadValue(reader)); - - ReadTuple(reader, tuple); - int x = int.Parse(tuple[0]); - int y = int.Parse(tuple[1]); - - ReadTuple(reader, tuple); - int width = int.Parse(tuple[0]); - int height = int.Parse(tuple[1]); - - region.u = x / (float)page.width; - region.v = y / (float)page.height; - if (region.rotate) { - region.u2 = (x + height) / (float)page.width; - region.v2 = (y + width) / (float)page.height; - } else { - region.u2 = (x + width) / (float)page.width; - region.v2 = (y + height) / (float)page.height; - } - region.x = x; - region.y = y; - region.width = Math.Abs(width); - region.height = Math.Abs(height); - - if (ReadTuple(reader, tuple) == 4) { // split is optional - region.splits = new int[] {int.Parse(tuple[0]), int.Parse(tuple[1]), - int.Parse(tuple[2]), int.Parse(tuple[3])}; - - if (ReadTuple(reader, tuple) == 4) { // pad is optional, but only present with splits - region.pads = new int[] {int.Parse(tuple[0]), int.Parse(tuple[1]), - int.Parse(tuple[2]), int.Parse(tuple[3])}; - - ReadTuple(reader, tuple); - } - } - - region.originalWidth = int.Parse(tuple[0]); - region.originalHeight = int.Parse(tuple[1]); - - ReadTuple(reader, tuple); - region.offsetX = int.Parse(tuple[0]); - region.offsetY = int.Parse(tuple[1]); - - region.index = int.Parse(ReadValue(reader)); - - regions.Add(region); - } - } - } - - static String ReadValue (TextReader reader) { - String line = reader.ReadLine(); - int colon = line.IndexOf(':'); - if (colon == -1) throw new Exception("Invalid line: " + line); - return line.Substring(colon + 1).Trim(); - } - - /// Returns the number of tuple values read (1, 2 or 4). - static int ReadTuple (TextReader reader, String[] tuple) { - String line = reader.ReadLine(); - int colon = line.IndexOf(':'); - if (colon == -1) throw new Exception("Invalid line: " + line); - int i = 0, lastMatch = colon + 1; - for (; i < 3; i++) { - int comma = line.IndexOf(',', lastMatch); - if (comma == -1) break; - tuple[i] = line.Substring(lastMatch, comma - lastMatch).Trim(); - lastMatch = comma + 1; - } - tuple[i] = line.Substring(lastMatch).Trim(); - return i + 1; - } - - public void FlipV () { - for (int i = 0, n = regions.Count; i < n; i++) { - AtlasRegion region = regions[i]; - region.v = 1 - region.v; - region.v2 = 1 - region.v2; - } - } - - /// Returns the first region found with the specified name. This method uses string comparison to find the region, so the result - /// should be cached rather than calling this method multiple times. - /// The region, or null. - public AtlasRegion FindRegion (String name) { - for (int i = 0, n = regions.Count; i < n; i++) - if (regions[i].name == name) return regions[i]; - return null; - } - - public void Dispose () { - if (textureLoader == null) return; - for (int i = 0, n = pages.Count; i < n; i++) - textureLoader.Unload(pages[i].rendererObject); - } - } - - public enum Format { - Alpha, - Intensity, - LuminanceAlpha, - RGB565, - RGBA4444, - RGB888, - RGBA8888 - } - - public enum TextureFilter { - Nearest, - Linear, - MipMap, - MipMapNearestNearest, - MipMapLinearNearest, - MipMapNearestLinear, - MipMapLinearLinear - } - - public enum TextureWrap { - MirroredRepeat, - ClampToEdge, - Repeat - } - - public class AtlasPage { - public String name; - public Format format; - public TextureFilter minFilter; - public TextureFilter magFilter; - public TextureWrap uWrap; - public TextureWrap vWrap; - public Object rendererObject; - public int width, height; - } - - public class AtlasRegion { - public AtlasPage page; - public String name; - public int x, y, width, height; - public float u, v, u2, v2; - public float offsetX, offsetY; - public int originalWidth, originalHeight; - public int index; - public bool rotate; - public int[] splits; - public int[] pads; - } - - public interface TextureLoader { - void Load (AtlasPage page, String path); - void Unload (Object texture); - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; + +#if WINDOWS_STOREAPP +using System.Threading.Tasks; +using Windows.Storage; +#endif + +namespace Spine { + public class Atlas { + List pages = new List(); + List regions = new List(); + TextureLoader textureLoader; + + #if !(UNITY_5 || UNITY_4 || UNITY_WSA || UNITY_WP8 || UNITY_WP8_1) // !UNITY + #if WINDOWS_STOREAPP + private async Task ReadFile(string path, TextureLoader textureLoader) { + var folder = Windows.ApplicationModel.Package.Current.InstalledLocation; + var file = await folder.GetFileAsync(path).AsTask().ConfigureAwait(false); + using (var reader = new StreamReader(await file.OpenStreamForReadAsync().ConfigureAwait(false))) { + try { + Load(reader, Path.GetDirectoryName(path), textureLoader); + } catch (Exception ex) { + throw new Exception("Error reading atlas file: " + path, ex); + } + } + } + + public Atlas(String path, TextureLoader textureLoader) { + this.ReadFile(path, textureLoader).Wait(); + } + #else + + public Atlas (String path, TextureLoader textureLoader) { + + #if WINDOWS_PHONE + Stream stream = Microsoft.Xna.Framework.TitleContainer.OpenStream(path); + using (StreamReader reader = new StreamReader(stream)) { + #else + using (StreamReader reader = new StreamReader(path)) { + #endif // WINDOWS_PHONE + + try { + Load(reader, Path.GetDirectoryName(path), textureLoader); + } catch (Exception ex) { + throw new Exception("Error reading atlas file: " + path, ex); + } + + } + } + #endif // WINDOWS_STOREAPP + + #endif // !(UNITY) + + public Atlas (TextReader reader, String dir, TextureLoader textureLoader) { + Load(reader, dir, textureLoader); + } + + public Atlas (List pages, List regions) { + this.pages = pages; + this.regions = regions; + this.textureLoader = null; + } + + private void Load (TextReader reader, String imagesDir, TextureLoader textureLoader) { + if (textureLoader == null) throw new ArgumentNullException("textureLoader cannot be null."); + this.textureLoader = textureLoader; + + String[] tuple = new String[4]; + AtlasPage page = null; + while (true) { + String line = reader.ReadLine(); + if (line == null) break; + if (line.Trim().Length == 0) + page = null; + else if (page == null) { + page = new AtlasPage(); + page.name = line; + + if (ReadTuple(reader, tuple) == 2) { // size is only optional for an atlas packed with an old TexturePacker. + page.width = int.Parse(tuple[0]); + page.height = int.Parse(tuple[1]); + ReadTuple(reader, tuple); + } + page.format = (Format)Enum.Parse(typeof(Format), tuple[0], false); + + ReadTuple(reader, tuple); + page.minFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[0], false); + page.magFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[1], false); + + String direction = ReadValue(reader); + page.uWrap = TextureWrap.ClampToEdge; + page.vWrap = TextureWrap.ClampToEdge; + if (direction == "x") + page.uWrap = TextureWrap.Repeat; + else if (direction == "y") + page.vWrap = TextureWrap.Repeat; + else if (direction == "xy") + page.uWrap = page.vWrap = TextureWrap.Repeat; + + textureLoader.Load(page, Path.Combine(imagesDir, line)); + + pages.Add(page); + + } else { + AtlasRegion region = new AtlasRegion(); + region.name = line; + region.page = page; + + region.rotate = Boolean.Parse(ReadValue(reader)); + + ReadTuple(reader, tuple); + int x = int.Parse(tuple[0]); + int y = int.Parse(tuple[1]); + + ReadTuple(reader, tuple); + int width = int.Parse(tuple[0]); + int height = int.Parse(tuple[1]); + + region.u = x / (float)page.width; + region.v = y / (float)page.height; + if (region.rotate) { + region.u2 = (x + height) / (float)page.width; + region.v2 = (y + width) / (float)page.height; + } else { + region.u2 = (x + width) / (float)page.width; + region.v2 = (y + height) / (float)page.height; + } + region.x = x; + region.y = y; + region.width = Math.Abs(width); + region.height = Math.Abs(height); + + if (ReadTuple(reader, tuple) == 4) { // split is optional + region.splits = new int[] {int.Parse(tuple[0]), int.Parse(tuple[1]), + int.Parse(tuple[2]), int.Parse(tuple[3])}; + + if (ReadTuple(reader, tuple) == 4) { // pad is optional, but only present with splits + region.pads = new int[] {int.Parse(tuple[0]), int.Parse(tuple[1]), + int.Parse(tuple[2]), int.Parse(tuple[3])}; + + ReadTuple(reader, tuple); + } + } + + region.originalWidth = int.Parse(tuple[0]); + region.originalHeight = int.Parse(tuple[1]); + + ReadTuple(reader, tuple); + region.offsetX = int.Parse(tuple[0]); + region.offsetY = int.Parse(tuple[1]); + + region.index = int.Parse(ReadValue(reader)); + + regions.Add(region); + } + } + } + + static String ReadValue (TextReader reader) { + String line = reader.ReadLine(); + int colon = line.IndexOf(':'); + if (colon == -1) throw new Exception("Invalid line: " + line); + return line.Substring(colon + 1).Trim(); + } + + /// Returns the number of tuple values read (1, 2 or 4). + static int ReadTuple (TextReader reader, String[] tuple) { + String line = reader.ReadLine(); + int colon = line.IndexOf(':'); + if (colon == -1) throw new Exception("Invalid line: " + line); + int i = 0, lastMatch = colon + 1; + for (; i < 3; i++) { + int comma = line.IndexOf(',', lastMatch); + if (comma == -1) break; + tuple[i] = line.Substring(lastMatch, comma - lastMatch).Trim(); + lastMatch = comma + 1; + } + tuple[i] = line.Substring(lastMatch).Trim(); + return i + 1; + } + + public void FlipV () { + for (int i = 0, n = regions.Count; i < n; i++) { + AtlasRegion region = regions[i]; + region.v = 1 - region.v; + region.v2 = 1 - region.v2; + } + } + + /// Returns the first region found with the specified name. This method uses string comparison to find the region, so the result + /// should be cached rather than calling this method multiple times. + /// The region, or null. + public AtlasRegion FindRegion (String name) { + for (int i = 0, n = regions.Count; i < n; i++) + if (regions[i].name == name) return regions[i]; + return null; + } + + public void Dispose () { + if (textureLoader == null) return; + for (int i = 0, n = pages.Count; i < n; i++) + textureLoader.Unload(pages[i].rendererObject); + } + } + + public enum Format { + Alpha, + Intensity, + LuminanceAlpha, + RGB565, + RGBA4444, + RGB888, + RGBA8888 + } + + public enum TextureFilter { + Nearest, + Linear, + MipMap, + MipMapNearestNearest, + MipMapLinearNearest, + MipMapNearestLinear, + MipMapLinearLinear + } + + public enum TextureWrap { + MirroredRepeat, + ClampToEdge, + Repeat + } + + public class AtlasPage { + public String name; + public Format format; + public TextureFilter minFilter; + public TextureFilter magFilter; + public TextureWrap uWrap; + public TextureWrap vWrap; + public Object rendererObject; + public int width, height; + } + + public class AtlasRegion { + public AtlasPage page; + public String name; + public int x, y, width, height; + public float u, v, u2, v2; + public float offsetX, offsetY; + public int originalWidth, originalHeight; + public int index; + public bool rotate; + public int[] splits; + public int[] pads; + } + + public interface TextureLoader { + void Load (AtlasPage page, String path); + void Unload (Object texture); + } } diff --git a/spine-csharp/src/Attachments/AtlasAttachmentLoader.cs b/spine-csharp/src/Attachments/AtlasAttachmentLoader.cs index b3d133c2f5..bc1e94ca21 100644 --- a/spine-csharp/src/Attachments/AtlasAttachmentLoader.cs +++ b/spine-csharp/src/Attachments/AtlasAttachmentLoader.cs @@ -1,97 +1,96 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - public class AtlasAttachmentLoader : AttachmentLoader { - private Atlas[] atlasArray; - - public AtlasAttachmentLoader (params Atlas[] atlasArray) { - if (atlasArray == null) throw new ArgumentNullException("atlas array cannot be null."); - this.atlasArray = atlasArray; - } - - public RegionAttachment NewRegionAttachment (Skin skin, String name, String path) { - AtlasRegion region = FindRegion(path); - if (region == null) throw new Exception("Region not found in atlas: " + path + " (region attachment: " + name + ")"); - RegionAttachment attachment = new RegionAttachment(name); - attachment.RendererObject = region; - attachment.SetUVs(region.u, region.v, region.u2, region.v2, region.rotate); - attachment.regionOffsetX = region.offsetX; - attachment.regionOffsetY = region.offsetY; - attachment.regionWidth = region.width; - attachment.regionHeight = region.height; - attachment.regionOriginalWidth = region.originalWidth; - attachment.regionOriginalHeight = region.originalHeight; - return attachment; - } - - public MeshAttachment NewMeshAttachment (Skin skin, String name, String path) { - AtlasRegion region = FindRegion(path); - if (region == null) throw new Exception("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); - MeshAttachment attachment = new MeshAttachment(name); - attachment.RendererObject = region; - attachment.RegionU = region.u; - attachment.RegionV = region.v; - attachment.RegionU2 = region.u2; - attachment.RegionV2 = region.v2; - attachment.RegionRotate = region.rotate; - attachment.regionOffsetX = region.offsetX; - attachment.regionOffsetY = region.offsetY; - attachment.regionWidth = region.width; - attachment.regionHeight = region.height; - attachment.regionOriginalWidth = region.originalWidth; - attachment.regionOriginalHeight = region.originalHeight; - return attachment; - } - - public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name) { - return new BoundingBoxAttachment(name); - } - - public PathAttachment NewPathAttachment (Skin skin, String name) { - return new PathAttachment (name); - } - - public AtlasRegion FindRegion (string name) { - AtlasRegion region; - - for (int i = 0; i < atlasArray.Length; i++) { - region = atlasArray[i].FindRegion(name); - if (region != null) - return region; - } - - return null; - } - } +using System; + +namespace Spine { + public class AtlasAttachmentLoader : AttachmentLoader { + private Atlas[] atlasArray; + + public AtlasAttachmentLoader (params Atlas[] atlasArray) { + if (atlasArray == null) throw new ArgumentNullException("atlas array cannot be null."); + this.atlasArray = atlasArray; + } + + public RegionAttachment NewRegionAttachment (Skin skin, String name, String path) { + AtlasRegion region = FindRegion(path); + if (region == null) throw new Exception("Region not found in atlas: " + path + " (region attachment: " + name + ")"); + RegionAttachment attachment = new RegionAttachment(name); + attachment.RendererObject = region; + attachment.SetUVs(region.u, region.v, region.u2, region.v2, region.rotate); + attachment.regionOffsetX = region.offsetX; + attachment.regionOffsetY = region.offsetY; + attachment.regionWidth = region.width; + attachment.regionHeight = region.height; + attachment.regionOriginalWidth = region.originalWidth; + attachment.regionOriginalHeight = region.originalHeight; + return attachment; + } + + public MeshAttachment NewMeshAttachment (Skin skin, String name, String path) { + AtlasRegion region = FindRegion(path); + if (region == null) throw new Exception("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); + MeshAttachment attachment = new MeshAttachment(name); + attachment.RendererObject = region; + attachment.RegionU = region.u; + attachment.RegionV = region.v; + attachment.RegionU2 = region.u2; + attachment.RegionV2 = region.v2; + attachment.RegionRotate = region.rotate; + attachment.regionOffsetX = region.offsetX; + attachment.regionOffsetY = region.offsetY; + attachment.regionWidth = region.width; + attachment.regionHeight = region.height; + attachment.regionOriginalWidth = region.originalWidth; + attachment.regionOriginalHeight = region.originalHeight; + return attachment; + } + + public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name) { + return new BoundingBoxAttachment(name); + } + + public PathAttachment NewPathAttachment (Skin skin, String name) { + return new PathAttachment (name); + } + + public AtlasRegion FindRegion (string name) { + AtlasRegion region; + + for (int i = 0; i < atlasArray.Length; i++) { + region = atlasArray[i].FindRegion(name); + if (region != null) + return region; + } + + return null; + } + } } diff --git a/spine-csharp/src/Attachments/Attachment.cs b/spine-csharp/src/Attachments/Attachment.cs index 44d8bc2a31..be7ea6d986 100644 --- a/spine-csharp/src/Attachments/Attachment.cs +++ b/spine-csharp/src/Attachments/Attachment.cs @@ -1,47 +1,46 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - abstract public class Attachment { - public String Name { get; private set; } - - public Attachment (String name) { - if (name == null) throw new ArgumentNullException("name", "name cannot be null"); - Name = name; - } - - override public String ToString () { - return Name; - } - } +using System; + +namespace Spine { + abstract public class Attachment { + public String Name { get; private set; } + + public Attachment (String name) { + if (name == null) throw new ArgumentNullException("name", "name cannot be null"); + Name = name; + } + + override public String ToString () { + return Name; + } + } } diff --git a/spine-csharp/src/Attachments/AttachmentLoader.cs b/spine-csharp/src/Attachments/AttachmentLoader.cs index 801b8a7785..eaa2aba426 100644 --- a/spine-csharp/src/Attachments/AttachmentLoader.cs +++ b/spine-csharp/src/Attachments/AttachmentLoader.cs @@ -1,48 +1,47 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - public interface AttachmentLoader { - /// May be null to not load any attachment. - RegionAttachment NewRegionAttachment (Skin skin, String name, String path); - - /// May be null to not load any attachment. - MeshAttachment NewMeshAttachment (Skin skin, String name, String path); - - /// May be null to not load any attachment. - BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name); - - /// May be null to not load any attachment - PathAttachment NewPathAttachment (Skin skin, String name); - } +using System; + +namespace Spine { + public interface AttachmentLoader { + /// May be null to not load any attachment. + RegionAttachment NewRegionAttachment (Skin skin, String name, String path); + + /// May be null to not load any attachment. + MeshAttachment NewMeshAttachment (Skin skin, String name, String path); + + /// May be null to not load any attachment. + BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name); + + /// May be null to not load any attachment + PathAttachment NewPathAttachment (Skin skin, String name); + } } diff --git a/spine-csharp/src/Attachments/AttachmentType.cs b/spine-csharp/src/Attachments/AttachmentType.cs index 81b55a99a4..8b7c69bc45 100644 --- a/spine-csharp/src/Attachments/AttachmentType.cs +++ b/spine-csharp/src/Attachments/AttachmentType.cs @@ -1,36 +1,35 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -namespace Spine { - public enum AttachmentType { - Region, Boundingbox, Mesh, Linkedmesh, Path - } +namespace Spine { + public enum AttachmentType { + Region, Boundingbox, Mesh, Linkedmesh, Path + } } diff --git a/spine-csharp/src/Attachments/BoundingBoxAttachment.cs b/spine-csharp/src/Attachments/BoundingBoxAttachment.cs index 41b42c2368..c1d0066c33 100644 --- a/spine-csharp/src/Attachments/BoundingBoxAttachment.cs +++ b/spine-csharp/src/Attachments/BoundingBoxAttachment.cs @@ -1,41 +1,40 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - /// Attachment that has a polygon for bounds checking. - public class BoundingBoxAttachment : VertexAttachment { - public BoundingBoxAttachment (string name) - : base(name) { - } - } +using System; + +namespace Spine { + /// Attachment that has a polygon for bounds checking. + public class BoundingBoxAttachment : VertexAttachment { + public BoundingBoxAttachment (string name) + : base(name) { + } + } } diff --git a/spine-csharp/src/Attachments/MeshAttachment.cs b/spine-csharp/src/Attachments/MeshAttachment.cs index e9e4912cf8..c6c7e285e2 100644 --- a/spine-csharp/src/Attachments/MeshAttachment.cs +++ b/spine-csharp/src/Attachments/MeshAttachment.cs @@ -1,120 +1,119 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - /// Attachment that displays a texture region using a mesh. - public class MeshAttachment : VertexAttachment { - internal float regionOffsetX, regionOffsetY, regionWidth, regionHeight, regionOriginalWidth, regionOriginalHeight; - internal float[] uvs, regionUVs; - internal int[] triangles; - internal float r = 1, g = 1, b = 1, a = 1; - internal int hulllength; - internal MeshAttachment parentMesh; - internal bool inheritDeform; - - public int HullLength { get { return hulllength; } set { hulllength = value; } } - public float[] RegionUVs { get { return regionUVs; } set { regionUVs = value; } } - public float[] UVs { get { return uvs; } set { uvs = value; } } - public int[] Triangles { get { return triangles; } set { triangles = value; } } - - public float R { get { return r; } set { r = value; } } - public float G { get { return g; } set { g = value; } } - public float B { get { return b; } set { b = value; } } - public float A { get { return a; } set { a = value; } } - - public String Path { get; set; } - public Object RendererObject { get; set; } - public float RegionU { get; set; } - public float RegionV { get; set; } - public float RegionU2 { get; set; } - public float RegionV2 { get; set; } - public bool RegionRotate { get; set; } - public float RegionOffsetX { get { return regionOffsetX; } set { regionOffsetX = value; } } - public float RegionOffsetY { get { return regionOffsetY; } set { regionOffsetY = value; } } // Pixels stripped from the bottom left, unrotated. - public float RegionWidth { get { return regionWidth; } set { regionWidth = value; } } - public float RegionHeight { get { return regionHeight; } set { regionHeight = value; } } // Unrotated, stripped size. - public float RegionOriginalWidth { get { return regionOriginalWidth; } set { regionOriginalWidth = value; } } - public float RegionOriginalHeight { get { return regionOriginalHeight; } set { regionOriginalHeight = value; } } // Unrotated, unstripped size. - - public bool InheritDeform { get { return inheritDeform; } set { inheritDeform = value; } } - - public MeshAttachment ParentMesh { - get { return parentMesh; } - set { - parentMesh = value; - if (value != null) { - bones = value.bones; - vertices = value.vertices; - worldVerticesLength = value.worldVerticesLength; - regionUVs = value.regionUVs; - triangles = value.triangles; - HullLength = value.HullLength; - Edges = value.Edges; - Width = value.Width; - Height = value.Height; - } - } - } - - // Nonessential. - public int[] Edges { get; set; } - public float Width { get; set; } - public float Height { get; set; } - - public MeshAttachment (string name) - : base(name) { - } - - public void UpdateUVs () { - float u = RegionU, v = RegionV, width = RegionU2 - RegionU, height = RegionV2 - RegionV; - float[] regionUVs = this.regionUVs; - if (this.uvs == null || this.uvs.Length != regionUVs.Length) this.uvs = new float[regionUVs.Length]; - float[] uvs = this.uvs; - if (RegionRotate) { - for (int i = 0, n = uvs.Length; i < n; i += 2) { - uvs[i] = u + regionUVs[i + 1] * width; - uvs[i + 1] = v + height - regionUVs[i] * height; - } - } else { - for (int i = 0, n = uvs.Length; i < n; i += 2) { - uvs[i] = u + regionUVs[i] * width; - uvs[i + 1] = v + regionUVs[i + 1] * height; - } - } - } - - override public bool ApplyDeform (VertexAttachment sourceAttachment) { - return this == sourceAttachment || (inheritDeform && parentMesh == sourceAttachment); - } - } +using System; + +namespace Spine { + /// Attachment that displays a texture region using a mesh. + public class MeshAttachment : VertexAttachment { + internal float regionOffsetX, regionOffsetY, regionWidth, regionHeight, regionOriginalWidth, regionOriginalHeight; + internal float[] uvs, regionUVs; + internal int[] triangles; + internal float r = 1, g = 1, b = 1, a = 1; + internal int hulllength; + internal MeshAttachment parentMesh; + internal bool inheritDeform; + + public int HullLength { get { return hulllength; } set { hulllength = value; } } + public float[] RegionUVs { get { return regionUVs; } set { regionUVs = value; } } + public float[] UVs { get { return uvs; } set { uvs = value; } } + public int[] Triangles { get { return triangles; } set { triangles = value; } } + + public float R { get { return r; } set { r = value; } } + public float G { get { return g; } set { g = value; } } + public float B { get { return b; } set { b = value; } } + public float A { get { return a; } set { a = value; } } + + public String Path { get; set; } + public Object RendererObject { get; set; } + public float RegionU { get; set; } + public float RegionV { get; set; } + public float RegionU2 { get; set; } + public float RegionV2 { get; set; } + public bool RegionRotate { get; set; } + public float RegionOffsetX { get { return regionOffsetX; } set { regionOffsetX = value; } } + public float RegionOffsetY { get { return regionOffsetY; } set { regionOffsetY = value; } } // Pixels stripped from the bottom left, unrotated. + public float RegionWidth { get { return regionWidth; } set { regionWidth = value; } } + public float RegionHeight { get { return regionHeight; } set { regionHeight = value; } } // Unrotated, stripped size. + public float RegionOriginalWidth { get { return regionOriginalWidth; } set { regionOriginalWidth = value; } } + public float RegionOriginalHeight { get { return regionOriginalHeight; } set { regionOriginalHeight = value; } } // Unrotated, unstripped size. + + public bool InheritDeform { get { return inheritDeform; } set { inheritDeform = value; } } + + public MeshAttachment ParentMesh { + get { return parentMesh; } + set { + parentMesh = value; + if (value != null) { + bones = value.bones; + vertices = value.vertices; + worldVerticesLength = value.worldVerticesLength; + regionUVs = value.regionUVs; + triangles = value.triangles; + HullLength = value.HullLength; + Edges = value.Edges; + Width = value.Width; + Height = value.Height; + } + } + } + + // Nonessential. + public int[] Edges { get; set; } + public float Width { get; set; } + public float Height { get; set; } + + public MeshAttachment (string name) + : base(name) { + } + + public void UpdateUVs () { + float u = RegionU, v = RegionV, width = RegionU2 - RegionU, height = RegionV2 - RegionV; + float[] regionUVs = this.regionUVs; + if (this.uvs == null || this.uvs.Length != regionUVs.Length) this.uvs = new float[regionUVs.Length]; + float[] uvs = this.uvs; + if (RegionRotate) { + for (int i = 0, n = uvs.Length; i < n; i += 2) { + uvs[i] = u + regionUVs[i + 1] * width; + uvs[i + 1] = v + height - regionUVs[i] * height; + } + } else { + for (int i = 0, n = uvs.Length; i < n; i += 2) { + uvs[i] = u + regionUVs[i] * width; + uvs[i + 1] = v + regionUVs[i + 1] * height; + } + } + } + + override public bool ApplyDeform (VertexAttachment sourceAttachment) { + return this == sourceAttachment || (inheritDeform && parentMesh == sourceAttachment); + } + } } diff --git a/spine-csharp/src/Attachments/PathAttachment.cs b/spine-csharp/src/Attachments/PathAttachment.cs index 661f4bbdce..3a4d9db870 100644 --- a/spine-csharp/src/Attachments/PathAttachment.cs +++ b/spine-csharp/src/Attachments/PathAttachment.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,13 +21,13 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + using System; using System.Collections.Generic; @@ -46,4 +45,4 @@ public PathAttachment (String name) : base(name) { } } -} +} diff --git a/spine-csharp/src/Attachments/RegionAttachment.cs b/spine-csharp/src/Attachments/RegionAttachment.cs index 99199397a5..70cf575766 100644 --- a/spine-csharp/src/Attachments/RegionAttachment.cs +++ b/spine-csharp/src/Attachments/RegionAttachment.cs @@ -1,153 +1,152 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - /// Attachment that displays a texture region. - public class RegionAttachment : Attachment { - public const int X1 = 0; - public const int Y1 = 1; - public const int X2 = 2; - public const int Y2 = 3; - public const int X3 = 4; - public const int Y3 = 5; - public const int X4 = 6; - public const int Y4 = 7; - - internal float x, y, rotation, scaleX = 1, scaleY = 1, width, height; - internal float regionOffsetX, regionOffsetY, regionWidth, regionHeight, regionOriginalWidth, regionOriginalHeight; - internal float[] offset = new float[8], uvs = new float[8]; - internal float r = 1, g = 1, b = 1, a = 1; - - public float X { get { return x; } set { x = value; } } - public float Y { get { return y; } set { y = value; } } - public float Rotation { get { return rotation; } set { rotation = value; } } - public float ScaleX { get { return scaleX; } set { scaleX = value; } } - public float ScaleY { get { return scaleY; } set { scaleY = value; } } - public float Width { get { return width; } set { width = value; } } - public float Height { get { return height; } set { height = value; } } - - public float R { get { return r; } set { r = value; } } - public float G { get { return g; } set { g = value; } } - public float B { get { return b; } set { b = value; } } - public float A { get { return a; } set { a = value; } } - - public String Path { get; set; } - public Object RendererObject { get; set; } - public float RegionOffsetX { get { return regionOffsetX; } set { regionOffsetX = value; } } - public float RegionOffsetY { get { return regionOffsetY; } set { regionOffsetY = value; } } // Pixels stripped from the bottom left, unrotated. - public float RegionWidth { get { return regionWidth; } set { regionWidth = value; } } - public float RegionHeight { get { return regionHeight; } set { regionHeight = value; } } // Unrotated, stripped size. - public float RegionOriginalWidth { get { return regionOriginalWidth; } set { regionOriginalWidth = value; } } - public float RegionOriginalHeight { get { return regionOriginalHeight; } set { regionOriginalHeight = value; } } // Unrotated, unstripped size. - - public float[] Offset { get { return offset; } } - public float[] UVs { get { return uvs; } } - - public RegionAttachment (string name) - : base(name) { - } - - public void SetUVs (float u, float v, float u2, float v2, bool rotate) { - float[] uvs = this.uvs; - if (rotate) { - uvs[X2] = u; - uvs[Y2] = v2; - uvs[X3] = u; - uvs[Y3] = v; - uvs[X4] = u2; - uvs[Y4] = v; - uvs[X1] = u2; - uvs[Y1] = v2; - } else { - uvs[X1] = u; - uvs[Y1] = v2; - uvs[X2] = u; - uvs[Y2] = v; - uvs[X3] = u2; - uvs[Y3] = v; - uvs[X4] = u2; - uvs[Y4] = v2; - } - } - - public void UpdateOffset () { - float width = this.width; - float height = this.height; - float scaleX = this.scaleX; - float scaleY = this.scaleY; - float regionScaleX = width / regionOriginalWidth * scaleX; - float regionScaleY = height / regionOriginalHeight * scaleY; - float localX = -width / 2 * scaleX + regionOffsetX * regionScaleX; - float localY = -height / 2 * scaleY + regionOffsetY * regionScaleY; - float localX2 = localX + regionWidth * regionScaleX; - float localY2 = localY + regionHeight * regionScaleY; - float rotation = this.rotation; - float cos = MathUtils.CosDeg(rotation); - float sin = MathUtils.SinDeg(rotation); - float x = this.x; - float y = this.y; - float localXCos = localX * cos + x; - float localXSin = localX * sin; - float localYCos = localY * cos + y; - float localYSin = localY * sin; - float localX2Cos = localX2 * cos + x; - float localX2Sin = localX2 * sin; - float localY2Cos = localY2 * cos + y; - float localY2Sin = localY2 * sin; - float[] offset = this.offset; - offset[X1] = localXCos - localYSin; - offset[Y1] = localYCos + localXSin; - offset[X2] = localXCos - localY2Sin; - offset[Y2] = localY2Cos + localXSin; - offset[X3] = localX2Cos - localY2Sin; - offset[Y3] = localY2Cos + localX2Sin; - offset[X4] = localX2Cos - localYSin; - offset[Y4] = localYCos + localX2Sin; - } - - public void ComputeWorldVertices (Bone bone, float[] worldVertices) { - Skeleton skeleton = bone.skeleton; - float x = skeleton.x + bone.worldX, y = skeleton.y + bone.worldY; - float a = bone.a, b = bone.b, c = bone.c, d = bone.d; - float[] offset = this.offset; - worldVertices[X1] = offset[X1] * a + offset[Y1] * b + x; - worldVertices[Y1] = offset[X1] * c + offset[Y1] * d + y; - worldVertices[X2] = offset[X2] * a + offset[Y2] * b + x; - worldVertices[Y2] = offset[X2] * c + offset[Y2] * d + y; - worldVertices[X3] = offset[X3] * a + offset[Y3] * b + x; - worldVertices[Y3] = offset[X3] * c + offset[Y3] * d + y; - worldVertices[X4] = offset[X4] * a + offset[Y4] * b + x; - worldVertices[Y4] = offset[X4] * c + offset[Y4] * d + y; - } - } +using System; + +namespace Spine { + /// Attachment that displays a texture region. + public class RegionAttachment : Attachment { + public const int X1 = 0; + public const int Y1 = 1; + public const int X2 = 2; + public const int Y2 = 3; + public const int X3 = 4; + public const int Y3 = 5; + public const int X4 = 6; + public const int Y4 = 7; + + internal float x, y, rotation, scaleX = 1, scaleY = 1, width, height; + internal float regionOffsetX, regionOffsetY, regionWidth, regionHeight, regionOriginalWidth, regionOriginalHeight; + internal float[] offset = new float[8], uvs = new float[8]; + internal float r = 1, g = 1, b = 1, a = 1; + + public float X { get { return x; } set { x = value; } } + public float Y { get { return y; } set { y = value; } } + public float Rotation { get { return rotation; } set { rotation = value; } } + public float ScaleX { get { return scaleX; } set { scaleX = value; } } + public float ScaleY { get { return scaleY; } set { scaleY = value; } } + public float Width { get { return width; } set { width = value; } } + public float Height { get { return height; } set { height = value; } } + + public float R { get { return r; } set { r = value; } } + public float G { get { return g; } set { g = value; } } + public float B { get { return b; } set { b = value; } } + public float A { get { return a; } set { a = value; } } + + public String Path { get; set; } + public Object RendererObject { get; set; } + public float RegionOffsetX { get { return regionOffsetX; } set { regionOffsetX = value; } } + public float RegionOffsetY { get { return regionOffsetY; } set { regionOffsetY = value; } } // Pixels stripped from the bottom left, unrotated. + public float RegionWidth { get { return regionWidth; } set { regionWidth = value; } } + public float RegionHeight { get { return regionHeight; } set { regionHeight = value; } } // Unrotated, stripped size. + public float RegionOriginalWidth { get { return regionOriginalWidth; } set { regionOriginalWidth = value; } } + public float RegionOriginalHeight { get { return regionOriginalHeight; } set { regionOriginalHeight = value; } } // Unrotated, unstripped size. + + public float[] Offset { get { return offset; } } + public float[] UVs { get { return uvs; } } + + public RegionAttachment (string name) + : base(name) { + } + + public void SetUVs (float u, float v, float u2, float v2, bool rotate) { + float[] uvs = this.uvs; + if (rotate) { + uvs[X2] = u; + uvs[Y2] = v2; + uvs[X3] = u; + uvs[Y3] = v; + uvs[X4] = u2; + uvs[Y4] = v; + uvs[X1] = u2; + uvs[Y1] = v2; + } else { + uvs[X1] = u; + uvs[Y1] = v2; + uvs[X2] = u; + uvs[Y2] = v; + uvs[X3] = u2; + uvs[Y3] = v; + uvs[X4] = u2; + uvs[Y4] = v2; + } + } + + public void UpdateOffset () { + float width = this.width; + float height = this.height; + float scaleX = this.scaleX; + float scaleY = this.scaleY; + float regionScaleX = width / regionOriginalWidth * scaleX; + float regionScaleY = height / regionOriginalHeight * scaleY; + float localX = -width / 2 * scaleX + regionOffsetX * regionScaleX; + float localY = -height / 2 * scaleY + regionOffsetY * regionScaleY; + float localX2 = localX + regionWidth * regionScaleX; + float localY2 = localY + regionHeight * regionScaleY; + float rotation = this.rotation; + float cos = MathUtils.CosDeg(rotation); + float sin = MathUtils.SinDeg(rotation); + float x = this.x; + float y = this.y; + float localXCos = localX * cos + x; + float localXSin = localX * sin; + float localYCos = localY * cos + y; + float localYSin = localY * sin; + float localX2Cos = localX2 * cos + x; + float localX2Sin = localX2 * sin; + float localY2Cos = localY2 * cos + y; + float localY2Sin = localY2 * sin; + float[] offset = this.offset; + offset[X1] = localXCos - localYSin; + offset[Y1] = localYCos + localXSin; + offset[X2] = localXCos - localY2Sin; + offset[Y2] = localY2Cos + localXSin; + offset[X3] = localX2Cos - localY2Sin; + offset[Y3] = localY2Cos + localX2Sin; + offset[X4] = localX2Cos - localYSin; + offset[Y4] = localYCos + localX2Sin; + } + + public void ComputeWorldVertices (Bone bone, float[] worldVertices) { + Skeleton skeleton = bone.skeleton; + float x = skeleton.x + bone.worldX, y = skeleton.y + bone.worldY; + float a = bone.a, b = bone.b, c = bone.c, d = bone.d; + float[] offset = this.offset; + worldVertices[X1] = offset[X1] * a + offset[Y1] * b + x; + worldVertices[Y1] = offset[X1] * c + offset[Y1] * d + y; + worldVertices[X2] = offset[X2] * a + offset[Y2] * b + x; + worldVertices[Y2] = offset[X2] * c + offset[Y2] * d + y; + worldVertices[X3] = offset[X3] * a + offset[Y3] * b + x; + worldVertices[Y3] = offset[X3] * c + offset[Y3] * d + y; + worldVertices[X4] = offset[X4] * a + offset[Y4] * b + x; + worldVertices[Y4] = offset[X4] * c + offset[Y4] * d + y; + } + } } diff --git a/spine-csharp/src/Attachments/VertexAttachment.cs b/spine-csharp/src/Attachments/VertexAttachment.cs index 962c491224..1f3e87e8b2 100644 --- a/spine-csharp/src/Attachments/VertexAttachment.cs +++ b/spine-csharp/src/Attachments/VertexAttachment.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,13 +21,13 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + using System; using System.Collections.Generic; @@ -115,4 +114,4 @@ public VertexAttachment (String name) return this == sourceAttachment; } } -} +} diff --git a/spine-csharp/src/BlendMode.cs b/spine-csharp/src/BlendMode.cs index 6c53e00497..2d33091017 100644 --- a/spine-csharp/src/BlendMode.cs +++ b/spine-csharp/src/BlendMode.cs @@ -1,36 +1,35 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -namespace Spine { - public enum BlendMode { - normal, additive, multiply, screen - } +namespace Spine { + public enum BlendMode { + normal, additive, multiply, screen + } } diff --git a/spine-csharp/src/Bone.cs b/spine-csharp/src/Bone.cs index 7bf48e31b3..203c28d692 100644 --- a/spine-csharp/src/Bone.cs +++ b/spine-csharp/src/Bone.cs @@ -1,315 +1,314 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - public class Bone : IUpdatable { - static public bool yDown; - - internal BoneData data; - internal Skeleton skeleton; - internal Bone parent; - internal ExposedList children = new ExposedList(); - internal float x, y, rotation, scaleX, scaleY, shearX, shearY; - internal float appliedRotation; - - internal float a, b, worldX; - internal float c, d, worldY; - internal float worldSignX, worldSignY; - - internal bool sorted; - - public BoneData Data { get { return data; } } - public Skeleton Skeleton { get { return skeleton; } } - public Bone Parent { get { return parent; } } - public ExposedList Children { get { return children; } } - public float X { get { return x; } set { x = value; } } - public float Y { get { return y; } set { y = value; } } - public float Rotation { get { return rotation; } set { rotation = value; } } - /// The rotation, as calculated by any constraints. - public float AppliedRotation { get { return appliedRotation; } set { appliedRotation = value; } } - public float ScaleX { get { return scaleX; } set { scaleX = value; } } - public float ScaleY { get { return scaleY; } set { scaleY = value; } } - public float ShearX { get { return shearX; } set { shearX = value; } } - public float ShearY { get { return shearY; } set { shearY = value; } } - - public float A { get { return a; } } - public float B { get { return b; } } - public float C { get { return c; } } - public float D { get { return d; } } - public float WorldX { get { return worldX; } } - public float WorldY { get { return worldY; } } - public float WorldSignX { get { return worldSignX; } } - public float WorldSignY { get { return worldSignY; } } - public float WorldRotationX { get { return MathUtils.Atan2(c, a) * MathUtils.radDeg; } } - public float WorldRotationY { get { return MathUtils.Atan2(d, b) * MathUtils.radDeg; } } - public float WorldScaleX { get { return (float)Math.Sqrt(a * a + c * c) * worldSignX; } } - public float WorldScaleY { get { return (float)Math.Sqrt(b * b + d * d) * worldSignY; } } - - /// May be null. - public Bone (BoneData data, Skeleton skeleton, Bone parent) { - if (data == null) throw new ArgumentNullException("data", "data cannot be null."); - if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null."); - this.data = data; - this.skeleton = skeleton; - this.parent = parent; - SetToSetupPose(); - } - - /// Same as . This method exists for Bone to implement . - public void Update () { - UpdateWorldTransform(x, y, rotation, scaleX, scaleY, shearX, shearY); - } - - /// Computes the world transform using the parent bone and this bone's local transform. - public void UpdateWorldTransform () { - UpdateWorldTransform(x, y, rotation, scaleX, scaleY, shearX, shearY); - } - - /// Computes the world transform using the parent bone and the specified local transform. - public void UpdateWorldTransform (float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY) { - appliedRotation = rotation; - - float rotationY = rotation + 90 + shearY; - float la = MathUtils.CosDeg(rotation + shearX) * scaleX, lb = MathUtils.CosDeg(rotationY) * scaleY; - float lc = MathUtils.SinDeg(rotation + shearX) * scaleX, ld = MathUtils.SinDeg(rotationY) * scaleY; - - Bone parent = this.parent; - if (parent == null) { // Root bone. - Skeleton skeleton = this.skeleton; - if (skeleton.flipX) { - x = -x; - la = -la; - lb = -lb; - } - if (skeleton.flipY != yDown) { - y = -y; - lc = -lc; - ld = -ld; - } - a = la; - b = lb; - c = lc; - d = ld; - worldX = x; - worldY = y; - worldSignX = Math.Sign(scaleX); - worldSignY = Math.Sign(scaleY); - return; - } - - float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; - worldX = pa * x + pb * y + parent.worldX; - worldY = pc * x + pd * y + parent.worldY; - worldSignX = parent.worldSignX * Math.Sign(scaleX); - worldSignY = parent.worldSignY * Math.Sign(scaleY); - - if (data.inheritRotation && data.inheritScale) { - a = pa * la + pb * lc; - b = pa * lb + pb * ld; - c = pc * la + pd * lc; - d = pc * lb + pd * ld; - } else { - if (data.inheritRotation) { // No scale inheritance. - pa = 1; - pb = 0; - pc = 0; - pd = 1; - do { - float cos = MathUtils.CosDeg(parent.appliedRotation), sin = MathUtils.SinDeg(parent.appliedRotation); - float temp = pa * cos + pb * sin; - pb = pb * cos - pa * sin; - pa = temp; - temp = pc * cos + pd * sin; - pd = pd * cos - pc * sin; - pc = temp; - - if (!parent.data.inheritRotation) break; - parent = parent.parent; - } while (parent != null); - a = pa * la + pb * lc; - b = pa * lb + pb * ld; - c = pc * la + pd * lc; - d = pc * lb + pd * ld; - } else if (data.inheritScale) { // No rotation inheritance. - pa = 1; - pb = 0; - pc = 0; - pd = 1; - do { - float cos = MathUtils.CosDeg(parent.appliedRotation), sin = MathUtils.SinDeg(parent.appliedRotation); - float psx = parent.scaleX, psy = parent.scaleY; - float za = cos * psx, zb = sin * psy, zc = sin * psx, zd = cos * psy; - float temp = pa * za + pb * zc; - pb = pb * zd - pa * zb; - pa = temp; - temp = pc * za + pd * zc; - pd = pd * zd - pc * zb; - pc = temp; - - if (psx >= 0) sin = -sin; - temp = pa * cos + pb * sin; - pb = pb * cos - pa * sin; - pa = temp; - temp = pc * cos + pd * sin; - pd = pd * cos - pc * sin; - pc = temp; - - if (!parent.data.inheritScale) break; - parent = parent.parent; - } while (parent != null); - a = pa * la + pb * lc; - b = pa * lb + pb * ld; - c = pc * la + pd * lc; - d = pc * lb + pd * ld; - } else { - a = la; - b = lb; - c = lc; - d = ld; - } - if (skeleton.flipX) { - a = -a; - b = -b; - } - if (skeleton.flipY != yDown) { - c = -c; - d = -d; - } - } - } - - public void SetToSetupPose () { - BoneData data = this.data; - x = data.x; - y = data.y; - rotation = data.rotation; - scaleX = data.scaleX; - scaleY = data.scaleY; - shearX = data.shearX; - shearY = data.shearY; - } - - public float WorldToLocalRotationX { - get { - Bone parent = this.parent; - if (parent == null) return rotation; - float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, a = this.a, c = this.c; - return MathUtils.Atan2(pa * c - pc * a, pd * a - pb * c) * MathUtils.radDeg; - } - } - - public float WorldToLocalRotationY { - get { - Bone parent = this.parent; - if (parent == null) return rotation; - float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, b = this.b, d = this.d; - return MathUtils.Atan2(pa * d - pc * b, pd * b - pb * d) * MathUtils.radDeg; - } - } - - public void RotateWorld (float degrees) { - float a = this.a, b = this.b, c = this.c, d = this.d; - float cos = MathUtils.CosDeg(degrees), sin = MathUtils.SinDeg(degrees); - this.a = cos * a - sin * c; - this.b = cos * b - sin * d; - this.c = sin * a + cos * c; - this.d = sin * b + cos * d; - } - - /// - /// Computes the local transform from the world transform. This can be useful to perform processing on the local transform - /// after the world transform has been modified directly (eg, by a constraint). - /// - /// Some redundant information is lost by the world transform, such as -1,-1 scale versus 180 rotation. The computed local - /// transform values may differ from the original values but are functionally the same. - /// - public void UpdateLocalTransform () { - Bone parent = this.parent; - if (parent == null) { - x = worldX; - y = worldY; - rotation = MathUtils.Atan2(c, a) * MathUtils.radDeg; - scaleX = (float)Math.Sqrt(a * a + c * c); - scaleY = (float)Math.Sqrt(b * b + d * d); - float det = a * d - b * c; - shearX = 0; - shearY = MathUtils.Atan2(a * b + c * d, det) * MathUtils.radDeg; - return; - } - float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; - float pid = 1 / (pa * pd - pb * pc); - float dx = worldX - parent.worldX, dy = worldY - parent.worldY; - x = (dx * pd * pid - dy * pb * pid); - y = (dy * pa * pid - dx * pc * pid); - float ia = pid * pd; - float id = pid * pa; - float ib = pid * pb; - float ic = pid * pc; - float ra = ia * a - ib * c; - float rb = ia * b - ib * d; - float rc = id * c - ic * a; - float rd = id * d - ic * b; - shearX = 0; - scaleX = (float)Math.Sqrt(ra * ra + rc * rc); - if (scaleX > 0.0001f) { - float det = ra * rd - rb * rc; - scaleY = det / scaleX; - shearY = MathUtils.Atan2(ra * rb + rc * rd, det) * MathUtils.radDeg; - rotation = MathUtils.Atan2(rc, ra) * MathUtils.radDeg; - } else { - scaleX = 0; - scaleY = (float)Math.Sqrt(rb * rb + rd * rd); - shearY = 0; - rotation = 90 - MathUtils.Atan2(rd, rb) * MathUtils.radDeg; - } - appliedRotation = rotation; - } - - public void WorldToLocal (float worldX, float worldY, out float localX, out float localY) { - float a = this.a, b = this.b, c = this.c, d = this.d; - float invDet = 1 / (a * d - b * c); - float x = worldX - this.worldX, y = worldY - this.worldY; - localX = (x * d * invDet - y * b * invDet); - localY = (y * a * invDet - x * c * invDet); - } - - public void LocalToWorld (float localX, float localY, out float worldX, out float worldY) { - worldX = localX * a + localY * b + this.worldX; - worldY = localX * c + localY * d + this.worldY; - } - - override public String ToString () { - return data.name; - } - } +using System; + +namespace Spine { + public class Bone : IUpdatable { + static public bool yDown; + + internal BoneData data; + internal Skeleton skeleton; + internal Bone parent; + internal ExposedList children = new ExposedList(); + internal float x, y, rotation, scaleX, scaleY, shearX, shearY; + internal float appliedRotation; + + internal float a, b, worldX; + internal float c, d, worldY; + internal float worldSignX, worldSignY; + + internal bool sorted; + + public BoneData Data { get { return data; } } + public Skeleton Skeleton { get { return skeleton; } } + public Bone Parent { get { return parent; } } + public ExposedList Children { get { return children; } } + public float X { get { return x; } set { x = value; } } + public float Y { get { return y; } set { y = value; } } + public float Rotation { get { return rotation; } set { rotation = value; } } + /// The rotation, as calculated by any constraints. + public float AppliedRotation { get { return appliedRotation; } set { appliedRotation = value; } } + public float ScaleX { get { return scaleX; } set { scaleX = value; } } + public float ScaleY { get { return scaleY; } set { scaleY = value; } } + public float ShearX { get { return shearX; } set { shearX = value; } } + public float ShearY { get { return shearY; } set { shearY = value; } } + + public float A { get { return a; } } + public float B { get { return b; } } + public float C { get { return c; } } + public float D { get { return d; } } + public float WorldX { get { return worldX; } } + public float WorldY { get { return worldY; } } + public float WorldSignX { get { return worldSignX; } } + public float WorldSignY { get { return worldSignY; } } + public float WorldRotationX { get { return MathUtils.Atan2(c, a) * MathUtils.radDeg; } } + public float WorldRotationY { get { return MathUtils.Atan2(d, b) * MathUtils.radDeg; } } + public float WorldScaleX { get { return (float)Math.Sqrt(a * a + c * c) * worldSignX; } } + public float WorldScaleY { get { return (float)Math.Sqrt(b * b + d * d) * worldSignY; } } + + /// May be null. + public Bone (BoneData data, Skeleton skeleton, Bone parent) { + if (data == null) throw new ArgumentNullException("data", "data cannot be null."); + if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null."); + this.data = data; + this.skeleton = skeleton; + this.parent = parent; + SetToSetupPose(); + } + + /// Same as . This method exists for Bone to implement . + public void Update () { + UpdateWorldTransform(x, y, rotation, scaleX, scaleY, shearX, shearY); + } + + /// Computes the world transform using the parent bone and this bone's local transform. + public void UpdateWorldTransform () { + UpdateWorldTransform(x, y, rotation, scaleX, scaleY, shearX, shearY); + } + + /// Computes the world transform using the parent bone and the specified local transform. + public void UpdateWorldTransform (float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY) { + appliedRotation = rotation; + + float rotationY = rotation + 90 + shearY; + float la = MathUtils.CosDeg(rotation + shearX) * scaleX, lb = MathUtils.CosDeg(rotationY) * scaleY; + float lc = MathUtils.SinDeg(rotation + shearX) * scaleX, ld = MathUtils.SinDeg(rotationY) * scaleY; + + Bone parent = this.parent; + if (parent == null) { // Root bone. + Skeleton skeleton = this.skeleton; + if (skeleton.flipX) { + x = -x; + la = -la; + lb = -lb; + } + if (skeleton.flipY != yDown) { + y = -y; + lc = -lc; + ld = -ld; + } + a = la; + b = lb; + c = lc; + d = ld; + worldX = x; + worldY = y; + worldSignX = Math.Sign(scaleX); + worldSignY = Math.Sign(scaleY); + return; + } + + float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + worldX = pa * x + pb * y + parent.worldX; + worldY = pc * x + pd * y + parent.worldY; + worldSignX = parent.worldSignX * Math.Sign(scaleX); + worldSignY = parent.worldSignY * Math.Sign(scaleY); + + if (data.inheritRotation && data.inheritScale) { + a = pa * la + pb * lc; + b = pa * lb + pb * ld; + c = pc * la + pd * lc; + d = pc * lb + pd * ld; + } else { + if (data.inheritRotation) { // No scale inheritance. + pa = 1; + pb = 0; + pc = 0; + pd = 1; + do { + float cos = MathUtils.CosDeg(parent.appliedRotation), sin = MathUtils.SinDeg(parent.appliedRotation); + float temp = pa * cos + pb * sin; + pb = pb * cos - pa * sin; + pa = temp; + temp = pc * cos + pd * sin; + pd = pd * cos - pc * sin; + pc = temp; + + if (!parent.data.inheritRotation) break; + parent = parent.parent; + } while (parent != null); + a = pa * la + pb * lc; + b = pa * lb + pb * ld; + c = pc * la + pd * lc; + d = pc * lb + pd * ld; + } else if (data.inheritScale) { // No rotation inheritance. + pa = 1; + pb = 0; + pc = 0; + pd = 1; + do { + float cos = MathUtils.CosDeg(parent.appliedRotation), sin = MathUtils.SinDeg(parent.appliedRotation); + float psx = parent.scaleX, psy = parent.scaleY; + float za = cos * psx, zb = sin * psy, zc = sin * psx, zd = cos * psy; + float temp = pa * za + pb * zc; + pb = pb * zd - pa * zb; + pa = temp; + temp = pc * za + pd * zc; + pd = pd * zd - pc * zb; + pc = temp; + + if (psx >= 0) sin = -sin; + temp = pa * cos + pb * sin; + pb = pb * cos - pa * sin; + pa = temp; + temp = pc * cos + pd * sin; + pd = pd * cos - pc * sin; + pc = temp; + + if (!parent.data.inheritScale) break; + parent = parent.parent; + } while (parent != null); + a = pa * la + pb * lc; + b = pa * lb + pb * ld; + c = pc * la + pd * lc; + d = pc * lb + pd * ld; + } else { + a = la; + b = lb; + c = lc; + d = ld; + } + if (skeleton.flipX) { + a = -a; + b = -b; + } + if (skeleton.flipY != yDown) { + c = -c; + d = -d; + } + } + } + + public void SetToSetupPose () { + BoneData data = this.data; + x = data.x; + y = data.y; + rotation = data.rotation; + scaleX = data.scaleX; + scaleY = data.scaleY; + shearX = data.shearX; + shearY = data.shearY; + } + + public float WorldToLocalRotationX { + get { + Bone parent = this.parent; + if (parent == null) return rotation; + float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, a = this.a, c = this.c; + return MathUtils.Atan2(pa * c - pc * a, pd * a - pb * c) * MathUtils.radDeg; + } + } + + public float WorldToLocalRotationY { + get { + Bone parent = this.parent; + if (parent == null) return rotation; + float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, b = this.b, d = this.d; + return MathUtils.Atan2(pa * d - pc * b, pd * b - pb * d) * MathUtils.radDeg; + } + } + + public void RotateWorld (float degrees) { + float a = this.a, b = this.b, c = this.c, d = this.d; + float cos = MathUtils.CosDeg(degrees), sin = MathUtils.SinDeg(degrees); + this.a = cos * a - sin * c; + this.b = cos * b - sin * d; + this.c = sin * a + cos * c; + this.d = sin * b + cos * d; + } + + /// + /// Computes the local transform from the world transform. This can be useful to perform processing on the local transform + /// after the world transform has been modified directly (eg, by a constraint). + /// + /// Some redundant information is lost by the world transform, such as -1,-1 scale versus 180 rotation. The computed local + /// transform values may differ from the original values but are functionally the same. + /// + public void UpdateLocalTransform () { + Bone parent = this.parent; + if (parent == null) { + x = worldX; + y = worldY; + rotation = MathUtils.Atan2(c, a) * MathUtils.radDeg; + scaleX = (float)Math.Sqrt(a * a + c * c); + scaleY = (float)Math.Sqrt(b * b + d * d); + float det = a * d - b * c; + shearX = 0; + shearY = MathUtils.Atan2(a * b + c * d, det) * MathUtils.radDeg; + return; + } + float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + float pid = 1 / (pa * pd - pb * pc); + float dx = worldX - parent.worldX, dy = worldY - parent.worldY; + x = (dx * pd * pid - dy * pb * pid); + y = (dy * pa * pid - dx * pc * pid); + float ia = pid * pd; + float id = pid * pa; + float ib = pid * pb; + float ic = pid * pc; + float ra = ia * a - ib * c; + float rb = ia * b - ib * d; + float rc = id * c - ic * a; + float rd = id * d - ic * b; + shearX = 0; + scaleX = (float)Math.Sqrt(ra * ra + rc * rc); + if (scaleX > 0.0001f) { + float det = ra * rd - rb * rc; + scaleY = det / scaleX; + shearY = MathUtils.Atan2(ra * rb + rc * rd, det) * MathUtils.radDeg; + rotation = MathUtils.Atan2(rc, ra) * MathUtils.radDeg; + } else { + scaleX = 0; + scaleY = (float)Math.Sqrt(rb * rb + rd * rd); + shearY = 0; + rotation = 90 - MathUtils.Atan2(rd, rb) * MathUtils.radDeg; + } + appliedRotation = rotation; + } + + public void WorldToLocal (float worldX, float worldY, out float localX, out float localY) { + float a = this.a, b = this.b, c = this.c, d = this.d; + float invDet = 1 / (a * d - b * c); + float x = worldX - this.worldX, y = worldY - this.worldY; + localX = (x * d * invDet - y * b * invDet); + localY = (y * a * invDet - x * c * invDet); + } + + public void LocalToWorld (float localX, float localY, out float worldX, out float worldY) { + worldX = localX * a + localY * b + this.worldX; + worldY = localX * c + localY * d + this.worldY; + } + + override public String ToString () { + return data.name; + } + } } diff --git a/spine-csharp/src/BoneData.cs b/spine-csharp/src/BoneData.cs index db51b67389..58525ab22f 100644 --- a/spine-csharp/src/BoneData.cs +++ b/spine-csharp/src/BoneData.cs @@ -1,71 +1,70 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - public class BoneData { - internal int index; - internal String name; - internal BoneData parent; - internal float length; - internal float x, y, rotation, scaleX = 1, scaleY = 1, shearX, shearY; - internal bool inheritRotation = true, inheritScale = true; - - /// May be null. - public int Index { get { return index; } } - public String Name { get { return name; } } - public BoneData Parent { get { return parent; } } - public float Length { get { return length; } set { length = value; } } - public float X { get { return x; } set { x = value; } } - public float Y { get { return y; } set { y = value; } } - public float Rotation { get { return rotation; } set { rotation = value; } } - public float ScaleX { get { return scaleX; } set { scaleX = value; } } - public float ScaleY { get { return scaleY; } set { scaleY = value; } } - public float ShearX { get { return shearX; } set { shearX = value; } } - public float ShearY { get { return shearY; } set { shearY = value; } } - public bool InheritRotation { get { return inheritRotation; } set { inheritRotation = value; } } - public bool InheritScale { get { return inheritScale; } set { inheritScale = value; } } - - /// May be null. - public BoneData (int index, String name, BoneData parent) { - if (index < 0) throw new ArgumentException("index must be >= 0", "index"); - if (name == null) throw new ArgumentNullException("name", "name cannot be null."); - this.index = index; - this.name = name; - this.parent = parent; - } - - override public String ToString () { - return name; - } - } +using System; + +namespace Spine { + public class BoneData { + internal int index; + internal String name; + internal BoneData parent; + internal float length; + internal float x, y, rotation, scaleX = 1, scaleY = 1, shearX, shearY; + internal bool inheritRotation = true, inheritScale = true; + + /// May be null. + public int Index { get { return index; } } + public String Name { get { return name; } } + public BoneData Parent { get { return parent; } } + public float Length { get { return length; } set { length = value; } } + public float X { get { return x; } set { x = value; } } + public float Y { get { return y; } set { y = value; } } + public float Rotation { get { return rotation; } set { rotation = value; } } + public float ScaleX { get { return scaleX; } set { scaleX = value; } } + public float ScaleY { get { return scaleY; } set { scaleY = value; } } + public float ShearX { get { return shearX; } set { shearX = value; } } + public float ShearY { get { return shearY; } set { shearY = value; } } + public bool InheritRotation { get { return inheritRotation; } set { inheritRotation = value; } } + public bool InheritScale { get { return inheritScale; } set { inheritScale = value; } } + + /// May be null. + public BoneData (int index, String name, BoneData parent) { + if (index < 0) throw new ArgumentException("index must be >= 0", "index"); + if (name == null) throw new ArgumentNullException("name", "name cannot be null."); + this.index = index; + this.name = name; + this.parent = parent; + } + + override public String ToString () { + return name; + } + } } diff --git a/spine-csharp/src/Event.cs b/spine-csharp/src/Event.cs index 134a980267..b36b2ef4bc 100644 --- a/spine-csharp/src/Event.cs +++ b/spine-csharp/src/Event.cs @@ -1,52 +1,51 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - public class Event { - public EventData Data { get; private set; } - public int Int { get; set; } - public float Float { get; set; } - public String String { get; set; } - public float Time { get; private set; } - - public Event (float time, EventData data) { - if (data == null) throw new ArgumentNullException("data", "data cannot be null."); - Time = time; - Data = data; - } - - override public String ToString () { - return Data.Name; - } - } +using System; + +namespace Spine { + public class Event { + public EventData Data { get; private set; } + public int Int { get; set; } + public float Float { get; set; } + public String String { get; set; } + public float Time { get; private set; } + + public Event (float time, EventData data) { + if (data == null) throw new ArgumentNullException("data", "data cannot be null."); + Time = time; + Data = data; + } + + override public String ToString () { + return Data.Name; + } + } } diff --git a/spine-csharp/src/EventData.cs b/spine-csharp/src/EventData.cs index 3dc647bf54..0160dbb0ab 100644 --- a/spine-csharp/src/EventData.cs +++ b/spine-csharp/src/EventData.cs @@ -1,52 +1,51 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - public class EventData { - internal String name; - - public String Name { get { return name; } } - public int Int { get; set; } - public float Float { get; set; } - public String String { get; set; } - - public EventData (String name) { - if (name == null) throw new ArgumentNullException("name", "name cannot be null."); - this.name = name; - } - - override public String ToString () { - return Name; - } - } +using System; + +namespace Spine { + public class EventData { + internal String name; + + public String Name { get { return name; } } + public int Int { get; set; } + public float Float { get; set; } + public String String { get; set; } + + public EventData (String name) { + if (name == null) throw new ArgumentNullException("name", "name cannot be null."); + this.name = name; + } + + override public String ToString () { + return Name; + } + } } diff --git a/spine-csharp/src/IUpdatable.cs b/spine-csharp/src/IUpdatable.cs index 824c9a560c..25987a2d39 100644 --- a/spine-csharp/src/IUpdatable.cs +++ b/spine-csharp/src/IUpdatable.cs @@ -1,38 +1,37 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - public interface IUpdatable { - void Update (); - } +using System; + +namespace Spine { + public interface IUpdatable { + void Update (); + } } diff --git a/spine-csharp/src/IkConstraint.cs b/spine-csharp/src/IkConstraint.cs index c15627f729..b0e8eb68d6 100644 --- a/spine-csharp/src/IkConstraint.cs +++ b/spine-csharp/src/IkConstraint.cs @@ -1,235 +1,234 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - public class IkConstraint : IUpdatable { - internal IkConstraintData data; - internal ExposedList bones = new ExposedList(); - internal Bone target; - internal float mix; - internal int bendDirection; - - internal int level; - - public IkConstraintData Data { get { return data; } } - public ExposedList Bones { get { return bones; } } - public Bone Target { get { return target; } set { target = value; } } - public int BendDirection { get { return bendDirection; } set { bendDirection = value; } } - public float Mix { get { return mix; } set { mix = value; } } - - public IkConstraint (IkConstraintData data, Skeleton skeleton) { - if (data == null) throw new ArgumentNullException("data", "data cannot be null."); - if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null."); - this.data = data; - mix = data.mix; - bendDirection = data.bendDirection; - - bones = new ExposedList(data.bones.Count); - foreach (BoneData boneData in data.bones) - bones.Add(skeleton.FindBone(boneData.name)); - target = skeleton.FindBone(data.target.name); - } - - public void Update () { - Apply(); - } - - public void Apply () { - Bone target = this.target; - ExposedList bones = this.bones; - switch (bones.Count) { - case 1: - Apply(bones.Items[0], target.worldX, target.worldY, mix); - break; - case 2: - Apply(bones.Items[0], bones.Items[1], target.worldX, target.worldY, bendDirection, mix); - break; - } - } - - override public String ToString () { - return data.name; - } - - /// Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified - /// in the world coordinate system. - static public void Apply (Bone bone, float targetX, float targetY, float alpha) { - Bone pp = bone.parent; - float id = 1 / (pp.a * pp.d - pp.b * pp.c); - float x = targetX - pp.worldX, y = targetY - pp.worldY; - float tx = (x * pp.d - y * pp.b) * id - bone.x, ty = (y * pp.a - x * pp.c) * id - bone.y; - float rotationIK = MathUtils.Atan2(ty, tx) * MathUtils.radDeg - bone.shearX - bone.rotation; - if (bone.scaleX < 0) rotationIK += 180; - if (rotationIK > 180) - rotationIK -= 360; - else if (rotationIK < -180) rotationIK += 360; - bone.UpdateWorldTransform(bone.x, bone.y, bone.rotation + rotationIK * alpha, bone.scaleX, bone.scaleY, - bone.shearX, bone.shearY); - } - - /// Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as - /// possible. The target is specified in the world coordinate system. - /// A direct descendant of the parent bone. - static public void Apply (Bone parent, Bone child, float targetX, float targetY, int bendDir, float alpha) { - if (alpha == 0) { - child.UpdateWorldTransform (); - return; - } - float px = parent.x, py = parent.y, psx = parent.scaleX, psy = parent.scaleY, csx = child.scaleX; - int os1, os2, s2; - if (psx < 0) { - psx = -psx; - os1 = 180; - s2 = -1; - } else { - os1 = 0; - s2 = 1; - } - if (psy < 0) { - psy = -psy; - s2 = -s2; - } - if (csx < 0) { - csx = -csx; - os2 = 180; - } else - os2 = 0; - float cx = child.x, cy, cwx, cwy, a = parent.a, b = parent.b, c = parent.c, d = parent.d; - bool u = Math.Abs(psx - psy) <= 0.0001f; - if (!u) { - cy = 0; - cwx = a * cx + parent.worldX; - cwy = c * cx + parent.worldY; - } else { - cy = child.y; - cwx = a * cx + b * cy + parent.worldX; - cwy = c * cx + d * cy + parent.worldY; - } - Bone pp = parent.parent; - a = pp.a; - b = pp.b; - c = pp.c; - d = pp.d; - float id = 1 / (a * d - b * c), x = targetX - pp.worldX, y = targetY - pp.worldY; - float tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py; - x = cwx - pp.worldX; - y = cwy - pp.worldY; - float dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; - float l1 = (float)Math.Sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2; - if (u) { - l2 *= psx; - float cos = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2); - if (cos < -1) - cos = -1; - else if (cos > 1) cos = 1; - a2 = (float)Math.Acos(cos) * bendDir; - a = l1 + l2 * cos; - b = l2 * MathUtils.Sin(a2); - a1 = MathUtils.Atan2(ty * a - tx * b, tx * a + ty * b); - } else { - a = psx * l2; - b = psy * l2; - float aa = a * a, bb = b * b, dd = tx * tx + ty * ty, ta = MathUtils.Atan2(ty, tx); - c = bb * l1 * l1 + aa * dd - aa * bb; - float c1 = -2 * bb * l1, c2 = bb - aa; - d = c1 * c1 - 4 * c2 * c; - if (d >= 0) { - float q = (float)Math.Sqrt(d); - if (c1 < 0) q = -q; - q = -(c1 + q) / 2; - float r0 = q / c2, r1 = c / q; - float r = Math.Abs(r0) < Math.Abs(r1) ? r0 : r1; - if (r * r <= dd) { - y = (float)Math.Sqrt(dd - r * r) * bendDir; - a1 = ta - MathUtils.Atan2(y, r); - a2 = MathUtils.Atan2(y / psy, (r - l1) / psx); - goto outer; - } - } - float minAngle = 0, minDist = float.MaxValue, minX = 0, minY = 0; - float maxAngle = 0, maxDist = 0, maxX = 0, maxY = 0; - x = l1 + a; - d = x * x; - if (d > maxDist) { - maxAngle = 0; - maxDist = d; - maxX = x; - } - x = l1 - a; - d = x * x; - if (d < minDist) { - minAngle = MathUtils.PI; - minDist = d; - minX = x; - } - float angle = (float)Math.Acos(-a * l1 / (aa - bb)); - x = a * MathUtils.Cos(angle) + l1; - y = b * MathUtils.Sin(angle); - d = x * x + y * y; - if (d < minDist) { - minAngle = angle; - minDist = d; - minX = x; - minY = y; - } - if (d > maxDist) { - maxAngle = angle; - maxDist = d; - maxX = x; - maxY = y; - } - if (dd <= (minDist + maxDist) / 2) { - a1 = ta - MathUtils.Atan2(minY * bendDir, minX); - a2 = minAngle * bendDir; - } else { - a1 = ta - MathUtils.Atan2(maxY * bendDir, maxX); - a2 = maxAngle * bendDir; - } - } - outer: - float os = MathUtils.Atan2(cy, cx) * s2; - float rotation = parent.rotation; - a1 = (a1 - os) * MathUtils.radDeg + os1 - rotation; - if (a1 > 180) - a1 -= 360; - else if (a1 < -180) a1 += 360; - parent.UpdateWorldTransform(px, py, rotation + a1 * alpha, parent.scaleX, parent.scaleY, 0, 0); - rotation = child.rotation; - a2 = ((a2 + os) * MathUtils.radDeg - child.shearX) * s2 + os2 - rotation; - if (a2 > 180) - a2 -= 360; - else if (a2 < -180) a2 += 360; - child.UpdateWorldTransform(cx, cy, rotation + a2 * alpha, child.scaleX, child.scaleY, child.shearX, child.shearY); - } - } +using System; + +namespace Spine { + public class IkConstraint : IUpdatable { + internal IkConstraintData data; + internal ExposedList bones = new ExposedList(); + internal Bone target; + internal float mix; + internal int bendDirection; + + internal int level; + + public IkConstraintData Data { get { return data; } } + public ExposedList Bones { get { return bones; } } + public Bone Target { get { return target; } set { target = value; } } + public int BendDirection { get { return bendDirection; } set { bendDirection = value; } } + public float Mix { get { return mix; } set { mix = value; } } + + public IkConstraint (IkConstraintData data, Skeleton skeleton) { + if (data == null) throw new ArgumentNullException("data", "data cannot be null."); + if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null."); + this.data = data; + mix = data.mix; + bendDirection = data.bendDirection; + + bones = new ExposedList(data.bones.Count); + foreach (BoneData boneData in data.bones) + bones.Add(skeleton.FindBone(boneData.name)); + target = skeleton.FindBone(data.target.name); + } + + public void Update () { + Apply(); + } + + public void Apply () { + Bone target = this.target; + ExposedList bones = this.bones; + switch (bones.Count) { + case 1: + Apply(bones.Items[0], target.worldX, target.worldY, mix); + break; + case 2: + Apply(bones.Items[0], bones.Items[1], target.worldX, target.worldY, bendDirection, mix); + break; + } + } + + override public String ToString () { + return data.name; + } + + /// Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified + /// in the world coordinate system. + static public void Apply (Bone bone, float targetX, float targetY, float alpha) { + Bone pp = bone.parent; + float id = 1 / (pp.a * pp.d - pp.b * pp.c); + float x = targetX - pp.worldX, y = targetY - pp.worldY; + float tx = (x * pp.d - y * pp.b) * id - bone.x, ty = (y * pp.a - x * pp.c) * id - bone.y; + float rotationIK = MathUtils.Atan2(ty, tx) * MathUtils.radDeg - bone.shearX - bone.rotation; + if (bone.scaleX < 0) rotationIK += 180; + if (rotationIK > 180) + rotationIK -= 360; + else if (rotationIK < -180) rotationIK += 360; + bone.UpdateWorldTransform(bone.x, bone.y, bone.rotation + rotationIK * alpha, bone.scaleX, bone.scaleY, + bone.shearX, bone.shearY); + } + + /// Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as + /// possible. The target is specified in the world coordinate system. + /// A direct descendant of the parent bone. + static public void Apply (Bone parent, Bone child, float targetX, float targetY, int bendDir, float alpha) { + if (alpha == 0) { + child.UpdateWorldTransform (); + return; + } + float px = parent.x, py = parent.y, psx = parent.scaleX, psy = parent.scaleY, csx = child.scaleX; + int os1, os2, s2; + if (psx < 0) { + psx = -psx; + os1 = 180; + s2 = -1; + } else { + os1 = 0; + s2 = 1; + } + if (psy < 0) { + psy = -psy; + s2 = -s2; + } + if (csx < 0) { + csx = -csx; + os2 = 180; + } else + os2 = 0; + float cx = child.x, cy, cwx, cwy, a = parent.a, b = parent.b, c = parent.c, d = parent.d; + bool u = Math.Abs(psx - psy) <= 0.0001f; + if (!u) { + cy = 0; + cwx = a * cx + parent.worldX; + cwy = c * cx + parent.worldY; + } else { + cy = child.y; + cwx = a * cx + b * cy + parent.worldX; + cwy = c * cx + d * cy + parent.worldY; + } + Bone pp = parent.parent; + a = pp.a; + b = pp.b; + c = pp.c; + d = pp.d; + float id = 1 / (a * d - b * c), x = targetX - pp.worldX, y = targetY - pp.worldY; + float tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py; + x = cwx - pp.worldX; + y = cwy - pp.worldY; + float dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; + float l1 = (float)Math.Sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2; + if (u) { + l2 *= psx; + float cos = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2); + if (cos < -1) + cos = -1; + else if (cos > 1) cos = 1; + a2 = (float)Math.Acos(cos) * bendDir; + a = l1 + l2 * cos; + b = l2 * MathUtils.Sin(a2); + a1 = MathUtils.Atan2(ty * a - tx * b, tx * a + ty * b); + } else { + a = psx * l2; + b = psy * l2; + float aa = a * a, bb = b * b, dd = tx * tx + ty * ty, ta = MathUtils.Atan2(ty, tx); + c = bb * l1 * l1 + aa * dd - aa * bb; + float c1 = -2 * bb * l1, c2 = bb - aa; + d = c1 * c1 - 4 * c2 * c; + if (d >= 0) { + float q = (float)Math.Sqrt(d); + if (c1 < 0) q = -q; + q = -(c1 + q) / 2; + float r0 = q / c2, r1 = c / q; + float r = Math.Abs(r0) < Math.Abs(r1) ? r0 : r1; + if (r * r <= dd) { + y = (float)Math.Sqrt(dd - r * r) * bendDir; + a1 = ta - MathUtils.Atan2(y, r); + a2 = MathUtils.Atan2(y / psy, (r - l1) / psx); + goto outer; + } + } + float minAngle = 0, minDist = float.MaxValue, minX = 0, minY = 0; + float maxAngle = 0, maxDist = 0, maxX = 0, maxY = 0; + x = l1 + a; + d = x * x; + if (d > maxDist) { + maxAngle = 0; + maxDist = d; + maxX = x; + } + x = l1 - a; + d = x * x; + if (d < minDist) { + minAngle = MathUtils.PI; + minDist = d; + minX = x; + } + float angle = (float)Math.Acos(-a * l1 / (aa - bb)); + x = a * MathUtils.Cos(angle) + l1; + y = b * MathUtils.Sin(angle); + d = x * x + y * y; + if (d < minDist) { + minAngle = angle; + minDist = d; + minX = x; + minY = y; + } + if (d > maxDist) { + maxAngle = angle; + maxDist = d; + maxX = x; + maxY = y; + } + if (dd <= (minDist + maxDist) / 2) { + a1 = ta - MathUtils.Atan2(minY * bendDir, minX); + a2 = minAngle * bendDir; + } else { + a1 = ta - MathUtils.Atan2(maxY * bendDir, maxX); + a2 = maxAngle * bendDir; + } + } + outer: + float os = MathUtils.Atan2(cy, cx) * s2; + float rotation = parent.rotation; + a1 = (a1 - os) * MathUtils.radDeg + os1 - rotation; + if (a1 > 180) + a1 -= 360; + else if (a1 < -180) a1 += 360; + parent.UpdateWorldTransform(px, py, rotation + a1 * alpha, parent.scaleX, parent.scaleY, 0, 0); + rotation = child.rotation; + a2 = ((a2 + os) * MathUtils.radDeg - child.shearX) * s2 + os2 - rotation; + if (a2 > 180) + a2 -= 360; + else if (a2 < -180) a2 += 360; + child.UpdateWorldTransform(cx, cy, rotation + a2 * alpha, child.scaleX, child.scaleY, child.shearX, child.shearY); + } + } } diff --git a/spine-csharp/src/IkConstraintData.cs b/spine-csharp/src/IkConstraintData.cs index 2b0723b936..f56d54a58e 100644 --- a/spine-csharp/src/IkConstraintData.cs +++ b/spine-csharp/src/IkConstraintData.cs @@ -1,58 +1,57 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using System.Collections.Generic; - -namespace Spine { - public class IkConstraintData { - internal String name; - internal List bones = new List(); - internal BoneData target; - internal int bendDirection = 1; - internal float mix = 1; - - public String Name { get { return name; } } - public List Bones { get { return bones; } } - public BoneData Target { get { return target; } set { target = value; } } - public int BendDirection { get { return bendDirection; } set { bendDirection = value; } } - public float Mix { get { return mix; } set { mix = value; } } - - public IkConstraintData (String name) { - if (name == null) throw new ArgumentNullException("name", "name cannot be null."); - this.name = name; - } - - override public String ToString () { - return name; - } - } +using System; +using System.Collections.Generic; + +namespace Spine { + public class IkConstraintData { + internal String name; + internal List bones = new List(); + internal BoneData target; + internal int bendDirection = 1; + internal float mix = 1; + + public String Name { get { return name; } } + public List Bones { get { return bones; } } + public BoneData Target { get { return target; } set { target = value; } } + public int BendDirection { get { return bendDirection; } set { bendDirection = value; } } + public float Mix { get { return mix; } set { mix = value; } } + + public IkConstraintData (String name) { + if (name == null) throw new ArgumentNullException("name", "name cannot be null."); + this.name = name; + } + + override public String ToString () { + return name; + } + } } diff --git a/spine-csharp/src/Json.cs b/spine-csharp/src/Json.cs index 3db6782484..9a2e1e72fe 100644 --- a/spine-csharp/src/Json.cs +++ b/spine-csharp/src/Json.cs @@ -1,536 +1,535 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using System.IO; -using System.Text; -using System.Collections; -using System.Globalization; -using System.Collections.Generic; - -namespace Spine { - public static class Json { - public static object Deserialize (TextReader text) { - var parser = new SharpJson.JsonDecoder(); - parser.parseNumbersAsFloat = true; - return parser.Decode(text.ReadToEnd()); - } - } -} - -/** - * - * Copyright (c) 2016 Adriano Tinoco d'Oliveira Rezende - * - * Based on the JSON parser by Patrick van Bergen - * http://techblog.procurios.nl/k/news/view/14605/14863/how-do-i-write-my-own-parser-(for-json).html - * - * Changes made: - * - * - Optimized parser speed (deserialize roughly near 3x faster than original) - * - Added support to handle lexer/parser error messages with line numbers - * - Added more fine grained control over type conversions during the parsing - * - Refactory API (Separate Lexer code from Parser code and the Encoder from Decoder) - * - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * The above copyright notice and this permission notice shall be included in all copies or substantial - * portions of the Software. - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT - * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -namespace SharpJson -{ - class Lexer - { - public enum Token { - None, - Null, - True, - False, - Colon, - Comma, - String, - Number, - CurlyOpen, - CurlyClose, - SquaredOpen, - SquaredClose, - }; - - public bool hasError { - get { - return !success; - } - } - - public int lineNumber { - get; - private set; - } - - public bool parseNumbersAsFloat { - get; - set; - } - - char[] json; - int index = 0; - bool success = true; - char[] stringBuffer = new char[4096]; - - public Lexer(string text) - { - Reset(); - - json = text.ToCharArray(); - parseNumbersAsFloat = false; - } - - public void Reset() - { - index = 0; - lineNumber = 1; - success = true; - } - - public string ParseString() - { - int idx = 0; - StringBuilder builder = null; - - SkipWhiteSpaces(); - - // " - char c = json[index++]; - - bool failed = false; - bool complete = false; - - while (!complete && !failed) { - if (index == json.Length) - break; - - c = json[index++]; - if (c == '"') { - complete = true; - break; - } else if (c == '\\') { - if (index == json.Length) - break; - - c = json[index++]; - - switch (c) { - case '"': - stringBuffer[idx++] = '"'; - break; - case '\\': - stringBuffer[idx++] = '\\'; - break; - case '/': - stringBuffer[idx++] = '/'; - break; - case 'b': - stringBuffer[idx++] = '\b'; - break; - case'f': - stringBuffer[idx++] = '\f'; - break; - case 'n': - stringBuffer[idx++] = '\n'; - break; - case 'r': - stringBuffer[idx++] = '\r'; - break; - case 't': - stringBuffer[idx++] = '\t'; - break; - case 'u': - int remainingLength = json.Length - index; - if (remainingLength >= 4) { - var hex = new string(json, index, 4); - - // XXX: handle UTF - stringBuffer[idx++] = (char) Convert.ToInt32(hex, 16); - - // skip 4 chars - index += 4; - } else { - failed = true; - } - break; - } - } else { - stringBuffer[idx++] = c; - } - - if (idx >= stringBuffer.Length) { - if (builder == null) - builder = new StringBuilder(); - - builder.Append(stringBuffer, 0, idx); - idx = 0; - } - } - - if (!complete) { - success = false; - return null; - } - - if (builder != null) - return builder.ToString (); - else - return new string (stringBuffer, 0, idx); - } - - string GetNumberString() - { - SkipWhiteSpaces(); - - int lastIndex = GetLastIndexOfNumber(index); - int charLength = (lastIndex - index) + 1; - - var result = new string (json, index, charLength); - - index = lastIndex + 1; - - return result; - } - - public float ParseFloatNumber() - { - float number; - var str = GetNumberString (); - - if (!float.TryParse (str, NumberStyles.Float, CultureInfo.InvariantCulture, out number)) - return 0; - - return number; - } - - public double ParseDoubleNumber() - { - double number; - var str = GetNumberString (); - - if (!double.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out number)) - return 0; - - return number; - } - - int GetLastIndexOfNumber(int index) - { - int lastIndex; - - for (lastIndex = index; lastIndex < json.Length; lastIndex++) { - char ch = json[lastIndex]; - - if ((ch < '0' || ch > '9') && ch != '+' && ch != '-' - && ch != '.' && ch != 'e' && ch != 'E') - break; - } - - return lastIndex - 1; - } - - void SkipWhiteSpaces() - { - for (; index < json.Length; index++) { - char ch = json[index]; - - if (ch == '\n') - lineNumber++; - - if (!char.IsWhiteSpace(json[index])) - break; - } - } - - public Token LookAhead() - { - SkipWhiteSpaces(); - - int savedIndex = index; - return NextToken(json, ref savedIndex); - } - - public Token NextToken() - { - SkipWhiteSpaces(); - return NextToken(json, ref index); - } - - static Token NextToken(char[] json, ref int index) - { - if (index == json.Length) - return Token.None; - - char c = json[index++]; - - switch (c) { - case '{': - return Token.CurlyOpen; - case '}': - return Token.CurlyClose; - case '[': - return Token.SquaredOpen; - case ']': - return Token.SquaredClose; - case ',': - return Token.Comma; - case '"': - return Token.String; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case '-': - return Token.Number; - case ':': - return Token.Colon; - } - - index--; - - int remainingLength = json.Length - index; - - // false - if (remainingLength >= 5) { - if (json[index] == 'f' && - json[index + 1] == 'a' && - json[index + 2] == 'l' && - json[index + 3] == 's' && - json[index + 4] == 'e') { - index += 5; - return Token.False; - } - } - - // true - if (remainingLength >= 4) { - if (json[index] == 't' && - json[index + 1] == 'r' && - json[index + 2] == 'u' && - json[index + 3] == 'e') { - index += 4; - return Token.True; - } - } - - // null - if (remainingLength >= 4) { - if (json[index] == 'n' && - json[index + 1] == 'u' && - json[index + 2] == 'l' && - json[index + 3] == 'l') { - index += 4; - return Token.Null; - } - } - - return Token.None; - } - } - - public class JsonDecoder - { - public string errorMessage { - get; - private set; - } - - public bool parseNumbersAsFloat { - get; - set; - } - - Lexer lexer; - - public JsonDecoder() - { - errorMessage = null; - parseNumbersAsFloat = false; - } - - public object Decode(string text) - { - errorMessage = null; - - lexer = new Lexer(text); - lexer.parseNumbersAsFloat = parseNumbersAsFloat; - - return ParseValue(); - } - - public static object DecodeText(string text) - { - var builder = new JsonDecoder(); - return builder.Decode(text); - } - - IDictionary ParseObject() - { - var table = new Dictionary(); - - // { - lexer.NextToken(); - - while (true) { - var token = lexer.LookAhead(); - - switch (token) { - case Lexer.Token.None: - TriggerError("Invalid token"); - return null; - case Lexer.Token.Comma: - lexer.NextToken(); - break; - case Lexer.Token.CurlyClose: - lexer.NextToken(); - return table; - default: - // name - string name = EvalLexer(lexer.ParseString()); - - if (errorMessage != null) - return null; - - // : - token = lexer.NextToken(); - - if (token != Lexer.Token.Colon) { - TriggerError("Invalid token; expected ':'"); - return null; - } - - // value - object value = ParseValue(); - - if (errorMessage != null) - return null; - - table[name] = value; - break; - } - } - - //return null; // Unreachable code - } - - IList ParseArray() - { - var array = new List(); - - // [ - lexer.NextToken(); - - while (true) { - var token = lexer.LookAhead(); - - switch (token) { - case Lexer.Token.None: - TriggerError("Invalid token"); - return null; - case Lexer.Token.Comma: - lexer.NextToken(); - break; - case Lexer.Token.SquaredClose: - lexer.NextToken(); - return array; - default: - object value = ParseValue(); - - if (errorMessage != null) - return null; - - array.Add(value); - break; - } - } - - //return null; // Unreachable code - } - - object ParseValue() - { - switch (lexer.LookAhead()) { - case Lexer.Token.String: - return EvalLexer(lexer.ParseString()); - case Lexer.Token.Number: - if (parseNumbersAsFloat) - return EvalLexer(lexer.ParseFloatNumber()); - else - return EvalLexer(lexer.ParseDoubleNumber()); - case Lexer.Token.CurlyOpen: - return ParseObject(); - case Lexer.Token.SquaredOpen: - return ParseArray(); - case Lexer.Token.True: - lexer.NextToken(); - return true; - case Lexer.Token.False: - lexer.NextToken(); - return false; - case Lexer.Token.Null: - lexer.NextToken(); - return null; - case Lexer.Token.None: - break; - } - - TriggerError("Unable to parse value"); - return null; - } - - void TriggerError(string message) - { - errorMessage = string.Format("Error: '{0}' at line {1}", - message, lexer.lineNumber); - } - - T EvalLexer(T value) - { - if (lexer.hasError) - TriggerError("Lexical error ocurred"); - - return value; - } - } +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.Globalization; +using System.Collections.Generic; + +namespace Spine { + public static class Json { + public static object Deserialize (TextReader text) { + var parser = new SharpJson.JsonDecoder(); + parser.parseNumbersAsFloat = true; + return parser.Decode(text.ReadToEnd()); + } + } +} + +/** + * + * Copyright (c) 2016 Adriano Tinoco d'Oliveira Rezende + * + * Based on the JSON parser by Patrick van Bergen + * http://techblog.procurios.nl/k/news/view/14605/14863/how-do-i-write-my-own-parser-(for-json).html + * + * Changes made: + * + * - Optimized parser speed (deserialize roughly near 3x faster than original) + * - Added support to handle lexer/parser error messages with line numbers + * - Added more fine grained control over type conversions during the parsing + * - Refactory API (Separate Lexer code from Parser code and the Encoder from Decoder) + * + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * The above copyright notice and this permission notice shall be included in all copies or substantial + * portions of the Software. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +namespace SharpJson +{ + class Lexer + { + public enum Token { + None, + Null, + True, + False, + Colon, + Comma, + String, + Number, + CurlyOpen, + CurlyClose, + SquaredOpen, + SquaredClose, + }; + + public bool hasError { + get { + return !success; + } + } + + public int lineNumber { + get; + private set; + } + + public bool parseNumbersAsFloat { + get; + set; + } + + char[] json; + int index = 0; + bool success = true; + char[] stringBuffer = new char[4096]; + + public Lexer(string text) + { + Reset(); + + json = text.ToCharArray(); + parseNumbersAsFloat = false; + } + + public void Reset() + { + index = 0; + lineNumber = 1; + success = true; + } + + public string ParseString() + { + int idx = 0; + StringBuilder builder = null; + + SkipWhiteSpaces(); + + // " + char c = json[index++]; + + bool failed = false; + bool complete = false; + + while (!complete && !failed) { + if (index == json.Length) + break; + + c = json[index++]; + if (c == '"') { + complete = true; + break; + } else if (c == '\\') { + if (index == json.Length) + break; + + c = json[index++]; + + switch (c) { + case '"': + stringBuffer[idx++] = '"'; + break; + case '\\': + stringBuffer[idx++] = '\\'; + break; + case '/': + stringBuffer[idx++] = '/'; + break; + case 'b': + stringBuffer[idx++] = '\b'; + break; + case'f': + stringBuffer[idx++] = '\f'; + break; + case 'n': + stringBuffer[idx++] = '\n'; + break; + case 'r': + stringBuffer[idx++] = '\r'; + break; + case 't': + stringBuffer[idx++] = '\t'; + break; + case 'u': + int remainingLength = json.Length - index; + if (remainingLength >= 4) { + var hex = new string(json, index, 4); + + // XXX: handle UTF + stringBuffer[idx++] = (char) Convert.ToInt32(hex, 16); + + // skip 4 chars + index += 4; + } else { + failed = true; + } + break; + } + } else { + stringBuffer[idx++] = c; + } + + if (idx >= stringBuffer.Length) { + if (builder == null) + builder = new StringBuilder(); + + builder.Append(stringBuffer, 0, idx); + idx = 0; + } + } + + if (!complete) { + success = false; + return null; + } + + if (builder != null) + return builder.ToString (); + else + return new string (stringBuffer, 0, idx); + } + + string GetNumberString() + { + SkipWhiteSpaces(); + + int lastIndex = GetLastIndexOfNumber(index); + int charLength = (lastIndex - index) + 1; + + var result = new string (json, index, charLength); + + index = lastIndex + 1; + + return result; + } + + public float ParseFloatNumber() + { + float number; + var str = GetNumberString (); + + if (!float.TryParse (str, NumberStyles.Float, CultureInfo.InvariantCulture, out number)) + return 0; + + return number; + } + + public double ParseDoubleNumber() + { + double number; + var str = GetNumberString (); + + if (!double.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out number)) + return 0; + + return number; + } + + int GetLastIndexOfNumber(int index) + { + int lastIndex; + + for (lastIndex = index; lastIndex < json.Length; lastIndex++) { + char ch = json[lastIndex]; + + if ((ch < '0' || ch > '9') && ch != '+' && ch != '-' + && ch != '.' && ch != 'e' && ch != 'E') + break; + } + + return lastIndex - 1; + } + + void SkipWhiteSpaces() + { + for (; index < json.Length; index++) { + char ch = json[index]; + + if (ch == '\n') + lineNumber++; + + if (!char.IsWhiteSpace(json[index])) + break; + } + } + + public Token LookAhead() + { + SkipWhiteSpaces(); + + int savedIndex = index; + return NextToken(json, ref savedIndex); + } + + public Token NextToken() + { + SkipWhiteSpaces(); + return NextToken(json, ref index); + } + + static Token NextToken(char[] json, ref int index) + { + if (index == json.Length) + return Token.None; + + char c = json[index++]; + + switch (c) { + case '{': + return Token.CurlyOpen; + case '}': + return Token.CurlyClose; + case '[': + return Token.SquaredOpen; + case ']': + return Token.SquaredClose; + case ',': + return Token.Comma; + case '"': + return Token.String; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '-': + return Token.Number; + case ':': + return Token.Colon; + } + + index--; + + int remainingLength = json.Length - index; + + // false + if (remainingLength >= 5) { + if (json[index] == 'f' && + json[index + 1] == 'a' && + json[index + 2] == 'l' && + json[index + 3] == 's' && + json[index + 4] == 'e') { + index += 5; + return Token.False; + } + } + + // true + if (remainingLength >= 4) { + if (json[index] == 't' && + json[index + 1] == 'r' && + json[index + 2] == 'u' && + json[index + 3] == 'e') { + index += 4; + return Token.True; + } + } + + // null + if (remainingLength >= 4) { + if (json[index] == 'n' && + json[index + 1] == 'u' && + json[index + 2] == 'l' && + json[index + 3] == 'l') { + index += 4; + return Token.Null; + } + } + + return Token.None; + } + } + + public class JsonDecoder + { + public string errorMessage { + get; + private set; + } + + public bool parseNumbersAsFloat { + get; + set; + } + + Lexer lexer; + + public JsonDecoder() + { + errorMessage = null; + parseNumbersAsFloat = false; + } + + public object Decode(string text) + { + errorMessage = null; + + lexer = new Lexer(text); + lexer.parseNumbersAsFloat = parseNumbersAsFloat; + + return ParseValue(); + } + + public static object DecodeText(string text) + { + var builder = new JsonDecoder(); + return builder.Decode(text); + } + + IDictionary ParseObject() + { + var table = new Dictionary(); + + // { + lexer.NextToken(); + + while (true) { + var token = lexer.LookAhead(); + + switch (token) { + case Lexer.Token.None: + TriggerError("Invalid token"); + return null; + case Lexer.Token.Comma: + lexer.NextToken(); + break; + case Lexer.Token.CurlyClose: + lexer.NextToken(); + return table; + default: + // name + string name = EvalLexer(lexer.ParseString()); + + if (errorMessage != null) + return null; + + // : + token = lexer.NextToken(); + + if (token != Lexer.Token.Colon) { + TriggerError("Invalid token; expected ':'"); + return null; + } + + // value + object value = ParseValue(); + + if (errorMessage != null) + return null; + + table[name] = value; + break; + } + } + + //return null; // Unreachable code + } + + IList ParseArray() + { + var array = new List(); + + // [ + lexer.NextToken(); + + while (true) { + var token = lexer.LookAhead(); + + switch (token) { + case Lexer.Token.None: + TriggerError("Invalid token"); + return null; + case Lexer.Token.Comma: + lexer.NextToken(); + break; + case Lexer.Token.SquaredClose: + lexer.NextToken(); + return array; + default: + object value = ParseValue(); + + if (errorMessage != null) + return null; + + array.Add(value); + break; + } + } + + //return null; // Unreachable code + } + + object ParseValue() + { + switch (lexer.LookAhead()) { + case Lexer.Token.String: + return EvalLexer(lexer.ParseString()); + case Lexer.Token.Number: + if (parseNumbersAsFloat) + return EvalLexer(lexer.ParseFloatNumber()); + else + return EvalLexer(lexer.ParseDoubleNumber()); + case Lexer.Token.CurlyOpen: + return ParseObject(); + case Lexer.Token.SquaredOpen: + return ParseArray(); + case Lexer.Token.True: + lexer.NextToken(); + return true; + case Lexer.Token.False: + lexer.NextToken(); + return false; + case Lexer.Token.Null: + lexer.NextToken(); + return null; + case Lexer.Token.None: + break; + } + + TriggerError("Unable to parse value"); + return null; + } + + void TriggerError(string message) + { + errorMessage = string.Format("Error: '{0}' at line {1}", + message, lexer.lineNumber); + } + + T EvalLexer(T value) + { + if (lexer.hasError) + TriggerError("Lexical error ocurred"); + + return value; + } + } } diff --git a/spine-csharp/src/MathUtils.cs b/spine-csharp/src/MathUtils.cs index e8a8f86df8..8a64c3a5eb 100644 --- a/spine-csharp/src/MathUtils.cs +++ b/spine-csharp/src/MathUtils.cs @@ -1,101 +1,100 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - public static class MathUtils { - public const float PI = 3.1415927f; - public const float PI2 = PI * 2; - public const float radDeg = 180f / PI; - public const float degRad = PI / 180; - - const int SIN_BITS = 14; // 16KB. Adjust for accuracy. - const int SIN_MASK = ~(-1 << SIN_BITS); - const int SIN_COUNT = SIN_MASK + 1; - const float radFull = PI * 2; - const float degFull = 360; - const float radToIndex = SIN_COUNT / radFull; - const float degToIndex = SIN_COUNT / degFull; - static float[] sin = new float[SIN_COUNT]; - - static MathUtils () { - for (int i = 0; i < SIN_COUNT; i++) - sin[i] = (float)Math.Sin((i + 0.5f) / SIN_COUNT * radFull); - for (int i = 0; i < 360; i += 90) - sin[(int)(i * degToIndex) & SIN_MASK] = (float)Math.Sin(i * degRad); - } - - /// Returns the sine in radians from a lookup table. - static public float Sin (float radians) { - return sin[(int)(radians * radToIndex) & SIN_MASK]; - } - - /// Returns the cosine in radians from a lookup table. - static public float Cos (float radians) { - return sin[(int)((radians + PI / 2) * radToIndex) & SIN_MASK]; - } - - /// Returns the sine in radians from a lookup table. - static public float SinDeg (float degrees) { - return sin[(int)(degrees * degToIndex) & SIN_MASK]; - } - - /// Returns the cosine in radians from a lookup table. - static public float CosDeg (float degrees) { - return sin[(int)((degrees + 90) * degToIndex) & SIN_MASK]; - } - - /// Returns atan2 in radians, faster but less accurate than Math.Atan2. Average error of 0.00231 radians (0.1323 - /// degrees), largest error of 0.00488 radians (0.2796 degrees). - static public float Atan2 (float y, float x) { - if (x == 0f) { - if (y > 0f) return PI / 2; - if (y == 0f) return 0f; - return -PI / 2; - } - float atan, z = y / x; - if (Math.Abs(z) < 1f) { - atan = z / (1f + 0.28f * z * z); - if (x < 0f) return atan + (y < 0f ? -PI : PI); - return atan; - } - atan = PI / 2 - z / (z * z + 0.28f); - return y < 0f ? atan - PI : atan; - } - - static public float Clamp (float value, float min, float max) { - if (value < min) return min; - if (value > max) return max; - return value; - } - } +using System; + +namespace Spine { + public static class MathUtils { + public const float PI = 3.1415927f; + public const float PI2 = PI * 2; + public const float radDeg = 180f / PI; + public const float degRad = PI / 180; + + const int SIN_BITS = 14; // 16KB. Adjust for accuracy. + const int SIN_MASK = ~(-1 << SIN_BITS); + const int SIN_COUNT = SIN_MASK + 1; + const float radFull = PI * 2; + const float degFull = 360; + const float radToIndex = SIN_COUNT / radFull; + const float degToIndex = SIN_COUNT / degFull; + static float[] sin = new float[SIN_COUNT]; + + static MathUtils () { + for (int i = 0; i < SIN_COUNT; i++) + sin[i] = (float)Math.Sin((i + 0.5f) / SIN_COUNT * radFull); + for (int i = 0; i < 360; i += 90) + sin[(int)(i * degToIndex) & SIN_MASK] = (float)Math.Sin(i * degRad); + } + + /// Returns the sine in radians from a lookup table. + static public float Sin (float radians) { + return sin[(int)(radians * radToIndex) & SIN_MASK]; + } + + /// Returns the cosine in radians from a lookup table. + static public float Cos (float radians) { + return sin[(int)((radians + PI / 2) * radToIndex) & SIN_MASK]; + } + + /// Returns the sine in radians from a lookup table. + static public float SinDeg (float degrees) { + return sin[(int)(degrees * degToIndex) & SIN_MASK]; + } + + /// Returns the cosine in radians from a lookup table. + static public float CosDeg (float degrees) { + return sin[(int)((degrees + 90) * degToIndex) & SIN_MASK]; + } + + /// Returns atan2 in radians, faster but less accurate than Math.Atan2. Average error of 0.00231 radians (0.1323 + /// degrees), largest error of 0.00488 radians (0.2796 degrees). + static public float Atan2 (float y, float x) { + if (x == 0f) { + if (y > 0f) return PI / 2; + if (y == 0f) return 0f; + return -PI / 2; + } + float atan, z = y / x; + if (Math.Abs(z) < 1f) { + atan = z / (1f + 0.28f * z * z); + if (x < 0f) return atan + (y < 0f ? -PI : PI); + return atan; + } + atan = PI / 2 - z / (z * z + 0.28f); + return y < 0f ? atan - PI : atan; + } + + static public float Clamp (float value, float min, float max) { + if (value < min) return min; + if (value > max) return max; + return value; + } + } } diff --git a/spine-csharp/src/PathConstraint.cs b/spine-csharp/src/PathConstraint.cs index 15b03d5de5..3c0262b06f 100644 --- a/spine-csharp/src/PathConstraint.cs +++ b/spine-csharp/src/PathConstraint.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,13 +21,13 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + using System; namespace Spine { @@ -397,4 +396,4 @@ public class PathConstraint : IUpdatable { if (tangents) output[o + 2] = (float)Math.Atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); } } -} +} diff --git a/spine-csharp/src/PathConstraintData.cs b/spine-csharp/src/PathConstraintData.cs index a6b2dd600f..20d5f5b09e 100644 --- a/spine-csharp/src/PathConstraintData.cs +++ b/spine-csharp/src/PathConstraintData.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,13 +21,13 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + using System; namespace Spine { @@ -71,4 +70,4 @@ public enum SpacingMode { public enum RotateMode { Tangent, Chain, ChainScale } -} +} diff --git a/spine-csharp/src/Skeleton.cs b/spine-csharp/src/Skeleton.cs index 65e536ce86..4ba9222873 100644 --- a/spine-csharp/src/Skeleton.cs +++ b/spine-csharp/src/Skeleton.cs @@ -1,458 +1,457 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using System.Collections.Generic; - -namespace Spine { - public class Skeleton { - internal SkeletonData data; - internal ExposedList bones; - internal ExposedList slots; - internal ExposedList drawOrder; - internal ExposedList ikConstraints, ikConstraintsSorted; - internal ExposedList transformConstraints; - internal ExposedList pathConstraints; - internal ExposedList updateCache = new ExposedList(); - internal Skin skin; - internal float r = 1, g = 1, b = 1, a = 1; - internal float time; - internal bool flipX, flipY; - internal float x, y; - - public SkeletonData Data { get { return data; } } - public ExposedList Bones { get { return bones; } } - public ExposedList UpdateCacheList { get { return updateCache; } } - public ExposedList Slots { get { return slots; } } - public ExposedList DrawOrder { get { return drawOrder; } } - public ExposedList IkConstraints { get { return ikConstraints; } } - public ExposedList PathConstraints { get { return pathConstraints; } } - public ExposedList TransformConstraints { get { return transformConstraints; } } - public Skin Skin { get { return skin; } set { skin = value; } } - public float R { get { return r; } set { r = value; } } - public float G { get { return g; } set { g = value; } } - public float B { get { return b; } set { b = value; } } - public float A { get { return a; } set { a = value; } } - public float Time { get { return time; } set { time = value; } } - public float X { get { return x; } set { x = value; } } - public float Y { get { return y; } set { y = value; } } - public bool FlipX { get { return flipX; } set { flipX = value; } } - public bool FlipY { get { return flipY; } set { flipY = value; } } - - public Bone RootBone { - get { return bones.Count == 0 ? null : bones.Items[0]; } - } - - public Skeleton (SkeletonData data) { - if (data == null) throw new ArgumentNullException("data", "data cannot be null."); - this.data = data; - - bones = new ExposedList(data.bones.Count); - foreach (BoneData boneData in data.bones) { - Bone bone; - if (boneData.parent == null) { - bone = new Bone(boneData, this, null); - } else { - Bone parent = bones.Items[boneData.parent.index]; - bone = new Bone(boneData, this, parent); - parent.children.Add(bone); - } - bones.Add(bone); - } - - slots = new ExposedList(data.slots.Count); - drawOrder = new ExposedList(data.slots.Count); - foreach (SlotData slotData in data.slots) { - Bone bone = bones.Items[slotData.boneData.index]; - Slot slot = new Slot(slotData, bone); - slots.Add(slot); - drawOrder.Add(slot); - } - - ikConstraints = new ExposedList(data.ikConstraints.Count); - ikConstraintsSorted = new ExposedList(data.ikConstraints.Count); - foreach (IkConstraintData ikConstraintData in data.ikConstraints) - ikConstraints.Add(new IkConstraint(ikConstraintData, this)); - - transformConstraints = new ExposedList(data.transformConstraints.Count); - foreach (TransformConstraintData transformConstraintData in data.transformConstraints) - transformConstraints.Add(new TransformConstraint(transformConstraintData, this)); - - pathConstraints = new ExposedList (data.pathConstraints.Count); - foreach (PathConstraintData pathConstraintData in data.pathConstraints) - pathConstraints.Add(new PathConstraint(pathConstraintData, this)); - - UpdateCache(); - UpdateWorldTransform(); - } - - /// Caches information about bones and constraints. Must be called if bones, constraints or weighted path attachments are added - /// or removed. - public void UpdateCache () { - ExposedList updateCache = this.updateCache; - updateCache.Clear(); - - ExposedList bones = this.bones; - for (int i = 0, n = bones.Count; i < n; i++) - bones.Items[i].sorted = false; - - ExposedList ikConstraints = this.ikConstraintsSorted; - ikConstraints.Clear(); - ikConstraints.AddRange(this.ikConstraints); - int ikCount = ikConstraints.Count; - for (int i = 0, level, n = ikCount; i < n; i++) { - IkConstraint ik = ikConstraints.Items[i]; - Bone bone = ik.bones.Items[0].parent; - for (level = 0; bone != null; level++) - bone = bone.parent; - ik.level = level; - } - for (int i = 1, ii; i < ikCount; i++) { - IkConstraint ik = ikConstraints.Items[i]; - int level = ik.level; - for (ii = i - 1; ii >= 0; ii--) { - IkConstraint other = ikConstraints.Items[ii]; - if (other.level < level) break; - ikConstraints.Items[ii + 1] = other; - } - ikConstraints.Items[ii + 1] = ik; - } - for (int i = 0, n = ikConstraints.Count; i < n; i++) { - IkConstraint constraint = ikConstraints.Items[i]; - Bone target = constraint.target; - SortBone(target); - - ExposedList constrained = constraint.bones; - Bone parent = constrained.Items[0]; - SortBone(parent); - - updateCache.Add(constraint); - - SortReset(parent.children); - constrained.Items[constrained.Count - 1].sorted = true; - } - - ExposedList pathConstraints = this.pathConstraints; - for (int i = 0, n = pathConstraints.Count; i < n; i++) { - PathConstraint constraint = pathConstraints.Items[i]; - - Slot slot = constraint.target; - int slotIndex = slot.data.index; - Bone slotBone = slot.bone; - if (skin != null) SortPathConstraintAttachment(skin, slotIndex, slotBone); - if (data.defaultSkin != null && data.defaultSkin != skin) - SortPathConstraintAttachment(data.defaultSkin, slotIndex, slotBone); - for (int ii = 0, nn = data.skins.Count; ii < nn; ii++) - SortPathConstraintAttachment(data.skins.Items[ii], slotIndex, slotBone); - - PathAttachment attachment = slot.Attachment as PathAttachment; - if (attachment != null) SortPathConstraintAttachment(attachment, slotBone); - - ExposedList constrained = constraint.bones; - int boneCount = constrained.Count; - for (int ii = 0; ii < boneCount; ii++) - SortBone(constrained.Items[ii]); - - updateCache.Add(constraint); - - for (int ii = 0; ii < boneCount; ii++) - SortReset(constrained.Items[ii].children); - for (int ii = 0; ii < boneCount; ii++) - constrained.Items[ii].sorted = true; - } - - ExposedList transformConstraints = this.transformConstraints; - for (int i = 0, n = transformConstraints.Count; i < n; i++) { - TransformConstraint constraint = transformConstraints.Items[i]; - - SortBone(constraint.target); - - ExposedList constrained = constraint.bones; - int boneCount = constrained.Count; - for (int ii = 0; ii < boneCount; ii++) - SortBone(constrained.Items[ii]); - - updateCache.Add(constraint); - - for (int ii = 0; ii < boneCount; ii++) - SortReset(constrained.Items[ii].children); - for (int ii = 0; ii < boneCount; ii++) - constrained.Items[ii].sorted = true; - } - - for (int i = 0, n = bones.Count; i < n; i++) - SortBone(bones.Items[i]); - } - - private void SortPathConstraintAttachment (Skin skin, int slotIndex, Bone slotBone) { - foreach (var entry in skin.Attachments) - if (entry.Key.slotIndex == slotIndex) SortPathConstraintAttachment(entry.Value, slotBone); - } - - private void SortPathConstraintAttachment (Attachment attachment, Bone slotBone) { - var pathAttachment = attachment as PathAttachment; - if (pathAttachment == null) return; - int[] pathBones = pathAttachment.bones; - if (pathBones == null) - SortBone(slotBone); - else { - var bonesItems = this.bones.Items; - for (int i = 0, n = pathBones.Length; i < n;) { - int nn = pathBones[i++]; - nn += i; - while (i < nn) - SortBone(bonesItems[pathBones[i++]]); - } - } - } - - private void SortBone (Bone bone) { - if (bone.sorted) return; - Bone parent = bone.parent; - if (parent != null) SortBone(parent); - bone.sorted = true; - updateCache.Add(bone); - } - - private void SortReset (ExposedList bones) { - var bonesItems = bones.Items; - for (int i = 0, n = bones.Count; i < n; i++) { - Bone bone = bonesItems[i]; - if (bone.sorted) SortReset(bone.children); - bone.sorted = false; - } - } - - /// Updates the world transform for each bone and applies constraints. - public void UpdateWorldTransform () { - var updateItems = this.updateCache.Items; - for (int i = 0, n = updateCache.Count; i < n; i++) - updateItems[i].Update(); - } - - /// Sets the bones, constraints, and slots to their setup pose values. - public void SetToSetupPose () { - SetBonesToSetupPose(); - SetSlotsToSetupPose(); - } - - /// Sets the bones and constraints to their setup pose values. - public void SetBonesToSetupPose () { - var bonesItems = this.bones.Items; - for (int i = 0, n = bones.Count; i < n; i++) - bonesItems[i].SetToSetupPose(); - - var ikConstraintsItems = this.ikConstraints.Items; - for (int i = 0, n = ikConstraints.Count; i < n; i++) { - IkConstraint constraint = ikConstraintsItems[i]; - constraint.bendDirection = constraint.data.bendDirection; - constraint.mix = constraint.data.mix; - } - - var transformConstraintsItems = this.transformConstraints.Items; - for (int i = 0, n = transformConstraints.Count; i < n; i++) { - TransformConstraint constraint = transformConstraintsItems[i]; - TransformConstraintData data = constraint.data; - constraint.rotateMix = data.rotateMix; - constraint.translateMix = data.translateMix; - constraint.scaleMix = data.scaleMix; - constraint.shearMix = data.shearMix; - } - - var pathConstraintItems = this.pathConstraints.Items; - for (int i = 0, n = pathConstraints.Count; i < n; i++) { - PathConstraint constraint = pathConstraintItems[i]; - PathConstraintData data = constraint.data; - constraint.position = data.position; - constraint.spacing = data.spacing; - constraint.rotateMix = data.rotateMix; - constraint.translateMix = data.translateMix; - } - } - - public void SetSlotsToSetupPose () { - var slots = this.slots; - var slotsItems = slots.Items; - drawOrder.Clear(); - for (int i = 0, n = slots.Count; i < n; i++) - drawOrder.Add(slotsItems[i]); - - for (int i = 0, n = slots.Count; i < n; i++) - slotsItems[i].SetToSetupPose(); - } - - /// May be null. - public Bone FindBone (String boneName) { - if (boneName == null) throw new ArgumentNullException("boneName", "boneName cannot be null."); - var bones = this.bones; - var bonesItems = bones.Items; - for (int i = 0, n = bones.Count; i < n; i++) { - Bone bone = bonesItems[i]; - if (bone.data.name == boneName) return bone; - } - return null; - } - - /// -1 if the bone was not found. - public int FindBoneIndex (String boneName) { - if (boneName == null) throw new ArgumentNullException("boneName", "boneName cannot be null."); - var bones = this.bones; - var bonesItems = bones.Items; - for (int i = 0, n = bones.Count; i < n; i++) - if (bonesItems[i].data.name == boneName) return i; - return -1; - } - - /// May be null. - public Slot FindSlot (String slotName) { - if (slotName == null) throw new ArgumentNullException("slotName", "slotName cannot be null."); - var slots = this.slots; - var slotsItems = slots.Items; - for (int i = 0, n = slots.Count; i < n; i++) { - Slot slot = slotsItems[i]; - if (slot.data.name == slotName) return slot; - } - return null; - } - - /// -1 if the bone was not found. - public int FindSlotIndex (String slotName) { - if (slotName == null) throw new ArgumentNullException("slotName", "slotName cannot be null."); - var slots = this.slots; - var slotsItems = slots.Items; - for (int i = 0, n = slots.Count; i < n; i++) - if (slotsItems[i].data.name.Equals(slotName)) return i; - return -1; - } - - /// Sets a skin by name (see SetSkin). - public void SetSkin (String skinName) { - Skin skin = data.FindSkin(skinName); - if (skin == null) throw new ArgumentException("Skin not found: " + skinName, "skinName"); - SetSkin(skin); - } - - /// Sets the skin used to look up attachments before looking in the {@link SkeletonData#getDefaultSkin() default - /// skin}. Attachmentsfrom 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. - /// May be null. - public void SetSkin (Skin newSkin) { - if (newSkin != null) { - if (skin != null) - newSkin.AttachAll(this, skin); - else { - ExposedList slots = this.slots; - for (int i = 0, n = slots.Count; i < n; i++) { - Slot slot = slots.Items[i]; - String name = slot.data.attachmentName; - if (name != null) { - Attachment attachment = newSkin.GetAttachment(i, name); - if (attachment != null) slot.Attachment = attachment; - } - } - } - } - skin = newSkin; - } - - /// May be null. - public Attachment GetAttachment (String slotName, String attachmentName) { - return GetAttachment(data.FindSlotIndex(slotName), attachmentName); - } - - /// May be null. - public Attachment GetAttachment (int slotIndex, String attachmentName) { - if (attachmentName == null) throw new ArgumentNullException("attachmentName", "attachmentName cannot be null."); - if (skin != null) { - Attachment attachment = skin.GetAttachment(slotIndex, attachmentName); - if (attachment != null) return attachment; - } - if (data.defaultSkin != null) return data.defaultSkin.GetAttachment(slotIndex, attachmentName); - return null; - } - - /// May be null. - public void SetAttachment (String slotName, String attachmentName) { - if (slotName == null) throw new ArgumentNullException("slotName", "slotName cannot be null."); - ExposedList slots = this.slots; - for (int i = 0, n = slots.Count; i < n; i++) { - Slot slot = slots.Items[i]; - if (slot.data.name == slotName) { - Attachment attachment = null; - if (attachmentName != null) { - attachment = GetAttachment(i, attachmentName); - if (attachment == null) throw new Exception("Attachment not found: " + attachmentName + ", for slot: " + slotName); - } - slot.Attachment = attachment; - return; - } - } - throw new Exception("Slot not found: " + slotName); - } - - /// May be null. - public IkConstraint FindIkConstraint (String constraintName) { - if (constraintName == null) throw new ArgumentNullException("constraintName", "constraintName cannot be null."); - ExposedList ikConstraints = this.ikConstraints; - for (int i = 0, n = ikConstraints.Count; i < n; i++) { - IkConstraint ikConstraint = ikConstraints.Items[i]; - if (ikConstraint.data.name == constraintName) return ikConstraint; - } - return null; - } - - /// May be null. - public TransformConstraint FindTransformConstraint (String constraintName) { - if (constraintName == null) throw new ArgumentNullException("constraintName", "constraintName cannot be null."); - ExposedList transformConstraints = this.transformConstraints; - for (int i = 0, n = transformConstraints.Count; i < n; i++) { - TransformConstraint transformConstraint = transformConstraints.Items[i]; - if (transformConstraint.data.name == constraintName) return transformConstraint; - } - return null; - } - - /// May be null. - public PathConstraint FindPathConstraint (String constraintName) { - if (constraintName == null) throw new ArgumentNullException("constraintName", "constraintName cannot be null."); - ExposedList pathConstraints = this.pathConstraints; - for (int i = 0, n = pathConstraints.Count; i < n; i++) { - PathConstraint constraint = pathConstraints.Items[i]; - if (constraint.data.name.Equals(constraintName)) return constraint; - } - return null; - } - - public void Update (float delta) { - time += delta; - } - } +using System; +using System.Collections.Generic; + +namespace Spine { + public class Skeleton { + internal SkeletonData data; + internal ExposedList bones; + internal ExposedList slots; + internal ExposedList drawOrder; + internal ExposedList ikConstraints, ikConstraintsSorted; + internal ExposedList transformConstraints; + internal ExposedList pathConstraints; + internal ExposedList updateCache = new ExposedList(); + internal Skin skin; + internal float r = 1, g = 1, b = 1, a = 1; + internal float time; + internal bool flipX, flipY; + internal float x, y; + + public SkeletonData Data { get { return data; } } + public ExposedList Bones { get { return bones; } } + public ExposedList UpdateCacheList { get { return updateCache; } } + public ExposedList Slots { get { return slots; } } + public ExposedList DrawOrder { get { return drawOrder; } } + public ExposedList IkConstraints { get { return ikConstraints; } } + public ExposedList PathConstraints { get { return pathConstraints; } } + public ExposedList TransformConstraints { get { return transformConstraints; } } + public Skin Skin { get { return skin; } set { skin = value; } } + public float R { get { return r; } set { r = value; } } + public float G { get { return g; } set { g = value; } } + public float B { get { return b; } set { b = value; } } + public float A { get { return a; } set { a = value; } } + public float Time { get { return time; } set { time = value; } } + public float X { get { return x; } set { x = value; } } + public float Y { get { return y; } set { y = value; } } + public bool FlipX { get { return flipX; } set { flipX = value; } } + public bool FlipY { get { return flipY; } set { flipY = value; } } + + public Bone RootBone { + get { return bones.Count == 0 ? null : bones.Items[0]; } + } + + public Skeleton (SkeletonData data) { + if (data == null) throw new ArgumentNullException("data", "data cannot be null."); + this.data = data; + + bones = new ExposedList(data.bones.Count); + foreach (BoneData boneData in data.bones) { + Bone bone; + if (boneData.parent == null) { + bone = new Bone(boneData, this, null); + } else { + Bone parent = bones.Items[boneData.parent.index]; + bone = new Bone(boneData, this, parent); + parent.children.Add(bone); + } + bones.Add(bone); + } + + slots = new ExposedList(data.slots.Count); + drawOrder = new ExposedList(data.slots.Count); + foreach (SlotData slotData in data.slots) { + Bone bone = bones.Items[slotData.boneData.index]; + Slot slot = new Slot(slotData, bone); + slots.Add(slot); + drawOrder.Add(slot); + } + + ikConstraints = new ExposedList(data.ikConstraints.Count); + ikConstraintsSorted = new ExposedList(data.ikConstraints.Count); + foreach (IkConstraintData ikConstraintData in data.ikConstraints) + ikConstraints.Add(new IkConstraint(ikConstraintData, this)); + + transformConstraints = new ExposedList(data.transformConstraints.Count); + foreach (TransformConstraintData transformConstraintData in data.transformConstraints) + transformConstraints.Add(new TransformConstraint(transformConstraintData, this)); + + pathConstraints = new ExposedList (data.pathConstraints.Count); + foreach (PathConstraintData pathConstraintData in data.pathConstraints) + pathConstraints.Add(new PathConstraint(pathConstraintData, this)); + + UpdateCache(); + UpdateWorldTransform(); + } + + /// Caches information about bones and constraints. Must be called if bones, constraints or weighted path attachments are added + /// or removed. + public void UpdateCache () { + ExposedList updateCache = this.updateCache; + updateCache.Clear(); + + ExposedList bones = this.bones; + for (int i = 0, n = bones.Count; i < n; i++) + bones.Items[i].sorted = false; + + ExposedList ikConstraints = this.ikConstraintsSorted; + ikConstraints.Clear(); + ikConstraints.AddRange(this.ikConstraints); + int ikCount = ikConstraints.Count; + for (int i = 0, level, n = ikCount; i < n; i++) { + IkConstraint ik = ikConstraints.Items[i]; + Bone bone = ik.bones.Items[0].parent; + for (level = 0; bone != null; level++) + bone = bone.parent; + ik.level = level; + } + for (int i = 1, ii; i < ikCount; i++) { + IkConstraint ik = ikConstraints.Items[i]; + int level = ik.level; + for (ii = i - 1; ii >= 0; ii--) { + IkConstraint other = ikConstraints.Items[ii]; + if (other.level < level) break; + ikConstraints.Items[ii + 1] = other; + } + ikConstraints.Items[ii + 1] = ik; + } + for (int i = 0, n = ikConstraints.Count; i < n; i++) { + IkConstraint constraint = ikConstraints.Items[i]; + Bone target = constraint.target; + SortBone(target); + + ExposedList constrained = constraint.bones; + Bone parent = constrained.Items[0]; + SortBone(parent); + + updateCache.Add(constraint); + + SortReset(parent.children); + constrained.Items[constrained.Count - 1].sorted = true; + } + + ExposedList pathConstraints = this.pathConstraints; + for (int i = 0, n = pathConstraints.Count; i < n; i++) { + PathConstraint constraint = pathConstraints.Items[i]; + + Slot slot = constraint.target; + int slotIndex = slot.data.index; + Bone slotBone = slot.bone; + if (skin != null) SortPathConstraintAttachment(skin, slotIndex, slotBone); + if (data.defaultSkin != null && data.defaultSkin != skin) + SortPathConstraintAttachment(data.defaultSkin, slotIndex, slotBone); + for (int ii = 0, nn = data.skins.Count; ii < nn; ii++) + SortPathConstraintAttachment(data.skins.Items[ii], slotIndex, slotBone); + + PathAttachment attachment = slot.Attachment as PathAttachment; + if (attachment != null) SortPathConstraintAttachment(attachment, slotBone); + + ExposedList constrained = constraint.bones; + int boneCount = constrained.Count; + for (int ii = 0; ii < boneCount; ii++) + SortBone(constrained.Items[ii]); + + updateCache.Add(constraint); + + for (int ii = 0; ii < boneCount; ii++) + SortReset(constrained.Items[ii].children); + for (int ii = 0; ii < boneCount; ii++) + constrained.Items[ii].sorted = true; + } + + ExposedList transformConstraints = this.transformConstraints; + for (int i = 0, n = transformConstraints.Count; i < n; i++) { + TransformConstraint constraint = transformConstraints.Items[i]; + + SortBone(constraint.target); + + ExposedList constrained = constraint.bones; + int boneCount = constrained.Count; + for (int ii = 0; ii < boneCount; ii++) + SortBone(constrained.Items[ii]); + + updateCache.Add(constraint); + + for (int ii = 0; ii < boneCount; ii++) + SortReset(constrained.Items[ii].children); + for (int ii = 0; ii < boneCount; ii++) + constrained.Items[ii].sorted = true; + } + + for (int i = 0, n = bones.Count; i < n; i++) + SortBone(bones.Items[i]); + } + + private void SortPathConstraintAttachment (Skin skin, int slotIndex, Bone slotBone) { + foreach (var entry in skin.Attachments) + if (entry.Key.slotIndex == slotIndex) SortPathConstraintAttachment(entry.Value, slotBone); + } + + private void SortPathConstraintAttachment (Attachment attachment, Bone slotBone) { + var pathAttachment = attachment as PathAttachment; + if (pathAttachment == null) return; + int[] pathBones = pathAttachment.bones; + if (pathBones == null) + SortBone(slotBone); + else { + var bonesItems = this.bones.Items; + for (int i = 0, n = pathBones.Length; i < n;) { + int nn = pathBones[i++]; + nn += i; + while (i < nn) + SortBone(bonesItems[pathBones[i++]]); + } + } + } + + private void SortBone (Bone bone) { + if (bone.sorted) return; + Bone parent = bone.parent; + if (parent != null) SortBone(parent); + bone.sorted = true; + updateCache.Add(bone); + } + + private void SortReset (ExposedList bones) { + var bonesItems = bones.Items; + for (int i = 0, n = bones.Count; i < n; i++) { + Bone bone = bonesItems[i]; + if (bone.sorted) SortReset(bone.children); + bone.sorted = false; + } + } + + /// Updates the world transform for each bone and applies constraints. + public void UpdateWorldTransform () { + var updateItems = this.updateCache.Items; + for (int i = 0, n = updateCache.Count; i < n; i++) + updateItems[i].Update(); + } + + /// Sets the bones, constraints, and slots to their setup pose values. + public void SetToSetupPose () { + SetBonesToSetupPose(); + SetSlotsToSetupPose(); + } + + /// Sets the bones and constraints to their setup pose values. + public void SetBonesToSetupPose () { + var bonesItems = this.bones.Items; + for (int i = 0, n = bones.Count; i < n; i++) + bonesItems[i].SetToSetupPose(); + + var ikConstraintsItems = this.ikConstraints.Items; + for (int i = 0, n = ikConstraints.Count; i < n; i++) { + IkConstraint constraint = ikConstraintsItems[i]; + constraint.bendDirection = constraint.data.bendDirection; + constraint.mix = constraint.data.mix; + } + + var transformConstraintsItems = this.transformConstraints.Items; + for (int i = 0, n = transformConstraints.Count; i < n; i++) { + TransformConstraint constraint = transformConstraintsItems[i]; + TransformConstraintData data = constraint.data; + constraint.rotateMix = data.rotateMix; + constraint.translateMix = data.translateMix; + constraint.scaleMix = data.scaleMix; + constraint.shearMix = data.shearMix; + } + + var pathConstraintItems = this.pathConstraints.Items; + for (int i = 0, n = pathConstraints.Count; i < n; i++) { + PathConstraint constraint = pathConstraintItems[i]; + PathConstraintData data = constraint.data; + constraint.position = data.position; + constraint.spacing = data.spacing; + constraint.rotateMix = data.rotateMix; + constraint.translateMix = data.translateMix; + } + } + + public void SetSlotsToSetupPose () { + var slots = this.slots; + var slotsItems = slots.Items; + drawOrder.Clear(); + for (int i = 0, n = slots.Count; i < n; i++) + drawOrder.Add(slotsItems[i]); + + for (int i = 0, n = slots.Count; i < n; i++) + slotsItems[i].SetToSetupPose(); + } + + /// May be null. + public Bone FindBone (String boneName) { + if (boneName == null) throw new ArgumentNullException("boneName", "boneName cannot be null."); + var bones = this.bones; + var bonesItems = bones.Items; + for (int i = 0, n = bones.Count; i < n; i++) { + Bone bone = bonesItems[i]; + if (bone.data.name == boneName) return bone; + } + return null; + } + + /// -1 if the bone was not found. + public int FindBoneIndex (String boneName) { + if (boneName == null) throw new ArgumentNullException("boneName", "boneName cannot be null."); + var bones = this.bones; + var bonesItems = bones.Items; + for (int i = 0, n = bones.Count; i < n; i++) + if (bonesItems[i].data.name == boneName) return i; + return -1; + } + + /// May be null. + public Slot FindSlot (String slotName) { + if (slotName == null) throw new ArgumentNullException("slotName", "slotName cannot be null."); + var slots = this.slots; + var slotsItems = slots.Items; + for (int i = 0, n = slots.Count; i < n; i++) { + Slot slot = slotsItems[i]; + if (slot.data.name == slotName) return slot; + } + return null; + } + + /// -1 if the bone was not found. + public int FindSlotIndex (String slotName) { + if (slotName == null) throw new ArgumentNullException("slotName", "slotName cannot be null."); + var slots = this.slots; + var slotsItems = slots.Items; + for (int i = 0, n = slots.Count; i < n; i++) + if (slotsItems[i].data.name.Equals(slotName)) return i; + return -1; + } + + /// Sets a skin by name (see SetSkin). + public void SetSkin (String skinName) { + Skin skin = data.FindSkin(skinName); + if (skin == null) throw new ArgumentException("Skin not found: " + skinName, "skinName"); + SetSkin(skin); + } + + /// Sets the skin used to look up attachments before looking in the {@link SkeletonData#getDefaultSkin() default + /// skin}. Attachmentsfrom 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. + /// May be null. + public void SetSkin (Skin newSkin) { + if (newSkin != null) { + if (skin != null) + newSkin.AttachAll(this, skin); + else { + ExposedList slots = this.slots; + for (int i = 0, n = slots.Count; i < n; i++) { + Slot slot = slots.Items[i]; + String name = slot.data.attachmentName; + if (name != null) { + Attachment attachment = newSkin.GetAttachment(i, name); + if (attachment != null) slot.Attachment = attachment; + } + } + } + } + skin = newSkin; + } + + /// May be null. + public Attachment GetAttachment (String slotName, String attachmentName) { + return GetAttachment(data.FindSlotIndex(slotName), attachmentName); + } + + /// May be null. + public Attachment GetAttachment (int slotIndex, String attachmentName) { + if (attachmentName == null) throw new ArgumentNullException("attachmentName", "attachmentName cannot be null."); + if (skin != null) { + Attachment attachment = skin.GetAttachment(slotIndex, attachmentName); + if (attachment != null) return attachment; + } + if (data.defaultSkin != null) return data.defaultSkin.GetAttachment(slotIndex, attachmentName); + return null; + } + + /// May be null. + public void SetAttachment (String slotName, String attachmentName) { + if (slotName == null) throw new ArgumentNullException("slotName", "slotName cannot be null."); + ExposedList slots = this.slots; + for (int i = 0, n = slots.Count; i < n; i++) { + Slot slot = slots.Items[i]; + if (slot.data.name == slotName) { + Attachment attachment = null; + if (attachmentName != null) { + attachment = GetAttachment(i, attachmentName); + if (attachment == null) throw new Exception("Attachment not found: " + attachmentName + ", for slot: " + slotName); + } + slot.Attachment = attachment; + return; + } + } + throw new Exception("Slot not found: " + slotName); + } + + /// May be null. + public IkConstraint FindIkConstraint (String constraintName) { + if (constraintName == null) throw new ArgumentNullException("constraintName", "constraintName cannot be null."); + ExposedList ikConstraints = this.ikConstraints; + for (int i = 0, n = ikConstraints.Count; i < n; i++) { + IkConstraint ikConstraint = ikConstraints.Items[i]; + if (ikConstraint.data.name == constraintName) return ikConstraint; + } + return null; + } + + /// May be null. + public TransformConstraint FindTransformConstraint (String constraintName) { + if (constraintName == null) throw new ArgumentNullException("constraintName", "constraintName cannot be null."); + ExposedList transformConstraints = this.transformConstraints; + for (int i = 0, n = transformConstraints.Count; i < n; i++) { + TransformConstraint transformConstraint = transformConstraints.Items[i]; + if (transformConstraint.data.name == constraintName) return transformConstraint; + } + return null; + } + + /// May be null. + public PathConstraint FindPathConstraint (String constraintName) { + if (constraintName == null) throw new ArgumentNullException("constraintName", "constraintName cannot be null."); + ExposedList pathConstraints = this.pathConstraints; + for (int i = 0, n = pathConstraints.Count; i < n; i++) { + PathConstraint constraint = pathConstraints.Items[i]; + if (constraint.data.name.Equals(constraintName)) return constraint; + } + return null; + } + + public void Update (float delta) { + time += delta; + } + } } diff --git a/spine-csharp/src/SkeletonBinary.cs b/spine-csharp/src/SkeletonBinary.cs index e564952ea4..b642bf1645 100644 --- a/spine-csharp/src/SkeletonBinary.cs +++ b/spine-csharp/src/SkeletonBinary.cs @@ -1,797 +1,796 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#if (UNITY_5 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_WSA || UNITY_WP8 || UNITY_WP8_1) -#define IS_UNITY -#endif - -using System; -using System.IO; -using System.Collections.Generic; - -#if WINDOWS_STOREAPP -using System.Threading.Tasks; -using Windows.Storage; -#endif - -namespace Spine { - public class SkeletonBinary { - public const int BONE_ROTATE = 0; - public const int BONE_TRANSLATE = 1; - public const int BONE_SCALE = 2; - public const int BONE_SHEAR = 3; - - public const int SLOT_ATTACHMENT = 0; - public const int SLOT_COLOR = 1; - - public const int PATH_POSITION = 0; - public const int PATH_SPACING = 1; - public const int PATH_MIX = 2; - - public const int CURVE_LINEAR = 0; - public const int CURVE_STEPPED = 1; - public const int CURVE_BEZIER = 2; - - public float Scale { get; set; } - - private AttachmentLoader attachmentLoader; - private byte[] buffer = new byte[32]; - private List linkedMeshes = new List(); - - public SkeletonBinary (params Atlas[] atlasArray) - : this(new AtlasAttachmentLoader(atlasArray)) { - } - - public SkeletonBinary (AttachmentLoader attachmentLoader) { - if (attachmentLoader == null) throw new ArgumentNullException("attachmentLoader"); - this.attachmentLoader = attachmentLoader; - Scale = 1; - } - - #if !ISUNITY && WINDOWS_STOREAPP - private async Task ReadFile(string path) { - var folder = Windows.ApplicationModel.Package.Current.InstalledLocation; - using (var input = new BufferedStream(await folder.GetFileAsync(path).AsTask().ConfigureAwait(false))) { - SkeletonData skeletonData = ReadSkeletonData(input); - skeletonData.Name = Path.GetFileNameWithoutExtension(path); - return skeletonData; - } - } - - public SkeletonData ReadSkeletonData (String path) { - return this.ReadFile(path).Result; - } - #else - public SkeletonData ReadSkeletonData (String path) { - #if WINDOWS_PHONE - using (var input = new BufferedStream(Microsoft.Xna.Framework.TitleContainer.OpenStream(path))) { - #else - using (var input = new BufferedStream(new FileStream(path, FileMode.Open))) { - #endif // WINDOWS_PHONE - SkeletonData skeletonData = ReadSkeletonData(input); - skeletonData.name = Path.GetFileNameWithoutExtension(path); - return skeletonData; - } - } - - #endif // WINDOWS_STOREAPP - - public SkeletonData ReadSkeletonData (Stream input) { - if (input == null) throw new ArgumentNullException("input"); - float scale = Scale; - - var skeletonData = new SkeletonData(); - skeletonData.hash = ReadString(input); - if (skeletonData.hash.Length == 0) skeletonData.hash = null; - skeletonData.version = ReadString(input); - if (skeletonData.version.Length == 0) skeletonData.version = null; - skeletonData.width = ReadFloat(input); - skeletonData.height = ReadFloat(input); - - bool nonessential = ReadBoolean(input); - - if (nonessential) { - skeletonData.imagesPath = ReadString(input); - if (skeletonData.imagesPath.Length == 0) skeletonData.imagesPath = null; - } - - // Bones. - for (int i = 0, n = ReadVarint(input, true); i < n; i++) { - String name = ReadString(input); - BoneData parent = i == 0 ? null : skeletonData.bones.Items[ReadVarint(input, true)]; - BoneData data = new BoneData(i, name, parent); - data.rotation = ReadFloat(input); - data.x = ReadFloat(input) * scale; - data.y = ReadFloat(input) * scale; - data.scaleX = ReadFloat(input); - data.scaleY = ReadFloat(input); - data.shearX = ReadFloat(input); - data.shearY = ReadFloat(input); - data.length = ReadFloat(input) * scale; - data.inheritRotation = ReadBoolean(input); - data.inheritScale = ReadBoolean(input); - if (nonessential) ReadInt(input); // Skip bone color. - skeletonData.bones.Add(data); - } - - // Slots. - for (int i = 0, n = ReadVarint(input, true); i < n; i++) { - String slotName = ReadString(input); - BoneData boneData = skeletonData.bones.Items[ReadVarint(input, true)]; - SlotData slotData = new SlotData(i, slotName, boneData); - int color = ReadInt(input); - slotData.r = ((color & 0xff000000) >> 24) / 255f; - slotData.g = ((color & 0x00ff0000) >> 16) / 255f; - slotData.b = ((color & 0x0000ff00) >> 8) / 255f; - slotData.a = ((color & 0x000000ff)) / 255f; - slotData.attachmentName = ReadString(input); - slotData.blendMode = (BlendMode)ReadVarint(input, true); - skeletonData.slots.Add(slotData); - } - - // IK constraints. - for (int i = 0, n = ReadVarint(input, true); i < n; i++) { - IkConstraintData data = new IkConstraintData(ReadString(input)); - for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++) - data.bones.Add(skeletonData.bones.Items[ReadVarint(input, true)]); - data.target = skeletonData.bones.Items[ReadVarint(input, true)]; - data.mix = ReadFloat(input); - data.bendDirection = ReadSByte(input); - skeletonData.ikConstraints.Add(data); - } - - // Transform constraints. - for (int i = 0, n = ReadVarint(input, true); i < n; i++) { - TransformConstraintData data = new TransformConstraintData(ReadString(input)); - for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++) - data.bones.Add(skeletonData.bones.Items[ReadVarint(input, true)]); - data.target = skeletonData.bones.Items[ReadVarint(input, true)]; - data.offsetRotation = ReadFloat(input); - data.offsetX = ReadFloat(input) * scale; - data.offsetY = ReadFloat(input) * scale; - data.offsetScaleX = ReadFloat(input); - data.offsetScaleY = ReadFloat(input); - data.offsetShearY = ReadFloat(input); - data.rotateMix = ReadFloat(input); - data.translateMix = ReadFloat(input); - data.scaleMix = ReadFloat(input); - data.shearMix = ReadFloat(input); - skeletonData.transformConstraints.Add(data); - } - - // Path constraints - for (int i = 0, n = ReadVarint(input, true); i < n; i++) { - PathConstraintData data = new PathConstraintData(ReadString(input)); - for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++) - data.bones.Add(skeletonData.bones.Items[ReadVarint(input, true)]); - data.target = skeletonData.slots.Items[ReadVarint(input, true)]; - data.positionMode = (PositionMode)Enum.GetValues(typeof(PositionMode)).GetValue(ReadVarint(input, true)); - data.spacingMode = (SpacingMode)Enum.GetValues(typeof(SpacingMode)).GetValue(ReadVarint(input, true)); - data.rotateMode = (RotateMode)Enum.GetValues(typeof(RotateMode)).GetValue(ReadVarint(input, true)); - data.offsetRotation = ReadFloat(input); - data.position = ReadFloat(input); - if (data.positionMode == PositionMode.Fixed) data.position *= scale; - data.spacing = ReadFloat(input); - if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed) data.spacing *= scale; - data.rotateMix = ReadFloat(input); - data.translateMix = ReadFloat(input); - skeletonData.pathConstraints.Add(data); - } - - // Default skin. - Skin defaultSkin = ReadSkin(input, "default", nonessential); - if (defaultSkin != null) { - skeletonData.defaultSkin = defaultSkin; - skeletonData.skins.Add(defaultSkin); - } - - // Skins. - for (int i = 0, n = ReadVarint(input, true); i < n; i++) - skeletonData.skins.Add(ReadSkin(input, ReadString(input), nonessential)); - - // Linked meshes. - for (int i = 0, n = linkedMeshes.Count; i < n; i++) { - SkeletonJson.LinkedMesh linkedMesh = linkedMeshes[i]; - Skin skin = linkedMesh.skin == null ? skeletonData.DefaultSkin : skeletonData.FindSkin(linkedMesh.skin); - if (skin == null) throw new Exception("Skin not found: " + linkedMesh.skin); - Attachment parent = skin.GetAttachment(linkedMesh.slotIndex, linkedMesh.parent); - if (parent == null) throw new Exception("Parent mesh not found: " + linkedMesh.parent); - linkedMesh.mesh.ParentMesh = (MeshAttachment)parent; - linkedMesh.mesh.UpdateUVs(); - } - linkedMeshes.Clear(); - - // Events. - for (int i = 0, n = ReadVarint(input, true); i < n; i++) { - EventData data = new EventData(ReadString(input)); - data.Int = ReadVarint(input, false); - data.Float = ReadFloat(input); - data.String = ReadString(input); - skeletonData.events.Add(data); - } - - // Animations. - for (int i = 0, n = ReadVarint(input, true); i < n; i++) - ReadAnimation(ReadString(input), input, skeletonData); - - skeletonData.bones.TrimExcess(); - skeletonData.slots.TrimExcess(); - skeletonData.skins.TrimExcess(); - skeletonData.events.TrimExcess(); - skeletonData.animations.TrimExcess(); - skeletonData.ikConstraints.TrimExcess(); - skeletonData.pathConstraints.TrimExcess(); - return skeletonData; - } - - - /// May be null. - private Skin ReadSkin (Stream input, String skinName, bool nonessential) { - int slotCount = ReadVarint(input, true); - if (slotCount == 0) return null; - Skin skin = new Skin(skinName); - for (int i = 0; i < slotCount; i++) { - int slotIndex = ReadVarint(input, true); - for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++) { - String name = ReadString(input); - skin.AddAttachment(slotIndex, name, ReadAttachment(input, skin, slotIndex, name, nonessential)); - } - } - return skin; - } - - private Attachment ReadAttachment (Stream input, Skin skin, int slotIndex, String attachmentName, bool nonessential) { - float scale = Scale; - - String name = ReadString(input); - if (name == null) name = attachmentName; - - AttachmentType type = (AttachmentType)input.ReadByte(); - switch (type) { - case AttachmentType.Region: { - String path = ReadString(input); - float rotation = ReadFloat(input); - float x = ReadFloat(input); - float y = ReadFloat(input); - float scaleX = ReadFloat(input); - float scaleY = ReadFloat(input); - float width = ReadFloat(input); - float height = ReadFloat(input); - int color = ReadInt(input); - - if (path == null) path = name; - RegionAttachment region = attachmentLoader.NewRegionAttachment(skin, name, path); - if (region == null) return null; - region.Path = path; - region.x = x * scale; - region.y = y * scale; - region.scaleX = scaleX; - region.scaleY = scaleY; - region.rotation = rotation; - region.width = width * scale; - region.height = height * scale; - region.r = ((color & 0xff000000) >> 24) / 255f; - region.g = ((color & 0x00ff0000) >> 16) / 255f; - region.b = ((color & 0x0000ff00) >> 8) / 255f; - region.a = ((color & 0x000000ff)) / 255f; - region.UpdateOffset(); - return region; - } - case AttachmentType.Boundingbox: { - int vertexCount = ReadVarint(input, true); - Vertices vertices = ReadVertices(input, vertexCount); - if (nonessential) ReadInt(input); //int color = nonessential ? ReadInt(input) : 0; // Avoid unused local warning. - - BoundingBoxAttachment box = attachmentLoader.NewBoundingBoxAttachment(skin, name); - if (box == null) return null; - box.worldVerticesLength = vertexCount << 1; - box.vertices = vertices.vertices; - box.bones = vertices.bones; - return box; - } - case AttachmentType.Mesh: { - String path = ReadString(input); - int color = ReadInt(input); - int vertexCount = ReadVarint(input, true); - float[] uvs = ReadFloatArray(input, vertexCount << 1, 1); - int[] triangles = ReadShortArray(input); - Vertices vertices = ReadVertices(input, vertexCount); - int hullLength = ReadVarint(input, true); - int[] edges = null; - float width = 0, height = 0; - if (nonessential) { - edges = ReadShortArray(input); - width = ReadFloat(input); - height = ReadFloat(input); - } - - if (path == null) path = name; - MeshAttachment mesh = attachmentLoader.NewMeshAttachment(skin, name, path); - if (mesh == null) return null; - mesh.Path = path; - mesh.r = ((color & 0xff000000) >> 24) / 255f; - mesh.g = ((color & 0x00ff0000) >> 16) / 255f; - mesh.b = ((color & 0x0000ff00) >> 8) / 255f; - mesh.a = ((color & 0x000000ff)) / 255f; - mesh.bones = vertices.bones; - mesh.vertices = vertices.vertices; - mesh.WorldVerticesLength = vertexCount << 1; - mesh.triangles = triangles; - mesh.regionUVs = uvs; - mesh.UpdateUVs(); - mesh.HullLength = hullLength << 1; - if (nonessential) { - mesh.Edges = edges; - mesh.Width = width * scale; - mesh.Height = height * scale; - } - return mesh; - } - case AttachmentType.Linkedmesh: { - String path = ReadString(input); - int color = ReadInt(input); - String skinName = ReadString(input); - String parent = ReadString(input); - bool inheritDeform = ReadBoolean(input); - float width = 0, height = 0; - if (nonessential) { - width = ReadFloat(input); - height = ReadFloat(input); - } - - if (path == null) path = name; - MeshAttachment mesh = attachmentLoader.NewMeshAttachment(skin, name, path); - if (mesh == null) return null; - mesh.Path = path; - mesh.r = ((color & 0xff000000) >> 24) / 255f; - mesh.g = ((color & 0x00ff0000) >> 16) / 255f; - mesh.b = ((color & 0x0000ff00) >> 8) / 255f; - mesh.a = ((color & 0x000000ff)) / 255f; - mesh.inheritDeform = inheritDeform; - if (nonessential) { - mesh.Width = width * scale; - mesh.Height = height * scale; - } - linkedMeshes.Add(new SkeletonJson.LinkedMesh(mesh, skinName, slotIndex, parent)); - return mesh; - } - case AttachmentType.Path: { - bool closed = ReadBoolean(input); - bool constantSpeed = ReadBoolean(input); - int vertexCount = ReadVarint(input, true); - Vertices vertices = ReadVertices(input, vertexCount); - float[] lengths = new float[vertexCount / 3]; - for (int i = 0, n = lengths.Length; i < n; i++) - lengths[i] = ReadFloat(input) * scale; - if (nonessential) ReadInt(input); //int color = nonessential ? ReadInt(input) : 0; // Avoid unused local warning. - - PathAttachment path = attachmentLoader.NewPathAttachment(skin, name); - if (path == null) return null; - path.closed = closed; - path.constantSpeed = constantSpeed; - path.worldVerticesLength = vertexCount << 1; - path.vertices = vertices.vertices; - path.bones = vertices.bones; - path.lengths = lengths; - return path; - } - } - return null; - } - - private Vertices ReadVertices (Stream input, int vertexCount) { - float scale = Scale; - int verticesLength = vertexCount << 1; - Vertices vertices = new Vertices(); - if(!ReadBoolean(input)) { - vertices.vertices = ReadFloatArray(input, verticesLength, scale); - return vertices; - } - var weights = new ExposedList(verticesLength * 3 * 3); - var bonesArray = new ExposedList(verticesLength * 3); - for (int i = 0; i < vertexCount; i++) { - int boneCount = ReadVarint(input, true); - bonesArray.Add(boneCount); - for (int ii = 0; ii < boneCount; ii++) { - bonesArray.Add(ReadVarint(input, true)); - weights.Add(ReadFloat(input) * scale); - weights.Add(ReadFloat(input) * scale); - weights.Add(ReadFloat(input)); - } - } - - vertices.vertices = weights.ToArray(); - vertices.bones = bonesArray.ToArray(); - return vertices; - } - - private float[] ReadFloatArray (Stream input, int n, float scale) { - float[] array = new float[n]; - if (scale == 1) { - for (int i = 0; i < n; i++) - array[i] = ReadFloat(input); - } else { - for (int i = 0; i < n; i++) - array[i] = ReadFloat(input) * scale; - } - return array; - } - - private int[] ReadShortArray (Stream input) { - int n = ReadVarint(input, true); - int[] array = new int[n]; - for (int i = 0; i < n; i++) - array[i] = (input.ReadByte() << 8) | input.ReadByte(); - return array; - } - - private void ReadAnimation (String name, Stream input, SkeletonData skeletonData) { - var timelines = new ExposedList(); - float scale = Scale; - float duration = 0; - - // Slot timelines. - for (int i = 0, n = ReadVarint(input, true); i < n; i++) { - int slotIndex = ReadVarint(input, true); - for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++) { - int timelineType = input.ReadByte(); - int frameCount = ReadVarint(input, true); - switch (timelineType) { - case SLOT_COLOR: { - ColorTimeline timeline = new ColorTimeline(frameCount); - timeline.slotIndex = slotIndex; - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { - float time = ReadFloat(input); - int color = ReadInt(input); - float r = ((color & 0xff000000) >> 24) / 255f; - float g = ((color & 0x00ff0000) >> 16) / 255f; - float b = ((color & 0x0000ff00) >> 8) / 255f; - float a = ((color & 0x000000ff)) / 255f; - timeline.SetFrame(frameIndex, time, r, g, b, a); - if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline); - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * ColorTimeline.ENTRIES]); - break; - } - case SLOT_ATTACHMENT: { - AttachmentTimeline timeline = new AttachmentTimeline(frameCount); - timeline.slotIndex = slotIndex; - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) - timeline.SetFrame(frameIndex, ReadFloat(input), ReadString(input)); - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[frameCount - 1]); - break; - } - } - } - } - - // Bone timelines. - for (int i = 0, n = ReadVarint(input, true); i < n; i++) { - int boneIndex = ReadVarint(input, true); - for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++) { - int timelineType = input.ReadByte(); - int frameCount = ReadVarint(input, true); - switch (timelineType) { - case BONE_ROTATE: { - RotateTimeline timeline = new RotateTimeline(frameCount); - timeline.boneIndex = boneIndex; - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { - timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input)); - if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline); - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[(frameCount - 1) * RotateTimeline.ENTRIES]); - break; - } - case BONE_TRANSLATE: - case BONE_SCALE: - case BONE_SHEAR: { - TranslateTimeline timeline; - float timelineScale = 1; - if (timelineType == BONE_SCALE) - timeline = new ScaleTimeline(frameCount); - else if (timelineType == BONE_SHEAR) - timeline = new ShearTimeline(frameCount); - else { - timeline = new TranslateTimeline(frameCount); - timelineScale = scale; - } - timeline.boneIndex = boneIndex; - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { - timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input) * timelineScale, ReadFloat(input) - * timelineScale); - if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline); - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[(frameCount - 1) * TranslateTimeline.ENTRIES]); - break; - } - } - } - } - - // IK timelines. - for (int i = 0, n = ReadVarint(input, true); i < n; i++) { - int index = ReadVarint(input, true); - int frameCount = ReadVarint(input, true); - IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount); - timeline.ikConstraintIndex = index; - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { - timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input), ReadSByte(input)); - if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline); - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[(frameCount - 1) * IkConstraintTimeline.ENTRIES]); - } - - // Transform constraint timelines. - for (int i = 0, n = ReadVarint(input, true); i < n; i++) { - int index = ReadVarint(input, true); - int frameCount = ReadVarint(input, true); - TransformConstraintTimeline timeline = new TransformConstraintTimeline(frameCount); - timeline.transformConstraintIndex = index; - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { - timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input), ReadFloat(input), ReadFloat(input), ReadFloat(input)); - if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline); - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[(frameCount - 1) * TransformConstraintTimeline.ENTRIES]); - } - - // Path constraint timelines. - for (int i = 0, n = ReadVarint(input, true); i < n; i++) { - int index = ReadVarint(input, true); - PathConstraintData data = skeletonData.pathConstraints.Items[index]; - for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++) { - int timelineType = ReadSByte(input); - int frameCount = ReadVarint(input, true); - switch(timelineType) { - case PATH_POSITION: - case PATH_SPACING: { - PathConstraintPositionTimeline timeline; - float timelineScale = 1; - if (timelineType == PATH_SPACING) { - timeline = new PathConstraintSpacingTimeline(frameCount); - if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed) timelineScale = scale; - } else { - timeline = new PathConstraintPositionTimeline(frameCount); - if (data.positionMode == PositionMode.Fixed) timelineScale = scale; - } - timeline.pathConstraintIndex = index; - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { - timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input) * timelineScale); - if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline); - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[(frameCount - 1) * PathConstraintPositionTimeline.ENTRIES]); - break; - } - case PATH_MIX: { - PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(frameCount); - timeline.pathConstraintIndex = index; - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { - timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input), ReadFloat(input)); - if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline); - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[(frameCount - 1) * PathConstraintMixTimeline.ENTRIES]); - break; - } - } - } - } - - // Deform timelines. - for (int i = 0, n = ReadVarint(input, true); i < n; i++) { - Skin skin = skeletonData.skins.Items[ReadVarint(input, true)]; - for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++) { - int slotIndex = ReadVarint(input, true); - for (int iii = 0, nnn = ReadVarint(input, true); iii < nnn; iii++) { - VertexAttachment attachment = (VertexAttachment)skin.GetAttachment(slotIndex, ReadString(input)); - bool weighted = attachment.bones != null; - float[] vertices = attachment.vertices; - int deformLength = weighted ? vertices.Length / 3 * 2 : vertices.Length; - - int frameCount = ReadVarint(input, true); - DeformTimeline timeline = new DeformTimeline(frameCount); - timeline.slotIndex = slotIndex; - timeline.attachment = attachment; - - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { - float time = ReadFloat(input); - float[] deform; - int end = ReadVarint(input, true); - if (end == 0) - deform = weighted ? new float[deformLength] : vertices; - else { - deform = new float[deformLength]; - int start = ReadVarint(input, true); - end += start; - if (scale == 1) { - for (int v = start; v < end; v++) - deform[v] = ReadFloat(input); - } else { - for (int v = start; v < end; v++) - deform[v] = ReadFloat(input) * scale; - } - if (!weighted) { - for (int v = 0, vn = deform.Length; v < vn; v++) - deform[v] += vertices[v]; - } - } - - timeline.SetFrame(frameIndex, time, deform); - if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline); - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[frameCount - 1]); - } - } - } - - // Draw order timeline. - int drawOrderCount = ReadVarint(input, true); - if (drawOrderCount > 0) { - DrawOrderTimeline timeline = new DrawOrderTimeline(drawOrderCount); - int slotCount = skeletonData.slots.Count; - for (int i = 0; i < drawOrderCount; i++) { - float time = ReadFloat(input); - int offsetCount = ReadVarint(input, true); - int[] drawOrder = new int[slotCount]; - for (int ii = slotCount - 1; ii >= 0; ii--) - drawOrder[ii] = -1; - int[] unchanged = new int[slotCount - offsetCount]; - int originalIndex = 0, unchangedIndex = 0; - for (int ii = 0; ii < offsetCount; ii++) { - int slotIndex = ReadVarint(input, true); - // Collect unchanged items. - while (originalIndex != slotIndex) - unchanged[unchangedIndex++] = originalIndex++; - // Set changed items. - drawOrder[originalIndex + ReadVarint(input, true)] = originalIndex++; - } - // Collect remaining unchanged items. - while (originalIndex < slotCount) - unchanged[unchangedIndex++] = originalIndex++; - // Fill in unchanged items. - for (int ii = slotCount - 1; ii >= 0; ii--) - if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex]; - timeline.SetFrame(i, time, drawOrder); - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[drawOrderCount - 1]); - } - - // Event timeline. - int eventCount = ReadVarint(input, true); - if (eventCount > 0) { - EventTimeline timeline = new EventTimeline(eventCount); - for (int i = 0; i < eventCount; i++) { - float time = ReadFloat(input); - EventData eventData = skeletonData.events.Items[ReadVarint(input, true)]; - Event e = new Event(time, eventData); - e.Int = ReadVarint(input, false); - e.Float = ReadFloat(input); - e.String = ReadBoolean(input) ? ReadString(input) : eventData.String; - timeline.SetFrame(i, e); - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[eventCount - 1]); - } - - timelines.TrimExcess(); - skeletonData.animations.Add(new Animation(name, timelines, duration)); - } - - private void ReadCurve (Stream input, int frameIndex, CurveTimeline timeline) { - switch (input.ReadByte()) { - case CURVE_STEPPED: - timeline.SetStepped(frameIndex); - break; - case CURVE_BEZIER: - timeline.SetCurve(frameIndex, ReadFloat(input), ReadFloat(input), ReadFloat(input), ReadFloat(input)); - break; - } - } - - private static sbyte ReadSByte (Stream input) { - int value = input.ReadByte(); - if (value == -1) throw new EndOfStreamException(); - return (sbyte)value; - } - - private static bool ReadBoolean (Stream input) { - return input.ReadByte() != 0; - } - - private float ReadFloat (Stream input) { - buffer[3] = (byte)input.ReadByte(); - buffer[2] = (byte)input.ReadByte(); - buffer[1] = (byte)input.ReadByte(); - buffer[0] = (byte)input.ReadByte(); - return BitConverter.ToSingle(buffer, 0); - } - - private static int ReadInt (Stream input) { - return (input.ReadByte() << 24) + (input.ReadByte() << 16) + (input.ReadByte() << 8) + input.ReadByte(); - } - - private static int ReadVarint (Stream input, bool optimizePositive) { - int b = input.ReadByte(); - int result = b & 0x7F; - if ((b & 0x80) != 0) { - b = input.ReadByte(); - result |= (b & 0x7F) << 7; - if ((b & 0x80) != 0) { - b = input.ReadByte(); - result |= (b & 0x7F) << 14; - if ((b & 0x80) != 0) { - b = input.ReadByte(); - result |= (b & 0x7F) << 21; - if ((b & 0x80) != 0) result |= (input.ReadByte() & 0x7F) << 28; - } - } - } - return optimizePositive ? result : ((result >> 1) ^ -(result & 1)); - } - - private string ReadString (Stream input) { - int byteCount = ReadVarint(input, true); - switch (byteCount) { - case 0: - return null; - case 1: - return ""; - } - byteCount--; - byte[] buffer = this.buffer; - if (buffer.Length < byteCount) buffer = new byte[byteCount]; - ReadFully(input, buffer, 0, byteCount); - return System.Text.Encoding.UTF8.GetString(buffer, 0, byteCount); - } - - private static void ReadFully (Stream input, byte[] buffer, int offset, int length) { - while (length > 0) { - int count = input.Read(buffer, offset, length); - if (count <= 0) throw new EndOfStreamException(); - offset += count; - length -= count; - } - } - - internal class Vertices { - public int[] bones; - public float[] vertices; - } - } +#if (UNITY_5 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_WSA || UNITY_WP8 || UNITY_WP8_1) +#define IS_UNITY +#endif + +using System; +using System.IO; +using System.Collections.Generic; + +#if WINDOWS_STOREAPP +using System.Threading.Tasks; +using Windows.Storage; +#endif + +namespace Spine { + public class SkeletonBinary { + public const int BONE_ROTATE = 0; + public const int BONE_TRANSLATE = 1; + public const int BONE_SCALE = 2; + public const int BONE_SHEAR = 3; + + public const int SLOT_ATTACHMENT = 0; + public const int SLOT_COLOR = 1; + + public const int PATH_POSITION = 0; + public const int PATH_SPACING = 1; + public const int PATH_MIX = 2; + + public const int CURVE_LINEAR = 0; + public const int CURVE_STEPPED = 1; + public const int CURVE_BEZIER = 2; + + public float Scale { get; set; } + + private AttachmentLoader attachmentLoader; + private byte[] buffer = new byte[32]; + private List linkedMeshes = new List(); + + public SkeletonBinary (params Atlas[] atlasArray) + : this(new AtlasAttachmentLoader(atlasArray)) { + } + + public SkeletonBinary (AttachmentLoader attachmentLoader) { + if (attachmentLoader == null) throw new ArgumentNullException("attachmentLoader"); + this.attachmentLoader = attachmentLoader; + Scale = 1; + } + + #if !ISUNITY && WINDOWS_STOREAPP + private async Task ReadFile(string path) { + var folder = Windows.ApplicationModel.Package.Current.InstalledLocation; + using (var input = new BufferedStream(await folder.GetFileAsync(path).AsTask().ConfigureAwait(false))) { + SkeletonData skeletonData = ReadSkeletonData(input); + skeletonData.Name = Path.GetFileNameWithoutExtension(path); + return skeletonData; + } + } + + public SkeletonData ReadSkeletonData (String path) { + return this.ReadFile(path).Result; + } + #else + public SkeletonData ReadSkeletonData (String path) { + #if WINDOWS_PHONE + using (var input = new BufferedStream(Microsoft.Xna.Framework.TitleContainer.OpenStream(path))) { + #else + using (var input = new BufferedStream(new FileStream(path, FileMode.Open))) { + #endif // WINDOWS_PHONE + SkeletonData skeletonData = ReadSkeletonData(input); + skeletonData.name = Path.GetFileNameWithoutExtension(path); + return skeletonData; + } + } + + #endif // WINDOWS_STOREAPP + + public SkeletonData ReadSkeletonData (Stream input) { + if (input == null) throw new ArgumentNullException("input"); + float scale = Scale; + + var skeletonData = new SkeletonData(); + skeletonData.hash = ReadString(input); + if (skeletonData.hash.Length == 0) skeletonData.hash = null; + skeletonData.version = ReadString(input); + if (skeletonData.version.Length == 0) skeletonData.version = null; + skeletonData.width = ReadFloat(input); + skeletonData.height = ReadFloat(input); + + bool nonessential = ReadBoolean(input); + + if (nonessential) { + skeletonData.imagesPath = ReadString(input); + if (skeletonData.imagesPath.Length == 0) skeletonData.imagesPath = null; + } + + // Bones. + for (int i = 0, n = ReadVarint(input, true); i < n; i++) { + String name = ReadString(input); + BoneData parent = i == 0 ? null : skeletonData.bones.Items[ReadVarint(input, true)]; + BoneData data = new BoneData(i, name, parent); + data.rotation = ReadFloat(input); + data.x = ReadFloat(input) * scale; + data.y = ReadFloat(input) * scale; + data.scaleX = ReadFloat(input); + data.scaleY = ReadFloat(input); + data.shearX = ReadFloat(input); + data.shearY = ReadFloat(input); + data.length = ReadFloat(input) * scale; + data.inheritRotation = ReadBoolean(input); + data.inheritScale = ReadBoolean(input); + if (nonessential) ReadInt(input); // Skip bone color. + skeletonData.bones.Add(data); + } + + // Slots. + for (int i = 0, n = ReadVarint(input, true); i < n; i++) { + String slotName = ReadString(input); + BoneData boneData = skeletonData.bones.Items[ReadVarint(input, true)]; + SlotData slotData = new SlotData(i, slotName, boneData); + int color = ReadInt(input); + slotData.r = ((color & 0xff000000) >> 24) / 255f; + slotData.g = ((color & 0x00ff0000) >> 16) / 255f; + slotData.b = ((color & 0x0000ff00) >> 8) / 255f; + slotData.a = ((color & 0x000000ff)) / 255f; + slotData.attachmentName = ReadString(input); + slotData.blendMode = (BlendMode)ReadVarint(input, true); + skeletonData.slots.Add(slotData); + } + + // IK constraints. + for (int i = 0, n = ReadVarint(input, true); i < n; i++) { + IkConstraintData data = new IkConstraintData(ReadString(input)); + for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++) + data.bones.Add(skeletonData.bones.Items[ReadVarint(input, true)]); + data.target = skeletonData.bones.Items[ReadVarint(input, true)]; + data.mix = ReadFloat(input); + data.bendDirection = ReadSByte(input); + skeletonData.ikConstraints.Add(data); + } + + // Transform constraints. + for (int i = 0, n = ReadVarint(input, true); i < n; i++) { + TransformConstraintData data = new TransformConstraintData(ReadString(input)); + for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++) + data.bones.Add(skeletonData.bones.Items[ReadVarint(input, true)]); + data.target = skeletonData.bones.Items[ReadVarint(input, true)]; + data.offsetRotation = ReadFloat(input); + data.offsetX = ReadFloat(input) * scale; + data.offsetY = ReadFloat(input) * scale; + data.offsetScaleX = ReadFloat(input); + data.offsetScaleY = ReadFloat(input); + data.offsetShearY = ReadFloat(input); + data.rotateMix = ReadFloat(input); + data.translateMix = ReadFloat(input); + data.scaleMix = ReadFloat(input); + data.shearMix = ReadFloat(input); + skeletonData.transformConstraints.Add(data); + } + + // Path constraints + for (int i = 0, n = ReadVarint(input, true); i < n; i++) { + PathConstraintData data = new PathConstraintData(ReadString(input)); + for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++) + data.bones.Add(skeletonData.bones.Items[ReadVarint(input, true)]); + data.target = skeletonData.slots.Items[ReadVarint(input, true)]; + data.positionMode = (PositionMode)Enum.GetValues(typeof(PositionMode)).GetValue(ReadVarint(input, true)); + data.spacingMode = (SpacingMode)Enum.GetValues(typeof(SpacingMode)).GetValue(ReadVarint(input, true)); + data.rotateMode = (RotateMode)Enum.GetValues(typeof(RotateMode)).GetValue(ReadVarint(input, true)); + data.offsetRotation = ReadFloat(input); + data.position = ReadFloat(input); + if (data.positionMode == PositionMode.Fixed) data.position *= scale; + data.spacing = ReadFloat(input); + if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed) data.spacing *= scale; + data.rotateMix = ReadFloat(input); + data.translateMix = ReadFloat(input); + skeletonData.pathConstraints.Add(data); + } + + // Default skin. + Skin defaultSkin = ReadSkin(input, "default", nonessential); + if (defaultSkin != null) { + skeletonData.defaultSkin = defaultSkin; + skeletonData.skins.Add(defaultSkin); + } + + // Skins. + for (int i = 0, n = ReadVarint(input, true); i < n; i++) + skeletonData.skins.Add(ReadSkin(input, ReadString(input), nonessential)); + + // Linked meshes. + for (int i = 0, n = linkedMeshes.Count; i < n; i++) { + SkeletonJson.LinkedMesh linkedMesh = linkedMeshes[i]; + Skin skin = linkedMesh.skin == null ? skeletonData.DefaultSkin : skeletonData.FindSkin(linkedMesh.skin); + if (skin == null) throw new Exception("Skin not found: " + linkedMesh.skin); + Attachment parent = skin.GetAttachment(linkedMesh.slotIndex, linkedMesh.parent); + if (parent == null) throw new Exception("Parent mesh not found: " + linkedMesh.parent); + linkedMesh.mesh.ParentMesh = (MeshAttachment)parent; + linkedMesh.mesh.UpdateUVs(); + } + linkedMeshes.Clear(); + + // Events. + for (int i = 0, n = ReadVarint(input, true); i < n; i++) { + EventData data = new EventData(ReadString(input)); + data.Int = ReadVarint(input, false); + data.Float = ReadFloat(input); + data.String = ReadString(input); + skeletonData.events.Add(data); + } + + // Animations. + for (int i = 0, n = ReadVarint(input, true); i < n; i++) + ReadAnimation(ReadString(input), input, skeletonData); + + skeletonData.bones.TrimExcess(); + skeletonData.slots.TrimExcess(); + skeletonData.skins.TrimExcess(); + skeletonData.events.TrimExcess(); + skeletonData.animations.TrimExcess(); + skeletonData.ikConstraints.TrimExcess(); + skeletonData.pathConstraints.TrimExcess(); + return skeletonData; + } + + + /// May be null. + private Skin ReadSkin (Stream input, String skinName, bool nonessential) { + int slotCount = ReadVarint(input, true); + if (slotCount == 0) return null; + Skin skin = new Skin(skinName); + for (int i = 0; i < slotCount; i++) { + int slotIndex = ReadVarint(input, true); + for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++) { + String name = ReadString(input); + skin.AddAttachment(slotIndex, name, ReadAttachment(input, skin, slotIndex, name, nonessential)); + } + } + return skin; + } + + private Attachment ReadAttachment (Stream input, Skin skin, int slotIndex, String attachmentName, bool nonessential) { + float scale = Scale; + + String name = ReadString(input); + if (name == null) name = attachmentName; + + AttachmentType type = (AttachmentType)input.ReadByte(); + switch (type) { + case AttachmentType.Region: { + String path = ReadString(input); + float rotation = ReadFloat(input); + float x = ReadFloat(input); + float y = ReadFloat(input); + float scaleX = ReadFloat(input); + float scaleY = ReadFloat(input); + float width = ReadFloat(input); + float height = ReadFloat(input); + int color = ReadInt(input); + + if (path == null) path = name; + RegionAttachment region = attachmentLoader.NewRegionAttachment(skin, name, path); + if (region == null) return null; + region.Path = path; + region.x = x * scale; + region.y = y * scale; + region.scaleX = scaleX; + region.scaleY = scaleY; + region.rotation = rotation; + region.width = width * scale; + region.height = height * scale; + region.r = ((color & 0xff000000) >> 24) / 255f; + region.g = ((color & 0x00ff0000) >> 16) / 255f; + region.b = ((color & 0x0000ff00) >> 8) / 255f; + region.a = ((color & 0x000000ff)) / 255f; + region.UpdateOffset(); + return region; + } + case AttachmentType.Boundingbox: { + int vertexCount = ReadVarint(input, true); + Vertices vertices = ReadVertices(input, vertexCount); + if (nonessential) ReadInt(input); //int color = nonessential ? ReadInt(input) : 0; // Avoid unused local warning. + + BoundingBoxAttachment box = attachmentLoader.NewBoundingBoxAttachment(skin, name); + if (box == null) return null; + box.worldVerticesLength = vertexCount << 1; + box.vertices = vertices.vertices; + box.bones = vertices.bones; + return box; + } + case AttachmentType.Mesh: { + String path = ReadString(input); + int color = ReadInt(input); + int vertexCount = ReadVarint(input, true); + float[] uvs = ReadFloatArray(input, vertexCount << 1, 1); + int[] triangles = ReadShortArray(input); + Vertices vertices = ReadVertices(input, vertexCount); + int hullLength = ReadVarint(input, true); + int[] edges = null; + float width = 0, height = 0; + if (nonessential) { + edges = ReadShortArray(input); + width = ReadFloat(input); + height = ReadFloat(input); + } + + if (path == null) path = name; + MeshAttachment mesh = attachmentLoader.NewMeshAttachment(skin, name, path); + if (mesh == null) return null; + mesh.Path = path; + mesh.r = ((color & 0xff000000) >> 24) / 255f; + mesh.g = ((color & 0x00ff0000) >> 16) / 255f; + mesh.b = ((color & 0x0000ff00) >> 8) / 255f; + mesh.a = ((color & 0x000000ff)) / 255f; + mesh.bones = vertices.bones; + mesh.vertices = vertices.vertices; + mesh.WorldVerticesLength = vertexCount << 1; + mesh.triangles = triangles; + mesh.regionUVs = uvs; + mesh.UpdateUVs(); + mesh.HullLength = hullLength << 1; + if (nonessential) { + mesh.Edges = edges; + mesh.Width = width * scale; + mesh.Height = height * scale; + } + return mesh; + } + case AttachmentType.Linkedmesh: { + String path = ReadString(input); + int color = ReadInt(input); + String skinName = ReadString(input); + String parent = ReadString(input); + bool inheritDeform = ReadBoolean(input); + float width = 0, height = 0; + if (nonessential) { + width = ReadFloat(input); + height = ReadFloat(input); + } + + if (path == null) path = name; + MeshAttachment mesh = attachmentLoader.NewMeshAttachment(skin, name, path); + if (mesh == null) return null; + mesh.Path = path; + mesh.r = ((color & 0xff000000) >> 24) / 255f; + mesh.g = ((color & 0x00ff0000) >> 16) / 255f; + mesh.b = ((color & 0x0000ff00) >> 8) / 255f; + mesh.a = ((color & 0x000000ff)) / 255f; + mesh.inheritDeform = inheritDeform; + if (nonessential) { + mesh.Width = width * scale; + mesh.Height = height * scale; + } + linkedMeshes.Add(new SkeletonJson.LinkedMesh(mesh, skinName, slotIndex, parent)); + return mesh; + } + case AttachmentType.Path: { + bool closed = ReadBoolean(input); + bool constantSpeed = ReadBoolean(input); + int vertexCount = ReadVarint(input, true); + Vertices vertices = ReadVertices(input, vertexCount); + float[] lengths = new float[vertexCount / 3]; + for (int i = 0, n = lengths.Length; i < n; i++) + lengths[i] = ReadFloat(input) * scale; + if (nonessential) ReadInt(input); //int color = nonessential ? ReadInt(input) : 0; // Avoid unused local warning. + + PathAttachment path = attachmentLoader.NewPathAttachment(skin, name); + if (path == null) return null; + path.closed = closed; + path.constantSpeed = constantSpeed; + path.worldVerticesLength = vertexCount << 1; + path.vertices = vertices.vertices; + path.bones = vertices.bones; + path.lengths = lengths; + return path; + } + } + return null; + } + + private Vertices ReadVertices (Stream input, int vertexCount) { + float scale = Scale; + int verticesLength = vertexCount << 1; + Vertices vertices = new Vertices(); + if(!ReadBoolean(input)) { + vertices.vertices = ReadFloatArray(input, verticesLength, scale); + return vertices; + } + var weights = new ExposedList(verticesLength * 3 * 3); + var bonesArray = new ExposedList(verticesLength * 3); + for (int i = 0; i < vertexCount; i++) { + int boneCount = ReadVarint(input, true); + bonesArray.Add(boneCount); + for (int ii = 0; ii < boneCount; ii++) { + bonesArray.Add(ReadVarint(input, true)); + weights.Add(ReadFloat(input) * scale); + weights.Add(ReadFloat(input) * scale); + weights.Add(ReadFloat(input)); + } + } + + vertices.vertices = weights.ToArray(); + vertices.bones = bonesArray.ToArray(); + return vertices; + } + + private float[] ReadFloatArray (Stream input, int n, float scale) { + float[] array = new float[n]; + if (scale == 1) { + for (int i = 0; i < n; i++) + array[i] = ReadFloat(input); + } else { + for (int i = 0; i < n; i++) + array[i] = ReadFloat(input) * scale; + } + return array; + } + + private int[] ReadShortArray (Stream input) { + int n = ReadVarint(input, true); + int[] array = new int[n]; + for (int i = 0; i < n; i++) + array[i] = (input.ReadByte() << 8) | input.ReadByte(); + return array; + } + + private void ReadAnimation (String name, Stream input, SkeletonData skeletonData) { + var timelines = new ExposedList(); + float scale = Scale; + float duration = 0; + + // Slot timelines. + for (int i = 0, n = ReadVarint(input, true); i < n; i++) { + int slotIndex = ReadVarint(input, true); + for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++) { + int timelineType = input.ReadByte(); + int frameCount = ReadVarint(input, true); + switch (timelineType) { + case SLOT_COLOR: { + ColorTimeline timeline = new ColorTimeline(frameCount); + timeline.slotIndex = slotIndex; + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { + float time = ReadFloat(input); + int color = ReadInt(input); + float r = ((color & 0xff000000) >> 24) / 255f; + float g = ((color & 0x00ff0000) >> 16) / 255f; + float b = ((color & 0x0000ff00) >> 8) / 255f; + float a = ((color & 0x000000ff)) / 255f; + timeline.SetFrame(frameIndex, time, r, g, b, a); + if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline); + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * ColorTimeline.ENTRIES]); + break; + } + case SLOT_ATTACHMENT: { + AttachmentTimeline timeline = new AttachmentTimeline(frameCount); + timeline.slotIndex = slotIndex; + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) + timeline.SetFrame(frameIndex, ReadFloat(input), ReadString(input)); + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[frameCount - 1]); + break; + } + } + } + } + + // Bone timelines. + for (int i = 0, n = ReadVarint(input, true); i < n; i++) { + int boneIndex = ReadVarint(input, true); + for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++) { + int timelineType = input.ReadByte(); + int frameCount = ReadVarint(input, true); + switch (timelineType) { + case BONE_ROTATE: { + RotateTimeline timeline = new RotateTimeline(frameCount); + timeline.boneIndex = boneIndex; + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input)); + if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline); + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[(frameCount - 1) * RotateTimeline.ENTRIES]); + break; + } + case BONE_TRANSLATE: + case BONE_SCALE: + case BONE_SHEAR: { + TranslateTimeline timeline; + float timelineScale = 1; + if (timelineType == BONE_SCALE) + timeline = new ScaleTimeline(frameCount); + else if (timelineType == BONE_SHEAR) + timeline = new ShearTimeline(frameCount); + else { + timeline = new TranslateTimeline(frameCount); + timelineScale = scale; + } + timeline.boneIndex = boneIndex; + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input) * timelineScale, ReadFloat(input) + * timelineScale); + if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline); + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[(frameCount - 1) * TranslateTimeline.ENTRIES]); + break; + } + } + } + } + + // IK timelines. + for (int i = 0, n = ReadVarint(input, true); i < n; i++) { + int index = ReadVarint(input, true); + int frameCount = ReadVarint(input, true); + IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount); + timeline.ikConstraintIndex = index; + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input), ReadSByte(input)); + if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline); + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[(frameCount - 1) * IkConstraintTimeline.ENTRIES]); + } + + // Transform constraint timelines. + for (int i = 0, n = ReadVarint(input, true); i < n; i++) { + int index = ReadVarint(input, true); + int frameCount = ReadVarint(input, true); + TransformConstraintTimeline timeline = new TransformConstraintTimeline(frameCount); + timeline.transformConstraintIndex = index; + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input), ReadFloat(input), ReadFloat(input), ReadFloat(input)); + if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline); + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[(frameCount - 1) * TransformConstraintTimeline.ENTRIES]); + } + + // Path constraint timelines. + for (int i = 0, n = ReadVarint(input, true); i < n; i++) { + int index = ReadVarint(input, true); + PathConstraintData data = skeletonData.pathConstraints.Items[index]; + for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++) { + int timelineType = ReadSByte(input); + int frameCount = ReadVarint(input, true); + switch(timelineType) { + case PATH_POSITION: + case PATH_SPACING: { + PathConstraintPositionTimeline timeline; + float timelineScale = 1; + if (timelineType == PATH_SPACING) { + timeline = new PathConstraintSpacingTimeline(frameCount); + if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed) timelineScale = scale; + } else { + timeline = new PathConstraintPositionTimeline(frameCount); + if (data.positionMode == PositionMode.Fixed) timelineScale = scale; + } + timeline.pathConstraintIndex = index; + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input) * timelineScale); + if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline); + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[(frameCount - 1) * PathConstraintPositionTimeline.ENTRIES]); + break; + } + case PATH_MIX: { + PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(frameCount); + timeline.pathConstraintIndex = index; + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input), ReadFloat(input)); + if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline); + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[(frameCount - 1) * PathConstraintMixTimeline.ENTRIES]); + break; + } + } + } + } + + // Deform timelines. + for (int i = 0, n = ReadVarint(input, true); i < n; i++) { + Skin skin = skeletonData.skins.Items[ReadVarint(input, true)]; + for (int ii = 0, nn = ReadVarint(input, true); ii < nn; ii++) { + int slotIndex = ReadVarint(input, true); + for (int iii = 0, nnn = ReadVarint(input, true); iii < nnn; iii++) { + VertexAttachment attachment = (VertexAttachment)skin.GetAttachment(slotIndex, ReadString(input)); + bool weighted = attachment.bones != null; + float[] vertices = attachment.vertices; + int deformLength = weighted ? vertices.Length / 3 * 2 : vertices.Length; + + int frameCount = ReadVarint(input, true); + DeformTimeline timeline = new DeformTimeline(frameCount); + timeline.slotIndex = slotIndex; + timeline.attachment = attachment; + + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { + float time = ReadFloat(input); + float[] deform; + int end = ReadVarint(input, true); + if (end == 0) + deform = weighted ? new float[deformLength] : vertices; + else { + deform = new float[deformLength]; + int start = ReadVarint(input, true); + end += start; + if (scale == 1) { + for (int v = start; v < end; v++) + deform[v] = ReadFloat(input); + } else { + for (int v = start; v < end; v++) + deform[v] = ReadFloat(input) * scale; + } + if (!weighted) { + for (int v = 0, vn = deform.Length; v < vn; v++) + deform[v] += vertices[v]; + } + } + + timeline.SetFrame(frameIndex, time, deform); + if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline); + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[frameCount - 1]); + } + } + } + + // Draw order timeline. + int drawOrderCount = ReadVarint(input, true); + if (drawOrderCount > 0) { + DrawOrderTimeline timeline = new DrawOrderTimeline(drawOrderCount); + int slotCount = skeletonData.slots.Count; + for (int i = 0; i < drawOrderCount; i++) { + float time = ReadFloat(input); + int offsetCount = ReadVarint(input, true); + int[] drawOrder = new int[slotCount]; + for (int ii = slotCount - 1; ii >= 0; ii--) + drawOrder[ii] = -1; + int[] unchanged = new int[slotCount - offsetCount]; + int originalIndex = 0, unchangedIndex = 0; + for (int ii = 0; ii < offsetCount; ii++) { + int slotIndex = ReadVarint(input, true); + // Collect unchanged items. + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + // Set changed items. + drawOrder[originalIndex + ReadVarint(input, true)] = originalIndex++; + } + // Collect remaining unchanged items. + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + // Fill in unchanged items. + for (int ii = slotCount - 1; ii >= 0; ii--) + if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex]; + timeline.SetFrame(i, time, drawOrder); + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[drawOrderCount - 1]); + } + + // Event timeline. + int eventCount = ReadVarint(input, true); + if (eventCount > 0) { + EventTimeline timeline = new EventTimeline(eventCount); + for (int i = 0; i < eventCount; i++) { + float time = ReadFloat(input); + EventData eventData = skeletonData.events.Items[ReadVarint(input, true)]; + Event e = new Event(time, eventData); + e.Int = ReadVarint(input, false); + e.Float = ReadFloat(input); + e.String = ReadBoolean(input) ? ReadString(input) : eventData.String; + timeline.SetFrame(i, e); + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[eventCount - 1]); + } + + timelines.TrimExcess(); + skeletonData.animations.Add(new Animation(name, timelines, duration)); + } + + private void ReadCurve (Stream input, int frameIndex, CurveTimeline timeline) { + switch (input.ReadByte()) { + case CURVE_STEPPED: + timeline.SetStepped(frameIndex); + break; + case CURVE_BEZIER: + timeline.SetCurve(frameIndex, ReadFloat(input), ReadFloat(input), ReadFloat(input), ReadFloat(input)); + break; + } + } + + private static sbyte ReadSByte (Stream input) { + int value = input.ReadByte(); + if (value == -1) throw new EndOfStreamException(); + return (sbyte)value; + } + + private static bool ReadBoolean (Stream input) { + return input.ReadByte() != 0; + } + + private float ReadFloat (Stream input) { + buffer[3] = (byte)input.ReadByte(); + buffer[2] = (byte)input.ReadByte(); + buffer[1] = (byte)input.ReadByte(); + buffer[0] = (byte)input.ReadByte(); + return BitConverter.ToSingle(buffer, 0); + } + + private static int ReadInt (Stream input) { + return (input.ReadByte() << 24) + (input.ReadByte() << 16) + (input.ReadByte() << 8) + input.ReadByte(); + } + + private static int ReadVarint (Stream input, bool optimizePositive) { + int b = input.ReadByte(); + int result = b & 0x7F; + if ((b & 0x80) != 0) { + b = input.ReadByte(); + result |= (b & 0x7F) << 7; + if ((b & 0x80) != 0) { + b = input.ReadByte(); + result |= (b & 0x7F) << 14; + if ((b & 0x80) != 0) { + b = input.ReadByte(); + result |= (b & 0x7F) << 21; + if ((b & 0x80) != 0) result |= (input.ReadByte() & 0x7F) << 28; + } + } + } + return optimizePositive ? result : ((result >> 1) ^ -(result & 1)); + } + + private string ReadString (Stream input) { + int byteCount = ReadVarint(input, true); + switch (byteCount) { + case 0: + return null; + case 1: + return ""; + } + byteCount--; + byte[] buffer = this.buffer; + if (buffer.Length < byteCount) buffer = new byte[byteCount]; + ReadFully(input, buffer, 0, byteCount); + return System.Text.Encoding.UTF8.GetString(buffer, 0, byteCount); + } + + private static void ReadFully (Stream input, byte[] buffer, int offset, int length) { + while (length > 0) { + int count = input.Read(buffer, offset, length); + if (count <= 0) throw new EndOfStreamException(); + offset += count; + length -= count; + } + } + + internal class Vertices { + public int[] bones; + public float[] vertices; + } + } } diff --git a/spine-csharp/src/SkeletonBounds.cs b/spine-csharp/src/SkeletonBounds.cs index e694e596e9..6c2d5b1ac5 100644 --- a/spine-csharp/src/SkeletonBounds.cs +++ b/spine-csharp/src/SkeletonBounds.cs @@ -1,215 +1,214 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - public class SkeletonBounds { - private ExposedList polygonPool = new ExposedList(); - private float minX, minY, maxX, maxY; - - public ExposedList BoundingBoxes { get; private set; } - public ExposedList Polygons { get; private set; } - public float MinX { get { return minX; } set { minX = value; } } - public float MinY { get { return minY; } set { minY = value; } } - public float MaxX { get { return maxX; } set { maxX = value; } } - public float MaxY { get { return maxY; } set { maxY = value; } } - public float Width { get { return maxX - minX; } } - public float Height { get { return maxY - minY; } } - - public SkeletonBounds () { - BoundingBoxes = new ExposedList(); - Polygons = new ExposedList(); - } - - public void Update (Skeleton skeleton, bool updateAabb) { - ExposedList boundingBoxes = BoundingBoxes; - ExposedList polygons = Polygons; - ExposedList slots = skeleton.slots; - int slotCount = slots.Count; - - boundingBoxes.Clear(); - for (int i = 0, n = polygons.Count; i < n; i++) - polygonPool.Add(polygons.Items[i]); - polygons.Clear(); - - for (int i = 0; i < slotCount; i++) { - Slot slot = slots.Items[i]; - BoundingBoxAttachment boundingBox = slot.attachment as BoundingBoxAttachment; - if (boundingBox == null) continue; - boundingBoxes.Add(boundingBox); - - Polygon polygon = null; - int poolCount = polygonPool.Count; - if (poolCount > 0) { - polygon = polygonPool.Items[poolCount - 1]; - polygonPool.RemoveAt(poolCount - 1); - } else - polygon = new Polygon(); - polygons.Add(polygon); - - int count = boundingBox.Vertices.Length; - polygon.Count = count; - if (polygon.Vertices.Length < count) polygon.Vertices = new float[count]; - boundingBox.ComputeWorldVertices(slot, polygon.Vertices); - } - - if (updateAabb) aabbCompute(); - } - - private void aabbCompute () { - float minX = int.MaxValue, minY = int.MaxValue, maxX = int.MinValue, maxY = int.MinValue; - ExposedList polygons = Polygons; - for (int i = 0, n = polygons.Count; i < n; i++) { - Polygon polygon = polygons.Items[i]; - float[] vertices = polygon.Vertices; - for (int ii = 0, nn = polygon.Count; ii < nn; ii += 2) { - float x = vertices[ii]; - float y = vertices[ii + 1]; - minX = Math.Min(minX, x); - minY = Math.Min(minY, y); - maxX = Math.Max(maxX, x); - maxY = Math.Max(maxY, y); - } - } - this.minX = minX; - this.minY = minY; - this.maxX = maxX; - this.maxY = maxY; - } - - - /// Returns true if the axis aligned bounding box contains the point. - public bool AabbContainsPoint (float x, float y) { - return x >= minX && x <= maxX && y >= minY && y <= maxY; - } - - /// Returns true if the axis aligned bounding box intersects the line segment. - public bool AabbIntersectsSegment (float x1, float y1, float x2, float y2) { - float minX = this.minX; - float minY = this.minY; - float maxX = this.maxX; - float maxY = this.maxY; - if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) - return false; - float m = (y2 - y1) / (x2 - x1); - float y = m * (minX - x1) + y1; - if (y > minY && y < maxY) return true; - y = m * (maxX - x1) + y1; - if (y > minY && y < maxY) return true; - float x = (minY - y1) / m + x1; - if (x > minX && x < maxX) return true; - x = (maxY - y1) / m + x1; - if (x > minX && x < maxX) return true; - return false; - } - - /// Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. - public bool AabbIntersectsSkeleton (SkeletonBounds bounds) { - return minX < bounds.maxX && maxX > bounds.minX && minY < bounds.maxY && maxY > bounds.minY; - } - - /// Returns true if the polygon contains the point. - public bool ContainsPoint (Polygon polygon, float x, float y) { - float[] vertices = polygon.Vertices; - int nn = polygon.Count; - - int prevIndex = nn - 2; - bool inside = false; - for (int ii = 0; ii < nn; ii += 2) { - float vertexY = vertices[ii + 1]; - float prevY = vertices[prevIndex + 1]; - if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { - float vertexX = vertices[ii]; - if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside; - } - prevIndex = ii; - } - return inside; - } - - /// Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more - /// efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. - public BoundingBoxAttachment ContainsPoint (float x, float y) { - ExposedList polygons = Polygons; - for (int i = 0, n = polygons.Count; i < n; i++) - if (ContainsPoint(polygons.Items[i], x, y)) return BoundingBoxes.Items[i]; - return null; - } - - /// Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually - /// more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns true. - public BoundingBoxAttachment IntersectsSegment (float x1, float y1, float x2, float y2) { - ExposedList polygons = Polygons; - for (int i = 0, n = polygons.Count; i < n; i++) - if (IntersectsSegment(polygons.Items[i], x1, y1, x2, y2)) return BoundingBoxes.Items[i]; - return null; - } - - /// Returns true if the polygon contains the line segment. - public bool IntersectsSegment (Polygon polygon, float x1, float y1, float x2, float y2) { - float[] vertices = polygon.Vertices; - int nn = polygon.Count; - - float width12 = x1 - x2, height12 = y1 - y2; - float det1 = x1 * y2 - y1 * x2; - float x3 = vertices[nn - 2], y3 = vertices[nn - 1]; - for (int ii = 0; ii < nn; ii += 2) { - float x4 = vertices[ii], y4 = vertices[ii + 1]; - float det2 = x3 * y4 - y3 * x4; - float width34 = x3 - x4, height34 = y3 - y4; - float det3 = width12 * height34 - height12 * width34; - float x = (det1 * width34 - width12 * det2) / det3; - if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { - float y = (det1 * height34 - height12 * det2) / det3; - if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; - } - x3 = x4; - y3 = y4; - } - return false; - } - - public Polygon getPolygon (BoundingBoxAttachment attachment) { - int index = BoundingBoxes.IndexOf(attachment); - return index == -1 ? null : Polygons.Items[index]; - } - } - - public class Polygon { - public float[] Vertices { get; set; } - public int Count { get; set; } - - public Polygon () { - Vertices = new float[16]; - } - } +using System; + +namespace Spine { + public class SkeletonBounds { + private ExposedList polygonPool = new ExposedList(); + private float minX, minY, maxX, maxY; + + public ExposedList BoundingBoxes { get; private set; } + public ExposedList Polygons { get; private set; } + public float MinX { get { return minX; } set { minX = value; } } + public float MinY { get { return minY; } set { minY = value; } } + public float MaxX { get { return maxX; } set { maxX = value; } } + public float MaxY { get { return maxY; } set { maxY = value; } } + public float Width { get { return maxX - minX; } } + public float Height { get { return maxY - minY; } } + + public SkeletonBounds () { + BoundingBoxes = new ExposedList(); + Polygons = new ExposedList(); + } + + public void Update (Skeleton skeleton, bool updateAabb) { + ExposedList boundingBoxes = BoundingBoxes; + ExposedList polygons = Polygons; + ExposedList slots = skeleton.slots; + int slotCount = slots.Count; + + boundingBoxes.Clear(); + for (int i = 0, n = polygons.Count; i < n; i++) + polygonPool.Add(polygons.Items[i]); + polygons.Clear(); + + for (int i = 0; i < slotCount; i++) { + Slot slot = slots.Items[i]; + BoundingBoxAttachment boundingBox = slot.attachment as BoundingBoxAttachment; + if (boundingBox == null) continue; + boundingBoxes.Add(boundingBox); + + Polygon polygon = null; + int poolCount = polygonPool.Count; + if (poolCount > 0) { + polygon = polygonPool.Items[poolCount - 1]; + polygonPool.RemoveAt(poolCount - 1); + } else + polygon = new Polygon(); + polygons.Add(polygon); + + int count = boundingBox.Vertices.Length; + polygon.Count = count; + if (polygon.Vertices.Length < count) polygon.Vertices = new float[count]; + boundingBox.ComputeWorldVertices(slot, polygon.Vertices); + } + + if (updateAabb) aabbCompute(); + } + + private void aabbCompute () { + float minX = int.MaxValue, minY = int.MaxValue, maxX = int.MinValue, maxY = int.MinValue; + ExposedList polygons = Polygons; + for (int i = 0, n = polygons.Count; i < n; i++) { + Polygon polygon = polygons.Items[i]; + float[] vertices = polygon.Vertices; + for (int ii = 0, nn = polygon.Count; ii < nn; ii += 2) { + float x = vertices[ii]; + float y = vertices[ii + 1]; + minX = Math.Min(minX, x); + minY = Math.Min(minY, y); + maxX = Math.Max(maxX, x); + maxY = Math.Max(maxY, y); + } + } + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } + + + /// Returns true if the axis aligned bounding box contains the point. + public bool AabbContainsPoint (float x, float y) { + return x >= minX && x <= maxX && y >= minY && y <= maxY; + } + + /// Returns true if the axis aligned bounding box intersects the line segment. + public bool AabbIntersectsSegment (float x1, float y1, float x2, float y2) { + float minX = this.minX; + float minY = this.minY; + float maxX = this.maxX; + float maxY = this.maxY; + if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) + return false; + float m = (y2 - y1) / (x2 - x1); + float y = m * (minX - x1) + y1; + if (y > minY && y < maxY) return true; + y = m * (maxX - x1) + y1; + if (y > minY && y < maxY) return true; + float x = (minY - y1) / m + x1; + if (x > minX && x < maxX) return true; + x = (maxY - y1) / m + x1; + if (x > minX && x < maxX) return true; + return false; + } + + /// Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. + public bool AabbIntersectsSkeleton (SkeletonBounds bounds) { + return minX < bounds.maxX && maxX > bounds.minX && minY < bounds.maxY && maxY > bounds.minY; + } + + /// Returns true if the polygon contains the point. + public bool ContainsPoint (Polygon polygon, float x, float y) { + float[] vertices = polygon.Vertices; + int nn = polygon.Count; + + int prevIndex = nn - 2; + bool inside = false; + for (int ii = 0; ii < nn; ii += 2) { + float vertexY = vertices[ii + 1]; + float prevY = vertices[prevIndex + 1]; + if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { + float vertexX = vertices[ii]; + if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside; + } + prevIndex = ii; + } + return inside; + } + + /// Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more + /// efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. + public BoundingBoxAttachment ContainsPoint (float x, float y) { + ExposedList polygons = Polygons; + for (int i = 0, n = polygons.Count; i < n; i++) + if (ContainsPoint(polygons.Items[i], x, y)) return BoundingBoxes.Items[i]; + return null; + } + + /// Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually + /// more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns true. + public BoundingBoxAttachment IntersectsSegment (float x1, float y1, float x2, float y2) { + ExposedList polygons = Polygons; + for (int i = 0, n = polygons.Count; i < n; i++) + if (IntersectsSegment(polygons.Items[i], x1, y1, x2, y2)) return BoundingBoxes.Items[i]; + return null; + } + + /// Returns true if the polygon contains the line segment. + public bool IntersectsSegment (Polygon polygon, float x1, float y1, float x2, float y2) { + float[] vertices = polygon.Vertices; + int nn = polygon.Count; + + float width12 = x1 - x2, height12 = y1 - y2; + float det1 = x1 * y2 - y1 * x2; + float x3 = vertices[nn - 2], y3 = vertices[nn - 1]; + for (int ii = 0; ii < nn; ii += 2) { + float x4 = vertices[ii], y4 = vertices[ii + 1]; + float det2 = x3 * y4 - y3 * x4; + float width34 = x3 - x4, height34 = y3 - y4; + float det3 = width12 * height34 - height12 * width34; + float x = (det1 * width34 - width12 * det2) / det3; + if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { + float y = (det1 * height34 - height12 * det2) / det3; + if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; + } + x3 = x4; + y3 = y4; + } + return false; + } + + public Polygon getPolygon (BoundingBoxAttachment attachment) { + int index = BoundingBoxes.IndexOf(attachment); + return index == -1 ? null : Polygons.Items[index]; + } + } + + public class Polygon { + public float[] Vertices { get; set; } + public int Count { get; set; } + + public Polygon () { + Vertices = new float[16]; + } + } } diff --git a/spine-csharp/src/SkeletonData.cs b/spine-csharp/src/SkeletonData.cs index dd3dcdbaba..d753916358 100644 --- a/spine-csharp/src/SkeletonData.cs +++ b/spine-csharp/src/SkeletonData.cs @@ -1,197 +1,196 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - public class SkeletonData { - internal String name; - internal ExposedList bones = new ExposedList(); - internal ExposedList slots = new ExposedList(); - internal ExposedList skins = new ExposedList(); - internal Skin defaultSkin; - internal ExposedList events = new ExposedList(); - internal ExposedList animations = new ExposedList(); - internal ExposedList ikConstraints = new ExposedList(); - internal ExposedList transformConstraints = new ExposedList(); - internal ExposedList pathConstraints = new ExposedList(); - internal float width, height; - internal String version, hash, imagesPath; - - public String Name { get { return name; } set { name = value; } } - public ExposedList Bones { get { return bones; } } // Ordered parents first. - public ExposedList Slots { get { return slots; } } // Setup pose draw order. - public ExposedList Skins { get { return skins; } set { skins = value; } } - /// May be null. - public Skin DefaultSkin { get { return defaultSkin; } set { defaultSkin = value; } } - public ExposedList Events { get { return events; } set { events = value; } } - public ExposedList Animations { get { return animations; } set { animations = value; } } - public ExposedList IkConstraints { get { return ikConstraints; } set { ikConstraints = value; } } - public ExposedList TransformConstraints { get { return transformConstraints; } set { transformConstraints = value; } } - public ExposedList PathConstraints { get { return pathConstraints; } set { pathConstraints = value; } } - public float Width { get { return width; } set { width = value; } } - public float Height { get { return height; } set { height = value; } } - /// The Spine version used to export this data. - public String Version { get { return version; } set { version = value; } } - public String Hash { get { return hash; } set { hash = value; } } - - // --- Bones. - - /// May be null. - public BoneData FindBone (String boneName) { - if (boneName == null) throw new ArgumentNullException("boneName", "boneName cannot be null."); - ExposedList bones = this.bones; - for (int i = 0, n = bones.Count; i < n; i++) { - BoneData bone = bones.Items[i]; - if (bone.name == boneName) return bone; - } - return null; - } - - /// -1 if the bone was not found. - public int FindBoneIndex (String boneName) { - if (boneName == null) throw new ArgumentNullException("boneName", "boneName cannot be null."); - ExposedList bones = this.bones; - for (int i = 0, n = bones.Count; i < n; i++) - if (bones.Items[i].name == boneName) return i; - return -1; - } - - // --- Slots. - - /// May be null. - public SlotData FindSlot (String slotName) { - if (slotName == null) throw new ArgumentNullException("slotName", "slotName cannot be null."); - ExposedList slots = this.slots; - for (int i = 0, n = slots.Count; i < n; i++) { - SlotData slot = slots.Items[i]; - if (slot.name == slotName) return slot; - } - return null; - } - - /// -1 if the slot was not found. - public int FindSlotIndex (String slotName) { - if (slotName == null) throw new ArgumentNullException("slotName", "slotName cannot be null."); - ExposedList slots = this.slots; - for (int i = 0, n = slots.Count; i < n; i++) - if (slots.Items[i].name == slotName) return i; - return -1; - } - - // --- Skins. - - /// May be null. - public Skin FindSkin (String skinName) { - if (skinName == null) throw new ArgumentNullException("skinName", "skinName cannot be null."); - foreach (Skin skin in skins) - if (skin.name == skinName) return skin; - return null; - } - - // --- Events. - - /// May be null. - public EventData FindEvent (String eventDataName) { - if (eventDataName == null) throw new ArgumentNullException("eventDataName", "eventDataName cannot be null."); - foreach (EventData eventData in events) - if (eventData.name == eventDataName) return eventData; - return null; - } - - // --- Animations. - - /// May be null. - public Animation FindAnimation (String animationName) { - if (animationName == null) throw new ArgumentNullException("animationName", "animationName cannot be null."); - ExposedList animations = this.animations; - for (int i = 0, n = animations.Count; i < n; i++) { - Animation animation = animations.Items[i]; - if (animation.name == animationName) return animation; - } - return null; - } - - // --- IK constraints. - - /// May be null. - public IkConstraintData FindIkConstraint (String constraintName) { - if (constraintName == null) throw new ArgumentNullException("constraintName", "constraintName cannot be null."); - ExposedList ikConstraints = this.ikConstraints; - for (int i = 0, n = ikConstraints.Count; i < n; i++) { - IkConstraintData ikConstraint = ikConstraints.Items[i]; - if (ikConstraint.name == constraintName) return ikConstraint; - } - return null; - } - - // --- Transform constraints. - - /// May be null. - public TransformConstraintData FindTransformConstraint (String constraintName) { - if (constraintName == null) throw new ArgumentNullException("constraintName", "constraintName cannot be null."); - ExposedList transformConstraints = this.transformConstraints; - for (int i = 0, n = transformConstraints.Count; i < n; i++) { - TransformConstraintData transformConstraint = transformConstraints.Items[i]; - if (transformConstraint.name == constraintName) return transformConstraint; - } - return null; - } - - // --- Path constraints. - - /// May be null. - public PathConstraintData FindPathConstraint (String constraintName) { - if (constraintName == null) throw new ArgumentNullException("constraintName", "constraintName cannot be null."); - ExposedList pathConstraints = this.pathConstraints; - for (int i = 0, n = pathConstraints.Count; i < n; i++) { - PathConstraintData constraint = pathConstraints.Items[i]; - if (constraint.name.Equals(constraintName)) return constraint; - } - return null; - } - - /// -1 if the path constraint was not found. - public int FindPathConstraintIndex (String pathConstraintName) { - if (pathConstraintName == null) throw new ArgumentNullException("pathConstraintName", "pathConstraintName cannot be null."); - ExposedList pathConstraints = this.pathConstraints; - for (int i = 0, n = pathConstraints.Count; i < n; i++) - if (pathConstraints.Items[i].name.Equals(pathConstraintName)) return i; - return -1; - } - - // --- - - override public String ToString () { - return name ?? base.ToString(); - } - } +using System; + +namespace Spine { + public class SkeletonData { + internal String name; + internal ExposedList bones = new ExposedList(); + internal ExposedList slots = new ExposedList(); + internal ExposedList skins = new ExposedList(); + internal Skin defaultSkin; + internal ExposedList events = new ExposedList(); + internal ExposedList animations = new ExposedList(); + internal ExposedList ikConstraints = new ExposedList(); + internal ExposedList transformConstraints = new ExposedList(); + internal ExposedList pathConstraints = new ExposedList(); + internal float width, height; + internal String version, hash, imagesPath; + + public String Name { get { return name; } set { name = value; } } + public ExposedList Bones { get { return bones; } } // Ordered parents first. + public ExposedList Slots { get { return slots; } } // Setup pose draw order. + public ExposedList Skins { get { return skins; } set { skins = value; } } + /// May be null. + public Skin DefaultSkin { get { return defaultSkin; } set { defaultSkin = value; } } + public ExposedList Events { get { return events; } set { events = value; } } + public ExposedList Animations { get { return animations; } set { animations = value; } } + public ExposedList IkConstraints { get { return ikConstraints; } set { ikConstraints = value; } } + public ExposedList TransformConstraints { get { return transformConstraints; } set { transformConstraints = value; } } + public ExposedList PathConstraints { get { return pathConstraints; } set { pathConstraints = value; } } + public float Width { get { return width; } set { width = value; } } + public float Height { get { return height; } set { height = value; } } + /// The Spine version used to export this data. + public String Version { get { return version; } set { version = value; } } + public String Hash { get { return hash; } set { hash = value; } } + + // --- Bones. + + /// May be null. + public BoneData FindBone (String boneName) { + if (boneName == null) throw new ArgumentNullException("boneName", "boneName cannot be null."); + ExposedList bones = this.bones; + for (int i = 0, n = bones.Count; i < n; i++) { + BoneData bone = bones.Items[i]; + if (bone.name == boneName) return bone; + } + return null; + } + + /// -1 if the bone was not found. + public int FindBoneIndex (String boneName) { + if (boneName == null) throw new ArgumentNullException("boneName", "boneName cannot be null."); + ExposedList bones = this.bones; + for (int i = 0, n = bones.Count; i < n; i++) + if (bones.Items[i].name == boneName) return i; + return -1; + } + + // --- Slots. + + /// May be null. + public SlotData FindSlot (String slotName) { + if (slotName == null) throw new ArgumentNullException("slotName", "slotName cannot be null."); + ExposedList slots = this.slots; + for (int i = 0, n = slots.Count; i < n; i++) { + SlotData slot = slots.Items[i]; + if (slot.name == slotName) return slot; + } + return null; + } + + /// -1 if the slot was not found. + public int FindSlotIndex (String slotName) { + if (slotName == null) throw new ArgumentNullException("slotName", "slotName cannot be null."); + ExposedList slots = this.slots; + for (int i = 0, n = slots.Count; i < n; i++) + if (slots.Items[i].name == slotName) return i; + return -1; + } + + // --- Skins. + + /// May be null. + public Skin FindSkin (String skinName) { + if (skinName == null) throw new ArgumentNullException("skinName", "skinName cannot be null."); + foreach (Skin skin in skins) + if (skin.name == skinName) return skin; + return null; + } + + // --- Events. + + /// May be null. + public EventData FindEvent (String eventDataName) { + if (eventDataName == null) throw new ArgumentNullException("eventDataName", "eventDataName cannot be null."); + foreach (EventData eventData in events) + if (eventData.name == eventDataName) return eventData; + return null; + } + + // --- Animations. + + /// May be null. + public Animation FindAnimation (String animationName) { + if (animationName == null) throw new ArgumentNullException("animationName", "animationName cannot be null."); + ExposedList animations = this.animations; + for (int i = 0, n = animations.Count; i < n; i++) { + Animation animation = animations.Items[i]; + if (animation.name == animationName) return animation; + } + return null; + } + + // --- IK constraints. + + /// May be null. + public IkConstraintData FindIkConstraint (String constraintName) { + if (constraintName == null) throw new ArgumentNullException("constraintName", "constraintName cannot be null."); + ExposedList ikConstraints = this.ikConstraints; + for (int i = 0, n = ikConstraints.Count; i < n; i++) { + IkConstraintData ikConstraint = ikConstraints.Items[i]; + if (ikConstraint.name == constraintName) return ikConstraint; + } + return null; + } + + // --- Transform constraints. + + /// May be null. + public TransformConstraintData FindTransformConstraint (String constraintName) { + if (constraintName == null) throw new ArgumentNullException("constraintName", "constraintName cannot be null."); + ExposedList transformConstraints = this.transformConstraints; + for (int i = 0, n = transformConstraints.Count; i < n; i++) { + TransformConstraintData transformConstraint = transformConstraints.Items[i]; + if (transformConstraint.name == constraintName) return transformConstraint; + } + return null; + } + + // --- Path constraints. + + /// May be null. + public PathConstraintData FindPathConstraint (String constraintName) { + if (constraintName == null) throw new ArgumentNullException("constraintName", "constraintName cannot be null."); + ExposedList pathConstraints = this.pathConstraints; + for (int i = 0, n = pathConstraints.Count; i < n; i++) { + PathConstraintData constraint = pathConstraints.Items[i]; + if (constraint.name.Equals(constraintName)) return constraint; + } + return null; + } + + /// -1 if the path constraint was not found. + public int FindPathConstraintIndex (String pathConstraintName) { + if (pathConstraintName == null) throw new ArgumentNullException("pathConstraintName", "pathConstraintName cannot be null."); + ExposedList pathConstraints = this.pathConstraints; + for (int i = 0, n = pathConstraints.Count; i < n; i++) + if (pathConstraints.Items[i].name.Equals(pathConstraintName)) return i; + return -1; + } + + // --- + + override public String ToString () { + return name ?? base.ToString(); + } + } } diff --git a/spine-csharp/src/SkeletonJson.cs b/spine-csharp/src/SkeletonJson.cs index bcecaeb85a..7858b91feb 100644 --- a/spine-csharp/src/SkeletonJson.cs +++ b/spine-csharp/src/SkeletonJson.cs @@ -1,806 +1,805 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#if (UNITY_5 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_WSA || UNITY_WP8 || UNITY_WP8_1) -#define IS_UNITY -#endif - -using System; -using System.IO; -using System.Collections.Generic; - -#if WINDOWS_STOREAPP -using System.Threading.Tasks; -using Windows.Storage; -#endif - -namespace Spine { - public class SkeletonJson { - public float Scale { get; set; } - - private AttachmentLoader attachmentLoader; - private List linkedMeshes = new List(); - - public SkeletonJson (params Atlas[] atlasArray) - : this(new AtlasAttachmentLoader(atlasArray)) { - } - - public SkeletonJson (AttachmentLoader attachmentLoader) { - if (attachmentLoader == null) throw new ArgumentNullException("attachmentLoader", "attachmentLoader cannot be null."); - this.attachmentLoader = attachmentLoader; - Scale = 1; - } - - #if !(IS_UNITY) && WINDOWS_STOREAPP - private async Task ReadFile(string path) { - var folder = Windows.ApplicationModel.Package.Current.InstalledLocation; - var file = await folder.GetFileAsync(path).AsTask().ConfigureAwait(false); - using (var reader = new StreamReader(await file.OpenStreamForReadAsync().ConfigureAwait(false))) { - SkeletonData skeletonData = ReadSkeletonData(reader); - skeletonData.Name = Path.GetFileNameWithoutExtension(path); - return skeletonData; - } - } - - public SkeletonData ReadSkeletonData (String path) { - return this.ReadFile(path).Result; - } - #else - public SkeletonData ReadSkeletonData (String path) { - #if WINDOWS_PHONE - Stream stream = Microsoft.Xna.Framework.TitleContainer.OpenStream(path); - using (StreamReader reader = new StreamReader(stream)) { - #else - using (var reader = new StreamReader(path)) { - #endif // WINDOWS_PHONE - SkeletonData skeletonData = ReadSkeletonData(reader); - skeletonData.name = Path.GetFileNameWithoutExtension(path); - return skeletonData; - } - } - #endif // WINDOWS_STOREAPP - - public SkeletonData ReadSkeletonData (TextReader reader) { - if (reader == null) throw new ArgumentNullException("reader", "reader cannot be null."); - - var scale = this.Scale; - var skeletonData = new SkeletonData(); - - var root = Json.Deserialize(reader) as Dictionary; - if (root == null) throw new Exception("Invalid JSON."); - - // Skeleton. - if (root.ContainsKey("skeleton")) { - var skeletonMap = (Dictionary)root["skeleton"]; - skeletonData.hash = (String)skeletonMap["hash"]; - skeletonData.version = (String)skeletonMap["spine"]; - skeletonData.width = GetFloat(skeletonMap, "width", 0); - skeletonData.height = GetFloat(skeletonMap, "height", 0); - } - - // Bones. - foreach (Dictionary boneMap in (List)root["bones"]) { - BoneData parent = null; - if (boneMap.ContainsKey("parent")) { - parent = skeletonData.FindBone((String)boneMap["parent"]); - if (parent == null) - throw new Exception("Parent bone not found: " + boneMap["parent"]); - } - var data = new BoneData(skeletonData.Bones.Count, (String)boneMap["name"], parent); - data.length = GetFloat(boneMap, "length", 0) * scale; - data.x = GetFloat(boneMap, "x", 0) * scale; - data.y = GetFloat(boneMap, "y", 0) * scale; - data.rotation = GetFloat(boneMap, "rotation", 0); - data.scaleX = GetFloat(boneMap, "scaleX", 1); - data.scaleY = GetFloat(boneMap, "scaleY", 1); - data.shearX = GetFloat(boneMap, "shearX", 0); - data.shearY = GetFloat(boneMap, "shearY", 0); - data.inheritRotation = GetBoolean(boneMap, "inheritRotation", true); - data.inheritScale = GetBoolean(boneMap, "inheritScale", true); - - skeletonData.bones.Add(data); - } - - // Slots. - if (root.ContainsKey("slots")) { - foreach (Dictionary slotMap in (List)root["slots"]) { - var slotName = (String)slotMap["name"]; - var boneName = (String)slotMap["bone"]; - BoneData boneData = skeletonData.FindBone(boneName); - if (boneData == null) throw new Exception("Slot bone not found: " + boneName); - var data = new SlotData(skeletonData.Slots.Count, slotName, boneData); - - if (slotMap.ContainsKey("color")) { - var color = (String)slotMap["color"]; - data.r = ToColor(color, 0); - data.g = ToColor(color, 1); - data.b = ToColor(color, 2); - data.a = ToColor(color, 3); - } - - data.attachmentName = GetString(slotMap, "attachment", null); - if (slotMap.ContainsKey("blend")) - data.blendMode = (BlendMode)Enum.Parse(typeof(BlendMode), (String)slotMap["blend"], false); - else - data.blendMode = BlendMode.normal; - skeletonData.slots.Add(data); - } - } - - // IK constraints. - if (root.ContainsKey("ik")) { - foreach (Dictionary constraintMap in (List)root["ik"]) { - IkConstraintData data = new IkConstraintData((String)constraintMap["name"]); - - foreach (String boneName in (List)constraintMap["bones"]) { - BoneData bone = skeletonData.FindBone(boneName); - if (bone == null) throw new Exception("IK constraint bone not found: " + boneName); - data.bones.Add(bone); - } - - String targetName = (String)constraintMap["target"]; - data.target = skeletonData.FindBone(targetName); - if (data.target == null) throw new Exception("Target bone not found: " + targetName); - - data.bendDirection = GetBoolean(constraintMap, "bendPositive", true) ? 1 : -1; - data.mix = GetFloat(constraintMap, "mix", 1); - - skeletonData.ikConstraints.Add(data); - } - } - - // Transform constraints. - if (root.ContainsKey("transform")) { - foreach (Dictionary constraintMap in (List)root["transform"]) { - TransformConstraintData data = new TransformConstraintData((String)constraintMap["name"]); - - foreach (String boneName in (List)constraintMap["bones"]) { - BoneData bone = skeletonData.FindBone(boneName); - if (bone == null) throw new Exception("Transform constraint bone not found: " + boneName); - data.bones.Add(bone); - } - - String targetName = (String)constraintMap["target"]; - data.target = skeletonData.FindBone(targetName); - if (data.target == null) throw new Exception("Target bone not found: " + targetName); - - data.offsetRotation = GetFloat(constraintMap, "rotation", 0); - data.offsetX = GetFloat(constraintMap, "x", 0) * scale; - data.offsetY = GetFloat(constraintMap, "y", 0) * scale; - data.offsetScaleX = GetFloat(constraintMap, "scaleX", 0); - data.offsetScaleY = GetFloat(constraintMap, "scaleY", 0); - data.offsetShearY = GetFloat(constraintMap, "shearY", 0); - - data.rotateMix = GetFloat(constraintMap, "rotateMix", 1); - data.translateMix = GetFloat(constraintMap, "translateMix", 1); - data.scaleMix = GetFloat(constraintMap, "scaleMix", 1); - data.shearMix = GetFloat(constraintMap, "shearMix", 1); - - skeletonData.transformConstraints.Add(data); - } - } - - // Path constraints. - if(root.ContainsKey("path")) { - foreach (Dictionary constraintMap in (List)root["path"]) { - PathConstraintData data = new PathConstraintData((String)constraintMap["name"]); - - foreach (String boneName in (List)constraintMap["bones"]) { - BoneData bone = skeletonData.FindBone(boneName); - if (bone == null) throw new Exception("Path bone not found: " + boneName); - data.bones.Add(bone); - } - - String targetName = (String)constraintMap["target"]; - data.target = skeletonData.FindSlot(targetName); - if (data.target == null) throw new Exception("Target slot not found: " + targetName); - - data.positionMode = (PositionMode)Enum.Parse(typeof(PositionMode), GetString(constraintMap, "positionMode", "percent"), true); - data.spacingMode = (SpacingMode)Enum.Parse(typeof(SpacingMode), GetString(constraintMap, "spacingMode", "length"), true); - data.rotateMode = (RotateMode)Enum.Parse(typeof(RotateMode), GetString(constraintMap, "rotateMode", "tangent"), true); - data.offsetRotation = GetFloat(constraintMap, "rotation", 0); - data.position = GetFloat(constraintMap, "position", 0); - if (data.positionMode == PositionMode.Fixed) data.position *= scale; - data.spacing = GetFloat(constraintMap, "spacing", 0); - if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed) data.spacing *= scale; - data.rotateMix = GetFloat(constraintMap, "rotateMix", 1); - data.translateMix = GetFloat(constraintMap, "translateMix", 1); - - skeletonData.pathConstraints.Add(data); - } - } - - // Skins. - if (root.ContainsKey("skins")) { - foreach (KeyValuePair skinMap in (Dictionary)root["skins"]) { - var skin = new Skin(skinMap.Key); - foreach (KeyValuePair slotEntry in (Dictionary)skinMap.Value) { - int slotIndex = skeletonData.FindSlotIndex(slotEntry.Key); - foreach (KeyValuePair entry in ((Dictionary)slotEntry.Value)) { - try { - Attachment attachment = ReadAttachment((Dictionary)entry.Value, skin, slotIndex, entry.Key); - if (attachment != null) skin.AddAttachment(slotIndex, entry.Key, attachment); - } catch (Exception e) { - throw new Exception("Error reading attachment: " + entry.Key + ", skin: " + skin, e); - } - } - } - skeletonData.skins.Add(skin); - if (skin.name == "default") skeletonData.defaultSkin = skin; - } - } - - // Linked meshes. - for (int i = 0, n = linkedMeshes.Count; i < n; i++) { - LinkedMesh linkedMesh = linkedMeshes[i]; - Skin skin = linkedMesh.skin == null ? skeletonData.defaultSkin : skeletonData.FindSkin(linkedMesh.skin); - if (skin == null) throw new Exception("Slot not found: " + linkedMesh.skin); - Attachment parent = skin.GetAttachment(linkedMesh.slotIndex, linkedMesh.parent); - if (parent == null) throw new Exception("Parent mesh not found: " + linkedMesh.parent); - linkedMesh.mesh.ParentMesh = (MeshAttachment)parent; - linkedMesh.mesh.UpdateUVs(); - } - linkedMeshes.Clear(); - - // Events. - if (root.ContainsKey("events")) { - foreach (KeyValuePair entry in (Dictionary)root["events"]) { - var entryMap = (Dictionary)entry.Value; - var data = new EventData(entry.Key); - data.Int = GetInt(entryMap, "int", 0); - data.Float = GetFloat(entryMap, "float", 0); - data.String = GetString(entryMap, "string", null); - skeletonData.events.Add(data); - } - } - - // Animations. - if (root.ContainsKey("animations")) { - foreach (KeyValuePair entry in (Dictionary)root["animations"]) { - try { - ReadAnimation((Dictionary)entry.Value, entry.Key, skeletonData); - } catch (Exception e) { - throw new Exception("Error reading animation: " + entry.Key, e); - } - } - } - - skeletonData.bones.TrimExcess(); - skeletonData.slots.TrimExcess(); - skeletonData.skins.TrimExcess(); - skeletonData.events.TrimExcess(); - skeletonData.animations.TrimExcess(); - skeletonData.ikConstraints.TrimExcess(); - return skeletonData; - } - - private Attachment ReadAttachment (Dictionary map, Skin skin, int slotIndex, String name) { - var scale = this.Scale; - name = GetString(map, "name", name); - - var typeName = GetString(map, "type", "region"); - if (typeName == "skinnedmesh") typeName = "weightedmesh"; - if (typeName == "weightedmesh") typeName = "mesh"; - if (typeName == "weightedlinkedmesh") typeName = "linkedmesh"; - var type = (AttachmentType)Enum.Parse(typeof(AttachmentType), typeName, true); - - String path = GetString(map, "path", name); - - switch (type) { - case AttachmentType.Region: - RegionAttachment region = attachmentLoader.NewRegionAttachment(skin, name, path); - if (region == null) return null; - region.Path = path; - region.x = GetFloat(map, "x", 0) * scale; - region.y = GetFloat(map, "y", 0) * scale; - region.scaleX = GetFloat(map, "scaleX", 1); - region.scaleY = GetFloat(map, "scaleY", 1); - region.rotation = GetFloat(map, "rotation", 0); - region.width = GetFloat(map, "width", 32) * scale; - region.height = GetFloat(map, "height", 32) * scale; - region.UpdateOffset(); - - if (map.ContainsKey("color")) { - var color = (String)map["color"]; - region.r = ToColor(color, 0); - region.g = ToColor(color, 1); - region.b = ToColor(color, 2); - region.a = ToColor(color, 3); - } - - region.UpdateOffset(); - return region; - case AttachmentType.Boundingbox: - BoundingBoxAttachment box = attachmentLoader.NewBoundingBoxAttachment(skin, name); - if (box == null) return null; - ReadVertices(map, box, GetInt(map, "vertexCount", 0) << 1); - return box; - case AttachmentType.Mesh: - case AttachmentType.Linkedmesh: { - MeshAttachment mesh = attachmentLoader.NewMeshAttachment(skin, name, path); - if (mesh == null) return null; - mesh.Path = path; - - if (map.ContainsKey("color")) { - var color = (String)map["color"]; - mesh.r = ToColor(color, 0); - mesh.g = ToColor(color, 1); - mesh.b = ToColor(color, 2); - mesh.a = ToColor(color, 3); - } - - mesh.Width = GetFloat(map, "width", 0) * scale; - mesh.Height = GetFloat(map, "height", 0) * scale; - - String parent = GetString(map, "parent", null); - if (parent != null) { - mesh.InheritDeform = GetBoolean(map, "deform", true); - linkedMeshes.Add(new LinkedMesh(mesh, GetString(map, "skin", null), slotIndex, parent)); - return mesh; - } - - float[] uvs = GetFloatArray(map, "uvs", 1); - ReadVertices(map, mesh, uvs.Length); - mesh.triangles = GetIntArray(map, "triangles"); - mesh.regionUVs = uvs; - mesh.UpdateUVs(); - - if (map.ContainsKey("hull")) mesh.HullLength = GetInt(map, "hull", 0) * 2; - if (map.ContainsKey("edges")) mesh.Edges = GetIntArray(map, "edges"); - return mesh; - } - case AttachmentType.Path: { - PathAttachment pathAttachment = attachmentLoader.NewPathAttachment(skin, name); - if (pathAttachment == null) return null; - pathAttachment.closed = GetBoolean(map, "closed", false); - pathAttachment.constantSpeed = GetBoolean(map, "constantSpeed", true); - - int vertexCount = GetInt(map, "vertexCount", 0); - ReadVertices(map, pathAttachment, vertexCount << 1); - - // potential BOZO see Java impl - pathAttachment.lengths = GetFloatArray(map, "lengths", scale); - return pathAttachment; - } - } - return null; - } - - private void ReadVertices (Dictionary map, VertexAttachment attachment, int verticesLength) { - attachment.WorldVerticesLength = verticesLength; - float[] vertices = GetFloatArray(map, "vertices", 1); - float scale = Scale; - if (verticesLength == vertices.Length) { - if (scale != 1) { - for (int i = 0; i < vertices.Length; i++) { - vertices[i] *= scale; - } - } - attachment.vertices = vertices; - return; - } - ExposedList weights = new ExposedList(verticesLength * 3 * 3); - ExposedList bones = new ExposedList(verticesLength * 3); - for (int i = 0, n = vertices.Length; i < n;) { - int boneCount = (int)vertices[i++]; - bones.Add(boneCount); - for (int nn = i + boneCount * 4; i < nn; i += 4) { - bones.Add((int)vertices[i]); - weights.Add(vertices[i + 1] * this.Scale); - weights.Add(vertices[i + 2] * this.Scale); - weights.Add(vertices[i + 3]); - } - } - attachment.bones = bones.ToArray(); - attachment.vertices = weights.ToArray(); - } - - private void ReadAnimation (Dictionary map, String name, SkeletonData skeletonData) { - var scale = this.Scale; - var timelines = new ExposedList(); - float duration = 0; - - // Slot timelines. - if (map.ContainsKey("slots")) { - foreach (KeyValuePair entry in (Dictionary)map["slots"]) { - String slotName = entry.Key; - int slotIndex = skeletonData.FindSlotIndex(slotName); - var timelineMap = (Dictionary)entry.Value; - foreach (KeyValuePair timelineEntry in timelineMap) { - var values = (List)timelineEntry.Value; - var timelineName = (String)timelineEntry.Key; - if (timelineName == "color") { - var timeline = new ColorTimeline(values.Count); - timeline.slotIndex = slotIndex; - - int frameIndex = 0; - foreach (Dictionary valueMap in values) { - float time = (float)valueMap["time"]; - String c = (String)valueMap["color"]; - timeline.SetFrame(frameIndex, time, ToColor(c, 0), ToColor(c, 1), ToColor(c, 2), ToColor(c, 3)); - ReadCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * ColorTimeline.ENTRIES]); - - } else if (timelineName == "attachment") { - var timeline = new AttachmentTimeline(values.Count); - timeline.slotIndex = slotIndex; - - int frameIndex = 0; - foreach (Dictionary valueMap in values) { - float time = (float)valueMap["time"]; - timeline.SetFrame(frameIndex++, time, (String)valueMap["name"]); - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]); - - } else - throw new Exception("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"); - } - } - } - - // Bone timelines. - if (map.ContainsKey("bones")) { - foreach (KeyValuePair entry in (Dictionary)map["bones"]) { - String boneName = entry.Key; - int boneIndex = skeletonData.FindBoneIndex(boneName); - if (boneIndex == -1) throw new Exception("Bone not found: " + boneName); - var timelineMap = (Dictionary)entry.Value; - foreach (KeyValuePair timelineEntry in timelineMap) { - var values = (List)timelineEntry.Value; - var timelineName = (String)timelineEntry.Key; - if (timelineName == "rotate") { - var timeline = new RotateTimeline(values.Count); - timeline.boneIndex = boneIndex; - - int frameIndex = 0; - foreach (Dictionary valueMap in values) { - timeline.SetFrame(frameIndex, (float)valueMap["time"], (float)valueMap["angle"]); - ReadCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * RotateTimeline.ENTRIES]); - - } else if (timelineName == "translate" || timelineName == "scale" || timelineName == "shear") { - TranslateTimeline timeline; - float timelineScale = 1; - if (timelineName == "scale") - timeline = new ScaleTimeline(values.Count); - else if (timelineName == "shear") - timeline = new ShearTimeline(values.Count); - else { - timeline = new TranslateTimeline(values.Count); - timelineScale = scale; - } - timeline.boneIndex = boneIndex; - - int frameIndex = 0; - foreach (Dictionary valueMap in values) { - float time = (float)valueMap["time"]; - float x = GetFloat(valueMap, "x", 0); - float y = GetFloat(valueMap, "y", 0); - timeline.SetFrame(frameIndex, time, x * timelineScale, y * timelineScale); - ReadCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * TranslateTimeline.ENTRIES]); - - } else - throw new Exception("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"); - } - } - } - - // IK constraint timelines. - if (map.ContainsKey("ik")) { - foreach (KeyValuePair constraintMap in (Dictionary)map["ik"]) { - IkConstraintData constraint = skeletonData.FindIkConstraint(constraintMap.Key); - var values = (List)constraintMap.Value; - var timeline = new IkConstraintTimeline(values.Count); - timeline.ikConstraintIndex = skeletonData.ikConstraints.IndexOf(constraint); - int frameIndex = 0; - foreach (Dictionary valueMap in values) { - float time = (float)valueMap["time"]; - float mix = GetFloat(valueMap, "mix", 1); - bool bendPositive = GetBoolean(valueMap, "bendPositive", true); - timeline.SetFrame(frameIndex, time, mix, bendPositive ? 1 : -1); - ReadCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * IkConstraintTimeline.ENTRIES]); - } - } - - // Transform constraint timelines. - if (map.ContainsKey("transform")) { - foreach (KeyValuePair constraintMap in (Dictionary)map["transform"]) { - TransformConstraintData constraint = skeletonData.FindTransformConstraint(constraintMap.Key); - var values = (List)constraintMap.Value; - var timeline = new TransformConstraintTimeline(values.Count); - timeline.transformConstraintIndex = skeletonData.transformConstraints.IndexOf(constraint); - int frameIndex = 0; - foreach (Dictionary valueMap in values) { - float time = (float)valueMap["time"]; - float rotateMix = GetFloat(valueMap, "rotateMix", 1); - float translateMix = GetFloat(valueMap, "translateMix", 1); - float scaleMix = GetFloat(valueMap, "scaleMix", 1); - float shearMix = GetFloat(valueMap, "shearMix", 1); - timeline.SetFrame(frameIndex, time, rotateMix, translateMix, scaleMix, shearMix); - ReadCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * TransformConstraintTimeline.ENTRIES]); - } - } - - // Path constraint timelines. - if (map.ContainsKey("paths")) { - foreach (KeyValuePair constraintMap in (Dictionary)map["paths"]) { - int index = skeletonData.FindPathConstraintIndex(constraintMap.Key); - if (index == -1) throw new Exception("Path constraint not found: " + constraintMap.Key); - PathConstraintData data = skeletonData.pathConstraints.Items[index]; - var timelineMap = (Dictionary)constraintMap.Value; - foreach (KeyValuePair timelineEntry in timelineMap) { - var values = (List)timelineEntry.Value; - var timelineName = (String)timelineEntry.Key; - if (timelineName == "position" || timelineName == "spacing") { - PathConstraintPositionTimeline timeline; - float timelineScale = 1; - if (timelineName == "spacing") { - timeline = new PathConstraintSpacingTimeline(values.Count); - if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed) timelineScale = scale; - } - else { - timeline = new PathConstraintPositionTimeline(values.Count); - if (data.positionMode == PositionMode.Fixed) timelineScale = scale; - } - timeline.pathConstraintIndex = index; - int frameIndex = 0; - foreach (Dictionary valueMap in values) { - timeline.SetFrame(frameIndex, (float)valueMap["time"], GetFloat(valueMap, timelineName, 0) * timelineScale); - ReadCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * PathConstraintPositionTimeline.ENTRIES]); - } - else if (timelineName == "mix") { - PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(values.Count); - timeline.pathConstraintIndex = index; - int frameIndex = 0; - foreach (Dictionary valueMap in values) { - timeline.SetFrame(frameIndex, (float)valueMap["time"], GetFloat(valueMap, "rotateMix", 1), GetFloat(valueMap, "translateMix", 1)); - ReadCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * PathConstraintMixTimeline.ENTRIES]); - } - } - } - } - - // Deform timelines. - if (map.ContainsKey("deform")) { - foreach (KeyValuePair deformMap in (Dictionary)map["deform"]) { - Skin skin = skeletonData.FindSkin(deformMap.Key); - foreach (KeyValuePair slotMap in (Dictionary)deformMap.Value) { - int slotIndex = skeletonData.FindSlotIndex(slotMap.Key); - if (slotIndex == -1) throw new Exception("Slot not found: " + slotMap.Key); - foreach (KeyValuePair timelineMap in (Dictionary)slotMap.Value) { - var values = (List)timelineMap.Value; - VertexAttachment attachment = (VertexAttachment)skin.GetAttachment(slotIndex, timelineMap.Key); - if (attachment == null) throw new Exception("Deform attachment not found: " + timelineMap.Key); - bool weighted = attachment.bones != null; - float[] vertices = attachment.vertices; - int deformLength = weighted ? vertices.Length / 3 * 2 : vertices.Length; - - var timeline = new DeformTimeline(values.Count); - timeline.slotIndex = slotIndex; - timeline.attachment = attachment; - - int frameIndex = 0; - foreach (Dictionary valueMap in values) { - float[] deform; - if (!valueMap.ContainsKey("vertices")) { - deform = weighted ? new float[deformLength] : vertices; - } else { - deform = new float[deformLength]; - int start = GetInt(valueMap, "offset", 0); - float[] verticesValue = GetFloatArray(valueMap, "vertices", 1); - Array.Copy(verticesValue, 0, deform, start, verticesValue.Length); - if (scale != 1) { - for (int i = start, n = i + verticesValue.Length; i < n; i++) - deform[i] *= scale; - } - - if (!weighted) { - for (int i = 0; i < deformLength; i++) - deform[i] += vertices[i]; - } - } - - timeline.SetFrame(frameIndex, (float)valueMap["time"], deform); - ReadCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]); - } - } - } - } - - // Draw order timeline. - if (map.ContainsKey("drawOrder") || map.ContainsKey("draworder")) { - var values = (List)map[map.ContainsKey("drawOrder") ? "drawOrder" : "draworder"]; - var timeline = new DrawOrderTimeline(values.Count); - int slotCount = skeletonData.slots.Count; - int frameIndex = 0; - foreach (Dictionary drawOrderMap in values) { - int[] drawOrder = null; - if (drawOrderMap.ContainsKey("offsets")) { - drawOrder = new int[slotCount]; - for (int i = slotCount - 1; i >= 0; i--) - drawOrder[i] = -1; - var offsets = (List)drawOrderMap["offsets"]; - int[] unchanged = new int[slotCount - offsets.Count]; - int originalIndex = 0, unchangedIndex = 0; - foreach (Dictionary offsetMap in offsets) { - int slotIndex = skeletonData.FindSlotIndex((String)offsetMap["slot"]); - if (slotIndex == -1) throw new Exception("Slot not found: " + offsetMap["slot"]); - // Collect unchanged items. - while (originalIndex != slotIndex) - unchanged[unchangedIndex++] = originalIndex++; - // Set changed items. - int index = originalIndex + (int)(float)offsetMap["offset"]; - drawOrder[index] = originalIndex++; - } - // Collect remaining unchanged items. - while (originalIndex < slotCount) - unchanged[unchangedIndex++] = originalIndex++; - // Fill in unchanged items. - for (int i = slotCount - 1; i >= 0; i--) - if (drawOrder[i] == -1) drawOrder[i] = unchanged[--unchangedIndex]; - } - timeline.SetFrame(frameIndex++, (float)drawOrderMap["time"], drawOrder); - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]); - } - - // Event timeline. - if (map.ContainsKey("events")) { - var eventsMap = (List)map["events"]; - var timeline = new EventTimeline(eventsMap.Count); - int frameIndex = 0; - foreach (Dictionary eventMap in eventsMap) { - EventData eventData = skeletonData.FindEvent((String)eventMap["name"]); - if (eventData == null) throw new Exception("Event not found: " + eventMap["name"]); - var e = new Event((float)eventMap["time"], eventData); - e.Int = GetInt(eventMap, "int", eventData.Int); - e.Float = GetFloat(eventMap, "float", eventData.Float); - e.String = GetString(eventMap, "string", eventData.String); - timeline.SetFrame(frameIndex++, e); - } - timelines.Add(timeline); - duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]); - } - - timelines.TrimExcess(); - skeletonData.animations.Add(new Animation(name, timelines, duration)); - } - - static void ReadCurve (Dictionary valueMap, CurveTimeline timeline, int frameIndex) { - if (!valueMap.ContainsKey("curve")) - return; - Object curveObject = valueMap["curve"]; - if (curveObject.Equals("stepped")) - timeline.SetStepped(frameIndex); - else { - var curve = curveObject as List; - if (curve != null) - timeline.SetCurve(frameIndex, (float)curve[0], (float)curve[1], (float)curve[2], (float)curve[3]); - } - } - - internal class LinkedMesh { - internal String parent, skin; - internal int slotIndex; - internal MeshAttachment mesh; - - public LinkedMesh (MeshAttachment mesh, String skin, int slotIndex, String parent) { - this.mesh = mesh; - this.skin = skin; - this.slotIndex = slotIndex; - this.parent = parent; - } - } - - static float[] GetFloatArray(Dictionary map, String name, float scale) { - var list = (List)map[name]; - var values = new float[list.Count]; - if (scale == 1) { - for (int i = 0, n = list.Count; i < n; i++) - values[i] = (float)list[i]; - } else { - for (int i = 0, n = list.Count; i < n; i++) - values[i] = (float)list[i] * scale; - } - return values; - } - - static int[] GetIntArray(Dictionary map, String name) { - var list = (List)map[name]; - var values = new int[list.Count]; - for (int i = 0, n = list.Count; i < n; i++) - values[i] = (int)(float)list[i]; - return values; - } - - static float GetFloat(Dictionary map, String name, float defaultValue) { - if (!map.ContainsKey(name)) - return defaultValue; - return (float)map[name]; - } - - static int GetInt(Dictionary map, String name, int defaultValue) { - if (!map.ContainsKey(name)) - return defaultValue; - return (int)(float)map[name]; - } - - static bool GetBoolean(Dictionary map, String name, bool defaultValue) { - if (!map.ContainsKey(name)) - return defaultValue; - return (bool)map[name]; - } - - static String GetString(Dictionary map, String name, String defaultValue) { - if (!map.ContainsKey(name)) - return defaultValue; - return (String)map[name]; - } - - static float ToColor(String hexString, int colorIndex) { - if (hexString.Length != 8) - throw new ArgumentException("Color hexidecimal length must be 8, recieved: " + hexString, "hexString"); - return Convert.ToInt32(hexString.Substring(colorIndex * 2, 2), 16) / (float)255; - } - } +#if (UNITY_5 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_WSA || UNITY_WP8 || UNITY_WP8_1) +#define IS_UNITY +#endif + +using System; +using System.IO; +using System.Collections.Generic; + +#if WINDOWS_STOREAPP +using System.Threading.Tasks; +using Windows.Storage; +#endif + +namespace Spine { + public class SkeletonJson { + public float Scale { get; set; } + + private AttachmentLoader attachmentLoader; + private List linkedMeshes = new List(); + + public SkeletonJson (params Atlas[] atlasArray) + : this(new AtlasAttachmentLoader(atlasArray)) { + } + + public SkeletonJson (AttachmentLoader attachmentLoader) { + if (attachmentLoader == null) throw new ArgumentNullException("attachmentLoader", "attachmentLoader cannot be null."); + this.attachmentLoader = attachmentLoader; + Scale = 1; + } + + #if !(IS_UNITY) && WINDOWS_STOREAPP + private async Task ReadFile(string path) { + var folder = Windows.ApplicationModel.Package.Current.InstalledLocation; + var file = await folder.GetFileAsync(path).AsTask().ConfigureAwait(false); + using (var reader = new StreamReader(await file.OpenStreamForReadAsync().ConfigureAwait(false))) { + SkeletonData skeletonData = ReadSkeletonData(reader); + skeletonData.Name = Path.GetFileNameWithoutExtension(path); + return skeletonData; + } + } + + public SkeletonData ReadSkeletonData (String path) { + return this.ReadFile(path).Result; + } + #else + public SkeletonData ReadSkeletonData (String path) { + #if WINDOWS_PHONE + Stream stream = Microsoft.Xna.Framework.TitleContainer.OpenStream(path); + using (StreamReader reader = new StreamReader(stream)) { + #else + using (var reader = new StreamReader(path)) { + #endif // WINDOWS_PHONE + SkeletonData skeletonData = ReadSkeletonData(reader); + skeletonData.name = Path.GetFileNameWithoutExtension(path); + return skeletonData; + } + } + #endif // WINDOWS_STOREAPP + + public SkeletonData ReadSkeletonData (TextReader reader) { + if (reader == null) throw new ArgumentNullException("reader", "reader cannot be null."); + + var scale = this.Scale; + var skeletonData = new SkeletonData(); + + var root = Json.Deserialize(reader) as Dictionary; + if (root == null) throw new Exception("Invalid JSON."); + + // Skeleton. + if (root.ContainsKey("skeleton")) { + var skeletonMap = (Dictionary)root["skeleton"]; + skeletonData.hash = (String)skeletonMap["hash"]; + skeletonData.version = (String)skeletonMap["spine"]; + skeletonData.width = GetFloat(skeletonMap, "width", 0); + skeletonData.height = GetFloat(skeletonMap, "height", 0); + } + + // Bones. + foreach (Dictionary boneMap in (List)root["bones"]) { + BoneData parent = null; + if (boneMap.ContainsKey("parent")) { + parent = skeletonData.FindBone((String)boneMap["parent"]); + if (parent == null) + throw new Exception("Parent bone not found: " + boneMap["parent"]); + } + var data = new BoneData(skeletonData.Bones.Count, (String)boneMap["name"], parent); + data.length = GetFloat(boneMap, "length", 0) * scale; + data.x = GetFloat(boneMap, "x", 0) * scale; + data.y = GetFloat(boneMap, "y", 0) * scale; + data.rotation = GetFloat(boneMap, "rotation", 0); + data.scaleX = GetFloat(boneMap, "scaleX", 1); + data.scaleY = GetFloat(boneMap, "scaleY", 1); + data.shearX = GetFloat(boneMap, "shearX", 0); + data.shearY = GetFloat(boneMap, "shearY", 0); + data.inheritRotation = GetBoolean(boneMap, "inheritRotation", true); + data.inheritScale = GetBoolean(boneMap, "inheritScale", true); + + skeletonData.bones.Add(data); + } + + // Slots. + if (root.ContainsKey("slots")) { + foreach (Dictionary slotMap in (List)root["slots"]) { + var slotName = (String)slotMap["name"]; + var boneName = (String)slotMap["bone"]; + BoneData boneData = skeletonData.FindBone(boneName); + if (boneData == null) throw new Exception("Slot bone not found: " + boneName); + var data = new SlotData(skeletonData.Slots.Count, slotName, boneData); + + if (slotMap.ContainsKey("color")) { + var color = (String)slotMap["color"]; + data.r = ToColor(color, 0); + data.g = ToColor(color, 1); + data.b = ToColor(color, 2); + data.a = ToColor(color, 3); + } + + data.attachmentName = GetString(slotMap, "attachment", null); + if (slotMap.ContainsKey("blend")) + data.blendMode = (BlendMode)Enum.Parse(typeof(BlendMode), (String)slotMap["blend"], false); + else + data.blendMode = BlendMode.normal; + skeletonData.slots.Add(data); + } + } + + // IK constraints. + if (root.ContainsKey("ik")) { + foreach (Dictionary constraintMap in (List)root["ik"]) { + IkConstraintData data = new IkConstraintData((String)constraintMap["name"]); + + foreach (String boneName in (List)constraintMap["bones"]) { + BoneData bone = skeletonData.FindBone(boneName); + if (bone == null) throw new Exception("IK constraint bone not found: " + boneName); + data.bones.Add(bone); + } + + String targetName = (String)constraintMap["target"]; + data.target = skeletonData.FindBone(targetName); + if (data.target == null) throw new Exception("Target bone not found: " + targetName); + + data.bendDirection = GetBoolean(constraintMap, "bendPositive", true) ? 1 : -1; + data.mix = GetFloat(constraintMap, "mix", 1); + + skeletonData.ikConstraints.Add(data); + } + } + + // Transform constraints. + if (root.ContainsKey("transform")) { + foreach (Dictionary constraintMap in (List)root["transform"]) { + TransformConstraintData data = new TransformConstraintData((String)constraintMap["name"]); + + foreach (String boneName in (List)constraintMap["bones"]) { + BoneData bone = skeletonData.FindBone(boneName); + if (bone == null) throw new Exception("Transform constraint bone not found: " + boneName); + data.bones.Add(bone); + } + + String targetName = (String)constraintMap["target"]; + data.target = skeletonData.FindBone(targetName); + if (data.target == null) throw new Exception("Target bone not found: " + targetName); + + data.offsetRotation = GetFloat(constraintMap, "rotation", 0); + data.offsetX = GetFloat(constraintMap, "x", 0) * scale; + data.offsetY = GetFloat(constraintMap, "y", 0) * scale; + data.offsetScaleX = GetFloat(constraintMap, "scaleX", 0); + data.offsetScaleY = GetFloat(constraintMap, "scaleY", 0); + data.offsetShearY = GetFloat(constraintMap, "shearY", 0); + + data.rotateMix = GetFloat(constraintMap, "rotateMix", 1); + data.translateMix = GetFloat(constraintMap, "translateMix", 1); + data.scaleMix = GetFloat(constraintMap, "scaleMix", 1); + data.shearMix = GetFloat(constraintMap, "shearMix", 1); + + skeletonData.transformConstraints.Add(data); + } + } + + // Path constraints. + if(root.ContainsKey("path")) { + foreach (Dictionary constraintMap in (List)root["path"]) { + PathConstraintData data = new PathConstraintData((String)constraintMap["name"]); + + foreach (String boneName in (List)constraintMap["bones"]) { + BoneData bone = skeletonData.FindBone(boneName); + if (bone == null) throw new Exception("Path bone not found: " + boneName); + data.bones.Add(bone); + } + + String targetName = (String)constraintMap["target"]; + data.target = skeletonData.FindSlot(targetName); + if (data.target == null) throw new Exception("Target slot not found: " + targetName); + + data.positionMode = (PositionMode)Enum.Parse(typeof(PositionMode), GetString(constraintMap, "positionMode", "percent"), true); + data.spacingMode = (SpacingMode)Enum.Parse(typeof(SpacingMode), GetString(constraintMap, "spacingMode", "length"), true); + data.rotateMode = (RotateMode)Enum.Parse(typeof(RotateMode), GetString(constraintMap, "rotateMode", "tangent"), true); + data.offsetRotation = GetFloat(constraintMap, "rotation", 0); + data.position = GetFloat(constraintMap, "position", 0); + if (data.positionMode == PositionMode.Fixed) data.position *= scale; + data.spacing = GetFloat(constraintMap, "spacing", 0); + if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed) data.spacing *= scale; + data.rotateMix = GetFloat(constraintMap, "rotateMix", 1); + data.translateMix = GetFloat(constraintMap, "translateMix", 1); + + skeletonData.pathConstraints.Add(data); + } + } + + // Skins. + if (root.ContainsKey("skins")) { + foreach (KeyValuePair skinMap in (Dictionary)root["skins"]) { + var skin = new Skin(skinMap.Key); + foreach (KeyValuePair slotEntry in (Dictionary)skinMap.Value) { + int slotIndex = skeletonData.FindSlotIndex(slotEntry.Key); + foreach (KeyValuePair entry in ((Dictionary)slotEntry.Value)) { + try { + Attachment attachment = ReadAttachment((Dictionary)entry.Value, skin, slotIndex, entry.Key); + if (attachment != null) skin.AddAttachment(slotIndex, entry.Key, attachment); + } catch (Exception e) { + throw new Exception("Error reading attachment: " + entry.Key + ", skin: " + skin, e); + } + } + } + skeletonData.skins.Add(skin); + if (skin.name == "default") skeletonData.defaultSkin = skin; + } + } + + // Linked meshes. + for (int i = 0, n = linkedMeshes.Count; i < n; i++) { + LinkedMesh linkedMesh = linkedMeshes[i]; + Skin skin = linkedMesh.skin == null ? skeletonData.defaultSkin : skeletonData.FindSkin(linkedMesh.skin); + if (skin == null) throw new Exception("Slot not found: " + linkedMesh.skin); + Attachment parent = skin.GetAttachment(linkedMesh.slotIndex, linkedMesh.parent); + if (parent == null) throw new Exception("Parent mesh not found: " + linkedMesh.parent); + linkedMesh.mesh.ParentMesh = (MeshAttachment)parent; + linkedMesh.mesh.UpdateUVs(); + } + linkedMeshes.Clear(); + + // Events. + if (root.ContainsKey("events")) { + foreach (KeyValuePair entry in (Dictionary)root["events"]) { + var entryMap = (Dictionary)entry.Value; + var data = new EventData(entry.Key); + data.Int = GetInt(entryMap, "int", 0); + data.Float = GetFloat(entryMap, "float", 0); + data.String = GetString(entryMap, "string", null); + skeletonData.events.Add(data); + } + } + + // Animations. + if (root.ContainsKey("animations")) { + foreach (KeyValuePair entry in (Dictionary)root["animations"]) { + try { + ReadAnimation((Dictionary)entry.Value, entry.Key, skeletonData); + } catch (Exception e) { + throw new Exception("Error reading animation: " + entry.Key, e); + } + } + } + + skeletonData.bones.TrimExcess(); + skeletonData.slots.TrimExcess(); + skeletonData.skins.TrimExcess(); + skeletonData.events.TrimExcess(); + skeletonData.animations.TrimExcess(); + skeletonData.ikConstraints.TrimExcess(); + return skeletonData; + } + + private Attachment ReadAttachment (Dictionary map, Skin skin, int slotIndex, String name) { + var scale = this.Scale; + name = GetString(map, "name", name); + + var typeName = GetString(map, "type", "region"); + if (typeName == "skinnedmesh") typeName = "weightedmesh"; + if (typeName == "weightedmesh") typeName = "mesh"; + if (typeName == "weightedlinkedmesh") typeName = "linkedmesh"; + var type = (AttachmentType)Enum.Parse(typeof(AttachmentType), typeName, true); + + String path = GetString(map, "path", name); + + switch (type) { + case AttachmentType.Region: + RegionAttachment region = attachmentLoader.NewRegionAttachment(skin, name, path); + if (region == null) return null; + region.Path = path; + region.x = GetFloat(map, "x", 0) * scale; + region.y = GetFloat(map, "y", 0) * scale; + region.scaleX = GetFloat(map, "scaleX", 1); + region.scaleY = GetFloat(map, "scaleY", 1); + region.rotation = GetFloat(map, "rotation", 0); + region.width = GetFloat(map, "width", 32) * scale; + region.height = GetFloat(map, "height", 32) * scale; + region.UpdateOffset(); + + if (map.ContainsKey("color")) { + var color = (String)map["color"]; + region.r = ToColor(color, 0); + region.g = ToColor(color, 1); + region.b = ToColor(color, 2); + region.a = ToColor(color, 3); + } + + region.UpdateOffset(); + return region; + case AttachmentType.Boundingbox: + BoundingBoxAttachment box = attachmentLoader.NewBoundingBoxAttachment(skin, name); + if (box == null) return null; + ReadVertices(map, box, GetInt(map, "vertexCount", 0) << 1); + return box; + case AttachmentType.Mesh: + case AttachmentType.Linkedmesh: { + MeshAttachment mesh = attachmentLoader.NewMeshAttachment(skin, name, path); + if (mesh == null) return null; + mesh.Path = path; + + if (map.ContainsKey("color")) { + var color = (String)map["color"]; + mesh.r = ToColor(color, 0); + mesh.g = ToColor(color, 1); + mesh.b = ToColor(color, 2); + mesh.a = ToColor(color, 3); + } + + mesh.Width = GetFloat(map, "width", 0) * scale; + mesh.Height = GetFloat(map, "height", 0) * scale; + + String parent = GetString(map, "parent", null); + if (parent != null) { + mesh.InheritDeform = GetBoolean(map, "deform", true); + linkedMeshes.Add(new LinkedMesh(mesh, GetString(map, "skin", null), slotIndex, parent)); + return mesh; + } + + float[] uvs = GetFloatArray(map, "uvs", 1); + ReadVertices(map, mesh, uvs.Length); + mesh.triangles = GetIntArray(map, "triangles"); + mesh.regionUVs = uvs; + mesh.UpdateUVs(); + + if (map.ContainsKey("hull")) mesh.HullLength = GetInt(map, "hull", 0) * 2; + if (map.ContainsKey("edges")) mesh.Edges = GetIntArray(map, "edges"); + return mesh; + } + case AttachmentType.Path: { + PathAttachment pathAttachment = attachmentLoader.NewPathAttachment(skin, name); + if (pathAttachment == null) return null; + pathAttachment.closed = GetBoolean(map, "closed", false); + pathAttachment.constantSpeed = GetBoolean(map, "constantSpeed", true); + + int vertexCount = GetInt(map, "vertexCount", 0); + ReadVertices(map, pathAttachment, vertexCount << 1); + + // potential BOZO see Java impl + pathAttachment.lengths = GetFloatArray(map, "lengths", scale); + return pathAttachment; + } + } + return null; + } + + private void ReadVertices (Dictionary map, VertexAttachment attachment, int verticesLength) { + attachment.WorldVerticesLength = verticesLength; + float[] vertices = GetFloatArray(map, "vertices", 1); + float scale = Scale; + if (verticesLength == vertices.Length) { + if (scale != 1) { + for (int i = 0; i < vertices.Length; i++) { + vertices[i] *= scale; + } + } + attachment.vertices = vertices; + return; + } + ExposedList weights = new ExposedList(verticesLength * 3 * 3); + ExposedList bones = new ExposedList(verticesLength * 3); + for (int i = 0, n = vertices.Length; i < n;) { + int boneCount = (int)vertices[i++]; + bones.Add(boneCount); + for (int nn = i + boneCount * 4; i < nn; i += 4) { + bones.Add((int)vertices[i]); + weights.Add(vertices[i + 1] * this.Scale); + weights.Add(vertices[i + 2] * this.Scale); + weights.Add(vertices[i + 3]); + } + } + attachment.bones = bones.ToArray(); + attachment.vertices = weights.ToArray(); + } + + private void ReadAnimation (Dictionary map, String name, SkeletonData skeletonData) { + var scale = this.Scale; + var timelines = new ExposedList(); + float duration = 0; + + // Slot timelines. + if (map.ContainsKey("slots")) { + foreach (KeyValuePair entry in (Dictionary)map["slots"]) { + String slotName = entry.Key; + int slotIndex = skeletonData.FindSlotIndex(slotName); + var timelineMap = (Dictionary)entry.Value; + foreach (KeyValuePair timelineEntry in timelineMap) { + var values = (List)timelineEntry.Value; + var timelineName = (String)timelineEntry.Key; + if (timelineName == "color") { + var timeline = new ColorTimeline(values.Count); + timeline.slotIndex = slotIndex; + + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + float time = (float)valueMap["time"]; + String c = (String)valueMap["color"]; + timeline.SetFrame(frameIndex, time, ToColor(c, 0), ToColor(c, 1), ToColor(c, 2), ToColor(c, 3)); + ReadCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * ColorTimeline.ENTRIES]); + + } else if (timelineName == "attachment") { + var timeline = new AttachmentTimeline(values.Count); + timeline.slotIndex = slotIndex; + + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + float time = (float)valueMap["time"]; + timeline.SetFrame(frameIndex++, time, (String)valueMap["name"]); + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]); + + } else + throw new Exception("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"); + } + } + } + + // Bone timelines. + if (map.ContainsKey("bones")) { + foreach (KeyValuePair entry in (Dictionary)map["bones"]) { + String boneName = entry.Key; + int boneIndex = skeletonData.FindBoneIndex(boneName); + if (boneIndex == -1) throw new Exception("Bone not found: " + boneName); + var timelineMap = (Dictionary)entry.Value; + foreach (KeyValuePair timelineEntry in timelineMap) { + var values = (List)timelineEntry.Value; + var timelineName = (String)timelineEntry.Key; + if (timelineName == "rotate") { + var timeline = new RotateTimeline(values.Count); + timeline.boneIndex = boneIndex; + + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + timeline.SetFrame(frameIndex, (float)valueMap["time"], (float)valueMap["angle"]); + ReadCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * RotateTimeline.ENTRIES]); + + } else if (timelineName == "translate" || timelineName == "scale" || timelineName == "shear") { + TranslateTimeline timeline; + float timelineScale = 1; + if (timelineName == "scale") + timeline = new ScaleTimeline(values.Count); + else if (timelineName == "shear") + timeline = new ShearTimeline(values.Count); + else { + timeline = new TranslateTimeline(values.Count); + timelineScale = scale; + } + timeline.boneIndex = boneIndex; + + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + float time = (float)valueMap["time"]; + float x = GetFloat(valueMap, "x", 0); + float y = GetFloat(valueMap, "y", 0); + timeline.SetFrame(frameIndex, time, x * timelineScale, y * timelineScale); + ReadCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * TranslateTimeline.ENTRIES]); + + } else + throw new Exception("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"); + } + } + } + + // IK constraint timelines. + if (map.ContainsKey("ik")) { + foreach (KeyValuePair constraintMap in (Dictionary)map["ik"]) { + IkConstraintData constraint = skeletonData.FindIkConstraint(constraintMap.Key); + var values = (List)constraintMap.Value; + var timeline = new IkConstraintTimeline(values.Count); + timeline.ikConstraintIndex = skeletonData.ikConstraints.IndexOf(constraint); + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + float time = (float)valueMap["time"]; + float mix = GetFloat(valueMap, "mix", 1); + bool bendPositive = GetBoolean(valueMap, "bendPositive", true); + timeline.SetFrame(frameIndex, time, mix, bendPositive ? 1 : -1); + ReadCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * IkConstraintTimeline.ENTRIES]); + } + } + + // Transform constraint timelines. + if (map.ContainsKey("transform")) { + foreach (KeyValuePair constraintMap in (Dictionary)map["transform"]) { + TransformConstraintData constraint = skeletonData.FindTransformConstraint(constraintMap.Key); + var values = (List)constraintMap.Value; + var timeline = new TransformConstraintTimeline(values.Count); + timeline.transformConstraintIndex = skeletonData.transformConstraints.IndexOf(constraint); + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + float time = (float)valueMap["time"]; + float rotateMix = GetFloat(valueMap, "rotateMix", 1); + float translateMix = GetFloat(valueMap, "translateMix", 1); + float scaleMix = GetFloat(valueMap, "scaleMix", 1); + float shearMix = GetFloat(valueMap, "shearMix", 1); + timeline.SetFrame(frameIndex, time, rotateMix, translateMix, scaleMix, shearMix); + ReadCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * TransformConstraintTimeline.ENTRIES]); + } + } + + // Path constraint timelines. + if (map.ContainsKey("paths")) { + foreach (KeyValuePair constraintMap in (Dictionary)map["paths"]) { + int index = skeletonData.FindPathConstraintIndex(constraintMap.Key); + if (index == -1) throw new Exception("Path constraint not found: " + constraintMap.Key); + PathConstraintData data = skeletonData.pathConstraints.Items[index]; + var timelineMap = (Dictionary)constraintMap.Value; + foreach (KeyValuePair timelineEntry in timelineMap) { + var values = (List)timelineEntry.Value; + var timelineName = (String)timelineEntry.Key; + if (timelineName == "position" || timelineName == "spacing") { + PathConstraintPositionTimeline timeline; + float timelineScale = 1; + if (timelineName == "spacing") { + timeline = new PathConstraintSpacingTimeline(values.Count); + if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed) timelineScale = scale; + } + else { + timeline = new PathConstraintPositionTimeline(values.Count); + if (data.positionMode == PositionMode.Fixed) timelineScale = scale; + } + timeline.pathConstraintIndex = index; + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + timeline.SetFrame(frameIndex, (float)valueMap["time"], GetFloat(valueMap, timelineName, 0) * timelineScale); + ReadCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * PathConstraintPositionTimeline.ENTRIES]); + } + else if (timelineName == "mix") { + PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(values.Count); + timeline.pathConstraintIndex = index; + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + timeline.SetFrame(frameIndex, (float)valueMap["time"], GetFloat(valueMap, "rotateMix", 1), GetFloat(valueMap, "translateMix", 1)); + ReadCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * PathConstraintMixTimeline.ENTRIES]); + } + } + } + } + + // Deform timelines. + if (map.ContainsKey("deform")) { + foreach (KeyValuePair deformMap in (Dictionary)map["deform"]) { + Skin skin = skeletonData.FindSkin(deformMap.Key); + foreach (KeyValuePair slotMap in (Dictionary)deformMap.Value) { + int slotIndex = skeletonData.FindSlotIndex(slotMap.Key); + if (slotIndex == -1) throw new Exception("Slot not found: " + slotMap.Key); + foreach (KeyValuePair timelineMap in (Dictionary)slotMap.Value) { + var values = (List)timelineMap.Value; + VertexAttachment attachment = (VertexAttachment)skin.GetAttachment(slotIndex, timelineMap.Key); + if (attachment == null) throw new Exception("Deform attachment not found: " + timelineMap.Key); + bool weighted = attachment.bones != null; + float[] vertices = attachment.vertices; + int deformLength = weighted ? vertices.Length / 3 * 2 : vertices.Length; + + var timeline = new DeformTimeline(values.Count); + timeline.slotIndex = slotIndex; + timeline.attachment = attachment; + + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + float[] deform; + if (!valueMap.ContainsKey("vertices")) { + deform = weighted ? new float[deformLength] : vertices; + } else { + deform = new float[deformLength]; + int start = GetInt(valueMap, "offset", 0); + float[] verticesValue = GetFloatArray(valueMap, "vertices", 1); + Array.Copy(verticesValue, 0, deform, start, verticesValue.Length); + if (scale != 1) { + for (int i = start, n = i + verticesValue.Length; i < n; i++) + deform[i] *= scale; + } + + if (!weighted) { + for (int i = 0; i < deformLength; i++) + deform[i] += vertices[i]; + } + } + + timeline.SetFrame(frameIndex, (float)valueMap["time"], deform); + ReadCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]); + } + } + } + } + + // Draw order timeline. + if (map.ContainsKey("drawOrder") || map.ContainsKey("draworder")) { + var values = (List)map[map.ContainsKey("drawOrder") ? "drawOrder" : "draworder"]; + var timeline = new DrawOrderTimeline(values.Count); + int slotCount = skeletonData.slots.Count; + int frameIndex = 0; + foreach (Dictionary drawOrderMap in values) { + int[] drawOrder = null; + if (drawOrderMap.ContainsKey("offsets")) { + drawOrder = new int[slotCount]; + for (int i = slotCount - 1; i >= 0; i--) + drawOrder[i] = -1; + var offsets = (List)drawOrderMap["offsets"]; + int[] unchanged = new int[slotCount - offsets.Count]; + int originalIndex = 0, unchangedIndex = 0; + foreach (Dictionary offsetMap in offsets) { + int slotIndex = skeletonData.FindSlotIndex((String)offsetMap["slot"]); + if (slotIndex == -1) throw new Exception("Slot not found: " + offsetMap["slot"]); + // Collect unchanged items. + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + // Set changed items. + int index = originalIndex + (int)(float)offsetMap["offset"]; + drawOrder[index] = originalIndex++; + } + // Collect remaining unchanged items. + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + // Fill in unchanged items. + for (int i = slotCount - 1; i >= 0; i--) + if (drawOrder[i] == -1) drawOrder[i] = unchanged[--unchangedIndex]; + } + timeline.SetFrame(frameIndex++, (float)drawOrderMap["time"], drawOrder); + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]); + } + + // Event timeline. + if (map.ContainsKey("events")) { + var eventsMap = (List)map["events"]; + var timeline = new EventTimeline(eventsMap.Count); + int frameIndex = 0; + foreach (Dictionary eventMap in eventsMap) { + EventData eventData = skeletonData.FindEvent((String)eventMap["name"]); + if (eventData == null) throw new Exception("Event not found: " + eventMap["name"]); + var e = new Event((float)eventMap["time"], eventData); + e.Int = GetInt(eventMap, "int", eventData.Int); + e.Float = GetFloat(eventMap, "float", eventData.Float); + e.String = GetString(eventMap, "string", eventData.String); + timeline.SetFrame(frameIndex++, e); + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]); + } + + timelines.TrimExcess(); + skeletonData.animations.Add(new Animation(name, timelines, duration)); + } + + static void ReadCurve (Dictionary valueMap, CurveTimeline timeline, int frameIndex) { + if (!valueMap.ContainsKey("curve")) + return; + Object curveObject = valueMap["curve"]; + if (curveObject.Equals("stepped")) + timeline.SetStepped(frameIndex); + else { + var curve = curveObject as List; + if (curve != null) + timeline.SetCurve(frameIndex, (float)curve[0], (float)curve[1], (float)curve[2], (float)curve[3]); + } + } + + internal class LinkedMesh { + internal String parent, skin; + internal int slotIndex; + internal MeshAttachment mesh; + + public LinkedMesh (MeshAttachment mesh, String skin, int slotIndex, String parent) { + this.mesh = mesh; + this.skin = skin; + this.slotIndex = slotIndex; + this.parent = parent; + } + } + + static float[] GetFloatArray(Dictionary map, String name, float scale) { + var list = (List)map[name]; + var values = new float[list.Count]; + if (scale == 1) { + for (int i = 0, n = list.Count; i < n; i++) + values[i] = (float)list[i]; + } else { + for (int i = 0, n = list.Count; i < n; i++) + values[i] = (float)list[i] * scale; + } + return values; + } + + static int[] GetIntArray(Dictionary map, String name) { + var list = (List)map[name]; + var values = new int[list.Count]; + for (int i = 0, n = list.Count; i < n; i++) + values[i] = (int)(float)list[i]; + return values; + } + + static float GetFloat(Dictionary map, String name, float defaultValue) { + if (!map.ContainsKey(name)) + return defaultValue; + return (float)map[name]; + } + + static int GetInt(Dictionary map, String name, int defaultValue) { + if (!map.ContainsKey(name)) + return defaultValue; + return (int)(float)map[name]; + } + + static bool GetBoolean(Dictionary map, String name, bool defaultValue) { + if (!map.ContainsKey(name)) + return defaultValue; + return (bool)map[name]; + } + + static String GetString(Dictionary map, String name, String defaultValue) { + if (!map.ContainsKey(name)) + return defaultValue; + return (String)map[name]; + } + + static float ToColor(String hexString, int colorIndex) { + if (hexString.Length != 8) + throw new ArgumentException("Color hexidecimal length must be 8, recieved: " + hexString, "hexString"); + return Convert.ToInt32(hexString.Substring(colorIndex * 2, 2), 16) / (float)255; + } + } } diff --git a/spine-csharp/src/Skin.cs b/spine-csharp/src/Skin.cs index c3fdd4e40c..1f7c8c396b 100644 --- a/spine-csharp/src/Skin.cs +++ b/spine-csharp/src/Skin.cs @@ -1,115 +1,114 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using System.Collections.Generic; - -namespace Spine { - /// Stores attachments by slot index and attachment name. - public class Skin { - internal String name; - private Dictionary attachments = - new Dictionary(AttachmentKeyTupleComparer.Instance); - - public String Name { get { return name; } } - public Dictionary Attachments { get { return attachments; } } - - public Skin (String name) { - if (name == null) throw new ArgumentNullException("name", "name cannot be null."); - this.name = name; - } - - public void AddAttachment (int slotIndex, String name, Attachment attachment) { - if (attachment == null) throw new ArgumentNullException("attachment", "attachment cannot be null."); - attachments[new AttachmentKeyTuple(slotIndex, name)] = attachment; - } - - /// May be null. - public Attachment GetAttachment (int slotIndex, String name) { - Attachment attachment; - attachments.TryGetValue(new AttachmentKeyTuple(slotIndex, name), out attachment); - return attachment; - } - - public void FindNamesForSlot (int slotIndex, List names) { - if (names == null) throw new ArgumentNullException("names", "names cannot be null."); - foreach (AttachmentKeyTuple key in attachments.Keys) - if (key.slotIndex == slotIndex) names.Add(key.name); - } - - public void FindAttachmentsForSlot (int slotIndex, List attachments) { - if (attachments == null) throw new ArgumentNullException("attachments", "attachments cannot be null."); - foreach (KeyValuePair entry in this.attachments) - if (entry.Key.slotIndex == slotIndex) attachments.Add(entry.Value); - } - - override public String ToString () { - return name; - } - - /// Attach all attachments from this skin if the corresponding attachment from the old skin is currently attached. - internal void AttachAll (Skeleton skeleton, Skin oldSkin) { - foreach (KeyValuePair entry in oldSkin.attachments) { - int slotIndex = entry.Key.slotIndex; - Slot slot = skeleton.slots.Items[slotIndex]; - if (slot.attachment == entry.Value) { - Attachment attachment = GetAttachment(slotIndex, entry.Key.name); - if (attachment != null) slot.Attachment = attachment; - } - } - } - - public struct AttachmentKeyTuple { - public readonly int slotIndex; - public readonly string name; - internal readonly int nameHashCode; - - public AttachmentKeyTuple (int slotIndex, string name) { - this.slotIndex = slotIndex; - this.name = name; - nameHashCode = this.name.GetHashCode(); - } - } - - // Avoids boxing in the dictionary. - class AttachmentKeyTupleComparer : IEqualityComparer { - internal static readonly AttachmentKeyTupleComparer Instance = new AttachmentKeyTupleComparer(); - - bool IEqualityComparer.Equals (AttachmentKeyTuple o1, AttachmentKeyTuple o2) { - return o1.slotIndex == o2.slotIndex && o1.nameHashCode == o2.nameHashCode && o1.name == o2.name; - } - - int IEqualityComparer.GetHashCode (AttachmentKeyTuple o) { - return o.slotIndex; - } - } - } +using System; +using System.Collections.Generic; + +namespace Spine { + /// Stores attachments by slot index and attachment name. + public class Skin { + internal String name; + private Dictionary attachments = + new Dictionary(AttachmentKeyTupleComparer.Instance); + + public String Name { get { return name; } } + public Dictionary Attachments { get { return attachments; } } + + public Skin (String name) { + if (name == null) throw new ArgumentNullException("name", "name cannot be null."); + this.name = name; + } + + public void AddAttachment (int slotIndex, String name, Attachment attachment) { + if (attachment == null) throw new ArgumentNullException("attachment", "attachment cannot be null."); + attachments[new AttachmentKeyTuple(slotIndex, name)] = attachment; + } + + /// May be null. + public Attachment GetAttachment (int slotIndex, String name) { + Attachment attachment; + attachments.TryGetValue(new AttachmentKeyTuple(slotIndex, name), out attachment); + return attachment; + } + + public void FindNamesForSlot (int slotIndex, List names) { + if (names == null) throw new ArgumentNullException("names", "names cannot be null."); + foreach (AttachmentKeyTuple key in attachments.Keys) + if (key.slotIndex == slotIndex) names.Add(key.name); + } + + public void FindAttachmentsForSlot (int slotIndex, List attachments) { + if (attachments == null) throw new ArgumentNullException("attachments", "attachments cannot be null."); + foreach (KeyValuePair entry in this.attachments) + if (entry.Key.slotIndex == slotIndex) attachments.Add(entry.Value); + } + + override public String ToString () { + return name; + } + + /// Attach all attachments from this skin if the corresponding attachment from the old skin is currently attached. + internal void AttachAll (Skeleton skeleton, Skin oldSkin) { + foreach (KeyValuePair entry in oldSkin.attachments) { + int slotIndex = entry.Key.slotIndex; + Slot slot = skeleton.slots.Items[slotIndex]; + if (slot.attachment == entry.Value) { + Attachment attachment = GetAttachment(slotIndex, entry.Key.name); + if (attachment != null) slot.Attachment = attachment; + } + } + } + + public struct AttachmentKeyTuple { + public readonly int slotIndex; + public readonly string name; + internal readonly int nameHashCode; + + public AttachmentKeyTuple (int slotIndex, string name) { + this.slotIndex = slotIndex; + this.name = name; + nameHashCode = this.name.GetHashCode(); + } + } + + // Avoids boxing in the dictionary. + class AttachmentKeyTupleComparer : IEqualityComparer { + internal static readonly AttachmentKeyTupleComparer Instance = new AttachmentKeyTupleComparer(); + + bool IEqualityComparer.Equals (AttachmentKeyTuple o1, AttachmentKeyTuple o2) { + return o1.slotIndex == o2.slotIndex && o1.nameHashCode == o2.nameHashCode && o1.name == o2.name; + } + + int IEqualityComparer.GetHashCode (AttachmentKeyTuple o) { + return o.slotIndex; + } + } + } } diff --git a/spine-csharp/src/Slot.cs b/spine-csharp/src/Slot.cs index 552264083f..e3041e5c06 100644 --- a/spine-csharp/src/Slot.cs +++ b/spine-csharp/src/Slot.cs @@ -1,94 +1,93 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - public class Slot { - internal SlotData data; - internal Bone bone; - internal float r, g, b, a; - internal Attachment attachment; - internal float attachmentTime; - internal ExposedList attachmentVertices = new ExposedList(); - - public SlotData Data { get { return data; } } - public Bone Bone { get { return bone; } } - public Skeleton Skeleton { get { return bone.skeleton; } } - public float R { get { return r; } set { r = value; } } - public float G { get { return g; } set { g = value; } } - public float B { get { return b; } set { b = value; } } - public float A { get { return a; } set { a = value; } } - - /// May be null. - public Attachment Attachment { - get { return attachment; } - set { - if (attachment == value) return; - attachment = value; - attachmentTime = bone.skeleton.time; - attachmentVertices.Clear(false); - } - } - - public float AttachmentTime { - get { return bone.skeleton.time - attachmentTime; } - set { attachmentTime = bone.skeleton.time - value; } - } - - public ExposedList AttachmentVertices { get { return attachmentVertices; } set { attachmentVertices = value; } } - - public Slot (SlotData data, Bone bone) { - if (data == null) throw new ArgumentNullException("data", "data cannot be null."); - if (bone == null) throw new ArgumentNullException("bone", "bone cannot be null."); - this.data = data; - this.bone = bone; - SetToSetupPose(); - } - - public void SetToSetupPose () { - r = data.r; - g = data.g; - b = data.b; - a = data.a; - if (data.attachmentName == null) - Attachment = null; - else { - attachment = null; - Attachment = bone.skeleton.GetAttachment(data.index, data.attachmentName); - } - } - - override public String ToString () { - return data.name; - } - } +using System; + +namespace Spine { + public class Slot { + internal SlotData data; + internal Bone bone; + internal float r, g, b, a; + internal Attachment attachment; + internal float attachmentTime; + internal ExposedList attachmentVertices = new ExposedList(); + + public SlotData Data { get { return data; } } + public Bone Bone { get { return bone; } } + public Skeleton Skeleton { get { return bone.skeleton; } } + public float R { get { return r; } set { r = value; } } + public float G { get { return g; } set { g = value; } } + public float B { get { return b; } set { b = value; } } + public float A { get { return a; } set { a = value; } } + + /// May be null. + public Attachment Attachment { + get { return attachment; } + set { + if (attachment == value) return; + attachment = value; + attachmentTime = bone.skeleton.time; + attachmentVertices.Clear(false); + } + } + + public float AttachmentTime { + get { return bone.skeleton.time - attachmentTime; } + set { attachmentTime = bone.skeleton.time - value; } + } + + public ExposedList AttachmentVertices { get { return attachmentVertices; } set { attachmentVertices = value; } } + + public Slot (SlotData data, Bone bone) { + if (data == null) throw new ArgumentNullException("data", "data cannot be null."); + if (bone == null) throw new ArgumentNullException("bone", "bone cannot be null."); + this.data = data; + this.bone = bone; + SetToSetupPose(); + } + + public void SetToSetupPose () { + r = data.r; + g = data.g; + b = data.b; + a = data.a; + if (data.attachmentName == null) + Attachment = null; + else { + attachment = null; + Attachment = bone.skeleton.GetAttachment(data.index, data.attachmentName); + } + } + + override public String ToString () { + return data.name; + } + } } diff --git a/spine-csharp/src/SlotData.cs b/spine-csharp/src/SlotData.cs index 0ba5631b86..2f0dca2700 100644 --- a/spine-csharp/src/SlotData.cs +++ b/spine-csharp/src/SlotData.cs @@ -1,67 +1,66 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - public class SlotData { - internal int index; - internal String name; - internal BoneData boneData; - internal float r = 1, g = 1, b = 1, a = 1; - internal String attachmentName; - internal BlendMode blendMode; - - public int Index { get { return index; } } - public String Name { get { return name; } } - public BoneData BoneData { get { return boneData; } } - public float R { get { return r; } set { r = value; } } - public float G { get { return g; } set { g = value; } } - public float B { get { return b; } set { b = value; } } - public float A { get { return a; } set { a = value; } } - /// May be null. - public String AttachmentName { get { return attachmentName; } set { attachmentName = value; } } - public BlendMode BlendMode { get { return blendMode; } set { blendMode = value; } } - - public SlotData (int index, String name, BoneData boneData) { - if (index < 0) throw new ArgumentException ("index must be >= 0.", "index"); - if (name == null) throw new ArgumentNullException("name", "name cannot be null."); - if (boneData == null) throw new ArgumentNullException("boneData", "boneData cannot be null."); - this.index = index; - this.name = name; - this.boneData = boneData; - } - - override public String ToString () { - return name; - } - } +using System; + +namespace Spine { + public class SlotData { + internal int index; + internal String name; + internal BoneData boneData; + internal float r = 1, g = 1, b = 1, a = 1; + internal String attachmentName; + internal BlendMode blendMode; + + public int Index { get { return index; } } + public String Name { get { return name; } } + public BoneData BoneData { get { return boneData; } } + public float R { get { return r; } set { r = value; } } + public float G { get { return g; } set { g = value; } } + public float B { get { return b; } set { b = value; } } + public float A { get { return a; } set { a = value; } } + /// May be null. + public String AttachmentName { get { return attachmentName; } set { attachmentName = value; } } + public BlendMode BlendMode { get { return blendMode; } set { blendMode = value; } } + + public SlotData (int index, String name, BoneData boneData) { + if (index < 0) throw new ArgumentException ("index must be >= 0.", "index"); + if (name == null) throw new ArgumentNullException("name", "name cannot be null."); + if (boneData == null) throw new ArgumentNullException("boneData", "boneData cannot be null."); + this.index = index; + this.name = name; + this.boneData = boneData; + } + + override public String ToString () { + return name; + } + } } diff --git a/spine-csharp/src/TransformConstraint.cs b/spine-csharp/src/TransformConstraint.cs index df83b9d086..ce35b7a67e 100644 --- a/spine-csharp/src/TransformConstraint.cs +++ b/spine-csharp/src/TransformConstraint.cs @@ -1,130 +1,129 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - public class TransformConstraint : IUpdatable { - internal TransformConstraintData data; - internal ExposedList bones; - internal Bone target; - internal float rotateMix, translateMix, scaleMix, shearMix; - - public TransformConstraintData Data { get { return data; } } - public ExposedList Bones { get { return bones; } } - public Bone Target { get { return target; } set { target = value; } } - public float RotateMix { get { return rotateMix; } set { rotateMix = value; } } - public float TranslateMix { get { return translateMix; } set { translateMix = value; } } - public float ScaleMix { get { return scaleMix; } set { scaleMix = value; } } - public float ShearMix { get { return shearMix; } set { shearMix = value; } } - - public TransformConstraint (TransformConstraintData data, Skeleton skeleton) { - if (data == null) throw new ArgumentNullException("data", "data cannot be null."); - if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null."); - this.data = data; - rotateMix = data.rotateMix; - translateMix = data.translateMix; - scaleMix = data.scaleMix; - shearMix = data.shearMix; - - bones = new ExposedList(); - foreach (BoneData boneData in data.bones) - bones.Add (skeleton.FindBone (boneData.name)); - - target = skeleton.FindBone(data.target.name); - } - - public void Apply () { - Update(); - } - - public void Update () { - float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; - Bone target = this.target; - float ta = target.a, tb = target.b, tc = target.c, td = target.d; - ExposedList bones = this.bones; - for (int i = 0, n = bones.Count; i < n; i++) { - Bone bone = bones.Items[i]; - - if (rotateMix > 0) { - float a = bone.a, b = bone.b, c = bone.c, d = bone.d; - float r = (float)Math.Atan2(tc, ta) - (float)Math.Atan2(c, a) + data.offsetRotation * MathUtils.degRad; - if (r > MathUtils.PI) - r -= MathUtils.PI2; - else if (r < -MathUtils.PI) r += MathUtils.PI2; - r *= rotateMix; - float cos = MathUtils.Cos(r), sin = MathUtils.Sin(r); - bone.a = cos * a - sin * c; - bone.b = cos * b - sin * d; - bone.c = sin * a + cos * c; - bone.d = sin * b + cos * d; - } - - if (translateMix > 0) { - float tempx, tempy; - target.LocalToWorld(data.offsetX, data.offsetY, out tempx, out tempy); - bone.worldX += (tempx - bone.worldX) * translateMix; - bone.worldY += (tempy - bone.worldY) * translateMix; - } - - if (scaleMix > 0) { - float bs = (float)Math.Sqrt(bone.a * bone.a + bone.c * bone.c); - float ts = (float)Math.Sqrt(ta * ta + tc * tc); - float s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleX) * scaleMix) / bs : 0; - bone.a *= s; - bone.c *= s; - bs = (float)Math.Sqrt(bone.b * bone.b + bone.d * bone.d); - ts = (float)Math.Sqrt(tb * tb + td * td); - s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleY) * scaleMix) / bs : 0; - bone.b *= s; - bone.d *= s; - } - - if (shearMix > 0) { - float b = bone.b, d = bone.d; - float by = MathUtils.Atan2(d, b); - float r = MathUtils.Atan2(td, tb) - MathUtils.Atan2(tc, ta) - (by - MathUtils.Atan2(bone.c, bone.a)); - if (r > MathUtils.PI) - r -= MathUtils.PI2; - else if (r < -MathUtils.PI) r += MathUtils.PI2; - r = by + (r + data.offsetShearY * MathUtils.degRad) * shearMix; - float s = (float)Math.Sqrt(b * b + d * d); - bone.b = MathUtils.Cos(r) * s; - bone.d = MathUtils.Sin(r) * s; - } - } - } - - override public String ToString () { - return data.name; - } - } +using System; + +namespace Spine { + public class TransformConstraint : IUpdatable { + internal TransformConstraintData data; + internal ExposedList bones; + internal Bone target; + internal float rotateMix, translateMix, scaleMix, shearMix; + + public TransformConstraintData Data { get { return data; } } + public ExposedList Bones { get { return bones; } } + public Bone Target { get { return target; } set { target = value; } } + public float RotateMix { get { return rotateMix; } set { rotateMix = value; } } + public float TranslateMix { get { return translateMix; } set { translateMix = value; } } + public float ScaleMix { get { return scaleMix; } set { scaleMix = value; } } + public float ShearMix { get { return shearMix; } set { shearMix = value; } } + + public TransformConstraint (TransformConstraintData data, Skeleton skeleton) { + if (data == null) throw new ArgumentNullException("data", "data cannot be null."); + if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null."); + this.data = data; + rotateMix = data.rotateMix; + translateMix = data.translateMix; + scaleMix = data.scaleMix; + shearMix = data.shearMix; + + bones = new ExposedList(); + foreach (BoneData boneData in data.bones) + bones.Add (skeleton.FindBone (boneData.name)); + + target = skeleton.FindBone(data.target.name); + } + + public void Apply () { + Update(); + } + + public void Update () { + float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; + Bone target = this.target; + float ta = target.a, tb = target.b, tc = target.c, td = target.d; + ExposedList bones = this.bones; + for (int i = 0, n = bones.Count; i < n; i++) { + Bone bone = bones.Items[i]; + + if (rotateMix > 0) { + float a = bone.a, b = bone.b, c = bone.c, d = bone.d; + float r = (float)Math.Atan2(tc, ta) - (float)Math.Atan2(c, a) + data.offsetRotation * MathUtils.degRad; + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) r += MathUtils.PI2; + r *= rotateMix; + float cos = MathUtils.Cos(r), sin = MathUtils.Sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + } + + if (translateMix > 0) { + float tempx, tempy; + target.LocalToWorld(data.offsetX, data.offsetY, out tempx, out tempy); + bone.worldX += (tempx - bone.worldX) * translateMix; + bone.worldY += (tempy - bone.worldY) * translateMix; + } + + if (scaleMix > 0) { + float bs = (float)Math.Sqrt(bone.a * bone.a + bone.c * bone.c); + float ts = (float)Math.Sqrt(ta * ta + tc * tc); + float s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleX) * scaleMix) / bs : 0; + bone.a *= s; + bone.c *= s; + bs = (float)Math.Sqrt(bone.b * bone.b + bone.d * bone.d); + ts = (float)Math.Sqrt(tb * tb + td * td); + s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleY) * scaleMix) / bs : 0; + bone.b *= s; + bone.d *= s; + } + + if (shearMix > 0) { + float b = bone.b, d = bone.d; + float by = MathUtils.Atan2(d, b); + float r = MathUtils.Atan2(td, tb) - MathUtils.Atan2(tc, ta) - (by - MathUtils.Atan2(bone.c, bone.a)); + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) r += MathUtils.PI2; + r = by + (r + data.offsetShearY * MathUtils.degRad) * shearMix; + float s = (float)Math.Sqrt(b * b + d * d); + bone.b = MathUtils.Cos(r) * s; + bone.d = MathUtils.Sin(r) * s; + } + } + } + + override public String ToString () { + return data.name; + } + } } diff --git a/spine-csharp/src/TransformConstraintData.cs b/spine-csharp/src/TransformConstraintData.cs index b4bba36ddb..e30d79f922 100644 --- a/spine-csharp/src/TransformConstraintData.cs +++ b/spine-csharp/src/TransformConstraintData.cs @@ -1,66 +1,65 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; - -namespace Spine { - public class TransformConstraintData { - internal String name; - internal ExposedList bones = new ExposedList(); - internal BoneData target; - internal float rotateMix, translateMix, scaleMix, shearMix; - internal float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY; - - public String Name { get { return name; } } - public ExposedList Bones { get { return bones; } } - public BoneData Target { get { return target; } set { target = value; } } - public float RotateMix { get { return rotateMix; } set { rotateMix = value; } } - public float TranslateMix { get { return translateMix; } set { translateMix = value; } } - public float ScaleMix { get { return scaleMix; } set { scaleMix = value; } } - public float ShearMix { get { return shearMix; } set { shearMix = value; } } - - public float OffsetRotation { get { return offsetRotation; } set { offsetRotation = value; } } - public float OffsetX { get { return offsetX; } set { offsetX = value; } } - public float OffsetY { get { return offsetY; } set { offsetY = value; } } - public float OffsetScaleX { get { return offsetScaleX; } set { offsetScaleX = value; } } - public float OffsetScaleY { get { return offsetScaleY; } set { offsetScaleY = value; } } - public float OffsetShearY { get { return offsetShearY; } set { offsetShearY = value; } } - - public TransformConstraintData (String name) { - if (name == null) throw new ArgumentNullException("name", "name cannot be null."); - this.name = name; - } - - override public String ToString () { - return name; - } - } +using System; + +namespace Spine { + public class TransformConstraintData { + internal String name; + internal ExposedList bones = new ExposedList(); + internal BoneData target; + internal float rotateMix, translateMix, scaleMix, shearMix; + internal float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY; + + public String Name { get { return name; } } + public ExposedList Bones { get { return bones; } } + public BoneData Target { get { return target; } set { target = value; } } + public float RotateMix { get { return rotateMix; } set { rotateMix = value; } } + public float TranslateMix { get { return translateMix; } set { translateMix = value; } } + public float ScaleMix { get { return scaleMix; } set { scaleMix = value; } } + public float ShearMix { get { return shearMix; } set { shearMix = value; } } + + public float OffsetRotation { get { return offsetRotation; } set { offsetRotation = value; } } + public float OffsetX { get { return offsetX; } set { offsetX = value; } } + public float OffsetY { get { return offsetY; } set { offsetY = value; } } + public float OffsetScaleX { get { return offsetScaleX; } set { offsetScaleX = value; } } + public float OffsetScaleY { get { return offsetScaleY; } set { offsetScaleY = value; } } + public float OffsetShearY { get { return offsetShearY; } set { offsetShearY = value; } } + + public TransformConstraintData (String name) { + if (name == null) throw new ArgumentNullException("name", "name cannot be null."); + this.name = name; + } + + override public String ToString () { + return name; + } + } } diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/AnimationStateTest.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/AnimationStateTest.java index 67503c58aa..26fb671078 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/AnimationStateTest.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/AnimationStateTest.java @@ -1,216 +1,215 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.Files.FileType; -import com.badlogic.gdx.backends.lwjgl.LwjglFileHandle; -import com.badlogic.gdx.utils.Array; -import com.esotericsoftware.spine.AnimationState.AnimationStateListener; -import com.esotericsoftware.spine.attachments.AttachmentLoader; -import com.esotericsoftware.spine.attachments.BoundingBoxAttachment; -import com.esotericsoftware.spine.attachments.RegionAttachment; -import com.esotericsoftware.spine.attachments.MeshAttachment; -import com.esotericsoftware.spine.attachments.PathAttachment; - -public class AnimationStateTest { - final SkeletonJson json = new SkeletonJson(new AttachmentLoader() { - public MeshAttachment newMeshAttachment (Skin skin, String name, String path) { - return null; - } - - public RegionAttachment newRegionAttachment (Skin skin, String name, String path) { - return null; - } - - public BoundingBoxAttachment newBoundingBoxAttachment (Skin skin, String name) { - return null; - } - - public PathAttachment newPathAttachment (Skin skin, String name) { - return null; - } - }); - - AnimationStateListener stateListener = new AnimationStateListener() { - public void start (int trackIndex) { - actual.add(new Result("start", null)); - } - - public void event (int trackIndex, Event event) { - actual.add(new Result("event", event.getString())); - } - - public void complete (int trackIndex, int loopCount) { - actual.add(new Result("complete", null)); - } - - public void end (int trackIndex) { - actual.add(new Result("end", null)); - } - }; - - final SkeletonData skeletonData; - final AnimationStateData stateData; - final Array actual = new Array(); - - public AnimationStateTest () { - skeletonData = json.readSkeletonData(new LwjglFileHandle("test/test.json", FileType.Internal)); - stateData = new AnimationStateData(skeletonData); - - AnimationState state; - - state = newState(); - state.setAnimation(0, "events", false); - test(state, 1 / 60f, 1000, // - new Result("start", null), // - new Result("event", "0"), // - new Result("event", "14"), // - new Result("event", "30"), // - new Result("complete", null), // - new Result("end", null) // - ); - - state = newState(); - state.setAnimation(0, "events", false); - test(state, 30, 1000, // - new Result("start", null), // - new Result("event", "0"), // - new Result("event", "14"), // - new Result("event", "30"), // - new Result("complete", null), // - new Result("end", null) // - ); - - state = newState(); - state.setAnimation(0, "events", false); - test(state, 1, 1.01f, // - new Result("start", null), // - new Result("event", "0"), // - new Result("event", "14"), // - new Result("event", "30"), // - new Result("complete", null), // - new Result("end", null) // - ); - - state = newState(); - state.setAnimation(0, "events", false); - state.addAnimation(0, "events", false, 0); - test(state, 0.1f, 3f, // - new Result("start", null), // - new Result("event", "0"), // - new Result("event", "14"), // - new Result("event", "30"), // - new Result("complete", null), // - new Result("end", null), // - new Result("start", null), // - new Result("event", "0"), // - new Result("event", "14"), // - new Result("event", "30"), // - new Result("complete", null), // - new Result("end", null) // - ); - } - - private AnimationState newState () { - AnimationState state = new AnimationState(stateData); - state.addListener(stateListener); - return state; - } - - private void test (AnimationState state, float incr, float endTime, Result... expectedArray) { - Array expected = new Array(expectedArray); - - Skeleton skeleton = new Skeleton(skeletonData); - - for (int i = 0; i < endTime; i++) { - skeleton.update(incr); - state.update(incr); - state.apply(skeleton); - } - - if (expected.equals(actual)) { - actual.clear(); - return; - } - int i = 0; - for (int n = expected.size; i < n; i++) { - System.out.print(expected.get(i) + " == " + (i < actual.size ? actual.get(i) : "")); - if (i >= actual.size || !actual.get(i).equals(expected.get(i))) - System.out.println(" <- FAIL"); - else - System.out.println(); - } - for (int n = actual.size; i < n; i++) - System.out.print(" == " + actual.get(i) + " <- FAIL"); - System.exit(0); - } - - static public class Result { - String eventName; - String payload; - - public Result (String eventName, String payload) { - this.eventName = eventName; - this.payload = payload; - } - - public int hashCode () { - final int prime = 31; - int result = 1; - result = prime * result + ((eventName == null) ? 0 : eventName.hashCode()); - result = prime * result + ((payload == null) ? 0 : payload.hashCode()); - return result; - } - - public boolean equals (Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - Result other = (Result)obj; - if (eventName == null) { - if (other.eventName != null) return false; - } else if (!eventName.equals(other.eventName)) return false; - if (payload == null) { - if (other.payload != null) return false; - } else if (!payload.equals(other.payload)) return false; - return true; - } - - public String toString () { - return "[" + eventName + ", " + payload + "]"; - } - } - - static public void main (String[] args) throws Exception { - new AnimationStateTest(); - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.Files.FileType; +import com.badlogic.gdx.backends.lwjgl.LwjglFileHandle; +import com.badlogic.gdx.utils.Array; +import com.esotericsoftware.spine.AnimationState.AnimationStateListener; +import com.esotericsoftware.spine.attachments.AttachmentLoader; +import com.esotericsoftware.spine.attachments.BoundingBoxAttachment; +import com.esotericsoftware.spine.attachments.RegionAttachment; +import com.esotericsoftware.spine.attachments.MeshAttachment; +import com.esotericsoftware.spine.attachments.PathAttachment; + +public class AnimationStateTest { + final SkeletonJson json = new SkeletonJson(new AttachmentLoader() { + public MeshAttachment newMeshAttachment (Skin skin, String name, String path) { + return null; + } + + public RegionAttachment newRegionAttachment (Skin skin, String name, String path) { + return null; + } + + public BoundingBoxAttachment newBoundingBoxAttachment (Skin skin, String name) { + return null; + } + + public PathAttachment newPathAttachment (Skin skin, String name) { + return null; + } + }); + + AnimationStateListener stateListener = new AnimationStateListener() { + public void start (int trackIndex) { + actual.add(new Result("start", null)); + } + + public void event (int trackIndex, Event event) { + actual.add(new Result("event", event.getString())); + } + + public void complete (int trackIndex, int loopCount) { + actual.add(new Result("complete", null)); + } + + public void end (int trackIndex) { + actual.add(new Result("end", null)); + } + }; + + final SkeletonData skeletonData; + final AnimationStateData stateData; + final Array actual = new Array(); + + public AnimationStateTest () { + skeletonData = json.readSkeletonData(new LwjglFileHandle("test/test.json", FileType.Internal)); + stateData = new AnimationStateData(skeletonData); + + AnimationState state; + + state = newState(); + state.setAnimation(0, "events", false); + test(state, 1 / 60f, 1000, // + new Result("start", null), // + new Result("event", "0"), // + new Result("event", "14"), // + new Result("event", "30"), // + new Result("complete", null), // + new Result("end", null) // + ); + + state = newState(); + state.setAnimation(0, "events", false); + test(state, 30, 1000, // + new Result("start", null), // + new Result("event", "0"), // + new Result("event", "14"), // + new Result("event", "30"), // + new Result("complete", null), // + new Result("end", null) // + ); + + state = newState(); + state.setAnimation(0, "events", false); + test(state, 1, 1.01f, // + new Result("start", null), // + new Result("event", "0"), // + new Result("event", "14"), // + new Result("event", "30"), // + new Result("complete", null), // + new Result("end", null) // + ); + + state = newState(); + state.setAnimation(0, "events", false); + state.addAnimation(0, "events", false, 0); + test(state, 0.1f, 3f, // + new Result("start", null), // + new Result("event", "0"), // + new Result("event", "14"), // + new Result("event", "30"), // + new Result("complete", null), // + new Result("end", null), // + new Result("start", null), // + new Result("event", "0"), // + new Result("event", "14"), // + new Result("event", "30"), // + new Result("complete", null), // + new Result("end", null) // + ); + } + + private AnimationState newState () { + AnimationState state = new AnimationState(stateData); + state.addListener(stateListener); + return state; + } + + private void test (AnimationState state, float incr, float endTime, Result... expectedArray) { + Array expected = new Array(expectedArray); + + Skeleton skeleton = new Skeleton(skeletonData); + + for (int i = 0; i < endTime; i++) { + skeleton.update(incr); + state.update(incr); + state.apply(skeleton); + } + + if (expected.equals(actual)) { + actual.clear(); + return; + } + int i = 0; + for (int n = expected.size; i < n; i++) { + System.out.print(expected.get(i) + " == " + (i < actual.size ? actual.get(i) : "")); + if (i >= actual.size || !actual.get(i).equals(expected.get(i))) + System.out.println(" <- FAIL"); + else + System.out.println(); + } + for (int n = actual.size; i < n; i++) + System.out.print(" == " + actual.get(i) + " <- FAIL"); + System.exit(0); + } + + static public class Result { + String eventName; + String payload; + + public Result (String eventName, String payload) { + this.eventName = eventName; + this.payload = payload; + } + + public int hashCode () { + final int prime = 31; + int result = 1; + result = prime * result + ((eventName == null) ? 0 : eventName.hashCode()); + result = prime * result + ((payload == null) ? 0 : payload.hashCode()); + return result; + } + + public boolean equals (Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + Result other = (Result)obj; + if (eventName == null) { + if (other.eventName != null) return false; + } else if (!eventName.equals(other.eventName)) return false; + if (payload == null) { + if (other.payload != null) return false; + } else if (!payload.equals(other.payload)) return false; + return true; + } + + public String toString () { + return "[" + eventName + ", " + payload + "]"; + } + } + + static public void main (String[] args) throws Exception { + new AnimationStateTest(); + } } diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/AttachmentTimelineTests.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/AttachmentTimelineTests.java index 2b3cdaa7a4..d1efab0b93 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/AttachmentTimelineTests.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/AttachmentTimelineTests.java @@ -1,102 +1,101 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.utils.Array; -import com.esotericsoftware.spine.Animation.AttachmentTimeline; -import com.esotericsoftware.spine.Animation.Timeline; -import com.esotericsoftware.spine.attachments.Attachment; - -/** Unit tests for {@link AttachmentTimeline}. */ -public class AttachmentTimelineTests { - private final SkeletonData skeletonData; - private final Skeleton skeleton; - private Slot slot; - private AnimationState state; - - public AttachmentTimelineTests () { - skeletonData = new SkeletonData(); - - BoneData boneData = new BoneData(0, "bone", null); - skeletonData.getBones().add(boneData); - - skeletonData.getSlots().add(new SlotData(0, "slot", boneData)); - - Attachment attachment1 = new Attachment("attachment1") {}; - Attachment attachment2 = new Attachment("attachment2") {}; - - Skin skin = new Skin("skin"); - skin.addAttachment(0, "attachment1", attachment1); - skin.addAttachment(0, "attachment2", attachment2); - skeletonData.setDefaultSkin(skin); - - skeleton = new Skeleton(skeletonData); - slot = skeleton.findSlot("slot"); - - AttachmentTimeline timeline = new AttachmentTimeline(2); - timeline.setFrame(0, 0, "attachment1"); - timeline.setFrame(1, 0.5f, "attachment2"); - - Animation animation = new Animation("animation", Array.with((Timeline)timeline), 1); - animation.setDuration(1); - - state = new AnimationState(new AnimationStateData(skeletonData)); - state.setAnimation(0, animation, true); - - test(0, attachment1); - test(0, attachment1); - test(0.25f, attachment1); - test(0f, attachment1); - test(0.25f, attachment2); - test(0.25f, attachment2); - - System.out.println("AttachmentTimeline tests passed."); - } - - private void test (float delta, Attachment attachment) { - state.update(delta); - state.apply(skeleton); - if (slot.getAttachment() != attachment) - throw new FailException("Wrong attachment: " + slot.getAttachment() + " != " + attachment); - - } - - static class FailException extends RuntimeException { - public FailException (String message) { - super(message); - } - } - - static public void main (String[] args) throws Exception { - new AttachmentTimelineTests(); - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.utils.Array; +import com.esotericsoftware.spine.Animation.AttachmentTimeline; +import com.esotericsoftware.spine.Animation.Timeline; +import com.esotericsoftware.spine.attachments.Attachment; + +/** Unit tests for {@link AttachmentTimeline}. */ +public class AttachmentTimelineTests { + private final SkeletonData skeletonData; + private final Skeleton skeleton; + private Slot slot; + private AnimationState state; + + public AttachmentTimelineTests () { + skeletonData = new SkeletonData(); + + BoneData boneData = new BoneData(0, "bone", null); + skeletonData.getBones().add(boneData); + + skeletonData.getSlots().add(new SlotData(0, "slot", boneData)); + + Attachment attachment1 = new Attachment("attachment1") {}; + Attachment attachment2 = new Attachment("attachment2") {}; + + Skin skin = new Skin("skin"); + skin.addAttachment(0, "attachment1", attachment1); + skin.addAttachment(0, "attachment2", attachment2); + skeletonData.setDefaultSkin(skin); + + skeleton = new Skeleton(skeletonData); + slot = skeleton.findSlot("slot"); + + AttachmentTimeline timeline = new AttachmentTimeline(2); + timeline.setFrame(0, 0, "attachment1"); + timeline.setFrame(1, 0.5f, "attachment2"); + + Animation animation = new Animation("animation", Array.with((Timeline)timeline), 1); + animation.setDuration(1); + + state = new AnimationState(new AnimationStateData(skeletonData)); + state.setAnimation(0, animation, true); + + test(0, attachment1); + test(0, attachment1); + test(0.25f, attachment1); + test(0f, attachment1); + test(0.25f, attachment2); + test(0.25f, attachment2); + + System.out.println("AttachmentTimeline tests passed."); + } + + private void test (float delta, Attachment attachment) { + state.update(delta); + state.apply(skeleton); + if (slot.getAttachment() != attachment) + throw new FailException("Wrong attachment: " + slot.getAttachment() + " != " + attachment); + + } + + static class FailException extends RuntimeException { + public FailException (String message) { + super(message); + } + } + + static public void main (String[] args) throws Exception { + new AttachmentTimelineTests(); + } } diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/BonePlotting.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/BonePlotting.java index b96161237c..fe80ebfa9e 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/BonePlotting.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/BonePlotting.java @@ -1,76 +1,75 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.files.FileHandle; -import com.esotericsoftware.spine.attachments.AttachmentLoader; -import com.esotericsoftware.spine.attachments.BoundingBoxAttachment; -import com.esotericsoftware.spine.attachments.RegionAttachment; -import com.esotericsoftware.spine.attachments.MeshAttachment; -import com.esotericsoftware.spine.attachments.PathAttachment; - -public class BonePlotting { - static public void main (String[] args) throws Exception { - // This example shows how to load skeleton data and plot a bone transform for each animation. - SkeletonJson json = new SkeletonJson(new AttachmentLoader() { - public RegionAttachment newRegionAttachment (Skin skin, String name, String path) { - return null; - } - - public MeshAttachment newMeshAttachment (Skin skin, String name, String path) { - return null; - } - - public BoundingBoxAttachment newBoundingBoxAttachment (Skin skin, String name) { - return null; - } - - public PathAttachment newPathAttachment (Skin skin, String name) { - return null; - } - }); - SkeletonData skeletonData = json.readSkeletonData(new FileHandle("assets/spineboy/spineboy.json")); - Skeleton skeleton = new Skeleton(skeletonData); - Bone bone = skeleton.findBone("gunTip"); - float fps = 1 / 15f; - for (Animation animation : skeletonData.getAnimations()) { - float time = 0; - while (time < animation.getDuration()) { - animation.apply(skeleton, time, time, false, null); - skeleton.updateWorldTransform(); - System.out - .println(animation.getName() + "," + bone.getWorldX() + "," + bone.getWorldY() + "," + bone.getWorldRotationX()); - time += fps; - } - } - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.files.FileHandle; +import com.esotericsoftware.spine.attachments.AttachmentLoader; +import com.esotericsoftware.spine.attachments.BoundingBoxAttachment; +import com.esotericsoftware.spine.attachments.RegionAttachment; +import com.esotericsoftware.spine.attachments.MeshAttachment; +import com.esotericsoftware.spine.attachments.PathAttachment; + +public class BonePlotting { + static public void main (String[] args) throws Exception { + // This example shows how to load skeleton data and plot a bone transform for each animation. + SkeletonJson json = new SkeletonJson(new AttachmentLoader() { + public RegionAttachment newRegionAttachment (Skin skin, String name, String path) { + return null; + } + + public MeshAttachment newMeshAttachment (Skin skin, String name, String path) { + return null; + } + + public BoundingBoxAttachment newBoundingBoxAttachment (Skin skin, String name) { + return null; + } + + public PathAttachment newPathAttachment (Skin skin, String name) { + return null; + } + }); + SkeletonData skeletonData = json.readSkeletonData(new FileHandle("assets/spineboy/spineboy.json")); + Skeleton skeleton = new Skeleton(skeletonData); + Bone bone = skeleton.findBone("gunTip"); + float fps = 1 / 15f; + for (Animation animation : skeletonData.getAnimations()) { + float time = 0; + while (time < animation.getDuration()) { + animation.apply(skeleton, time, time, false, null); + skeleton.updateWorldTransform(); + System.out + .println(animation.getName() + "," + bone.getWorldX() + "," + bone.getWorldY() + "," + bone.getWorldRotationX()); + time += fps; + } + } + } } diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/Box2DExample.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/Box2DExample.java index b1b1c6b73b..66c790d0d5 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/Box2DExample.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/Box2DExample.java @@ -1,250 +1,249 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader; -import com.esotericsoftware.spine.attachments.RegionAttachment; - -import com.badlogic.gdx.ApplicationAdapter; -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.backends.lwjgl.LwjglApplication; -import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.OrthographicCamera; -import com.badlogic.gdx.graphics.g2d.SpriteBatch; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion; -import com.badlogic.gdx.graphics.glutils.ShapeRenderer; -import com.badlogic.gdx.math.MathUtils; -import com.badlogic.gdx.math.Matrix4; -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.physics.box2d.Body; -import com.badlogic.gdx.physics.box2d.BodyDef; -import com.badlogic.gdx.physics.box2d.BodyDef.BodyType; -import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer; -import com.badlogic.gdx.physics.box2d.FixtureDef; -import com.badlogic.gdx.physics.box2d.PolygonShape; -import com.badlogic.gdx.physics.box2d.World; -import com.badlogic.gdx.utils.Array; - -public class Box2DExample extends ApplicationAdapter { - SpriteBatch batch; - ShapeRenderer renderer; - SkeletonRenderer skeletonRenderer; - - TextureAtlas atlas; - Skeleton skeleton; - Animation animation; - float time; - Array events = new Array(); - - OrthographicCamera camera; - Box2DDebugRenderer box2dRenderer; - World world; - Body groundBody; - Matrix4 transform = new Matrix4(); - Vector2 vector = new Vector2(); - - public void create () { - batch = new SpriteBatch(); - renderer = new ShapeRenderer(); - skeletonRenderer = new SkeletonRenderer(); - skeletonRenderer.setPremultipliedAlpha(true); - - atlas = new TextureAtlas(Gdx.files.internal("spineboy/spineboy-pma.atlas")); - - // This loader creates Box2dAttachments instead of RegionAttachments for an easy way to keep - // track of the Box2D body for each attachment. - AtlasAttachmentLoader atlasLoader = new AtlasAttachmentLoader(atlas) { - public RegionAttachment newRegionAttachment (Skin skin, String name, String path) { - Box2dAttachment attachment = new Box2dAttachment(name); - AtlasRegion region = atlas.findRegion(attachment.getName()); - if (region == null) throw new RuntimeException("Region not found in atlas: " + attachment); - attachment.setRegion(region); - return attachment; - } - }; - SkeletonJson json = new SkeletonJson(atlasLoader); - json.setScale(0.6f * 0.05f); - SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("spineboy/spineboy.json")); - animation = skeletonData.findAnimation("walk"); - - skeleton = new Skeleton(skeletonData); - skeleton.x = -32; - skeleton.y = 1; - skeleton.updateWorldTransform(); - - // See Box2DTest in libgdx for more detailed information about Box2D setup. - camera = new OrthographicCamera(48, 32); - camera.position.set(0, 16, 0); - box2dRenderer = new Box2DDebugRenderer(); - createWorld(); - - // Create a body for each attachment. Note it is probably better to create just a few bodies rather than one for each - // region attachment, but this is just an example. - for (Slot slot : skeleton.getSlots()) { - if (!(slot.getAttachment() instanceof Box2dAttachment)) continue; - Box2dAttachment attachment = (Box2dAttachment)slot.getAttachment(); - - PolygonShape boxPoly = new PolygonShape(); - boxPoly.setAsBox(attachment.getWidth() / 2 * attachment.getScaleX(), - attachment.getHeight() / 2 * attachment.getScaleY(), vector.set(attachment.getX(), attachment.getY()), - attachment.getRotation() * MathUtils.degRad); - - BodyDef boxBodyDef = new BodyDef(); - boxBodyDef.type = BodyType.StaticBody; - attachment.body = world.createBody(boxBodyDef); - attachment.body.createFixture(boxPoly, 1); - - boxPoly.dispose(); - } - } - - public void render () { - float delta = Gdx.graphics.getDeltaTime(); - float remaining = delta; - while (remaining > 0) { - float d = Math.min(0.016f, remaining); - world.step(d, 8, 3); - time += d; - remaining -= d; - } - - camera.update(); - - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); - batch.setProjectionMatrix(camera.projection); - batch.setTransformMatrix(camera.view); - batch.begin(); - - animation.apply(skeleton, time, time, true, events); - skeleton.x += 8 * delta; - skeleton.updateWorldTransform(); - skeletonRenderer.draw(batch, skeleton); - - batch.end(); - - // Position each attachment body. - for (Slot slot : skeleton.getSlots()) { - if (!(slot.getAttachment() instanceof Box2dAttachment)) continue; - Box2dAttachment attachment = (Box2dAttachment)slot.getAttachment(); - if (attachment.body == null) continue; - float x = skeleton.x + slot.getBone().getWorldX(); - float y = skeleton.y + slot.getBone().getWorldY(); - float rotation = slot.getBone().getWorldRotationX(); - attachment.body.setTransform(x, y, rotation * MathUtils.degRad); - } - - box2dRenderer.render(world, camera.combined); - } - - public void resize (int width, int height) { - batch.setProjectionMatrix(camera.projection); - renderer.setProjectionMatrix(camera.projection); - } - - private void createWorld () { - world = new World(new Vector2(0, -10), true); - - float[] vertices = {-0.07421887f, -0.16276085f, -0.12109375f, -0.22786504f, -0.157552f, -0.7122401f, 0.04296875f, - -0.7122401f, 0.110677004f, -0.6419276f, 0.13151026f, -0.49869835f, 0.08984375f, -0.3190109f}; - - PolygonShape shape = new PolygonShape(); - shape.set(vertices); - - // next we create a static ground platform. This platform - // is not moveable and will not react to any influences from - // outside. It will however influence other bodies. First we - // create a PolygonShape that holds the form of the platform. - // it will be 100 meters wide and 2 meters high, centered - // around the origin - PolygonShape groundPoly = new PolygonShape(); - groundPoly.setAsBox(50, 1); - - // next we create the body for the ground platform. It's - // simply a static body. - BodyDef groundBodyDef = new BodyDef(); - groundBodyDef.type = BodyType.StaticBody; - groundBody = world.createBody(groundBodyDef); - - // finally we add a fixture to the body using the polygon - // defined above. Note that we have to dispose PolygonShapes - // and CircleShapes once they are no longer used. This is the - // only time you have to care explicitely for memomry managment. - FixtureDef fixtureDef = new FixtureDef(); - fixtureDef.shape = groundPoly; - fixtureDef.filter.groupIndex = 0; - groundBody.createFixture(fixtureDef); - groundPoly.dispose(); - - PolygonShape boxPoly = new PolygonShape(); - boxPoly.setAsBox(1, 1); - - // Next we create the 50 box bodies using the PolygonShape we just - // defined. This process is similar to the one we used for the ground - // body. Note that we reuse the polygon for each body fixture. - for (int i = 0; i < 45; i++) { - // Create the BodyDef, set a random position above the - // ground and create a new body - BodyDef boxBodyDef = new BodyDef(); - boxBodyDef.type = BodyType.DynamicBody; - boxBodyDef.position.x = -24 + (float)(Math.random() * 48); - boxBodyDef.position.y = 10 + (float)(Math.random() * 100); - Body boxBody = world.createBody(boxBodyDef); - - boxBody.createFixture(boxPoly, 1); - } - - // we are done, all that's left is disposing the boxPoly - boxPoly.dispose(); - } - - public void dispose () { - atlas.dispose(); - } - - static class Box2dAttachment extends RegionAttachment { - Body body; - - public Box2dAttachment (String name) { - super(name); - } - } - - public static void main (String[] args) throws Exception { - LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); - config.title = "Box2D - Spine"; - config.width = 640; - config.height = 480; - new LwjglApplication(new Box2DExample(), config); - } +package com.esotericsoftware.spine; + +import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader; +import com.esotericsoftware.spine.attachments.RegionAttachment; + +import com.badlogic.gdx.ApplicationAdapter; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.backends.lwjgl.LwjglApplication; +import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.math.Matrix4; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.Body; +import com.badlogic.gdx.physics.box2d.BodyDef; +import com.badlogic.gdx.physics.box2d.BodyDef.BodyType; +import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer; +import com.badlogic.gdx.physics.box2d.FixtureDef; +import com.badlogic.gdx.physics.box2d.PolygonShape; +import com.badlogic.gdx.physics.box2d.World; +import com.badlogic.gdx.utils.Array; + +public class Box2DExample extends ApplicationAdapter { + SpriteBatch batch; + ShapeRenderer renderer; + SkeletonRenderer skeletonRenderer; + + TextureAtlas atlas; + Skeleton skeleton; + Animation animation; + float time; + Array events = new Array(); + + OrthographicCamera camera; + Box2DDebugRenderer box2dRenderer; + World world; + Body groundBody; + Matrix4 transform = new Matrix4(); + Vector2 vector = new Vector2(); + + public void create () { + batch = new SpriteBatch(); + renderer = new ShapeRenderer(); + skeletonRenderer = new SkeletonRenderer(); + skeletonRenderer.setPremultipliedAlpha(true); + + atlas = new TextureAtlas(Gdx.files.internal("spineboy/spineboy-pma.atlas")); + + // This loader creates Box2dAttachments instead of RegionAttachments for an easy way to keep + // track of the Box2D body for each attachment. + AtlasAttachmentLoader atlasLoader = new AtlasAttachmentLoader(atlas) { + public RegionAttachment newRegionAttachment (Skin skin, String name, String path) { + Box2dAttachment attachment = new Box2dAttachment(name); + AtlasRegion region = atlas.findRegion(attachment.getName()); + if (region == null) throw new RuntimeException("Region not found in atlas: " + attachment); + attachment.setRegion(region); + return attachment; + } + }; + SkeletonJson json = new SkeletonJson(atlasLoader); + json.setScale(0.6f * 0.05f); + SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("spineboy/spineboy.json")); + animation = skeletonData.findAnimation("walk"); + + skeleton = new Skeleton(skeletonData); + skeleton.x = -32; + skeleton.y = 1; + skeleton.updateWorldTransform(); + + // See Box2DTest in libgdx for more detailed information about Box2D setup. + camera = new OrthographicCamera(48, 32); + camera.position.set(0, 16, 0); + box2dRenderer = new Box2DDebugRenderer(); + createWorld(); + + // Create a body for each attachment. Note it is probably better to create just a few bodies rather than one for each + // region attachment, but this is just an example. + for (Slot slot : skeleton.getSlots()) { + if (!(slot.getAttachment() instanceof Box2dAttachment)) continue; + Box2dAttachment attachment = (Box2dAttachment)slot.getAttachment(); + + PolygonShape boxPoly = new PolygonShape(); + boxPoly.setAsBox(attachment.getWidth() / 2 * attachment.getScaleX(), + attachment.getHeight() / 2 * attachment.getScaleY(), vector.set(attachment.getX(), attachment.getY()), + attachment.getRotation() * MathUtils.degRad); + + BodyDef boxBodyDef = new BodyDef(); + boxBodyDef.type = BodyType.StaticBody; + attachment.body = world.createBody(boxBodyDef); + attachment.body.createFixture(boxPoly, 1); + + boxPoly.dispose(); + } + } + + public void render () { + float delta = Gdx.graphics.getDeltaTime(); + float remaining = delta; + while (remaining > 0) { + float d = Math.min(0.016f, remaining); + world.step(d, 8, 3); + time += d; + remaining -= d; + } + + camera.update(); + + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + batch.setProjectionMatrix(camera.projection); + batch.setTransformMatrix(camera.view); + batch.begin(); + + animation.apply(skeleton, time, time, true, events); + skeleton.x += 8 * delta; + skeleton.updateWorldTransform(); + skeletonRenderer.draw(batch, skeleton); + + batch.end(); + + // Position each attachment body. + for (Slot slot : skeleton.getSlots()) { + if (!(slot.getAttachment() instanceof Box2dAttachment)) continue; + Box2dAttachment attachment = (Box2dAttachment)slot.getAttachment(); + if (attachment.body == null) continue; + float x = skeleton.x + slot.getBone().getWorldX(); + float y = skeleton.y + slot.getBone().getWorldY(); + float rotation = slot.getBone().getWorldRotationX(); + attachment.body.setTransform(x, y, rotation * MathUtils.degRad); + } + + box2dRenderer.render(world, camera.combined); + } + + public void resize (int width, int height) { + batch.setProjectionMatrix(camera.projection); + renderer.setProjectionMatrix(camera.projection); + } + + private void createWorld () { + world = new World(new Vector2(0, -10), true); + + float[] vertices = {-0.07421887f, -0.16276085f, -0.12109375f, -0.22786504f, -0.157552f, -0.7122401f, 0.04296875f, + -0.7122401f, 0.110677004f, -0.6419276f, 0.13151026f, -0.49869835f, 0.08984375f, -0.3190109f}; + + PolygonShape shape = new PolygonShape(); + shape.set(vertices); + + // next we create a static ground platform. This platform + // is not moveable and will not react to any influences from + // outside. It will however influence other bodies. First we + // create a PolygonShape that holds the form of the platform. + // it will be 100 meters wide and 2 meters high, centered + // around the origin + PolygonShape groundPoly = new PolygonShape(); + groundPoly.setAsBox(50, 1); + + // next we create the body for the ground platform. It's + // simply a static body. + BodyDef groundBodyDef = new BodyDef(); + groundBodyDef.type = BodyType.StaticBody; + groundBody = world.createBody(groundBodyDef); + + // finally we add a fixture to the body using the polygon + // defined above. Note that we have to dispose PolygonShapes + // and CircleShapes once they are no longer used. This is the + // only time you have to care explicitely for memomry managment. + FixtureDef fixtureDef = new FixtureDef(); + fixtureDef.shape = groundPoly; + fixtureDef.filter.groupIndex = 0; + groundBody.createFixture(fixtureDef); + groundPoly.dispose(); + + PolygonShape boxPoly = new PolygonShape(); + boxPoly.setAsBox(1, 1); + + // Next we create the 50 box bodies using the PolygonShape we just + // defined. This process is similar to the one we used for the ground + // body. Note that we reuse the polygon for each body fixture. + for (int i = 0; i < 45; i++) { + // Create the BodyDef, set a random position above the + // ground and create a new body + BodyDef boxBodyDef = new BodyDef(); + boxBodyDef.type = BodyType.DynamicBody; + boxBodyDef.position.x = -24 + (float)(Math.random() * 48); + boxBodyDef.position.y = 10 + (float)(Math.random() * 100); + Body boxBody = world.createBody(boxBodyDef); + + boxBody.createFixture(boxPoly, 1); + } + + // we are done, all that's left is disposing the boxPoly + boxPoly.dispose(); + } + + public void dispose () { + atlas.dispose(); + } + + static class Box2dAttachment extends RegionAttachment { + Body body; + + public Box2dAttachment (String name) { + super(name); + } + } + + public static void main (String[] args) throws Exception { + LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); + config.title = "Box2D - Spine"; + config.width = 640; + config.height = 480; + new LwjglApplication(new Box2DExample(), config); + } } diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/EventTimelineTests.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/EventTimelineTests.java index 9c146485ec..e5526acc14 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/EventTimelineTests.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/EventTimelineTests.java @@ -1,228 +1,227 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.esotericsoftware.spine.Animation.EventTimeline; - -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.StringBuilder; - -import java.util.Arrays; - -/** Unit tests for {@link EventTimeline}. */ -public class EventTimelineTests { - private final SkeletonData skeletonData; - private final Skeleton skeleton; - private final Array firedEvents = new Array(); - private EventTimeline timeline = new EventTimeline(0); - private char[] events; - private float[] frames; - - public EventTimelineTests () { - skeletonData = new SkeletonData(); - skeleton = new Skeleton(skeletonData); - - test(0); - test(1); - test(1, 1); - test(1, 2); - test(1, 2); - test(1, 2, 3); - test(1, 2, 3); - test(0, 0, 0); - test(0, 0, 1); - test(0, 1, 1); - test(1, 1, 1); - test(1, 2, 3, 4); - test(0, 2, 3, 4); - test(0, 2, 2, 4); - test(0, 0, 0, 0); - test(2, 2, 2, 2); - test(0.1f); - test(0.1f, 0.1f); - test(0.1f, 50f); - test(0.1f, 0.2f, 0.3f, 0.4f); - test(1, 2, 3, 4, 5, 6, 6, 7, 7, 8, 9, 10, 11, 11.01f, 12, 12, 12, 12); - - System.out.println("EventTimeline tests passed."); - } - - private void test (float... frames) { - int eventCount = frames.length; - - StringBuilder buffer = new StringBuilder(); - for (int i = 0; i < eventCount; i++) - buffer.append((char)('a' + i)); - - this.events = buffer.toString().toCharArray(); - this.frames = frames; - timeline = new EventTimeline(eventCount); - - float maxFrame = 0; - int distinctCount = 0; - float lastFrame = -1; - for (int i = 0; i < eventCount; i++) { - float frame = frames[i]; - Event event = new Event(frame, new EventData("" + events[i])); - timeline.setFrame(i, event); - maxFrame = Math.max(maxFrame, frame); - if (lastFrame != frame) distinctCount++; - lastFrame = frame; - } - - run(0, 99, 0.1f); - run(0, maxFrame, 0.1f); - run(frames[0], 999, 2f); - run(frames[0], maxFrame, 0.1f); - run(0, maxFrame, (float)Math.ceil(maxFrame / 100)); - run(0, 99, 0.1f); - run(0, 999, 100f); - if (distinctCount > 1) { - float epsilon = 0.02f; - // Ending before last. - run(frames[0], maxFrame - epsilon, 0.1f); - run(0, maxFrame - epsilon, 0.1f); - // Starting after first. - run(frames[0] + epsilon, maxFrame, 0.1f); - run(frames[0] + epsilon, 99, 0.1f); - } - } - - private void run (float startTime, float endTime, float timeStep) { - timeStep = Math.max(timeStep, 0.00001f); - boolean loop = false; - try { - fire(startTime, endTime, timeStep, loop, false); - loop = true; - fire(startTime, endTime, timeStep, loop, false); - } catch (FailException ignored) { - try { - fire(startTime, endTime, timeStep, loop, true); - } catch (FailException ex) { - System.out.println(ex.getMessage()); - System.exit(0); - } - } - } - - private void fire (float timeStart, float timeEnd, float timeStep, boolean loop, boolean print) { - if (print) { - System.out.println("events: " + Arrays.toString(events)); - System.out.println("frames: " + Arrays.toString(frames)); - System.out.println("timeStart: " + timeStart); - System.out.println("timeEnd: " + timeEnd); - System.out.println("timeStep: " + timeStep); - System.out.println("loop: " + loop); - } - - // Expected starting event. - int eventIndex = 0; - while (frames[eventIndex] < timeStart) - eventIndex++; - - // Expected number of events when not looping. - int eventsCount = frames.length; - while (frames[eventsCount - 1] > timeEnd) - eventsCount--; - eventsCount -= eventIndex; - - float duration = frames[eventIndex + eventsCount - 1]; - if (loop && duration > 0) { // When looping timeStep can't be > nyquist. - while (timeStep > duration / 2f) - timeStep /= 2f; - } - // duration *= 2; // Everything should still pass with this uncommented. - - firedEvents.clear(); - int i = 0; - float lastTime = timeStart - 0.00001f; - float timeLooped, lastTimeLooped; - while (true) { - float time = Math.min(timeStart + timeStep * i, timeEnd); - lastTimeLooped = lastTime; - timeLooped = time; - if (loop && duration != 0) { - lastTimeLooped %= duration; - timeLooped %= duration; - } - - int beforeCount = firedEvents.size; - Array original = new Array(firedEvents); - timeline.apply(skeleton, lastTimeLooped, timeLooped, firedEvents, 1); - - while (beforeCount < firedEvents.size) { - char fired = firedEvents.get(beforeCount).getData().getName().charAt(0); - if (loop) { - eventIndex %= events.length; - } else { - if (firedEvents.size > eventsCount) { - if (print) System.out.println(lastTimeLooped + "->" + timeLooped + ": " + fired + " == ?"); - timeline.apply(skeleton, lastTimeLooped, timeLooped, original, 1); - fail("Too many events fired."); - } - } - if (print) { - System.out.println(lastTimeLooped + "->" + timeLooped + ": " + fired + " == " + events[eventIndex]); - } - if (fired != events[eventIndex]) { - timeline.apply(skeleton, lastTimeLooped, timeLooped, original, 1); - fail("Wrong event fired."); - } - eventIndex++; - beforeCount++; - } - - if (time >= timeEnd) break; - lastTime = time; - i++; - } - if (firedEvents.size < eventsCount) { - timeline.apply(skeleton, lastTimeLooped, timeLooped, firedEvents, 1); - if (print) System.out.println(firedEvents); - fail("Event not fired: " + events[eventIndex] + ", " + frames[eventIndex]); - } - } - - private void fail (String message) { - throw new FailException(message); - } - - static class FailException extends RuntimeException { - public FailException (String message) { - super(message); - } - } - - static public void main (String[] args) throws Exception { - new EventTimelineTests(); - } +package com.esotericsoftware.spine; + +import com.esotericsoftware.spine.Animation.EventTimeline; + +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.StringBuilder; + +import java.util.Arrays; + +/** Unit tests for {@link EventTimeline}. */ +public class EventTimelineTests { + private final SkeletonData skeletonData; + private final Skeleton skeleton; + private final Array firedEvents = new Array(); + private EventTimeline timeline = new EventTimeline(0); + private char[] events; + private float[] frames; + + public EventTimelineTests () { + skeletonData = new SkeletonData(); + skeleton = new Skeleton(skeletonData); + + test(0); + test(1); + test(1, 1); + test(1, 2); + test(1, 2); + test(1, 2, 3); + test(1, 2, 3); + test(0, 0, 0); + test(0, 0, 1); + test(0, 1, 1); + test(1, 1, 1); + test(1, 2, 3, 4); + test(0, 2, 3, 4); + test(0, 2, 2, 4); + test(0, 0, 0, 0); + test(2, 2, 2, 2); + test(0.1f); + test(0.1f, 0.1f); + test(0.1f, 50f); + test(0.1f, 0.2f, 0.3f, 0.4f); + test(1, 2, 3, 4, 5, 6, 6, 7, 7, 8, 9, 10, 11, 11.01f, 12, 12, 12, 12); + + System.out.println("EventTimeline tests passed."); + } + + private void test (float... frames) { + int eventCount = frames.length; + + StringBuilder buffer = new StringBuilder(); + for (int i = 0; i < eventCount; i++) + buffer.append((char)('a' + i)); + + this.events = buffer.toString().toCharArray(); + this.frames = frames; + timeline = new EventTimeline(eventCount); + + float maxFrame = 0; + int distinctCount = 0; + float lastFrame = -1; + for (int i = 0; i < eventCount; i++) { + float frame = frames[i]; + Event event = new Event(frame, new EventData("" + events[i])); + timeline.setFrame(i, event); + maxFrame = Math.max(maxFrame, frame); + if (lastFrame != frame) distinctCount++; + lastFrame = frame; + } + + run(0, 99, 0.1f); + run(0, maxFrame, 0.1f); + run(frames[0], 999, 2f); + run(frames[0], maxFrame, 0.1f); + run(0, maxFrame, (float)Math.ceil(maxFrame / 100)); + run(0, 99, 0.1f); + run(0, 999, 100f); + if (distinctCount > 1) { + float epsilon = 0.02f; + // Ending before last. + run(frames[0], maxFrame - epsilon, 0.1f); + run(0, maxFrame - epsilon, 0.1f); + // Starting after first. + run(frames[0] + epsilon, maxFrame, 0.1f); + run(frames[0] + epsilon, 99, 0.1f); + } + } + + private void run (float startTime, float endTime, float timeStep) { + timeStep = Math.max(timeStep, 0.00001f); + boolean loop = false; + try { + fire(startTime, endTime, timeStep, loop, false); + loop = true; + fire(startTime, endTime, timeStep, loop, false); + } catch (FailException ignored) { + try { + fire(startTime, endTime, timeStep, loop, true); + } catch (FailException ex) { + System.out.println(ex.getMessage()); + System.exit(0); + } + } + } + + private void fire (float timeStart, float timeEnd, float timeStep, boolean loop, boolean print) { + if (print) { + System.out.println("events: " + Arrays.toString(events)); + System.out.println("frames: " + Arrays.toString(frames)); + System.out.println("timeStart: " + timeStart); + System.out.println("timeEnd: " + timeEnd); + System.out.println("timeStep: " + timeStep); + System.out.println("loop: " + loop); + } + + // Expected starting event. + int eventIndex = 0; + while (frames[eventIndex] < timeStart) + eventIndex++; + + // Expected number of events when not looping. + int eventsCount = frames.length; + while (frames[eventsCount - 1] > timeEnd) + eventsCount--; + eventsCount -= eventIndex; + + float duration = frames[eventIndex + eventsCount - 1]; + if (loop && duration > 0) { // When looping timeStep can't be > nyquist. + while (timeStep > duration / 2f) + timeStep /= 2f; + } + // duration *= 2; // Everything should still pass with this uncommented. + + firedEvents.clear(); + int i = 0; + float lastTime = timeStart - 0.00001f; + float timeLooped, lastTimeLooped; + while (true) { + float time = Math.min(timeStart + timeStep * i, timeEnd); + lastTimeLooped = lastTime; + timeLooped = time; + if (loop && duration != 0) { + lastTimeLooped %= duration; + timeLooped %= duration; + } + + int beforeCount = firedEvents.size; + Array original = new Array(firedEvents); + timeline.apply(skeleton, lastTimeLooped, timeLooped, firedEvents, 1); + + while (beforeCount < firedEvents.size) { + char fired = firedEvents.get(beforeCount).getData().getName().charAt(0); + if (loop) { + eventIndex %= events.length; + } else { + if (firedEvents.size > eventsCount) { + if (print) System.out.println(lastTimeLooped + "->" + timeLooped + ": " + fired + " == ?"); + timeline.apply(skeleton, lastTimeLooped, timeLooped, original, 1); + fail("Too many events fired."); + } + } + if (print) { + System.out.println(lastTimeLooped + "->" + timeLooped + ": " + fired + " == " + events[eventIndex]); + } + if (fired != events[eventIndex]) { + timeline.apply(skeleton, lastTimeLooped, timeLooped, original, 1); + fail("Wrong event fired."); + } + eventIndex++; + beforeCount++; + } + + if (time >= timeEnd) break; + lastTime = time; + i++; + } + if (firedEvents.size < eventsCount) { + timeline.apply(skeleton, lastTimeLooped, timeLooped, firedEvents, 1); + if (print) System.out.println(firedEvents); + fail("Event not fired: " + events[eventIndex] + ", " + frames[eventIndex]); + } + } + + private void fail (String message) { + throw new FailException(message); + } + + static class FailException extends RuntimeException { + public FailException (String message) { + super(message); + } + } + + static public void main (String[] args) throws Exception { + new EventTimelineTests(); + } } diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/MixTest.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/MixTest.java index b8a4db77cb..bdb6120535 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/MixTest.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/MixTest.java @@ -1,142 +1,141 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.ApplicationAdapter; -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.backends.lwjgl.LwjglApplication; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.g2d.SpriteBatch; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.badlogic.gdx.utils.Array; - -public class MixTest extends ApplicationAdapter { - SpriteBatch batch; - float time; - Array events = new Array(); - - SkeletonRenderer renderer; - SkeletonRendererDebug debugRenderer; - - SkeletonData skeletonData; - Skeleton skeleton; - Animation walkAnimation; - Animation jumpAnimation; - - public void create () { - batch = new SpriteBatch(); - renderer = new SkeletonRenderer(); - renderer.setPremultipliedAlpha(true); - debugRenderer = new SkeletonRendererDebug(); - - final String name = "spineboy/spineboy"; - - TextureAtlas atlas = new TextureAtlas(Gdx.files.internal(name + "-pma.atlas")); - - if (true) { - SkeletonJson json = new SkeletonJson(atlas); - json.setScale(0.6f); - skeletonData = json.readSkeletonData(Gdx.files.internal(name + ".json")); - } else { - SkeletonBinary binary = new SkeletonBinary(atlas); - binary.setScale(0.6f); - skeletonData = binary.readSkeletonData(Gdx.files.internal(name + ".skel")); - } - walkAnimation = skeletonData.findAnimation("walk"); - jumpAnimation = skeletonData.findAnimation("jump"); - - skeleton = new Skeleton(skeletonData); - skeleton.updateWorldTransform(); - skeleton.setPosition(-50, 20); - } - - public void render () { - float delta = Gdx.graphics.getDeltaTime() * 0.25f; // Reduced to make mixing easier to see. - - float jump = jumpAnimation.getDuration(); - float beforeJump = 1f; - float blendIn = 0.2f; - float blendOut = 0.2f; - float blendOutStart = beforeJump + jump - blendOut; - float total = 3.75f; - - time += delta; - - float speed = 180; - if (time > beforeJump + blendIn && time < blendOutStart) speed = 360; - skeleton.setX(skeleton.getX() + speed * delta); - - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); - - // This shows how to manage state manually. See SimpleTest1 for a higher level API using AnimationState. - if (time > total) { - // restart - time = 0; - skeleton.setX(-50); - } else if (time > beforeJump + jump) { - // just walk after jump - walkAnimation.apply(skeleton, time, time, true, events); - } else if (time > blendOutStart) { - // blend out jump - walkAnimation.apply(skeleton, time, time, true, events); - jumpAnimation.mix(skeleton, time - beforeJump, time - beforeJump, false, events, 1 - (time - blendOutStart) / blendOut); - } else if (time > beforeJump + blendIn) { - // just jump - jumpAnimation.apply(skeleton, time - beforeJump, time - beforeJump, false, events); - } else if (time > beforeJump) { - // blend in jump - walkAnimation.apply(skeleton, time, time, true, events); - jumpAnimation.mix(skeleton, time - beforeJump, time - beforeJump, false, events, (time - beforeJump) / blendIn); - } else { - // just walk before jump - walkAnimation.apply(skeleton, time, time, true, events); - } - - skeleton.updateWorldTransform(); - skeleton.update(Gdx.graphics.getDeltaTime()); - - batch.begin(); - renderer.draw(batch, skeleton); - batch.end(); - - debugRenderer.draw(skeleton); - } - - public void resize (int width, int height) { - batch.getProjectionMatrix().setToOrtho2D(0, 0, width, height); - debugRenderer.getShapeRenderer().setProjectionMatrix(batch.getProjectionMatrix()); - } - - public static void main (String[] args) throws Exception { - new LwjglApplication(new MixTest()); - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.ApplicationAdapter; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.backends.lwjgl.LwjglApplication; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.utils.Array; + +public class MixTest extends ApplicationAdapter { + SpriteBatch batch; + float time; + Array events = new Array(); + + SkeletonRenderer renderer; + SkeletonRendererDebug debugRenderer; + + SkeletonData skeletonData; + Skeleton skeleton; + Animation walkAnimation; + Animation jumpAnimation; + + public void create () { + batch = new SpriteBatch(); + renderer = new SkeletonRenderer(); + renderer.setPremultipliedAlpha(true); + debugRenderer = new SkeletonRendererDebug(); + + final String name = "spineboy/spineboy"; + + TextureAtlas atlas = new TextureAtlas(Gdx.files.internal(name + "-pma.atlas")); + + if (true) { + SkeletonJson json = new SkeletonJson(atlas); + json.setScale(0.6f); + skeletonData = json.readSkeletonData(Gdx.files.internal(name + ".json")); + } else { + SkeletonBinary binary = new SkeletonBinary(atlas); + binary.setScale(0.6f); + skeletonData = binary.readSkeletonData(Gdx.files.internal(name + ".skel")); + } + walkAnimation = skeletonData.findAnimation("walk"); + jumpAnimation = skeletonData.findAnimation("jump"); + + skeleton = new Skeleton(skeletonData); + skeleton.updateWorldTransform(); + skeleton.setPosition(-50, 20); + } + + public void render () { + float delta = Gdx.graphics.getDeltaTime() * 0.25f; // Reduced to make mixing easier to see. + + float jump = jumpAnimation.getDuration(); + float beforeJump = 1f; + float blendIn = 0.2f; + float blendOut = 0.2f; + float blendOutStart = beforeJump + jump - blendOut; + float total = 3.75f; + + time += delta; + + float speed = 180; + if (time > beforeJump + blendIn && time < blendOutStart) speed = 360; + skeleton.setX(skeleton.getX() + speed * delta); + + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + // This shows how to manage state manually. See SimpleTest1 for a higher level API using AnimationState. + if (time > total) { + // restart + time = 0; + skeleton.setX(-50); + } else if (time > beforeJump + jump) { + // just walk after jump + walkAnimation.apply(skeleton, time, time, true, events); + } else if (time > blendOutStart) { + // blend out jump + walkAnimation.apply(skeleton, time, time, true, events); + jumpAnimation.mix(skeleton, time - beforeJump, time - beforeJump, false, events, 1 - (time - blendOutStart) / blendOut); + } else if (time > beforeJump + blendIn) { + // just jump + jumpAnimation.apply(skeleton, time - beforeJump, time - beforeJump, false, events); + } else if (time > beforeJump) { + // blend in jump + walkAnimation.apply(skeleton, time, time, true, events); + jumpAnimation.mix(skeleton, time - beforeJump, time - beforeJump, false, events, (time - beforeJump) / blendIn); + } else { + // just walk before jump + walkAnimation.apply(skeleton, time, time, true, events); + } + + skeleton.updateWorldTransform(); + skeleton.update(Gdx.graphics.getDeltaTime()); + + batch.begin(); + renderer.draw(batch, skeleton); + batch.end(); + + debugRenderer.draw(skeleton); + } + + public void resize (int width, int height) { + batch.getProjectionMatrix().setToOrtho2D(0, 0, width, height); + debugRenderer.getShapeRenderer().setProjectionMatrix(batch.getProjectionMatrix()); + } + + public static void main (String[] args) throws Exception { + new LwjglApplication(new MixTest()); + } } diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/NormalMapTest.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/NormalMapTest.java index 6372ecc92c..56c7fa1147 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/NormalMapTest.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/NormalMapTest.java @@ -1,385 +1,384 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.ApplicationAdapter; -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.InputAdapter; -import com.badlogic.gdx.InputMultiplexer; -import com.badlogic.gdx.Preferences; -import com.badlogic.gdx.backends.lwjgl.LwjglApplication; -import com.badlogic.gdx.files.FileHandle; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.SpriteBatch; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.badlogic.gdx.graphics.glutils.ShaderProgram; -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.math.Vector3; -import com.badlogic.gdx.scenes.scene2d.Actor; -import com.badlogic.gdx.scenes.scene2d.InputEvent; -import com.badlogic.gdx.scenes.scene2d.InputListener; -import com.badlogic.gdx.scenes.scene2d.Stage; -import com.badlogic.gdx.scenes.scene2d.ui.CheckBox; -import com.badlogic.gdx.scenes.scene2d.ui.Label; -import com.badlogic.gdx.scenes.scene2d.ui.Slider; -import com.badlogic.gdx.scenes.scene2d.ui.Table; -import com.badlogic.gdx.scenes.scene2d.ui.TextButton; -import com.badlogic.gdx.scenes.scene2d.ui.Window; -import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; -import com.badlogic.gdx.utils.Align; - -public class NormalMapTest extends ApplicationAdapter { - String skeletonPath, animationName; - SpriteBatch batch; - float time; - SkeletonRenderer renderer; - Texture atlasTexture, normalMapTexture; - ShaderProgram program; - UI ui; - - SkeletonData skeletonData; - Skeleton skeleton; - Animation animation; - - final Vector3 ambientColor = new Vector3(); - final Vector3 lightColor = new Vector3(); - final Vector3 lightPosition = new Vector3(); - final Vector2 resolution = new Vector2(); - final Vector3 attenuation = new Vector3(); - - public NormalMapTest (String skeletonPath, String animationName) { - this.skeletonPath = skeletonPath; - this.animationName = animationName; - } - - public void create () { - ui = new UI(); - - program = createShader(); - batch = new SpriteBatch(); - batch.setShader(program); - renderer = new SkeletonRenderer(); - - FileHandle file = Gdx.files.internal(skeletonPath + "-diffuse.atlas"); - TextureAtlas atlas = new TextureAtlas(file); - atlasTexture = atlas.getRegions().first().getTexture(); - - normalMapTexture = new Texture(Gdx.files.internal(skeletonPath + "-normal.png")); - - SkeletonJson json = new SkeletonJson(atlas); - skeletonData = json.readSkeletonData(Gdx.files.internal(skeletonPath + ".json")); - if (animationName != null) animation = skeletonData.findAnimation(animationName); - if (animation == null) animation = skeletonData.getAnimations().first(); - - skeleton = new Skeleton(skeletonData); - skeleton.setToSetupPose(); - skeleton = new Skeleton(skeleton); - skeleton.setX(ui.prefs.getFloat("x", Gdx.graphics.getWidth() / 2)); - skeleton.setY(ui.prefs.getFloat("y", Gdx.graphics.getHeight() / 4)); - skeleton.updateWorldTransform(); - - Gdx.input.setInputProcessor(new InputMultiplexer(ui.stage, new InputAdapter() { - public boolean touchDown (int screenX, int screenY, int pointer, int button) { - touchDragged(screenX, screenY, pointer); - return true; - } - - public boolean touchDragged (int screenX, int screenY, int pointer) { - skeleton.setPosition(screenX, Gdx.graphics.getHeight() - screenY); - return true; - } - - public boolean touchUp (int screenX, int screenY, int pointer, int button) { - ui.prefs.putFloat("x", skeleton.getX()); - ui.prefs.putFloat("y", skeleton.getY()); - ui.prefs.flush(); - return true; - } - })); - } - - public void render () { - float lastTime = time; - time += Gdx.graphics.getDeltaTime(); - if (animation != null) animation.apply(skeleton, lastTime, time, true, null); - skeleton.updateWorldTransform(); - skeleton.update(Gdx.graphics.getDeltaTime()); - - lightPosition.x = Gdx.input.getX(); - lightPosition.y = (Gdx.graphics.getHeight() - Gdx.input.getY()); - - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); - - ambientColor.x = ui.ambientColorR.getValue(); - ambientColor.y = ui.ambientColorG.getValue(); - ambientColor.z = ui.ambientColorB.getValue(); - lightColor.x = ui.lightColorR.getValue(); - lightColor.y = ui.lightColorG.getValue(); - lightColor.z = ui.lightColorB.getValue(); - attenuation.x = ui.attenuationX.getValue(); - attenuation.y = ui.attenuationY.getValue(); - attenuation.z = ui.attenuationZ.getValue(); - lightPosition.z = ui.lightZ.getValue(); - - batch.begin(); - program.setUniformi("yInvert", ui.yInvert.isChecked() ? 1 : 0); - program.setUniformf("resolution", resolution); - program.setUniformf("ambientColor", ambientColor); - program.setUniformf("ambientIntensity", ui.ambientIntensity.getValue()); - program.setUniformf("attenuation", attenuation); - program.setUniformf("light", lightPosition); - program.setUniformf("lightColor", lightColor); - program.setUniformi("useNormals", ui.useNormals.isChecked() ? 1 : 0); - program.setUniformi("useShadow", ui.useShadow.isChecked() ? 1 : 0); - program.setUniformf("strength", ui.strength.getValue()); - normalMapTexture.bind(1); - atlasTexture.bind(0); - renderer.draw(batch, skeleton); - batch.end(); - - ui.stage.act(); - ui.stage.draw(); - } - - public void resize (int width, int height) { - batch.getProjectionMatrix().setToOrtho2D(0, 0, width, height); - ui.stage.getViewport().update(width, height, true); - resolution.set(width, height); - } - - private ShaderProgram createShader () { - String vert = "attribute vec4 a_position;\n" // - + "attribute vec4 a_color;\n" // - + "attribute vec2 a_texCoord0;\n" // - + "uniform mat4 u_proj;\n" // - + "uniform mat4 u_trans;\n" // - + "uniform mat4 u_projTrans;\n" // - + "varying vec4 v_color;\n" // - + "varying vec2 v_texCoords;\n" // - + "\n" // - + "void main()\n" // - + "{\n" // - + " v_color = a_color;\n" // - + " v_texCoords = a_texCoord0;\n" // - + " gl_Position = u_projTrans * a_position;\n" // - + "}\n" // - + ""; - - String frag = "#ifdef GL_ES\n" // - + "precision mediump float;\n" // - + "#endif\n" // - + "varying vec4 v_color;\n" // - + "varying vec2 v_texCoords;\n" // - + "uniform sampler2D u_texture;\n" // - + "uniform sampler2D u_normals;\n" // - + "uniform vec3 light;\n" // - + "uniform vec3 ambientColor;\n" // - + "uniform float ambientIntensity; \n" // - + "uniform vec2 resolution;\n" // - + "uniform vec3 lightColor;\n" // - + "uniform bool useNormals;\n" // - + "uniform bool useShadow;\n" // - + "uniform vec3 attenuation;\n" // - + "uniform float strength;\n" // - + "uniform bool yInvert;\n" // - + "\n" // - + "void main() {\n" // - + " // sample color & normals from our textures\n" // - + " vec4 color = texture2D(u_texture, v_texCoords.st);\n" // - + " vec3 nColor = texture2D(u_normals, v_texCoords.st).rgb;\n" // - + "\n" // - + " // some bump map programs will need the Y value flipped..\n" // - + " nColor.g = yInvert ? 1.0 - nColor.g : nColor.g;\n" // - + "\n" // - + " // this is for debugging purposes, allowing us to lower the intensity of our bump map\n" // - + " vec3 nBase = vec3(0.5, 0.5, 1.0);\n" // - + " nColor = mix(nBase, nColor, strength);\n" // - + "\n" // - + " // normals need to be converted to [-1.0, 1.0] range and normalized\n" // - + " vec3 normal = normalize(nColor * 2.0 - 1.0);\n" // - + "\n" // - + " // here we do a simple distance calculation\n" // - + " vec3 deltaPos = vec3( (light.xy - gl_FragCoord.xy) / resolution.xy, light.z );\n" // - + "\n" // - + " vec3 lightDir = normalize(deltaPos);\n" // - + " float lambert = useNormals ? clamp(dot(normal, lightDir), 0.0, 1.0) : 1.0;\n" // - + " \n" // - + " // now let's get a nice little falloff\n" // - + " float d = sqrt(dot(deltaPos, deltaPos)); \n" // - + " float att = useShadow ? 1.0 / ( attenuation.x + (attenuation.y*d) + (attenuation.z*d*d) ) : 1.0;\n" // - + " \n" // - + " vec3 result = (ambientColor * ambientIntensity) + (lightColor.rgb * lambert) * att;\n" // - + " result *= color.rgb;\n" // - + " \n" // - + " gl_FragColor = v_color * vec4(result, color.a);\n" // - + "}"; - - // System.out.println("VERTEX PROGRAM:\n------------\n\n" + vert); - // System.out.println("FRAGMENT PROGRAM:\n------------\n\n" + frag); - ShaderProgram program = new ShaderProgram(vert, frag); - ShaderProgram.pedantic = false; - if (!program.isCompiled()) throw new IllegalArgumentException("Error compiling shader: " + program.getLog()); - - program.begin(); - program.setUniformi("u_texture", 0); - program.setUniformi("u_normals", 1); - program.end(); - - return program; - } - - class UI { - Stage stage = new Stage(); - com.badlogic.gdx.scenes.scene2d.ui.Skin skin = new com.badlogic.gdx.scenes.scene2d.ui.Skin( - Gdx.files.internal("skin/skin.json")); - Preferences prefs = Gdx.app.getPreferences(".spine/NormalMapTest"); - - Window window; - Table root; - Slider ambientColorR, ambientColorG, ambientColorB; - Slider lightColorR, lightColorG, lightColorB, lightZ; - Slider attenuationX, attenuationY, attenuationZ; - Slider ambientIntensity; - Slider strength; - CheckBox useShadow, useNormals, yInvert; - - public UI () { - create(); - } - - public void create () { - window = new Window("Light", skin); - - root = new Table(skin); - root.pad(2, 4, 4, 4).defaults().space(6); - root.columnDefaults(0).top().right(); - root.columnDefaults(1).left(); - ambientColorR = slider("Ambient R", 1); - ambientColorG = slider("Ambient G", 1); - ambientColorB = slider("Ambient B", 1); - ambientIntensity = slider("Ambient intensity", 0.35f); - lightColorR = slider("Light R", 1); - lightColorG = slider("Light G", 0.7f); - lightColorB = slider("Light B", 0.6f); - lightZ = slider("Light Z", 0.07f); - attenuationX = slider("Attenuation", 0.4f); - attenuationY = slider("Attenuation*d", 3); - attenuationZ = slider("Attenuation*d*d", 5); - strength = slider("Strength", 1); - { - Table table = new Table(); - table.defaults().space(12); - table.add(useShadow = checkbox(" Use shadow", true)); - table.add(useNormals = checkbox(" Use normals", true)); - table.add(yInvert = checkbox(" Invert Y", true)); - root.add(table).colspan(2).row(); - } - - TextButton resetButton = new TextButton("Reset", skin); - resetButton.getColor().a = 0.66f; - window.getTitleTable().add(resetButton).height(20); - - window.add(root).expand().fill(); - window.pack(); - stage.addActor(window); - - // Events. - - window.addListener(new InputListener() { - public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { - event.cancel(); - return true; - } - }); - - resetButton.addListener(new ChangeListener() { - public void changed (ChangeEvent event, Actor actor) { - window.remove(); - prefs.clear(); - prefs.flush(); - create(); - } - }); - } - - private CheckBox checkbox (final String name, boolean defaultValue) { - final CheckBox checkbox = new CheckBox(name, skin); - checkbox.setChecked(prefs.getBoolean(checkbox.getText().toString(), defaultValue)); - - checkbox.addListener(new ChangeListener() { - public void changed (ChangeEvent event, Actor actor) { - prefs.putBoolean(name, checkbox.isChecked()); - prefs.flush(); - } - }); - - return checkbox; - } - - private Slider slider (final String name, float defaultValue) { - final Slider slider = new Slider(0, 1, 0.01f, false, skin); - slider.setValue(prefs.getFloat(name, defaultValue)); - - final Label label = new Label("", skin); - label.setAlignment(Align.right); - label.setText(Float.toString((int)(slider.getValue() * 100) / 100f)); - - slider.addListener(new ChangeListener() { - public void changed (ChangeEvent event, Actor actor) { - label.setText(Float.toString((int)(slider.getValue() * 100) / 100f)); - if (!slider.isDragging()) { - prefs.putFloat(name, slider.getValue()); - prefs.flush(); - } - } - }); - - Table table = new Table(); - table.add(label).width(35).space(12); - table.add(slider); - - root.add(name); - root.add(table).fill().row(); - return slider; - } - } - - public static void main (String[] args) throws Exception { - if (args.length == 0) - args = new String[] {"spineboy-old/spineboy-old", "walk"}; - else if (args.length == 1) // - args = new String[] {args[0], null}; - - new LwjglApplication(new NormalMapTest(args[0], args[1])); - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.ApplicationAdapter; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.InputAdapter; +import com.badlogic.gdx.InputMultiplexer; +import com.badlogic.gdx.Preferences; +import com.badlogic.gdx.backends.lwjgl.LwjglApplication; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.glutils.ShaderProgram; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.math.Vector3; +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.InputListener; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.scenes.scene2d.ui.CheckBox; +import com.badlogic.gdx.scenes.scene2d.ui.Label; +import com.badlogic.gdx.scenes.scene2d.ui.Slider; +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton; +import com.badlogic.gdx.scenes.scene2d.ui.Window; +import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import com.badlogic.gdx.utils.Align; + +public class NormalMapTest extends ApplicationAdapter { + String skeletonPath, animationName; + SpriteBatch batch; + float time; + SkeletonRenderer renderer; + Texture atlasTexture, normalMapTexture; + ShaderProgram program; + UI ui; + + SkeletonData skeletonData; + Skeleton skeleton; + Animation animation; + + final Vector3 ambientColor = new Vector3(); + final Vector3 lightColor = new Vector3(); + final Vector3 lightPosition = new Vector3(); + final Vector2 resolution = new Vector2(); + final Vector3 attenuation = new Vector3(); + + public NormalMapTest (String skeletonPath, String animationName) { + this.skeletonPath = skeletonPath; + this.animationName = animationName; + } + + public void create () { + ui = new UI(); + + program = createShader(); + batch = new SpriteBatch(); + batch.setShader(program); + renderer = new SkeletonRenderer(); + + FileHandle file = Gdx.files.internal(skeletonPath + "-diffuse.atlas"); + TextureAtlas atlas = new TextureAtlas(file); + atlasTexture = atlas.getRegions().first().getTexture(); + + normalMapTexture = new Texture(Gdx.files.internal(skeletonPath + "-normal.png")); + + SkeletonJson json = new SkeletonJson(atlas); + skeletonData = json.readSkeletonData(Gdx.files.internal(skeletonPath + ".json")); + if (animationName != null) animation = skeletonData.findAnimation(animationName); + if (animation == null) animation = skeletonData.getAnimations().first(); + + skeleton = new Skeleton(skeletonData); + skeleton.setToSetupPose(); + skeleton = new Skeleton(skeleton); + skeleton.setX(ui.prefs.getFloat("x", Gdx.graphics.getWidth() / 2)); + skeleton.setY(ui.prefs.getFloat("y", Gdx.graphics.getHeight() / 4)); + skeleton.updateWorldTransform(); + + Gdx.input.setInputProcessor(new InputMultiplexer(ui.stage, new InputAdapter() { + public boolean touchDown (int screenX, int screenY, int pointer, int button) { + touchDragged(screenX, screenY, pointer); + return true; + } + + public boolean touchDragged (int screenX, int screenY, int pointer) { + skeleton.setPosition(screenX, Gdx.graphics.getHeight() - screenY); + return true; + } + + public boolean touchUp (int screenX, int screenY, int pointer, int button) { + ui.prefs.putFloat("x", skeleton.getX()); + ui.prefs.putFloat("y", skeleton.getY()); + ui.prefs.flush(); + return true; + } + })); + } + + public void render () { + float lastTime = time; + time += Gdx.graphics.getDeltaTime(); + if (animation != null) animation.apply(skeleton, lastTime, time, true, null); + skeleton.updateWorldTransform(); + skeleton.update(Gdx.graphics.getDeltaTime()); + + lightPosition.x = Gdx.input.getX(); + lightPosition.y = (Gdx.graphics.getHeight() - Gdx.input.getY()); + + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + ambientColor.x = ui.ambientColorR.getValue(); + ambientColor.y = ui.ambientColorG.getValue(); + ambientColor.z = ui.ambientColorB.getValue(); + lightColor.x = ui.lightColorR.getValue(); + lightColor.y = ui.lightColorG.getValue(); + lightColor.z = ui.lightColorB.getValue(); + attenuation.x = ui.attenuationX.getValue(); + attenuation.y = ui.attenuationY.getValue(); + attenuation.z = ui.attenuationZ.getValue(); + lightPosition.z = ui.lightZ.getValue(); + + batch.begin(); + program.setUniformi("yInvert", ui.yInvert.isChecked() ? 1 : 0); + program.setUniformf("resolution", resolution); + program.setUniformf("ambientColor", ambientColor); + program.setUniformf("ambientIntensity", ui.ambientIntensity.getValue()); + program.setUniformf("attenuation", attenuation); + program.setUniformf("light", lightPosition); + program.setUniformf("lightColor", lightColor); + program.setUniformi("useNormals", ui.useNormals.isChecked() ? 1 : 0); + program.setUniformi("useShadow", ui.useShadow.isChecked() ? 1 : 0); + program.setUniformf("strength", ui.strength.getValue()); + normalMapTexture.bind(1); + atlasTexture.bind(0); + renderer.draw(batch, skeleton); + batch.end(); + + ui.stage.act(); + ui.stage.draw(); + } + + public void resize (int width, int height) { + batch.getProjectionMatrix().setToOrtho2D(0, 0, width, height); + ui.stage.getViewport().update(width, height, true); + resolution.set(width, height); + } + + private ShaderProgram createShader () { + String vert = "attribute vec4 a_position;\n" // + + "attribute vec4 a_color;\n" // + + "attribute vec2 a_texCoord0;\n" // + + "uniform mat4 u_proj;\n" // + + "uniform mat4 u_trans;\n" // + + "uniform mat4 u_projTrans;\n" // + + "varying vec4 v_color;\n" // + + "varying vec2 v_texCoords;\n" // + + "\n" // + + "void main()\n" // + + "{\n" // + + " v_color = a_color;\n" // + + " v_texCoords = a_texCoord0;\n" // + + " gl_Position = u_projTrans * a_position;\n" // + + "}\n" // + + ""; + + String frag = "#ifdef GL_ES\n" // + + "precision mediump float;\n" // + + "#endif\n" // + + "varying vec4 v_color;\n" // + + "varying vec2 v_texCoords;\n" // + + "uniform sampler2D u_texture;\n" // + + "uniform sampler2D u_normals;\n" // + + "uniform vec3 light;\n" // + + "uniform vec3 ambientColor;\n" // + + "uniform float ambientIntensity; \n" // + + "uniform vec2 resolution;\n" // + + "uniform vec3 lightColor;\n" // + + "uniform bool useNormals;\n" // + + "uniform bool useShadow;\n" // + + "uniform vec3 attenuation;\n" // + + "uniform float strength;\n" // + + "uniform bool yInvert;\n" // + + "\n" // + + "void main() {\n" // + + " // sample color & normals from our textures\n" // + + " vec4 color = texture2D(u_texture, v_texCoords.st);\n" // + + " vec3 nColor = texture2D(u_normals, v_texCoords.st).rgb;\n" // + + "\n" // + + " // some bump map programs will need the Y value flipped..\n" // + + " nColor.g = yInvert ? 1.0 - nColor.g : nColor.g;\n" // + + "\n" // + + " // this is for debugging purposes, allowing us to lower the intensity of our bump map\n" // + + " vec3 nBase = vec3(0.5, 0.5, 1.0);\n" // + + " nColor = mix(nBase, nColor, strength);\n" // + + "\n" // + + " // normals need to be converted to [-1.0, 1.0] range and normalized\n" // + + " vec3 normal = normalize(nColor * 2.0 - 1.0);\n" // + + "\n" // + + " // here we do a simple distance calculation\n" // + + " vec3 deltaPos = vec3( (light.xy - gl_FragCoord.xy) / resolution.xy, light.z );\n" // + + "\n" // + + " vec3 lightDir = normalize(deltaPos);\n" // + + " float lambert = useNormals ? clamp(dot(normal, lightDir), 0.0, 1.0) : 1.0;\n" // + + " \n" // + + " // now let's get a nice little falloff\n" // + + " float d = sqrt(dot(deltaPos, deltaPos)); \n" // + + " float att = useShadow ? 1.0 / ( attenuation.x + (attenuation.y*d) + (attenuation.z*d*d) ) : 1.0;\n" // + + " \n" // + + " vec3 result = (ambientColor * ambientIntensity) + (lightColor.rgb * lambert) * att;\n" // + + " result *= color.rgb;\n" // + + " \n" // + + " gl_FragColor = v_color * vec4(result, color.a);\n" // + + "}"; + + // System.out.println("VERTEX PROGRAM:\n------------\n\n" + vert); + // System.out.println("FRAGMENT PROGRAM:\n------------\n\n" + frag); + ShaderProgram program = new ShaderProgram(vert, frag); + ShaderProgram.pedantic = false; + if (!program.isCompiled()) throw new IllegalArgumentException("Error compiling shader: " + program.getLog()); + + program.begin(); + program.setUniformi("u_texture", 0); + program.setUniformi("u_normals", 1); + program.end(); + + return program; + } + + class UI { + Stage stage = new Stage(); + com.badlogic.gdx.scenes.scene2d.ui.Skin skin = new com.badlogic.gdx.scenes.scene2d.ui.Skin( + Gdx.files.internal("skin/skin.json")); + Preferences prefs = Gdx.app.getPreferences(".spine/NormalMapTest"); + + Window window; + Table root; + Slider ambientColorR, ambientColorG, ambientColorB; + Slider lightColorR, lightColorG, lightColorB, lightZ; + Slider attenuationX, attenuationY, attenuationZ; + Slider ambientIntensity; + Slider strength; + CheckBox useShadow, useNormals, yInvert; + + public UI () { + create(); + } + + public void create () { + window = new Window("Light", skin); + + root = new Table(skin); + root.pad(2, 4, 4, 4).defaults().space(6); + root.columnDefaults(0).top().right(); + root.columnDefaults(1).left(); + ambientColorR = slider("Ambient R", 1); + ambientColorG = slider("Ambient G", 1); + ambientColorB = slider("Ambient B", 1); + ambientIntensity = slider("Ambient intensity", 0.35f); + lightColorR = slider("Light R", 1); + lightColorG = slider("Light G", 0.7f); + lightColorB = slider("Light B", 0.6f); + lightZ = slider("Light Z", 0.07f); + attenuationX = slider("Attenuation", 0.4f); + attenuationY = slider("Attenuation*d", 3); + attenuationZ = slider("Attenuation*d*d", 5); + strength = slider("Strength", 1); + { + Table table = new Table(); + table.defaults().space(12); + table.add(useShadow = checkbox(" Use shadow", true)); + table.add(useNormals = checkbox(" Use normals", true)); + table.add(yInvert = checkbox(" Invert Y", true)); + root.add(table).colspan(2).row(); + } + + TextButton resetButton = new TextButton("Reset", skin); + resetButton.getColor().a = 0.66f; + window.getTitleTable().add(resetButton).height(20); + + window.add(root).expand().fill(); + window.pack(); + stage.addActor(window); + + // Events. + + window.addListener(new InputListener() { + public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { + event.cancel(); + return true; + } + }); + + resetButton.addListener(new ChangeListener() { + public void changed (ChangeEvent event, Actor actor) { + window.remove(); + prefs.clear(); + prefs.flush(); + create(); + } + }); + } + + private CheckBox checkbox (final String name, boolean defaultValue) { + final CheckBox checkbox = new CheckBox(name, skin); + checkbox.setChecked(prefs.getBoolean(checkbox.getText().toString(), defaultValue)); + + checkbox.addListener(new ChangeListener() { + public void changed (ChangeEvent event, Actor actor) { + prefs.putBoolean(name, checkbox.isChecked()); + prefs.flush(); + } + }); + + return checkbox; + } + + private Slider slider (final String name, float defaultValue) { + final Slider slider = new Slider(0, 1, 0.01f, false, skin); + slider.setValue(prefs.getFloat(name, defaultValue)); + + final Label label = new Label("", skin); + label.setAlignment(Align.right); + label.setText(Float.toString((int)(slider.getValue() * 100) / 100f)); + + slider.addListener(new ChangeListener() { + public void changed (ChangeEvent event, Actor actor) { + label.setText(Float.toString((int)(slider.getValue() * 100) / 100f)); + if (!slider.isDragging()) { + prefs.putFloat(name, slider.getValue()); + prefs.flush(); + } + } + }); + + Table table = new Table(); + table.add(label).width(35).space(12); + table.add(slider); + + root.add(name); + root.add(table).fill().row(); + return slider; + } + } + + public static void main (String[] args) throws Exception { + if (args.length == 0) + args = new String[] {"spineboy-old/spineboy-old", "walk"}; + else if (args.length == 1) // + args = new String[] {args[0], null}; + + new LwjglApplication(new NormalMapTest(args[0], args[1])); + } } diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/Sandbox.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/Sandbox.java index f44a48cd44..ad5aee8932 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/Sandbox.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/Sandbox.java @@ -1,132 +1,131 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.ApplicationAdapter; -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.backends.lwjgl.LwjglApplication; -import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.OrthographicCamera; -import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; - -/** - * Sandbox for comparing values when porting to other - * runtimes. - */ -public class Sandbox extends ApplicationAdapter { - static final String ATLAS = "../../examples/tank/export/tank.atlas"; - static final String JSON = "../../examples/tank/export/tank.json"; - static final float scale = 0.3f; - static final float X = 400; - static final float Y = 500; - static final String ANIMATION = "drive"; - static final float ANIMATION_OFFSET = 0.5f; - static final boolean ANIMATION_UPDATE = false; - static final boolean Y_DOWN = true; - static final boolean DRAW_DEBUG = false; - - OrthographicCamera camera; - PolygonSpriteBatch batch; - SkeletonMeshRenderer renderer; - SkeletonRendererDebug debugRenderer; - - TextureAtlas atlas; - Skeleton skeleton; - AnimationState state; - - public void create () { - camera = new OrthographicCamera(); - camera.setToOrtho(Y_DOWN); - batch = new PolygonSpriteBatch(); - renderer = new SkeletonMeshRenderer(); - renderer.setPremultipliedAlpha(false); - debugRenderer = new SkeletonRendererDebug(); - debugRenderer.setBoundingBoxes(false); - debugRenderer.setRegionAttachments(false); - - atlas = new TextureAtlas(Gdx.files.internal(ATLAS)); - SkeletonJson json = new SkeletonJson(atlas); - json.setScale(scale); - SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal(JSON)); - - skeleton = new Skeleton(skeletonData); - skeleton.setFlipY(Y_DOWN); - skeleton.setPosition(X, Y); - - AnimationStateData stateData = new AnimationStateData(skeletonData); - state = new AnimationState(stateData); - if (ANIMATION != null) state.setAnimation(0, ANIMATION, true); - if (ANIMATION_OFFSET != 0) { - state.update(ANIMATION_OFFSET); - state.apply(skeleton); - skeleton.updateWorldTransform(); - } - } - - public void render () { - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); - - if (ANIMATION_UPDATE) { - state.update(Gdx.graphics.getDeltaTime()); - state.apply(skeleton); - } - skeleton.updateWorldTransform(); - - camera.update(); - batch.getProjectionMatrix().set(camera.combined); - debugRenderer.getShapeRenderer().setProjectionMatrix(camera.combined); - - batch.begin(); - renderer.draw(batch, skeleton); - batch.end(); - - if (DRAW_DEBUG) debugRenderer.draw(skeleton); - } - - public void resize (int width, int height) { - camera.setToOrtho(Y_DOWN); - } - - public void dispose () { - atlas.dispose(); - } - - public static void main (String[] args) throws Exception { - LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); - config.useHDPI = true; - config.width = 800; - config.height = 600; - new LwjglApplication(new Sandbox(), config); - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.ApplicationAdapter; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.backends.lwjgl.LwjglApplication; +import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; + +/** + * Sandbox for comparing values when porting to other + * runtimes. + */ +public class Sandbox extends ApplicationAdapter { + static final String ATLAS = "../../examples/tank/export/tank.atlas"; + static final String JSON = "../../examples/tank/export/tank.json"; + static final float scale = 0.3f; + static final float X = 400; + static final float Y = 500; + static final String ANIMATION = "drive"; + static final float ANIMATION_OFFSET = 0.5f; + static final boolean ANIMATION_UPDATE = false; + static final boolean Y_DOWN = true; + static final boolean DRAW_DEBUG = false; + + OrthographicCamera camera; + PolygonSpriteBatch batch; + SkeletonMeshRenderer renderer; + SkeletonRendererDebug debugRenderer; + + TextureAtlas atlas; + Skeleton skeleton; + AnimationState state; + + public void create () { + camera = new OrthographicCamera(); + camera.setToOrtho(Y_DOWN); + batch = new PolygonSpriteBatch(); + renderer = new SkeletonMeshRenderer(); + renderer.setPremultipliedAlpha(false); + debugRenderer = new SkeletonRendererDebug(); + debugRenderer.setBoundingBoxes(false); + debugRenderer.setRegionAttachments(false); + + atlas = new TextureAtlas(Gdx.files.internal(ATLAS)); + SkeletonJson json = new SkeletonJson(atlas); + json.setScale(scale); + SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal(JSON)); + + skeleton = new Skeleton(skeletonData); + skeleton.setFlipY(Y_DOWN); + skeleton.setPosition(X, Y); + + AnimationStateData stateData = new AnimationStateData(skeletonData); + state = new AnimationState(stateData); + if (ANIMATION != null) state.setAnimation(0, ANIMATION, true); + if (ANIMATION_OFFSET != 0) { + state.update(ANIMATION_OFFSET); + state.apply(skeleton); + skeleton.updateWorldTransform(); + } + } + + public void render () { + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + if (ANIMATION_UPDATE) { + state.update(Gdx.graphics.getDeltaTime()); + state.apply(skeleton); + } + skeleton.updateWorldTransform(); + + camera.update(); + batch.getProjectionMatrix().set(camera.combined); + debugRenderer.getShapeRenderer().setProjectionMatrix(camera.combined); + + batch.begin(); + renderer.draw(batch, skeleton); + batch.end(); + + if (DRAW_DEBUG) debugRenderer.draw(skeleton); + } + + public void resize (int width, int height) { + camera.setToOrtho(Y_DOWN); + } + + public void dispose () { + atlas.dispose(); + } + + public static void main (String[] args) throws Exception { + LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); + config.useHDPI = true; + config.width = 800; + config.height = 600; + new LwjglApplication(new Sandbox(), config); + } } diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/SimpleTest1.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/SimpleTest1.java index 424053bfe0..97293b1b39 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/SimpleTest1.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/SimpleTest1.java @@ -1,113 +1,112 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.ApplicationAdapter; -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.backends.lwjgl.LwjglApplication; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.OrthographicCamera; -import com.badlogic.gdx.graphics.g2d.SpriteBatch; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; - -public class SimpleTest1 extends ApplicationAdapter { - OrthographicCamera camera; - SpriteBatch batch; - SkeletonRenderer renderer; - SkeletonRendererDebug debugRenderer; - - TextureAtlas atlas; - Skeleton skeleton; - AnimationState state; - - public void create () { - camera = new OrthographicCamera(); - batch = new SpriteBatch(); - renderer = new SkeletonRenderer(); - renderer.setPremultipliedAlpha(true); // PMA results in correct blending without outlines. - debugRenderer = new SkeletonRendererDebug(); - debugRenderer.setBoundingBoxes(false); - debugRenderer.setRegionAttachments(false); - - atlas = new TextureAtlas(Gdx.files.internal("spineboy/spineboy-pma.atlas")); - SkeletonJson json = new SkeletonJson(atlas); // This loads skeleton JSON data, which is stateless. - json.setScale(0.6f); // Load the skeleton at 60% the size it was in Spine. - SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("spineboy/spineboy.json")); - - skeleton = new Skeleton(skeletonData); // Skeleton holds skeleton state (bone positions, slot attachments, etc). - skeleton.setPosition(250, 20); - - AnimationStateData stateData = new AnimationStateData(skeletonData); // Defines mixing (crossfading) between animations. - stateData.setMix("run", "jump", 0.2f); - stateData.setMix("jump", "run", 0.2f); - - state = new AnimationState(stateData); // Holds the animation state for a skeleton (current animation, time, etc). - state.setTimeScale(0.5f); // Slow all animations down to 50% speed. - - // Queue animations on track 0. - state.setAnimation(0, "run", true); - state.addAnimation(0, "jump", false, 2); // Jump after 2 seconds. - state.addAnimation(0, "run", true, 0); // Run after the jump. - } - - public void render () { - state.update(Gdx.graphics.getDeltaTime()); // Update the animation time. - - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); - - state.apply(skeleton); // Poses skeleton using current animations. This sets the bones' local SRT. - skeleton.updateWorldTransform(); // Uses the bones' local SRT to compute their world SRT. - - // Configure the camera, SpriteBatch, and SkeletonRendererDebug. - camera.update(); - batch.getProjectionMatrix().set(camera.combined); - debugRenderer.getShapeRenderer().setProjectionMatrix(camera.combined); - - batch.begin(); - renderer.draw(batch, skeleton); // Draw the skeleton images. - batch.end(); - - debugRenderer.draw(skeleton); // Draw debug lines. - } - - public void resize (int width, int height) { - camera.setToOrtho(false); // Update camera with new size. - } - - public void dispose () { - atlas.dispose(); - } - - public static void main (String[] args) throws Exception { - new LwjglApplication(new SimpleTest1()); - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.ApplicationAdapter; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.backends.lwjgl.LwjglApplication; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; + +public class SimpleTest1 extends ApplicationAdapter { + OrthographicCamera camera; + SpriteBatch batch; + SkeletonRenderer renderer; + SkeletonRendererDebug debugRenderer; + + TextureAtlas atlas; + Skeleton skeleton; + AnimationState state; + + public void create () { + camera = new OrthographicCamera(); + batch = new SpriteBatch(); + renderer = new SkeletonRenderer(); + renderer.setPremultipliedAlpha(true); // PMA results in correct blending without outlines. + debugRenderer = new SkeletonRendererDebug(); + debugRenderer.setBoundingBoxes(false); + debugRenderer.setRegionAttachments(false); + + atlas = new TextureAtlas(Gdx.files.internal("spineboy/spineboy-pma.atlas")); + SkeletonJson json = new SkeletonJson(atlas); // This loads skeleton JSON data, which is stateless. + json.setScale(0.6f); // Load the skeleton at 60% the size it was in Spine. + SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("spineboy/spineboy.json")); + + skeleton = new Skeleton(skeletonData); // Skeleton holds skeleton state (bone positions, slot attachments, etc). + skeleton.setPosition(250, 20); + + AnimationStateData stateData = new AnimationStateData(skeletonData); // Defines mixing (crossfading) between animations. + stateData.setMix("run", "jump", 0.2f); + stateData.setMix("jump", "run", 0.2f); + + state = new AnimationState(stateData); // Holds the animation state for a skeleton (current animation, time, etc). + state.setTimeScale(0.5f); // Slow all animations down to 50% speed. + + // Queue animations on track 0. + state.setAnimation(0, "run", true); + state.addAnimation(0, "jump", false, 2); // Jump after 2 seconds. + state.addAnimation(0, "run", true, 0); // Run after the jump. + } + + public void render () { + state.update(Gdx.graphics.getDeltaTime()); // Update the animation time. + + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + state.apply(skeleton); // Poses skeleton using current animations. This sets the bones' local SRT. + skeleton.updateWorldTransform(); // Uses the bones' local SRT to compute their world SRT. + + // Configure the camera, SpriteBatch, and SkeletonRendererDebug. + camera.update(); + batch.getProjectionMatrix().set(camera.combined); + debugRenderer.getShapeRenderer().setProjectionMatrix(camera.combined); + + batch.begin(); + renderer.draw(batch, skeleton); // Draw the skeleton images. + batch.end(); + + debugRenderer.draw(skeleton); // Draw debug lines. + } + + public void resize (int width, int height) { + camera.setToOrtho(false); // Update camera with new size. + } + + public void dispose () { + atlas.dispose(); + } + + public static void main (String[] args) throws Exception { + new LwjglApplication(new SimpleTest1()); + } } diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/SimpleTest2.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/SimpleTest2.java index 731628bcbf..a5ea2cf619 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/SimpleTest2.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/SimpleTest2.java @@ -1,166 +1,165 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.esotericsoftware.spine.AnimationState.AnimationStateListener; -import com.esotericsoftware.spine.attachments.BoundingBoxAttachment; - -import com.badlogic.gdx.ApplicationAdapter; -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.InputAdapter; -import com.badlogic.gdx.backends.lwjgl.LwjglApplication; -import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.OrthographicCamera; -import com.badlogic.gdx.graphics.g2d.SpriteBatch; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.badlogic.gdx.math.Vector3; - -public class SimpleTest2 extends ApplicationAdapter { - OrthographicCamera camera; - SpriteBatch batch; - SkeletonRenderer renderer; - SkeletonRendererDebug debugRenderer; - - TextureAtlas atlas; - Skeleton skeleton; - SkeletonBounds bounds; - AnimationState state; - - public void create () { - camera = new OrthographicCamera(); - batch = new SpriteBatch(); - renderer = new SkeletonRenderer(); - renderer.setPremultipliedAlpha(true); - debugRenderer = new SkeletonRendererDebug(); - - atlas = new TextureAtlas(Gdx.files.internal("spineboy/spineboy-pma.atlas")); - SkeletonJson json = new SkeletonJson(atlas); // This loads skeleton JSON data, which is stateless. - json.setScale(0.6f); // Load the skeleton at 60% the size it was in Spine. - SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("spineboy/spineboy.json")); - - skeleton = new Skeleton(skeletonData); // Skeleton holds skeleton state (bone positions, slot attachments, etc). - skeleton.setPosition(250, 20); - skeleton.setAttachment("head-bb", "head"); // Attach "head" bounding box to "head-bb" slot. - - bounds = new SkeletonBounds(); // Convenience class to do hit detection with bounding boxes. - - AnimationStateData stateData = new AnimationStateData(skeletonData); // Defines mixing (crossfading) between animations. - stateData.setMix("run", "jump", 0.2f); - stateData.setMix("jump", "run", 0.2f); - stateData.setMix("jump", "jump", 0); - - state = new AnimationState(stateData); // Holds the animation state for a skeleton (current animation, time, etc). - state.setTimeScale(0.3f); // Slow all animations down to 30% speed. - state.addListener(new AnimationStateListener() { - public void event (int trackIndex, Event event) { - System.out.println(trackIndex + " event: " + state.getCurrent(trackIndex) + ", " + event.getData().getName() + ", " - + event.getInt()); - } - - public void complete (int trackIndex, int loopCount) { - System.out.println(trackIndex + " complete: " + state.getCurrent(trackIndex) + ", " + loopCount); - } - - public void start (int trackIndex) { - System.out.println(trackIndex + " start: " + state.getCurrent(trackIndex)); - } - - public void end (int trackIndex) { - System.out.println(trackIndex + " end: " + state.getCurrent(trackIndex)); - } - }); - - // Set animation on track 0. - state.setAnimation(0, "run", true); - - Gdx.input.setInputProcessor(new InputAdapter() { - final Vector3 point = new Vector3(); - - public boolean touchDown (int screenX, int screenY, int pointer, int button) { - camera.unproject(point.set(screenX, screenY, 0)); // Convert window to world coordinates. - bounds.update(skeleton, true); // Update SkeletonBounds with current skeleton bounding box positions. - if (bounds.aabbContainsPoint(point.x, point.y)) { // Check if inside AABB first. This check is fast. - BoundingBoxAttachment hit = bounds.containsPoint(point.x, point.y); // Check if inside a bounding box. - if (hit != null) { - System.out.println("hit: " + hit); - skeleton.findSlot("head").getColor().set(Color.RED); // Turn head red until touchUp. - } - } - return true; - } - - public boolean touchUp (int screenX, int screenY, int pointer, int button) { - skeleton.findSlot("head").getColor().set(Color.WHITE); - return true; - } - - public boolean keyDown (int keycode) { - state.setAnimation(0, "jump", false); // Set animation on track 0 to jump. - state.addAnimation(0, "run", true, 0); // Queue run to play after jump. - return true; - } - }); - } - - public void render () { - state.update(Gdx.graphics.getDeltaTime()); // Update the animation time. - - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); - - state.apply(skeleton); // Poses skeleton using current animations. This sets the bones' local SRT. - skeleton.updateWorldTransform(); // Uses the bones' local SRT to compute their world SRT. - - // Configure the camera, SpriteBatch, and SkeletonRendererDebug. - camera.update(); - batch.getProjectionMatrix().set(camera.combined); - debugRenderer.getShapeRenderer().setProjectionMatrix(camera.combined); - - batch.begin(); - renderer.draw(batch, skeleton); // Draw the skeleton images. - batch.end(); - - debugRenderer.draw(skeleton); // Draw debug lines. - } - - public void resize (int width, int height) { - camera.setToOrtho(false); // Update camera with new size. - } - - public void dispose () { - atlas.dispose(); - } - - public static void main (String[] args) throws Exception { - new LwjglApplication(new SimpleTest2()); - } +package com.esotericsoftware.spine; + +import com.esotericsoftware.spine.AnimationState.AnimationStateListener; +import com.esotericsoftware.spine.attachments.BoundingBoxAttachment; + +import com.badlogic.gdx.ApplicationAdapter; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.InputAdapter; +import com.badlogic.gdx.backends.lwjgl.LwjglApplication; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.math.Vector3; + +public class SimpleTest2 extends ApplicationAdapter { + OrthographicCamera camera; + SpriteBatch batch; + SkeletonRenderer renderer; + SkeletonRendererDebug debugRenderer; + + TextureAtlas atlas; + Skeleton skeleton; + SkeletonBounds bounds; + AnimationState state; + + public void create () { + camera = new OrthographicCamera(); + batch = new SpriteBatch(); + renderer = new SkeletonRenderer(); + renderer.setPremultipliedAlpha(true); + debugRenderer = new SkeletonRendererDebug(); + + atlas = new TextureAtlas(Gdx.files.internal("spineboy/spineboy-pma.atlas")); + SkeletonJson json = new SkeletonJson(atlas); // This loads skeleton JSON data, which is stateless. + json.setScale(0.6f); // Load the skeleton at 60% the size it was in Spine. + SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("spineboy/spineboy.json")); + + skeleton = new Skeleton(skeletonData); // Skeleton holds skeleton state (bone positions, slot attachments, etc). + skeleton.setPosition(250, 20); + skeleton.setAttachment("head-bb", "head"); // Attach "head" bounding box to "head-bb" slot. + + bounds = new SkeletonBounds(); // Convenience class to do hit detection with bounding boxes. + + AnimationStateData stateData = new AnimationStateData(skeletonData); // Defines mixing (crossfading) between animations. + stateData.setMix("run", "jump", 0.2f); + stateData.setMix("jump", "run", 0.2f); + stateData.setMix("jump", "jump", 0); + + state = new AnimationState(stateData); // Holds the animation state for a skeleton (current animation, time, etc). + state.setTimeScale(0.3f); // Slow all animations down to 30% speed. + state.addListener(new AnimationStateListener() { + public void event (int trackIndex, Event event) { + System.out.println(trackIndex + " event: " + state.getCurrent(trackIndex) + ", " + event.getData().getName() + ", " + + event.getInt()); + } + + public void complete (int trackIndex, int loopCount) { + System.out.println(trackIndex + " complete: " + state.getCurrent(trackIndex) + ", " + loopCount); + } + + public void start (int trackIndex) { + System.out.println(trackIndex + " start: " + state.getCurrent(trackIndex)); + } + + public void end (int trackIndex) { + System.out.println(trackIndex + " end: " + state.getCurrent(trackIndex)); + } + }); + + // Set animation on track 0. + state.setAnimation(0, "run", true); + + Gdx.input.setInputProcessor(new InputAdapter() { + final Vector3 point = new Vector3(); + + public boolean touchDown (int screenX, int screenY, int pointer, int button) { + camera.unproject(point.set(screenX, screenY, 0)); // Convert window to world coordinates. + bounds.update(skeleton, true); // Update SkeletonBounds with current skeleton bounding box positions. + if (bounds.aabbContainsPoint(point.x, point.y)) { // Check if inside AABB first. This check is fast. + BoundingBoxAttachment hit = bounds.containsPoint(point.x, point.y); // Check if inside a bounding box. + if (hit != null) { + System.out.println("hit: " + hit); + skeleton.findSlot("head").getColor().set(Color.RED); // Turn head red until touchUp. + } + } + return true; + } + + public boolean touchUp (int screenX, int screenY, int pointer, int button) { + skeleton.findSlot("head").getColor().set(Color.WHITE); + return true; + } + + public boolean keyDown (int keycode) { + state.setAnimation(0, "jump", false); // Set animation on track 0 to jump. + state.addAnimation(0, "run", true, 0); // Queue run to play after jump. + return true; + } + }); + } + + public void render () { + state.update(Gdx.graphics.getDeltaTime()); // Update the animation time. + + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + state.apply(skeleton); // Poses skeleton using current animations. This sets the bones' local SRT. + skeleton.updateWorldTransform(); // Uses the bones' local SRT to compute their world SRT. + + // Configure the camera, SpriteBatch, and SkeletonRendererDebug. + camera.update(); + batch.getProjectionMatrix().set(camera.combined); + debugRenderer.getShapeRenderer().setProjectionMatrix(camera.combined); + + batch.begin(); + renderer.draw(batch, skeleton); // Draw the skeleton images. + batch.end(); + + debugRenderer.draw(skeleton); // Draw debug lines. + } + + public void resize (int width, int height) { + camera.setToOrtho(false); // Update camera with new size. + } + + public void dispose () { + atlas.dispose(); + } + + public static void main (String[] args) throws Exception { + new LwjglApplication(new SimpleTest2()); + } } diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/SimpleTest3.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/SimpleTest3.java index b6c7f18bf4..006bc1ae83 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/SimpleTest3.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/SimpleTest3.java @@ -1,112 +1,111 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.ApplicationAdapter; -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.backends.lwjgl.LwjglApplication; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.OrthographicCamera; -import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; - -public class SimpleTest3 extends ApplicationAdapter { - OrthographicCamera camera; - PolygonSpriteBatch batch; - SkeletonMeshRenderer renderer; - SkeletonRendererDebug debugRenderer; - - TextureAtlas atlas; - Skeleton skeleton; - AnimationState state; - - public void create () { - camera = new OrthographicCamera(); - batch = new PolygonSpriteBatch(); // Required to render meshes. SpriteBatch can't render meshes. - renderer = new SkeletonMeshRenderer(); - renderer.setPremultipliedAlpha(true); - debugRenderer = new SkeletonRendererDebug(); - debugRenderer.setMeshTriangles(false); - debugRenderer.setRegionAttachments(false); - debugRenderer.setMeshHull(false); - - atlas = new TextureAtlas(Gdx.files.internal("raptor/raptor-pma.atlas")); - SkeletonJson json = new SkeletonJson(atlas); // This loads skeleton JSON data, which is stateless. - json.setScale(0.5f); // Load the skeleton at 50% the size it was in Spine. - SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("raptor/raptor.json")); - - skeleton = new Skeleton(skeletonData); // Skeleton holds skeleton state (bone positions, slot attachments, etc). - skeleton.setPosition(250, 20); - - AnimationStateData stateData = new AnimationStateData(skeletonData); // Defines mixing (crossfading) between animations. - - state = new AnimationState(stateData); // Holds the animation state for a skeleton (current animation, time, etc). - state.setTimeScale(0.6f); // Slow all animations down to 60% speed. - - // Queue animations on tracks 0 and 1. - state.setAnimation(0, "walk", true); - state.setAnimation(1, "empty", false); - state.addAnimation(1, "gungrab", false, 2); // Keys in higher tracks override the pose from lower tracks. - } - - public void render () { - state.update(Gdx.graphics.getDeltaTime()); // Update the animation time. - - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); - - state.apply(skeleton); // Poses skeleton using current animations. This sets the bones' local SRT. - skeleton.updateWorldTransform(); // Uses the bones' local SRT to compute their world SRT. - - // Configure the camera, SpriteBatch, and SkeletonRendererDebug. - camera.update(); - batch.getProjectionMatrix().set(camera.combined); - debugRenderer.getShapeRenderer().setProjectionMatrix(camera.combined); - - batch.begin(); - renderer.draw(batch, skeleton); // Draw the skeleton images. - batch.end(); - - debugRenderer.draw(skeleton); // Draw debug lines. - } - - public void resize (int width, int height) { - camera.setToOrtho(false); // Update camera with new size. - } - - public void dispose () { - atlas.dispose(); - } - - public static void main (String[] args) throws Exception { - new LwjglApplication(new SimpleTest3()); - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.ApplicationAdapter; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.backends.lwjgl.LwjglApplication; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; + +public class SimpleTest3 extends ApplicationAdapter { + OrthographicCamera camera; + PolygonSpriteBatch batch; + SkeletonMeshRenderer renderer; + SkeletonRendererDebug debugRenderer; + + TextureAtlas atlas; + Skeleton skeleton; + AnimationState state; + + public void create () { + camera = new OrthographicCamera(); + batch = new PolygonSpriteBatch(); // Required to render meshes. SpriteBatch can't render meshes. + renderer = new SkeletonMeshRenderer(); + renderer.setPremultipliedAlpha(true); + debugRenderer = new SkeletonRendererDebug(); + debugRenderer.setMeshTriangles(false); + debugRenderer.setRegionAttachments(false); + debugRenderer.setMeshHull(false); + + atlas = new TextureAtlas(Gdx.files.internal("raptor/raptor-pma.atlas")); + SkeletonJson json = new SkeletonJson(atlas); // This loads skeleton JSON data, which is stateless. + json.setScale(0.5f); // Load the skeleton at 50% the size it was in Spine. + SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("raptor/raptor.json")); + + skeleton = new Skeleton(skeletonData); // Skeleton holds skeleton state (bone positions, slot attachments, etc). + skeleton.setPosition(250, 20); + + AnimationStateData stateData = new AnimationStateData(skeletonData); // Defines mixing (crossfading) between animations. + + state = new AnimationState(stateData); // Holds the animation state for a skeleton (current animation, time, etc). + state.setTimeScale(0.6f); // Slow all animations down to 60% speed. + + // Queue animations on tracks 0 and 1. + state.setAnimation(0, "walk", true); + state.setAnimation(1, "empty", false); + state.addAnimation(1, "gungrab", false, 2); // Keys in higher tracks override the pose from lower tracks. + } + + public void render () { + state.update(Gdx.graphics.getDeltaTime()); // Update the animation time. + + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + state.apply(skeleton); // Poses skeleton using current animations. This sets the bones' local SRT. + skeleton.updateWorldTransform(); // Uses the bones' local SRT to compute their world SRT. + + // Configure the camera, SpriteBatch, and SkeletonRendererDebug. + camera.update(); + batch.getProjectionMatrix().set(camera.combined); + debugRenderer.getShapeRenderer().setProjectionMatrix(camera.combined); + + batch.begin(); + renderer.draw(batch, skeleton); // Draw the skeleton images. + batch.end(); + + debugRenderer.draw(skeleton); // Draw debug lines. + } + + public void resize (int width, int height) { + camera.setToOrtho(false); // Update camera with new size. + } + + public void dispose () { + atlas.dispose(); + } + + public static void main (String[] args) throws Exception { + new LwjglApplication(new SimpleTest3()); + } } diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/SkeletonAttachmentTest.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/SkeletonAttachmentTest.java index 5e71143922..69feb019a7 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/SkeletonAttachmentTest.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/SkeletonAttachmentTest.java @@ -1,115 +1,114 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.ApplicationAdapter; -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.backends.lwjgl.LwjglApplication; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.OrthographicCamera; -import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.esotericsoftware.spine.attachments.SkeletonAttachment; - -public class SkeletonAttachmentTest extends ApplicationAdapter { - OrthographicCamera camera; - PolygonSpriteBatch batch; - SkeletonMeshRenderer renderer; - - Skeleton spineboy, goblin; - AnimationState spineboyState, goblinState; - - public void create () { - camera = new OrthographicCamera(); - batch = new PolygonSpriteBatch(); - renderer = new SkeletonMeshRenderer(); - renderer.setPremultipliedAlpha(true); - - { - TextureAtlas atlas = new TextureAtlas(Gdx.files.internal("spineboy/spineboy-pma.atlas")); - SkeletonJson json = new SkeletonJson(atlas); - json.setScale(0.6f); - SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("spineboy/spineboy.json")); - spineboy = new Skeleton(skeletonData); - spineboy.setPosition(320, 20); - - AnimationStateData stateData = new AnimationStateData(skeletonData); - stateData.setMix("walk", "jump", 0.2f); - stateData.setMix("jump", "walk", 0.2f); - spineboyState = new AnimationState(stateData); - spineboyState.addAnimation(0, "walk", true, 0); - } - - { - TextureAtlas atlas = new TextureAtlas(Gdx.files.internal("goblins/goblins-pma.atlas")); - SkeletonJson json = new SkeletonJson(atlas); - SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("goblins/goblins-mesh.json")); - goblin = new Skeleton(skeletonData); - goblin.setSkin("goblin"); - goblin.setSlotsToSetupPose(); - - goblinState = new AnimationState(new AnimationStateData(skeletonData)); - goblinState.setAnimation(0, "walk", true); - - // Instead of a right shoulder, spineboy will have a goblin! - SkeletonAttachment skeletonAttachment = new SkeletonAttachment("goblin"); - skeletonAttachment.setSkeleton(goblin); - spineboy.findSlot("front_upper_arm").setAttachment(skeletonAttachment); - } - } - - public void render () { - spineboyState.update(Gdx.graphics.getDeltaTime()); - spineboyState.apply(spineboy); - spineboy.updateWorldTransform(); - - goblinState.update(Gdx.graphics.getDeltaTime()); - goblinState.apply(goblin); - goblin.updateWorldTransform(); - - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); - - camera.update(); - batch.getProjectionMatrix().set(camera.combined); - batch.begin(); - renderer.draw(batch, spineboy); - batch.end(); - } - - public void resize (int width, int height) { - camera.setToOrtho(false); - } - - public static void main (String[] args) throws Exception { - new LwjglApplication(new SkeletonAttachmentTest()); - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.ApplicationAdapter; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.backends.lwjgl.LwjglApplication; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.esotericsoftware.spine.attachments.SkeletonAttachment; + +public class SkeletonAttachmentTest extends ApplicationAdapter { + OrthographicCamera camera; + PolygonSpriteBatch batch; + SkeletonMeshRenderer renderer; + + Skeleton spineboy, goblin; + AnimationState spineboyState, goblinState; + + public void create () { + camera = new OrthographicCamera(); + batch = new PolygonSpriteBatch(); + renderer = new SkeletonMeshRenderer(); + renderer.setPremultipliedAlpha(true); + + { + TextureAtlas atlas = new TextureAtlas(Gdx.files.internal("spineboy/spineboy-pma.atlas")); + SkeletonJson json = new SkeletonJson(atlas); + json.setScale(0.6f); + SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("spineboy/spineboy.json")); + spineboy = new Skeleton(skeletonData); + spineboy.setPosition(320, 20); + + AnimationStateData stateData = new AnimationStateData(skeletonData); + stateData.setMix("walk", "jump", 0.2f); + stateData.setMix("jump", "walk", 0.2f); + spineboyState = new AnimationState(stateData); + spineboyState.addAnimation(0, "walk", true, 0); + } + + { + TextureAtlas atlas = new TextureAtlas(Gdx.files.internal("goblins/goblins-pma.atlas")); + SkeletonJson json = new SkeletonJson(atlas); + SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal("goblins/goblins-mesh.json")); + goblin = new Skeleton(skeletonData); + goblin.setSkin("goblin"); + goblin.setSlotsToSetupPose(); + + goblinState = new AnimationState(new AnimationStateData(skeletonData)); + goblinState.setAnimation(0, "walk", true); + + // Instead of a right shoulder, spineboy will have a goblin! + SkeletonAttachment skeletonAttachment = new SkeletonAttachment("goblin"); + skeletonAttachment.setSkeleton(goblin); + spineboy.findSlot("front_upper_arm").setAttachment(skeletonAttachment); + } + } + + public void render () { + spineboyState.update(Gdx.graphics.getDeltaTime()); + spineboyState.apply(spineboy); + spineboy.updateWorldTransform(); + + goblinState.update(Gdx.graphics.getDeltaTime()); + goblinState.apply(goblin); + goblin.updateWorldTransform(); + + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + camera.update(); + batch.getProjectionMatrix().set(camera.combined); + batch.begin(); + renderer.draw(batch, spineboy); + batch.end(); + } + + public void resize (int width, int height) { + camera.setToOrtho(false); + } + + public static void main (String[] args) throws Exception { + new LwjglApplication(new SkeletonAttachmentTest()); + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java index 39b3689601..bf3021f4e2 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java @@ -1,1011 +1,1010 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.math.MathUtils; -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.FloatArray; -import com.esotericsoftware.spine.attachments.Attachment; -import com.esotericsoftware.spine.attachments.VertexAttachment; - -public class Animation { - final String name; - private final Array timelines; - private float duration; - - public Animation (String name, Array timelines, float duration) { - if (name == null) throw new IllegalArgumentException("name cannot be null."); - if (timelines == null) throw new IllegalArgumentException("timelines cannot be null."); - this.name = name; - this.timelines = timelines; - this.duration = duration; - } - - public Array getTimelines () { - return timelines; - } - - /** Returns the duration of the animation in seconds. */ - public float getDuration () { - return duration; - } - - public void setDuration (float duration) { - this.duration = duration; - } - - /** Poses the skeleton at the specified time for this animation. - * @param lastTime The last time the animation was applied. - * @param events Any triggered events are added. May be null. */ - public void apply (Skeleton skeleton, float lastTime, float time, boolean loop, Array events) { - if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); - - if (loop && duration != 0) { - time %= duration; - if (lastTime > 0) lastTime %= duration; - } - - Array timelines = this.timelines; - for (int i = 0, n = timelines.size; i < n; i++) - timelines.get(i).apply(skeleton, lastTime, time, events, 1); - } - - /** Poses the skeleton at the specified time for this animation mixed with the current pose. - * @param lastTime The last time the animation was applied. - * @param events Any triggered events are added. May be null. - * @param alpha The amount of this animation that affects the current pose. */ - public void mix (Skeleton skeleton, float lastTime, float time, boolean loop, Array events, float alpha) { - if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); - - if (loop && duration != 0) { - time %= duration; - if (lastTime > 0) lastTime %= duration; - } - - Array timelines = this.timelines; - for (int i = 0, n = timelines.size; i < n; i++) - timelines.get(i).apply(skeleton, lastTime, time, events, alpha); - } - - public String getName () { - return name; - } - - public String toString () { - return name; - } - - /** @param target After the first and before the last value. - * @return index of first value greater than the target. */ - static int binarySearch (float[] values, float target, int step) { - int low = 0; - int high = values.length / step - 2; - if (high == 0) return step; - int current = high >>> 1; - while (true) { - if (values[(current + 1) * step] <= target) - low = current + 1; - else - high = current; - if (low == high) return (low + 1) * step; - current = (low + high) >>> 1; - } - } - - /** @param target After the first and before the last value. - * @return index of first value greater than the target. */ - static int binarySearch (float[] values, float target) { - int low = 0; - int high = values.length - 2; - if (high == 0) return 1; - int current = high >>> 1; - while (true) { - if (values[current + 1] <= target) - low = current + 1; - else - high = current; - if (low == high) return low + 1; - current = (low + high) >>> 1; - } - } - - static int linearSearch (float[] values, float target, int step) { - for (int i = 0, last = values.length - step; i <= last; i += step) - if (values[i] > target) return i; - return -1; - } - - static public interface Timeline { - /** Sets the value(s) for the specified time. - * @param events May be null to not collect fired events. */ - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha); - } - - /** Base class for frames that use an interpolation bezier curve. */ - abstract static public class CurveTimeline implements Timeline { - static public final float LINEAR = 0, STEPPED = 1, BEZIER = 2; - static private final int BEZIER_SIZE = 10 * 2 - 1; - - private final float[] curves; // type, x, y, ... - - public CurveTimeline (int frameCount) { - if (frameCount <= 0) throw new IllegalArgumentException("frameCount must be > 0: " + frameCount); - curves = new float[(frameCount - 1) * BEZIER_SIZE]; - } - - public int getFrameCount () { - return curves.length / BEZIER_SIZE + 1; - } - - public void setLinear (int frameIndex) { - curves[frameIndex * BEZIER_SIZE] = LINEAR; - } - - public void setStepped (int frameIndex) { - curves[frameIndex * BEZIER_SIZE] = STEPPED; - } - - public float getCurveType (int frameIndex) { - int index = frameIndex * BEZIER_SIZE; - if (index == curves.length) return LINEAR; - float type = curves[index]; - if (type == LINEAR) return LINEAR; - if (type == STEPPED) return STEPPED; - return BEZIER; - } - - /** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. - * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of - * the difference between the keyframe's values. */ - public void setCurve (int frameIndex, float cx1, float cy1, float cx2, float cy2) { - float tmpx = (-cx1 * 2 + cx2) * 0.03f, tmpy = (-cy1 * 2 + cy2) * 0.03f; - float dddfx = ((cx1 - cx2) * 3 + 1) * 0.006f, dddfy = ((cy1 - cy2) * 3 + 1) * 0.006f; - float ddfx = tmpx * 2 + dddfx, ddfy = tmpy * 2 + dddfy; - float dfx = cx1 * 0.3f + tmpx + dddfx * 0.16666667f, dfy = cy1 * 0.3f + tmpy + dddfy * 0.16666667f; - - int i = frameIndex * BEZIER_SIZE; - float[] curves = this.curves; - curves[i++] = BEZIER; - - float x = dfx, y = dfy; - for (int n = i + BEZIER_SIZE - 1; i < n; i += 2) { - curves[i] = x; - curves[i + 1] = y; - dfx += ddfx; - dfy += ddfy; - ddfx += dddfx; - ddfy += dddfy; - x += dfx; - y += dfy; - } - } - - public float getCurvePercent (int frameIndex, float percent) { - percent = MathUtils.clamp(percent, 0, 1); - float[] curves = this.curves; - int i = frameIndex * BEZIER_SIZE; - float type = curves[i]; - if (type == LINEAR) return percent; - if (type == STEPPED) return 0; - i++; - float x = 0; - for (int start = i, n = i + BEZIER_SIZE - 1; i < n; i += 2) { - x = curves[i]; - if (x >= percent) { - float prevX, prevY; - if (i == start) { - prevX = 0; - prevY = 0; - } else { - prevX = curves[i - 2]; - prevY = curves[i - 1]; - } - return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX); - } - } - float y = curves[i - 1]; - return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. - } - } - - static public class RotateTimeline extends CurveTimeline { - static public final int ENTRIES = 2; - static private final int PREV_TIME = -2, PREV_ROTATION = -1; - static private final int ROTATION = 1; - - int boneIndex; - final float[] frames; // time, degrees, ... - - public RotateTimeline (int frameCount) { - super(frameCount); - frames = new float[frameCount << 1]; - } - - public void setBoneIndex (int index) { - if (index < 0) throw new IllegalArgumentException("index must be >= 0."); - this.boneIndex = index; - } - - public int getBoneIndex () { - return boneIndex; - } - - public float[] getFrames () { - return frames; - } - - /** Sets the time and angle of the specified keyframe. */ - public void setFrame (int frameIndex, float time, float degrees) { - frameIndex <<= 1; - frames[frameIndex] = time; - frames[frameIndex + ROTATION] = degrees; - } - - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - Bone bone = skeleton.bones.get(boneIndex); - - if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. - float amount = bone.data.rotation + frames[frames.length + PREV_ROTATION] - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = binarySearch(frames, time, ENTRIES); - float prevRotation = frames[frame + PREV_ROTATION]; - float frameTime = frames[frame]; - float percent = getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - float amount = frames[frame + ROTATION] - prevRotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - amount = bone.data.rotation + (prevRotation + amount * percent) - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - } - } - - static public class TranslateTimeline extends CurveTimeline { - static public final int ENTRIES = 3; - static final int PREV_TIME = -3, PREV_X = -2, PREV_Y = -1; - static final int X = 1, Y = 2; - - int boneIndex; - final float[] frames; // time, x, y, ... - - public TranslateTimeline (int frameCount) { - super(frameCount); - frames = new float[frameCount * ENTRIES]; - } - - public void setBoneIndex (int index) { - if (index < 0) throw new IllegalArgumentException("index must be >= 0."); - this.boneIndex = index; - } - - public int getBoneIndex () { - return boneIndex; - } - - public float[] getFrames () { - return frames; - } - - /** Sets the time and value of the specified keyframe. */ - public void setFrame (int frameIndex, float time, float x, float y) { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[frameIndex + X] = x; - frames[frameIndex + Y] = y; - } - - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - Bone bone = skeleton.bones.get(boneIndex); - - if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. - bone.x += (bone.data.x + frames[frames.length + PREV_X] - bone.x) * alpha; - bone.y += (bone.data.y + frames[frames.length + PREV_Y] - bone.y) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = binarySearch(frames, time, ENTRIES); - float prevX = frames[frame + PREV_X]; - float prevY = frames[frame + PREV_Y]; - float frameTime = frames[frame]; - float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - bone.x += (bone.data.x + prevX + (frames[frame + X] - prevX) * percent - bone.x) * alpha; - bone.y += (bone.data.y + prevY + (frames[frame + Y] - prevY) * percent - bone.y) * alpha; - } - } - - static public class ScaleTimeline extends TranslateTimeline { - public ScaleTimeline (int frameCount) { - super(frameCount); - } - - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - Bone bone = skeleton.bones.get(boneIndex); - if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. - bone.scaleX += (bone.data.scaleX * frames[frames.length + PREV_X] - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY * frames[frames.length + PREV_Y] - bone.scaleY) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = binarySearch(frames, time, ENTRIES); - float prevX = frames[frame + PREV_X]; - float prevY = frames[frame + PREV_Y]; - float frameTime = frames[frame]; - float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - bone.scaleX += (bone.data.scaleX * (prevX + (frames[frame + X] - prevX) * percent) - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY * (prevY + (frames[frame + Y] - prevY) * percent) - bone.scaleY) * alpha; - } - } - - static public class ShearTimeline extends TranslateTimeline { - public ShearTimeline (int frameCount) { - super(frameCount); - } - - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - Bone bone = skeleton.bones.get(boneIndex); - if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. - bone.shearX += (bone.data.shearX + frames[frames.length + PREV_X] - bone.shearX) * alpha; - bone.shearY += (bone.data.shearY + frames[frames.length + PREV_Y] - bone.shearY) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = binarySearch(frames, time, ENTRIES); - float prevX = frames[frame + PREV_X]; - float prevY = frames[frame + PREV_Y]; - float frameTime = frames[frame]; - float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - bone.shearX += (bone.data.shearX + (prevX + (frames[frame + X] - prevX) * percent) - bone.shearX) * alpha; - bone.shearY += (bone.data.shearY + (prevY + (frames[frame + Y] - prevY) * percent) - bone.shearY) * alpha; - } - } - - static public class ColorTimeline extends CurveTimeline { - static public final int ENTRIES = 5; - static private final int PREV_TIME = -5, PREV_R = -4, PREV_G = -3, PREV_B = -2, PREV_A = -1; - static private final int R = 1, G = 2, B = 3, A = 4; - - int slotIndex; - private final float[] frames; // time, r, g, b, a, ... - - public ColorTimeline (int frameCount) { - super(frameCount); - frames = new float[frameCount * ENTRIES]; - } - - public void setSlotIndex (int index) { - if (index < 0) throw new IllegalArgumentException("index must be >= 0."); - this.slotIndex = index; - } - - public int getSlotIndex () { - return slotIndex; - } - - public float[] getFrames () { - return frames; - } - - /** Sets the time and value of the specified keyframe. */ - public void setFrame (int frameIndex, float time, float r, float g, float b, float a) { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[frameIndex + R] = r; - frames[frameIndex + G] = g; - frames[frameIndex + B] = b; - frames[frameIndex + A] = a; - } - - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - float r, g, b, a; - if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. - int i = frames.length; - r = frames[i + PREV_R]; - g = frames[i + PREV_G]; - b = frames[i + PREV_B]; - a = frames[i + PREV_A]; - } else { - // Interpolate between the previous frame and the current frame. - int frame = binarySearch(frames, time, ENTRIES); - r = frames[frame + PREV_R]; - g = frames[frame + PREV_G]; - b = frames[frame + PREV_B]; - a = frames[frame + PREV_A]; - float frameTime = frames[frame]; - float percent = getCurvePercent(frame / ENTRIES - 1, - 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - r += (frames[frame + R] - r) * percent; - g += (frames[frame + G] - g) * percent; - b += (frames[frame + B] - b) * percent; - a += (frames[frame + A] - a) * percent; - } - Color color = skeleton.slots.get(slotIndex).color; - if (alpha < 1) - color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha); - else - color.set(r, g, b, a); - } - } - - static public class AttachmentTimeline implements Timeline { - int slotIndex; - final float[] frames; // time, ... - final String[] attachmentNames; - - public AttachmentTimeline (int frameCount) { - frames = new float[frameCount]; - attachmentNames = new String[frameCount]; - } - - public int getFrameCount () { - return frames.length; - } - - public void setSlotIndex (int index) { - if (index < 0) throw new IllegalArgumentException("index must be >= 0."); - this.slotIndex = index; - } - - public int getSlotIndex () { - return slotIndex; - } - - public float[] getFrames () { - return frames; - } - - public String[] getAttachmentNames () { - return attachmentNames; - } - - /** Sets the time and value of the specified keyframe. */ - public void setFrame (int frameIndex, float time, String attachmentName) { - frames[frameIndex] = time; - attachmentNames[frameIndex] = attachmentName; - } - - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - int frameIndex; - if (time >= frames[frames.length - 1]) // Time is after last frame. - frameIndex = frames.length - 1; - else - frameIndex = binarySearch(frames, time, 1) - 1; - - String attachmentName = attachmentNames[frameIndex]; - skeleton.slots.get(slotIndex) - .setAttachment(attachmentName == null ? null : skeleton.getAttachment(slotIndex, attachmentName)); - } - } - - static public class EventTimeline implements Timeline { - private final float[] frames; // time, ... - private final Event[] events; - - public EventTimeline (int frameCount) { - frames = new float[frameCount]; - events = new Event[frameCount]; - } - - public int getFrameCount () { - return frames.length; - } - - public float[] getFrames () { - return frames; - } - - public Event[] getEvents () { - return events; - } - - /** Sets the time of the specified keyframe. */ - public void setFrame (int frameIndex, Event event) { - frames[frameIndex] = event.time; - events[frameIndex] = event; - } - - /** Fires events for frames > lastTime and <= time. */ - public void apply (Skeleton skeleton, float lastTime, float time, Array firedEvents, float alpha) { - if (firedEvents == null) return; - float[] frames = this.frames; - int frameCount = frames.length; - - if (lastTime > time) { // Fire events after last time for looped animations. - apply(skeleton, lastTime, Integer.MAX_VALUE, firedEvents, alpha); - lastTime = -1f; - } else if (lastTime >= frames[frameCount - 1]) // Last time is after last frame. - return; - if (time < frames[0]) return; // Time is before first frame. - - int frame; - if (lastTime < frames[0]) - frame = 0; - else { - frame = binarySearch(frames, lastTime); - float frameTime = frames[frame]; - while (frame > 0) { // Fire multiple events with the same frame. - if (frames[frame - 1] != frameTime) break; - frame--; - } - } - for (; frame < frameCount && time >= frames[frame]; frame++) - firedEvents.add(events[frame]); - } - } - - static public class DrawOrderTimeline implements Timeline { - private final float[] frames; // time, ... - private final int[][] drawOrders; - - public DrawOrderTimeline (int frameCount) { - frames = new float[frameCount]; - drawOrders = new int[frameCount][]; - } - - public int getFrameCount () { - return frames.length; - } - - public float[] getFrames () { - return frames; - } - - public int[][] getDrawOrders () { - return drawOrders; - } - - /** Sets the time of the specified keyframe. - * @param drawOrder May be null to use bind pose draw order. */ - public void setFrame (int frameIndex, float time, int[] drawOrder) { - frames[frameIndex] = time; - drawOrders[frameIndex] = drawOrder; - } - - public void apply (Skeleton skeleton, float lastTime, float time, Array firedEvents, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - int frame; - if (time >= frames[frames.length - 1]) // Time is after last frame. - frame = frames.length - 1; - else - frame = binarySearch(frames, time) - 1; - - Array drawOrder = skeleton.drawOrder; - Array slots = skeleton.slots; - int[] drawOrderToSetupIndex = drawOrders[frame]; - if (drawOrderToSetupIndex == null) - System.arraycopy(slots.items, 0, drawOrder.items, 0, slots.size); - else { - for (int i = 0, n = drawOrderToSetupIndex.length; i < n; i++) - drawOrder.set(i, slots.get(drawOrderToSetupIndex[i])); - } - } - } - - static public class DeformTimeline extends CurveTimeline { - private final float[] frames; // time, ... - private final float[][] frameVertices; - int slotIndex; - VertexAttachment attachment; - - public DeformTimeline (int frameCount) { - super(frameCount); - frames = new float[frameCount]; - frameVertices = new float[frameCount][]; - } - - public void setSlotIndex (int index) { - if (index < 0) throw new IllegalArgumentException("index must be >= 0."); - this.slotIndex = index; - } - - public int getSlotIndex () { - return slotIndex; - } - - public void setAttachment (VertexAttachment attachment) { - this.attachment = attachment; - } - - public Attachment getAttachment () { - return attachment; - } - - public float[] getFrames () { - return frames; - } - - public float[][] getVertices () { - return frameVertices; - } - - /** Sets the time of the specified keyframe. */ - public void setFrame (int frameIndex, float time, float[] vertices) { - frames[frameIndex] = time; - frameVertices[frameIndex] = vertices; - } - - public void apply (Skeleton skeleton, float lastTime, float time, Array firedEvents, float alpha) { - Slot slot = skeleton.slots.get(slotIndex); - Attachment slotAttachment = slot.attachment; - if (!(slotAttachment instanceof VertexAttachment) || !((VertexAttachment)slotAttachment).applyDeform(attachment)) return; - - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - float[][] frameVertices = this.frameVertices; - int vertexCount = frameVertices[0].length; - - FloatArray verticesArray = slot.getAttachmentVertices(); - if (verticesArray.size != vertexCount) alpha = 1; // Don't mix from uninitialized slot vertices. - float[] vertices = verticesArray.setSize(vertexCount); - - if (time >= frames[frames.length - 1]) { // Time is after last frame. - float[] lastVertices = frameVertices[frames.length - 1]; - if (alpha < 1) { - for (int i = 0; i < vertexCount; i++) - vertices[i] += (lastVertices[i] - vertices[i]) * alpha; - } else - System.arraycopy(lastVertices, 0, vertices, 0, vertexCount); - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = binarySearch(frames, time); - float[] prevVertices = frameVertices[frame - 1]; - float[] nextVertices = frameVertices[frame]; - float frameTime = frames[frame]; - float percent = getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime)); - - if (alpha < 1) { - for (int i = 0; i < vertexCount; i++) { - float prev = prevVertices[i]; - vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha; - } - } else { - for (int i = 0; i < vertexCount; i++) { - float prev = prevVertices[i]; - vertices[i] = prev + (nextVertices[i] - prev) * percent; - } - } - } - } - - static public class IkConstraintTimeline extends CurveTimeline { - static public final int ENTRIES = 3; - static private final int PREV_TIME = -3, PREV_MIX = -2, PREV_BEND_DIRECTION = -1; - static private final int MIX = 1, BEND_DIRECTION = 2; - - int ikConstraintIndex; - private final float[] frames; // time, mix, bendDirection, ... - - public IkConstraintTimeline (int frameCount) { - super(frameCount); - frames = new float[frameCount * ENTRIES]; - } - - public void setIkConstraintIndex (int index) { - if (index < 0) throw new IllegalArgumentException("index must be >= 0."); - this.ikConstraintIndex = index; - } - - public int getIkConstraintIndex () { - return ikConstraintIndex; - } - - public float[] getFrames () { - return frames; - } - - /** Sets the time, mix and bend direction of the specified keyframe. */ - public void setFrame (int frameIndex, float time, float mix, int bendDirection) { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[frameIndex + MIX] = mix; - frames[frameIndex + BEND_DIRECTION] = bendDirection; - } - - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - IkConstraint constraint = skeleton.ikConstraints.get(ikConstraintIndex); - - if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. - constraint.mix += (frames[frames.length + PREV_MIX] - constraint.mix) * alpha; - constraint.bendDirection = (int)frames[frames.length + PREV_BEND_DIRECTION]; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = binarySearch(frames, time, ENTRIES); - float mix = frames[frame + PREV_MIX]; - float frameTime = frames[frame]; - float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - constraint.mix += (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha; - constraint.bendDirection = (int)frames[frame + PREV_BEND_DIRECTION]; - } - } - - static public class TransformConstraintTimeline extends CurveTimeline { - static public final int ENTRIES = 5; - static private final int PREV_TIME = -5, PREV_ROTATE = -4, PREV_TRANSLATE = -3, PREV_SCALE = -2, PREV_SHEAR = -1; - static private final int ROTATE = 1, TRANSLATE = 2, SCALE = 3, SHEAR = 4; - - int transformConstraintIndex; - private final float[] frames; // time, rotate mix, translate mix, scale mix, shear mix, ... - - public TransformConstraintTimeline (int frameCount) { - super(frameCount); - frames = new float[frameCount * ENTRIES]; - } - - public void setTransformConstraintIndex (int index) { - if (index < 0) throw new IllegalArgumentException("index must be >= 0."); - this.transformConstraintIndex = index; - } - - public int getTransformConstraintIndex () { - return transformConstraintIndex; - } - - public float[] getFrames () { - return frames; - } - - /** Sets the time and mixes of the specified keyframe. */ - public void setFrame (int frameIndex, float time, float rotateMix, float translateMix, float scaleMix, float shearMix) { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[frameIndex + ROTATE] = rotateMix; - frames[frameIndex + TRANSLATE] = translateMix; - frames[frameIndex + SCALE] = scaleMix; - frames[frameIndex + SHEAR] = shearMix; - } - - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - TransformConstraint constraint = skeleton.transformConstraints.get(transformConstraintIndex); - - if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. - int i = frames.length; - constraint.rotateMix += (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha; - constraint.translateMix += (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha; - constraint.scaleMix += (frames[i + PREV_SCALE] - constraint.scaleMix) * alpha; - constraint.shearMix += (frames[i + PREV_SHEAR] - constraint.shearMix) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = binarySearch(frames, time, ENTRIES); - float frameTime = frames[frame]; - float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - float rotate = frames[frame + PREV_ROTATE]; - float translate = frames[frame + PREV_TRANSLATE]; - float scale = frames[frame + PREV_SCALE]; - float shear = frames[frame + PREV_SHEAR]; - constraint.rotateMix += (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha; - constraint.translateMix += (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix) - * alpha; - constraint.scaleMix += (scale + (frames[frame + SCALE] - scale) * percent - constraint.scaleMix) * alpha; - constraint.shearMix += (shear + (frames[frame + SHEAR] - shear) * percent - constraint.shearMix) * alpha; - } - } - - static public class PathConstraintPositionTimeline extends CurveTimeline { - static public final int ENTRIES = 2; - static final int PREV_TIME = -2, PREV_VALUE = -1; - static final int VALUE = 1; - - int pathConstraintIndex; - - final float[] frames; // time, position, ... - - public PathConstraintPositionTimeline (int frameCount) { - super(frameCount); - frames = new float[frameCount * ENTRIES]; - } - - public void setPathConstraintIndex (int index) { - if (index < 0) throw new IllegalArgumentException("index must be >= 0."); - this.pathConstraintIndex = index; - } - - public int getPathConstraintIndex () { - return pathConstraintIndex; - } - - public float[] getFrames () { - return frames; - } - - /** Sets the time and value of the specified keyframe. */ - public void setFrame (int frameIndex, float time, float value) { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[frameIndex + VALUE] = value; - } - - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - PathConstraint constraint = skeleton.pathConstraints.get(pathConstraintIndex); - - if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. - int i = frames.length; - constraint.position += (frames[i + PREV_VALUE] - constraint.position) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = binarySearch(frames, time, ENTRIES); - float position = frames[frame + PREV_VALUE]; - float frameTime = frames[frame]; - float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - constraint.position += (position + (frames[frame + VALUE] - position) * percent - constraint.position) * alpha; - } - } - - static public class PathConstraintSpacingTimeline extends PathConstraintPositionTimeline { - public PathConstraintSpacingTimeline (int frameCount) { - super(frameCount); - } - - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - PathConstraint constraint = skeleton.pathConstraints.get(pathConstraintIndex); - - if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. - int i = frames.length; - constraint.spacing += (frames[i + PREV_VALUE] - constraint.spacing) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = binarySearch(frames, time, ENTRIES); - float spacing = frames[frame + PREV_VALUE]; - float frameTime = frames[frame]; - float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - constraint.spacing += (spacing + (frames[frame + VALUE] - spacing) * percent - constraint.spacing) * alpha; - } - } - - static public class PathConstraintMixTimeline extends CurveTimeline { - static public final int ENTRIES = 3; - static private final int PREV_TIME = -3, PREV_ROTATE = -2, PREV_TRANSLATE = -1; - static private final int ROTATE = 1, TRANSLATE = 2; - - int pathConstraintIndex; - - private final float[] frames; // time, rotate mix, translate mix, ... - - public PathConstraintMixTimeline (int frameCount) { - super(frameCount); - frames = new float[frameCount * ENTRIES]; - } - - public void setPathConstraintIndex (int index) { - if (index < 0) throw new IllegalArgumentException("index must be >= 0."); - this.pathConstraintIndex = index; - } - - public int getPathConstraintIndex () { - return pathConstraintIndex; - } - - public float[] getFrames () { - return frames; - } - - /** Sets the time and mixes of the specified keyframe. */ - public void setFrame (int frameIndex, float time, float rotateMix, float translateMix) { - frameIndex *= ENTRIES; - frames[frameIndex] = time; - frames[frameIndex + ROTATE] = rotateMix; - frames[frameIndex + TRANSLATE] = translateMix; - } - - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { - float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - PathConstraint constraint = skeleton.pathConstraints.get(pathConstraintIndex); - - if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. - int i = frames.length; - constraint.rotateMix += (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha; - constraint.translateMix += (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = binarySearch(frames, time, ENTRIES); - float rotate = frames[frame + PREV_ROTATE]; - float translate = frames[frame + PREV_TRANSLATE]; - float frameTime = frames[frame]; - float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - constraint.rotateMix += (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha; - constraint.translateMix += (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix) - * alpha; - } - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.FloatArray; +import com.esotericsoftware.spine.attachments.Attachment; +import com.esotericsoftware.spine.attachments.VertexAttachment; + +public class Animation { + final String name; + private final Array timelines; + private float duration; + + public Animation (String name, Array timelines, float duration) { + if (name == null) throw new IllegalArgumentException("name cannot be null."); + if (timelines == null) throw new IllegalArgumentException("timelines cannot be null."); + this.name = name; + this.timelines = timelines; + this.duration = duration; + } + + public Array getTimelines () { + return timelines; + } + + /** Returns the duration of the animation in seconds. */ + public float getDuration () { + return duration; + } + + public void setDuration (float duration) { + this.duration = duration; + } + + /** Poses the skeleton at the specified time for this animation. + * @param lastTime The last time the animation was applied. + * @param events Any triggered events are added. May be null. */ + public void apply (Skeleton skeleton, float lastTime, float time, boolean loop, Array events) { + if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); + + if (loop && duration != 0) { + time %= duration; + if (lastTime > 0) lastTime %= duration; + } + + Array timelines = this.timelines; + for (int i = 0, n = timelines.size; i < n; i++) + timelines.get(i).apply(skeleton, lastTime, time, events, 1); + } + + /** Poses the skeleton at the specified time for this animation mixed with the current pose. + * @param lastTime The last time the animation was applied. + * @param events Any triggered events are added. May be null. + * @param alpha The amount of this animation that affects the current pose. */ + public void mix (Skeleton skeleton, float lastTime, float time, boolean loop, Array events, float alpha) { + if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); + + if (loop && duration != 0) { + time %= duration; + if (lastTime > 0) lastTime %= duration; + } + + Array timelines = this.timelines; + for (int i = 0, n = timelines.size; i < n; i++) + timelines.get(i).apply(skeleton, lastTime, time, events, alpha); + } + + public String getName () { + return name; + } + + public String toString () { + return name; + } + + /** @param target After the first and before the last value. + * @return index of first value greater than the target. */ + static int binarySearch (float[] values, float target, int step) { + int low = 0; + int high = values.length / step - 2; + if (high == 0) return step; + int current = high >>> 1; + while (true) { + if (values[(current + 1) * step] <= target) + low = current + 1; + else + high = current; + if (low == high) return (low + 1) * step; + current = (low + high) >>> 1; + } + } + + /** @param target After the first and before the last value. + * @return index of first value greater than the target. */ + static int binarySearch (float[] values, float target) { + int low = 0; + int high = values.length - 2; + if (high == 0) return 1; + int current = high >>> 1; + while (true) { + if (values[current + 1] <= target) + low = current + 1; + else + high = current; + if (low == high) return low + 1; + current = (low + high) >>> 1; + } + } + + static int linearSearch (float[] values, float target, int step) { + for (int i = 0, last = values.length - step; i <= last; i += step) + if (values[i] > target) return i; + return -1; + } + + static public interface Timeline { + /** Sets the value(s) for the specified time. + * @param events May be null to not collect fired events. */ + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha); + } + + /** Base class for frames that use an interpolation bezier curve. */ + abstract static public class CurveTimeline implements Timeline { + static public final float LINEAR = 0, STEPPED = 1, BEZIER = 2; + static private final int BEZIER_SIZE = 10 * 2 - 1; + + private final float[] curves; // type, x, y, ... + + public CurveTimeline (int frameCount) { + if (frameCount <= 0) throw new IllegalArgumentException("frameCount must be > 0: " + frameCount); + curves = new float[(frameCount - 1) * BEZIER_SIZE]; + } + + public int getFrameCount () { + return curves.length / BEZIER_SIZE + 1; + } + + public void setLinear (int frameIndex) { + curves[frameIndex * BEZIER_SIZE] = LINEAR; + } + + public void setStepped (int frameIndex) { + curves[frameIndex * BEZIER_SIZE] = STEPPED; + } + + public float getCurveType (int frameIndex) { + int index = frameIndex * BEZIER_SIZE; + if (index == curves.length) return LINEAR; + float type = curves[index]; + if (type == LINEAR) return LINEAR; + if (type == STEPPED) return STEPPED; + return BEZIER; + } + + /** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. + * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of + * the difference between the keyframe's values. */ + public void setCurve (int frameIndex, float cx1, float cy1, float cx2, float cy2) { + float tmpx = (-cx1 * 2 + cx2) * 0.03f, tmpy = (-cy1 * 2 + cy2) * 0.03f; + float dddfx = ((cx1 - cx2) * 3 + 1) * 0.006f, dddfy = ((cy1 - cy2) * 3 + 1) * 0.006f; + float ddfx = tmpx * 2 + dddfx, ddfy = tmpy * 2 + dddfy; + float dfx = cx1 * 0.3f + tmpx + dddfx * 0.16666667f, dfy = cy1 * 0.3f + tmpy + dddfy * 0.16666667f; + + int i = frameIndex * BEZIER_SIZE; + float[] curves = this.curves; + curves[i++] = BEZIER; + + float x = dfx, y = dfy; + for (int n = i + BEZIER_SIZE - 1; i < n; i += 2) { + curves[i] = x; + curves[i + 1] = y; + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + x += dfx; + y += dfy; + } + } + + public float getCurvePercent (int frameIndex, float percent) { + percent = MathUtils.clamp(percent, 0, 1); + float[] curves = this.curves; + int i = frameIndex * BEZIER_SIZE; + float type = curves[i]; + if (type == LINEAR) return percent; + if (type == STEPPED) return 0; + i++; + float x = 0; + for (int start = i, n = i + BEZIER_SIZE - 1; i < n; i += 2) { + x = curves[i]; + if (x >= percent) { + float prevX, prevY; + if (i == start) { + prevX = 0; + prevY = 0; + } else { + prevX = curves[i - 2]; + prevY = curves[i - 1]; + } + return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX); + } + } + float y = curves[i - 1]; + return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. + } + } + + static public class RotateTimeline extends CurveTimeline { + static public final int ENTRIES = 2; + static private final int PREV_TIME = -2, PREV_ROTATION = -1; + static private final int ROTATION = 1; + + int boneIndex; + final float[] frames; // time, degrees, ... + + public RotateTimeline (int frameCount) { + super(frameCount); + frames = new float[frameCount << 1]; + } + + public void setBoneIndex (int index) { + if (index < 0) throw new IllegalArgumentException("index must be >= 0."); + this.boneIndex = index; + } + + public int getBoneIndex () { + return boneIndex; + } + + public float[] getFrames () { + return frames; + } + + /** Sets the time and angle of the specified keyframe. */ + public void setFrame (int frameIndex, float time, float degrees) { + frameIndex <<= 1; + frames[frameIndex] = time; + frames[frameIndex + ROTATION] = degrees; + } + + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + Bone bone = skeleton.bones.get(boneIndex); + + if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. + float amount = bone.data.rotation + frames[frames.length + PREV_ROTATION] - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = binarySearch(frames, time, ENTRIES); + float prevRotation = frames[frame + PREV_ROTATION]; + float frameTime = frames[frame]; + float percent = getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + float amount = frames[frame + ROTATION] - prevRotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + amount = bone.data.rotation + (prevRotation + amount * percent) - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + } + } + + static public class TranslateTimeline extends CurveTimeline { + static public final int ENTRIES = 3; + static final int PREV_TIME = -3, PREV_X = -2, PREV_Y = -1; + static final int X = 1, Y = 2; + + int boneIndex; + final float[] frames; // time, x, y, ... + + public TranslateTimeline (int frameCount) { + super(frameCount); + frames = new float[frameCount * ENTRIES]; + } + + public void setBoneIndex (int index) { + if (index < 0) throw new IllegalArgumentException("index must be >= 0."); + this.boneIndex = index; + } + + public int getBoneIndex () { + return boneIndex; + } + + public float[] getFrames () { + return frames; + } + + /** Sets the time and value of the specified keyframe. */ + public void setFrame (int frameIndex, float time, float x, float y) { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[frameIndex + X] = x; + frames[frameIndex + Y] = y; + } + + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + Bone bone = skeleton.bones.get(boneIndex); + + if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. + bone.x += (bone.data.x + frames[frames.length + PREV_X] - bone.x) * alpha; + bone.y += (bone.data.y + frames[frames.length + PREV_Y] - bone.y) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = binarySearch(frames, time, ENTRIES); + float prevX = frames[frame + PREV_X]; + float prevY = frames[frame + PREV_Y]; + float frameTime = frames[frame]; + float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + bone.x += (bone.data.x + prevX + (frames[frame + X] - prevX) * percent - bone.x) * alpha; + bone.y += (bone.data.y + prevY + (frames[frame + Y] - prevY) * percent - bone.y) * alpha; + } + } + + static public class ScaleTimeline extends TranslateTimeline { + public ScaleTimeline (int frameCount) { + super(frameCount); + } + + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + Bone bone = skeleton.bones.get(boneIndex); + if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. + bone.scaleX += (bone.data.scaleX * frames[frames.length + PREV_X] - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY * frames[frames.length + PREV_Y] - bone.scaleY) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = binarySearch(frames, time, ENTRIES); + float prevX = frames[frame + PREV_X]; + float prevY = frames[frame + PREV_Y]; + float frameTime = frames[frame]; + float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + bone.scaleX += (bone.data.scaleX * (prevX + (frames[frame + X] - prevX) * percent) - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY * (prevY + (frames[frame + Y] - prevY) * percent) - bone.scaleY) * alpha; + } + } + + static public class ShearTimeline extends TranslateTimeline { + public ShearTimeline (int frameCount) { + super(frameCount); + } + + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + Bone bone = skeleton.bones.get(boneIndex); + if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. + bone.shearX += (bone.data.shearX + frames[frames.length + PREV_X] - bone.shearX) * alpha; + bone.shearY += (bone.data.shearY + frames[frames.length + PREV_Y] - bone.shearY) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = binarySearch(frames, time, ENTRIES); + float prevX = frames[frame + PREV_X]; + float prevY = frames[frame + PREV_Y]; + float frameTime = frames[frame]; + float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + bone.shearX += (bone.data.shearX + (prevX + (frames[frame + X] - prevX) * percent) - bone.shearX) * alpha; + bone.shearY += (bone.data.shearY + (prevY + (frames[frame + Y] - prevY) * percent) - bone.shearY) * alpha; + } + } + + static public class ColorTimeline extends CurveTimeline { + static public final int ENTRIES = 5; + static private final int PREV_TIME = -5, PREV_R = -4, PREV_G = -3, PREV_B = -2, PREV_A = -1; + static private final int R = 1, G = 2, B = 3, A = 4; + + int slotIndex; + private final float[] frames; // time, r, g, b, a, ... + + public ColorTimeline (int frameCount) { + super(frameCount); + frames = new float[frameCount * ENTRIES]; + } + + public void setSlotIndex (int index) { + if (index < 0) throw new IllegalArgumentException("index must be >= 0."); + this.slotIndex = index; + } + + public int getSlotIndex () { + return slotIndex; + } + + public float[] getFrames () { + return frames; + } + + /** Sets the time and value of the specified keyframe. */ + public void setFrame (int frameIndex, float time, float r, float g, float b, float a) { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[frameIndex + R] = r; + frames[frameIndex + G] = g; + frames[frameIndex + B] = b; + frames[frameIndex + A] = a; + } + + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + float r, g, b, a; + if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. + int i = frames.length; + r = frames[i + PREV_R]; + g = frames[i + PREV_G]; + b = frames[i + PREV_B]; + a = frames[i + PREV_A]; + } else { + // Interpolate between the previous frame and the current frame. + int frame = binarySearch(frames, time, ENTRIES); + r = frames[frame + PREV_R]; + g = frames[frame + PREV_G]; + b = frames[frame + PREV_B]; + a = frames[frame + PREV_A]; + float frameTime = frames[frame]; + float percent = getCurvePercent(frame / ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + r += (frames[frame + R] - r) * percent; + g += (frames[frame + G] - g) * percent; + b += (frames[frame + B] - b) * percent; + a += (frames[frame + A] - a) * percent; + } + Color color = skeleton.slots.get(slotIndex).color; + if (alpha < 1) + color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha); + else + color.set(r, g, b, a); + } + } + + static public class AttachmentTimeline implements Timeline { + int slotIndex; + final float[] frames; // time, ... + final String[] attachmentNames; + + public AttachmentTimeline (int frameCount) { + frames = new float[frameCount]; + attachmentNames = new String[frameCount]; + } + + public int getFrameCount () { + return frames.length; + } + + public void setSlotIndex (int index) { + if (index < 0) throw new IllegalArgumentException("index must be >= 0."); + this.slotIndex = index; + } + + public int getSlotIndex () { + return slotIndex; + } + + public float[] getFrames () { + return frames; + } + + public String[] getAttachmentNames () { + return attachmentNames; + } + + /** Sets the time and value of the specified keyframe. */ + public void setFrame (int frameIndex, float time, String attachmentName) { + frames[frameIndex] = time; + attachmentNames[frameIndex] = attachmentName; + } + + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + int frameIndex; + if (time >= frames[frames.length - 1]) // Time is after last frame. + frameIndex = frames.length - 1; + else + frameIndex = binarySearch(frames, time, 1) - 1; + + String attachmentName = attachmentNames[frameIndex]; + skeleton.slots.get(slotIndex) + .setAttachment(attachmentName == null ? null : skeleton.getAttachment(slotIndex, attachmentName)); + } + } + + static public class EventTimeline implements Timeline { + private final float[] frames; // time, ... + private final Event[] events; + + public EventTimeline (int frameCount) { + frames = new float[frameCount]; + events = new Event[frameCount]; + } + + public int getFrameCount () { + return frames.length; + } + + public float[] getFrames () { + return frames; + } + + public Event[] getEvents () { + return events; + } + + /** Sets the time of the specified keyframe. */ + public void setFrame (int frameIndex, Event event) { + frames[frameIndex] = event.time; + events[frameIndex] = event; + } + + /** Fires events for frames > lastTime and <= time. */ + public void apply (Skeleton skeleton, float lastTime, float time, Array firedEvents, float alpha) { + if (firedEvents == null) return; + float[] frames = this.frames; + int frameCount = frames.length; + + if (lastTime > time) { // Fire events after last time for looped animations. + apply(skeleton, lastTime, Integer.MAX_VALUE, firedEvents, alpha); + lastTime = -1f; + } else if (lastTime >= frames[frameCount - 1]) // Last time is after last frame. + return; + if (time < frames[0]) return; // Time is before first frame. + + int frame; + if (lastTime < frames[0]) + frame = 0; + else { + frame = binarySearch(frames, lastTime); + float frameTime = frames[frame]; + while (frame > 0) { // Fire multiple events with the same frame. + if (frames[frame - 1] != frameTime) break; + frame--; + } + } + for (; frame < frameCount && time >= frames[frame]; frame++) + firedEvents.add(events[frame]); + } + } + + static public class DrawOrderTimeline implements Timeline { + private final float[] frames; // time, ... + private final int[][] drawOrders; + + public DrawOrderTimeline (int frameCount) { + frames = new float[frameCount]; + drawOrders = new int[frameCount][]; + } + + public int getFrameCount () { + return frames.length; + } + + public float[] getFrames () { + return frames; + } + + public int[][] getDrawOrders () { + return drawOrders; + } + + /** Sets the time of the specified keyframe. + * @param drawOrder May be null to use bind pose draw order. */ + public void setFrame (int frameIndex, float time, int[] drawOrder) { + frames[frameIndex] = time; + drawOrders[frameIndex] = drawOrder; + } + + public void apply (Skeleton skeleton, float lastTime, float time, Array firedEvents, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + int frame; + if (time >= frames[frames.length - 1]) // Time is after last frame. + frame = frames.length - 1; + else + frame = binarySearch(frames, time) - 1; + + Array drawOrder = skeleton.drawOrder; + Array slots = skeleton.slots; + int[] drawOrderToSetupIndex = drawOrders[frame]; + if (drawOrderToSetupIndex == null) + System.arraycopy(slots.items, 0, drawOrder.items, 0, slots.size); + else { + for (int i = 0, n = drawOrderToSetupIndex.length; i < n; i++) + drawOrder.set(i, slots.get(drawOrderToSetupIndex[i])); + } + } + } + + static public class DeformTimeline extends CurveTimeline { + private final float[] frames; // time, ... + private final float[][] frameVertices; + int slotIndex; + VertexAttachment attachment; + + public DeformTimeline (int frameCount) { + super(frameCount); + frames = new float[frameCount]; + frameVertices = new float[frameCount][]; + } + + public void setSlotIndex (int index) { + if (index < 0) throw new IllegalArgumentException("index must be >= 0."); + this.slotIndex = index; + } + + public int getSlotIndex () { + return slotIndex; + } + + public void setAttachment (VertexAttachment attachment) { + this.attachment = attachment; + } + + public Attachment getAttachment () { + return attachment; + } + + public float[] getFrames () { + return frames; + } + + public float[][] getVertices () { + return frameVertices; + } + + /** Sets the time of the specified keyframe. */ + public void setFrame (int frameIndex, float time, float[] vertices) { + frames[frameIndex] = time; + frameVertices[frameIndex] = vertices; + } + + public void apply (Skeleton skeleton, float lastTime, float time, Array firedEvents, float alpha) { + Slot slot = skeleton.slots.get(slotIndex); + Attachment slotAttachment = slot.attachment; + if (!(slotAttachment instanceof VertexAttachment) || !((VertexAttachment)slotAttachment).applyDeform(attachment)) return; + + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + float[][] frameVertices = this.frameVertices; + int vertexCount = frameVertices[0].length; + + FloatArray verticesArray = slot.getAttachmentVertices(); + if (verticesArray.size != vertexCount) alpha = 1; // Don't mix from uninitialized slot vertices. + float[] vertices = verticesArray.setSize(vertexCount); + + if (time >= frames[frames.length - 1]) { // Time is after last frame. + float[] lastVertices = frameVertices[frames.length - 1]; + if (alpha < 1) { + for (int i = 0; i < vertexCount; i++) + vertices[i] += (lastVertices[i] - vertices[i]) * alpha; + } else + System.arraycopy(lastVertices, 0, vertices, 0, vertexCount); + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = binarySearch(frames, time); + float[] prevVertices = frameVertices[frame - 1]; + float[] nextVertices = frameVertices[frame]; + float frameTime = frames[frame]; + float percent = getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime)); + + if (alpha < 1) { + for (int i = 0; i < vertexCount; i++) { + float prev = prevVertices[i]; + vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha; + } + } else { + for (int i = 0; i < vertexCount; i++) { + float prev = prevVertices[i]; + vertices[i] = prev + (nextVertices[i] - prev) * percent; + } + } + } + } + + static public class IkConstraintTimeline extends CurveTimeline { + static public final int ENTRIES = 3; + static private final int PREV_TIME = -3, PREV_MIX = -2, PREV_BEND_DIRECTION = -1; + static private final int MIX = 1, BEND_DIRECTION = 2; + + int ikConstraintIndex; + private final float[] frames; // time, mix, bendDirection, ... + + public IkConstraintTimeline (int frameCount) { + super(frameCount); + frames = new float[frameCount * ENTRIES]; + } + + public void setIkConstraintIndex (int index) { + if (index < 0) throw new IllegalArgumentException("index must be >= 0."); + this.ikConstraintIndex = index; + } + + public int getIkConstraintIndex () { + return ikConstraintIndex; + } + + public float[] getFrames () { + return frames; + } + + /** Sets the time, mix and bend direction of the specified keyframe. */ + public void setFrame (int frameIndex, float time, float mix, int bendDirection) { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[frameIndex + MIX] = mix; + frames[frameIndex + BEND_DIRECTION] = bendDirection; + } + + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + IkConstraint constraint = skeleton.ikConstraints.get(ikConstraintIndex); + + if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. + constraint.mix += (frames[frames.length + PREV_MIX] - constraint.mix) * alpha; + constraint.bendDirection = (int)frames[frames.length + PREV_BEND_DIRECTION]; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = binarySearch(frames, time, ENTRIES); + float mix = frames[frame + PREV_MIX]; + float frameTime = frames[frame]; + float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + constraint.mix += (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha; + constraint.bendDirection = (int)frames[frame + PREV_BEND_DIRECTION]; + } + } + + static public class TransformConstraintTimeline extends CurveTimeline { + static public final int ENTRIES = 5; + static private final int PREV_TIME = -5, PREV_ROTATE = -4, PREV_TRANSLATE = -3, PREV_SCALE = -2, PREV_SHEAR = -1; + static private final int ROTATE = 1, TRANSLATE = 2, SCALE = 3, SHEAR = 4; + + int transformConstraintIndex; + private final float[] frames; // time, rotate mix, translate mix, scale mix, shear mix, ... + + public TransformConstraintTimeline (int frameCount) { + super(frameCount); + frames = new float[frameCount * ENTRIES]; + } + + public void setTransformConstraintIndex (int index) { + if (index < 0) throw new IllegalArgumentException("index must be >= 0."); + this.transformConstraintIndex = index; + } + + public int getTransformConstraintIndex () { + return transformConstraintIndex; + } + + public float[] getFrames () { + return frames; + } + + /** Sets the time and mixes of the specified keyframe. */ + public void setFrame (int frameIndex, float time, float rotateMix, float translateMix, float scaleMix, float shearMix) { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[frameIndex + ROTATE] = rotateMix; + frames[frameIndex + TRANSLATE] = translateMix; + frames[frameIndex + SCALE] = scaleMix; + frames[frameIndex + SHEAR] = shearMix; + } + + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + TransformConstraint constraint = skeleton.transformConstraints.get(transformConstraintIndex); + + if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. + int i = frames.length; + constraint.rotateMix += (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha; + constraint.translateMix += (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha; + constraint.scaleMix += (frames[i + PREV_SCALE] - constraint.scaleMix) * alpha; + constraint.shearMix += (frames[i + PREV_SHEAR] - constraint.shearMix) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = binarySearch(frames, time, ENTRIES); + float frameTime = frames[frame]; + float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + float rotate = frames[frame + PREV_ROTATE]; + float translate = frames[frame + PREV_TRANSLATE]; + float scale = frames[frame + PREV_SCALE]; + float shear = frames[frame + PREV_SHEAR]; + constraint.rotateMix += (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha; + constraint.translateMix += (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix) + * alpha; + constraint.scaleMix += (scale + (frames[frame + SCALE] - scale) * percent - constraint.scaleMix) * alpha; + constraint.shearMix += (shear + (frames[frame + SHEAR] - shear) * percent - constraint.shearMix) * alpha; + } + } + + static public class PathConstraintPositionTimeline extends CurveTimeline { + static public final int ENTRIES = 2; + static final int PREV_TIME = -2, PREV_VALUE = -1; + static final int VALUE = 1; + + int pathConstraintIndex; + + final float[] frames; // time, position, ... + + public PathConstraintPositionTimeline (int frameCount) { + super(frameCount); + frames = new float[frameCount * ENTRIES]; + } + + public void setPathConstraintIndex (int index) { + if (index < 0) throw new IllegalArgumentException("index must be >= 0."); + this.pathConstraintIndex = index; + } + + public int getPathConstraintIndex () { + return pathConstraintIndex; + } + + public float[] getFrames () { + return frames; + } + + /** Sets the time and value of the specified keyframe. */ + public void setFrame (int frameIndex, float time, float value) { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[frameIndex + VALUE] = value; + } + + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + PathConstraint constraint = skeleton.pathConstraints.get(pathConstraintIndex); + + if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. + int i = frames.length; + constraint.position += (frames[i + PREV_VALUE] - constraint.position) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = binarySearch(frames, time, ENTRIES); + float position = frames[frame + PREV_VALUE]; + float frameTime = frames[frame]; + float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + constraint.position += (position + (frames[frame + VALUE] - position) * percent - constraint.position) * alpha; + } + } + + static public class PathConstraintSpacingTimeline extends PathConstraintPositionTimeline { + public PathConstraintSpacingTimeline (int frameCount) { + super(frameCount); + } + + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + PathConstraint constraint = skeleton.pathConstraints.get(pathConstraintIndex); + + if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. + int i = frames.length; + constraint.spacing += (frames[i + PREV_VALUE] - constraint.spacing) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = binarySearch(frames, time, ENTRIES); + float spacing = frames[frame + PREV_VALUE]; + float frameTime = frames[frame]; + float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + constraint.spacing += (spacing + (frames[frame + VALUE] - spacing) * percent - constraint.spacing) * alpha; + } + } + + static public class PathConstraintMixTimeline extends CurveTimeline { + static public final int ENTRIES = 3; + static private final int PREV_TIME = -3, PREV_ROTATE = -2, PREV_TRANSLATE = -1; + static private final int ROTATE = 1, TRANSLATE = 2; + + int pathConstraintIndex; + + private final float[] frames; // time, rotate mix, translate mix, ... + + public PathConstraintMixTimeline (int frameCount) { + super(frameCount); + frames = new float[frameCount * ENTRIES]; + } + + public void setPathConstraintIndex (int index) { + if (index < 0) throw new IllegalArgumentException("index must be >= 0."); + this.pathConstraintIndex = index; + } + + public int getPathConstraintIndex () { + return pathConstraintIndex; + } + + public float[] getFrames () { + return frames; + } + + /** Sets the time and mixes of the specified keyframe. */ + public void setFrame (int frameIndex, float time, float rotateMix, float translateMix) { + frameIndex *= ENTRIES; + frames[frameIndex] = time; + frames[frameIndex + ROTATE] = rotateMix; + frames[frameIndex + TRANSLATE] = translateMix; + } + + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + PathConstraint constraint = skeleton.pathConstraints.get(pathConstraintIndex); + + if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. + int i = frames.length; + constraint.rotateMix += (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha; + constraint.translateMix += (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + int frame = binarySearch(frames, time, ENTRIES); + float rotate = frames[frame + PREV_ROTATE]; + float translate = frames[frame + PREV_TRANSLATE]; + float frameTime = frames[frame]; + float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + constraint.rotateMix += (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha; + constraint.translateMix += (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix) + * alpha; + } + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java index eda2a2426b..4a60855c43 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java @@ -1,458 +1,457 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.Pool; -import com.badlogic.gdx.utils.Pool.Poolable; - -/** Stores state for an animation and automatically mixes between animations. */ -public class AnimationState { - private AnimationStateData data; - private Array tracks = new Array(); - private final Array events = new Array(); - private final Array listeners = new Array(); - private float timeScale = 1; - - private Pool trackEntryPool = new Pool() { - protected Object newObject () { - return new TrackEntry(); - } - }; - - /** Creates an uninitialized AnimationState. The animation state data must be set. */ - public AnimationState () { - } - - public AnimationState (AnimationStateData data) { - if (data == null) throw new IllegalArgumentException("data cannot be null."); - this.data = data; - } - - public void update (float delta) { - delta *= timeScale; - for (int i = 0; i < tracks.size; i++) { - TrackEntry current = tracks.get(i); - if (current == null) continue; - - TrackEntry next = current.next; - if (next != null) { - float nextTime = current.lastTime - next.delay; - if (nextTime >= 0) { - float nextDelta = delta * next.timeScale; - next.time = nextTime + nextDelta; // For start event to see correct time. - current.time += delta * current.timeScale; // For end event to see correct time. - setCurrent(i, next); - next.time -= nextDelta; // Prevent increasing time twice, below. - current = next; - } - } else if (!current.loop && current.lastTime >= current.endTime) { - // End non-looping animation when it reaches its end time and there is no next entry. - clearTrack(i); - continue; - } - - current.time += delta * current.timeScale; - if (current.previous != null) { - float previousDelta = delta * current.previous.timeScale; - current.previous.time += previousDelta; - current.mixTime += previousDelta; - } - } - } - - public void apply (Skeleton skeleton) { - Array events = this.events; - int listenerCount = listeners.size; - - for (int i = 0; i < tracks.size; i++) { - TrackEntry current = tracks.get(i); - if (current == null) continue; - - events.size = 0; - - float time = current.time; - float lastTime = current.lastTime; - float endTime = current.endTime; - boolean loop = current.loop; - if (!loop && time > endTime) time = endTime; - - TrackEntry previous = current.previous; - if (previous == null) - current.animation.mix(skeleton, lastTime, time, loop, events, current.mix); - else { - float previousTime = previous.time; - if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; - previous.animation.apply(skeleton, previousTime, previousTime, previous.loop, null); - - float alpha = current.mixTime / current.mixDuration * current.mix; - if (alpha >= 1) { - alpha = 1; - trackEntryPool.free(previous); - current.previous = null; - } - current.animation.mix(skeleton, lastTime, time, loop, events, alpha); - } - - for (int ii = 0, nn = events.size; ii < nn; ii++) { - Event event = events.get(ii); - if (current.listener != null) current.listener.event(i, event); - for (int iii = 0; iii < listenerCount; iii++) - listeners.get(iii).event(i, event); - } - - // Check if completed the animation or a loop iteration. - if (loop ? (lastTime % endTime > time % endTime) : (lastTime < endTime && time >= endTime)) { - int count = (int)(time / endTime); - if (current.listener != null) current.listener.complete(i, count); - for (int ii = 0, nn = listeners.size; ii < nn; ii++) - listeners.get(ii).complete(i, count); - } - - current.lastTime = current.time; - } - } - - public void clearTracks () { - for (int i = 0, n = tracks.size; i < n; i++) - clearTrack(i); - tracks.clear(); - } - - public void clearTrack (int trackIndex) { - if (trackIndex >= tracks.size) return; - TrackEntry current = tracks.get(trackIndex); - if (current == null) return; - - if (current.listener != null) current.listener.end(trackIndex); - for (int i = 0, n = listeners.size; i < n; i++) - listeners.get(i).end(trackIndex); - - tracks.set(trackIndex, null); - - freeAll(current); - if (current.previous != null) trackEntryPool.free(current.previous); - } - - private void freeAll (TrackEntry entry) { - while (entry != null) { - TrackEntry next = entry.next; - trackEntryPool.free(entry); - entry = next; - } - } - - private TrackEntry expandToIndex (int index) { - if (index < tracks.size) return tracks.get(index); - tracks.ensureCapacity(index - tracks.size + 1); - tracks.size = index + 1; - return null; - } - - private void setCurrent (int index, TrackEntry entry) { - TrackEntry current = expandToIndex(index); - if (current != null) { - TrackEntry previous = current.previous; - current.previous = null; - - if (current.listener != null) current.listener.end(index); - for (int i = 0, n = listeners.size; i < n; i++) - listeners.get(i).end(index); - - entry.mixDuration = data.getMix(current.animation, entry.animation); - if (entry.mixDuration > 0) { - entry.mixTime = 0; - // If a mix is in progress, mix from the closest animation. - if (previous != null && current.mixTime / current.mixDuration < 0.5f) { - entry.previous = previous; - previous = current; - } else - entry.previous = current; - } else - trackEntryPool.free(current); - - if (previous != null) trackEntryPool.free(previous); - } - - tracks.set(index, entry); - - if (entry.listener != null) entry.listener.start(index); - for (int i = 0, n = listeners.size; i < n; i++) - listeners.get(i).start(index); - } - - /** @see #setAnimation(int, Animation, boolean) */ - public TrackEntry setAnimation (int trackIndex, String animationName, boolean loop) { - Animation animation = data.getSkeletonData().findAnimation(animationName); - if (animation == null) throw new IllegalArgumentException("Animation not found: " + animationName); - return setAnimation(trackIndex, animation, loop); - } - - /** Set the current animation. Any queued animations are cleared. */ - public TrackEntry setAnimation (int trackIndex, Animation animation, boolean loop) { - TrackEntry current = expandToIndex(trackIndex); - if (current != null) freeAll(current.next); - - TrackEntry entry = trackEntryPool.obtain(); - entry.animation = animation; - entry.loop = loop; - entry.endTime = animation.getDuration(); - setCurrent(trackIndex, entry); - return entry; - } - - /** {@link #addAnimation(int, Animation, boolean, float)} */ - public TrackEntry addAnimation (int trackIndex, String animationName, boolean loop, float delay) { - Animation animation = data.getSkeletonData().findAnimation(animationName); - if (animation == null) throw new IllegalArgumentException("Animation not found: " + animationName); - return addAnimation(trackIndex, animation, loop, delay); - } - - /** Adds an animation to be played delay seconds after the current or last queued animation. - * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */ - public TrackEntry addAnimation (int trackIndex, Animation animation, boolean loop, float delay) { - TrackEntry entry = trackEntryPool.obtain(); - entry.animation = animation; - entry.loop = loop; - entry.endTime = animation.getDuration(); - - TrackEntry last = expandToIndex(trackIndex); - if (last != null) { - while (last.next != null) - last = last.next; - last.next = entry; - } else - tracks.set(trackIndex, entry); - - if (delay <= 0) { - if (last != null) - delay += last.endTime - data.getMix(last.animation, animation); - else - delay = 0; - } - entry.delay = delay; - - return entry; - } - - /** @return May be null. */ - public TrackEntry getCurrent (int trackIndex) { - if (trackIndex >= tracks.size) return null; - return tracks.get(trackIndex); - } - - /** Adds a listener to receive events for all animations. */ - public void addListener (AnimationStateListener listener) { - if (listener == null) throw new IllegalArgumentException("listener cannot be null."); - listeners.add(listener); - } - - /** Removes the listener added with {@link #addListener(AnimationStateListener)}. */ - public void removeListener (AnimationStateListener listener) { - listeners.removeValue(listener, true); - } - - public void clearListeners () { - listeners.clear(); - } - - public float getTimeScale () { - return timeScale; - } - - public void setTimeScale (float timeScale) { - this.timeScale = timeScale; - } - - public AnimationStateData getData () { - return data; - } - - public void setData (AnimationStateData data) { - this.data = data; - } - - /** Returns the list of tracks that have animations, which may contain nulls. */ - public Array getTracks () { - return tracks; - } - - public String toString () { - StringBuilder buffer = new StringBuilder(64); - for (int i = 0, n = tracks.size; i < n; i++) { - TrackEntry entry = tracks.get(i); - if (entry == null) continue; - if (buffer.length() > 0) buffer.append(", "); - buffer.append(entry.toString()); - } - if (buffer.length() == 0) return ""; - return buffer.toString(); - } - - static public class TrackEntry implements Poolable { - TrackEntry next, previous; - Animation animation; - boolean loop; - float delay, time, lastTime = -1, endTime, timeScale = 1; - float mixTime, mixDuration; - AnimationStateListener listener; - float mix = 1; - - public void reset () { - next = null; - previous = null; - animation = null; - listener = null; - timeScale = 1; - lastTime = -1; // Trigger events on frame zero. - time = 0; - } - - public Animation getAnimation () { - return animation; - } - - public void setAnimation (Animation animation) { - this.animation = animation; - } - - public boolean getLoop () { - return loop; - } - - public void setLoop (boolean loop) { - this.loop = loop; - } - - public float getDelay () { - return delay; - } - - public void setDelay (float delay) { - this.delay = delay; - } - - public float getTime () { - return time; - } - - public void setTime (float time) { - this.time = time; - } - - public float getEndTime () { - return endTime; - } - - public void setEndTime (float endTime) { - this.endTime = endTime; - } - - public AnimationStateListener getListener () { - return listener; - } - - public void setListener (AnimationStateListener listener) { - this.listener = listener; - } - - public float getLastTime () { - return lastTime; - } - - public void setLastTime (float lastTime) { - this.lastTime = lastTime; - } - - public float getMix () { - return mix; - } - - public void setMix (float mix) { - this.mix = mix; - } - - public float getTimeScale () { - return timeScale; - } - - public void setTimeScale (float timeScale) { - this.timeScale = timeScale; - } - - public TrackEntry getNext () { - return next; - } - - public void setNext (TrackEntry next) { - this.next = next; - } - - /** Returns true if the current time is greater than the end time, regardless of looping. */ - public boolean isComplete () { - return time >= endTime; - } - - public String toString () { - return animation == null ? "" : animation.name; - } - } - - static public interface AnimationStateListener { - /** Invoked when the current animation triggers an event. */ - public void event (int trackIndex, Event event); - - /** Invoked when the current animation has completed. - * @param loopCount The number of times the animation reached the end. */ - public void complete (int trackIndex, int loopCount); - - /** Invoked just after the current animation is set. */ - public void start (int trackIndex); - - /** Invoked just before the current animation is replaced. */ - public void end (int trackIndex); - } - - static public abstract class AnimationStateAdapter implements AnimationStateListener { - public void event (int trackIndex, Event event) { - } - - public void complete (int trackIndex, int loopCount) { - } - - public void start (int trackIndex) { - } - - public void end (int trackIndex) { - } - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Pool; +import com.badlogic.gdx.utils.Pool.Poolable; + +/** Stores state for an animation and automatically mixes between animations. */ +public class AnimationState { + private AnimationStateData data; + private Array tracks = new Array(); + private final Array events = new Array(); + private final Array listeners = new Array(); + private float timeScale = 1; + + private Pool trackEntryPool = new Pool() { + protected Object newObject () { + return new TrackEntry(); + } + }; + + /** Creates an uninitialized AnimationState. The animation state data must be set. */ + public AnimationState () { + } + + public AnimationState (AnimationStateData data) { + if (data == null) throw new IllegalArgumentException("data cannot be null."); + this.data = data; + } + + public void update (float delta) { + delta *= timeScale; + for (int i = 0; i < tracks.size; i++) { + TrackEntry current = tracks.get(i); + if (current == null) continue; + + TrackEntry next = current.next; + if (next != null) { + float nextTime = current.lastTime - next.delay; + if (nextTime >= 0) { + float nextDelta = delta * next.timeScale; + next.time = nextTime + nextDelta; // For start event to see correct time. + current.time += delta * current.timeScale; // For end event to see correct time. + setCurrent(i, next); + next.time -= nextDelta; // Prevent increasing time twice, below. + current = next; + } + } else if (!current.loop && current.lastTime >= current.endTime) { + // End non-looping animation when it reaches its end time and there is no next entry. + clearTrack(i); + continue; + } + + current.time += delta * current.timeScale; + if (current.previous != null) { + float previousDelta = delta * current.previous.timeScale; + current.previous.time += previousDelta; + current.mixTime += previousDelta; + } + } + } + + public void apply (Skeleton skeleton) { + Array events = this.events; + int listenerCount = listeners.size; + + for (int i = 0; i < tracks.size; i++) { + TrackEntry current = tracks.get(i); + if (current == null) continue; + + events.size = 0; + + float time = current.time; + float lastTime = current.lastTime; + float endTime = current.endTime; + boolean loop = current.loop; + if (!loop && time > endTime) time = endTime; + + TrackEntry previous = current.previous; + if (previous == null) + current.animation.mix(skeleton, lastTime, time, loop, events, current.mix); + else { + float previousTime = previous.time; + if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; + previous.animation.apply(skeleton, previousTime, previousTime, previous.loop, null); + + float alpha = current.mixTime / current.mixDuration * current.mix; + if (alpha >= 1) { + alpha = 1; + trackEntryPool.free(previous); + current.previous = null; + } + current.animation.mix(skeleton, lastTime, time, loop, events, alpha); + } + + for (int ii = 0, nn = events.size; ii < nn; ii++) { + Event event = events.get(ii); + if (current.listener != null) current.listener.event(i, event); + for (int iii = 0; iii < listenerCount; iii++) + listeners.get(iii).event(i, event); + } + + // Check if completed the animation or a loop iteration. + if (loop ? (lastTime % endTime > time % endTime) : (lastTime < endTime && time >= endTime)) { + int count = (int)(time / endTime); + if (current.listener != null) current.listener.complete(i, count); + for (int ii = 0, nn = listeners.size; ii < nn; ii++) + listeners.get(ii).complete(i, count); + } + + current.lastTime = current.time; + } + } + + public void clearTracks () { + for (int i = 0, n = tracks.size; i < n; i++) + clearTrack(i); + tracks.clear(); + } + + public void clearTrack (int trackIndex) { + if (trackIndex >= tracks.size) return; + TrackEntry current = tracks.get(trackIndex); + if (current == null) return; + + if (current.listener != null) current.listener.end(trackIndex); + for (int i = 0, n = listeners.size; i < n; i++) + listeners.get(i).end(trackIndex); + + tracks.set(trackIndex, null); + + freeAll(current); + if (current.previous != null) trackEntryPool.free(current.previous); + } + + private void freeAll (TrackEntry entry) { + while (entry != null) { + TrackEntry next = entry.next; + trackEntryPool.free(entry); + entry = next; + } + } + + private TrackEntry expandToIndex (int index) { + if (index < tracks.size) return tracks.get(index); + tracks.ensureCapacity(index - tracks.size + 1); + tracks.size = index + 1; + return null; + } + + private void setCurrent (int index, TrackEntry entry) { + TrackEntry current = expandToIndex(index); + if (current != null) { + TrackEntry previous = current.previous; + current.previous = null; + + if (current.listener != null) current.listener.end(index); + for (int i = 0, n = listeners.size; i < n; i++) + listeners.get(i).end(index); + + entry.mixDuration = data.getMix(current.animation, entry.animation); + if (entry.mixDuration > 0) { + entry.mixTime = 0; + // If a mix is in progress, mix from the closest animation. + if (previous != null && current.mixTime / current.mixDuration < 0.5f) { + entry.previous = previous; + previous = current; + } else + entry.previous = current; + } else + trackEntryPool.free(current); + + if (previous != null) trackEntryPool.free(previous); + } + + tracks.set(index, entry); + + if (entry.listener != null) entry.listener.start(index); + for (int i = 0, n = listeners.size; i < n; i++) + listeners.get(i).start(index); + } + + /** @see #setAnimation(int, Animation, boolean) */ + public TrackEntry setAnimation (int trackIndex, String animationName, boolean loop) { + Animation animation = data.getSkeletonData().findAnimation(animationName); + if (animation == null) throw new IllegalArgumentException("Animation not found: " + animationName); + return setAnimation(trackIndex, animation, loop); + } + + /** Set the current animation. Any queued animations are cleared. */ + public TrackEntry setAnimation (int trackIndex, Animation animation, boolean loop) { + TrackEntry current = expandToIndex(trackIndex); + if (current != null) freeAll(current.next); + + TrackEntry entry = trackEntryPool.obtain(); + entry.animation = animation; + entry.loop = loop; + entry.endTime = animation.getDuration(); + setCurrent(trackIndex, entry); + return entry; + } + + /** {@link #addAnimation(int, Animation, boolean, float)} */ + public TrackEntry addAnimation (int trackIndex, String animationName, boolean loop, float delay) { + Animation animation = data.getSkeletonData().findAnimation(animationName); + if (animation == null) throw new IllegalArgumentException("Animation not found: " + animationName); + return addAnimation(trackIndex, animation, loop, delay); + } + + /** Adds an animation to be played delay seconds after the current or last queued animation. + * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */ + public TrackEntry addAnimation (int trackIndex, Animation animation, boolean loop, float delay) { + TrackEntry entry = trackEntryPool.obtain(); + entry.animation = animation; + entry.loop = loop; + entry.endTime = animation.getDuration(); + + TrackEntry last = expandToIndex(trackIndex); + if (last != null) { + while (last.next != null) + last = last.next; + last.next = entry; + } else + tracks.set(trackIndex, entry); + + if (delay <= 0) { + if (last != null) + delay += last.endTime - data.getMix(last.animation, animation); + else + delay = 0; + } + entry.delay = delay; + + return entry; + } + + /** @return May be null. */ + public TrackEntry getCurrent (int trackIndex) { + if (trackIndex >= tracks.size) return null; + return tracks.get(trackIndex); + } + + /** Adds a listener to receive events for all animations. */ + public void addListener (AnimationStateListener listener) { + if (listener == null) throw new IllegalArgumentException("listener cannot be null."); + listeners.add(listener); + } + + /** Removes the listener added with {@link #addListener(AnimationStateListener)}. */ + public void removeListener (AnimationStateListener listener) { + listeners.removeValue(listener, true); + } + + public void clearListeners () { + listeners.clear(); + } + + public float getTimeScale () { + return timeScale; + } + + public void setTimeScale (float timeScale) { + this.timeScale = timeScale; + } + + public AnimationStateData getData () { + return data; + } + + public void setData (AnimationStateData data) { + this.data = data; + } + + /** Returns the list of tracks that have animations, which may contain nulls. */ + public Array getTracks () { + return tracks; + } + + public String toString () { + StringBuilder buffer = new StringBuilder(64); + for (int i = 0, n = tracks.size; i < n; i++) { + TrackEntry entry = tracks.get(i); + if (entry == null) continue; + if (buffer.length() > 0) buffer.append(", "); + buffer.append(entry.toString()); + } + if (buffer.length() == 0) return ""; + return buffer.toString(); + } + + static public class TrackEntry implements Poolable { + TrackEntry next, previous; + Animation animation; + boolean loop; + float delay, time, lastTime = -1, endTime, timeScale = 1; + float mixTime, mixDuration; + AnimationStateListener listener; + float mix = 1; + + public void reset () { + next = null; + previous = null; + animation = null; + listener = null; + timeScale = 1; + lastTime = -1; // Trigger events on frame zero. + time = 0; + } + + public Animation getAnimation () { + return animation; + } + + public void setAnimation (Animation animation) { + this.animation = animation; + } + + public boolean getLoop () { + return loop; + } + + public void setLoop (boolean loop) { + this.loop = loop; + } + + public float getDelay () { + return delay; + } + + public void setDelay (float delay) { + this.delay = delay; + } + + public float getTime () { + return time; + } + + public void setTime (float time) { + this.time = time; + } + + public float getEndTime () { + return endTime; + } + + public void setEndTime (float endTime) { + this.endTime = endTime; + } + + public AnimationStateListener getListener () { + return listener; + } + + public void setListener (AnimationStateListener listener) { + this.listener = listener; + } + + public float getLastTime () { + return lastTime; + } + + public void setLastTime (float lastTime) { + this.lastTime = lastTime; + } + + public float getMix () { + return mix; + } + + public void setMix (float mix) { + this.mix = mix; + } + + public float getTimeScale () { + return timeScale; + } + + public void setTimeScale (float timeScale) { + this.timeScale = timeScale; + } + + public TrackEntry getNext () { + return next; + } + + public void setNext (TrackEntry next) { + this.next = next; + } + + /** Returns true if the current time is greater than the end time, regardless of looping. */ + public boolean isComplete () { + return time >= endTime; + } + + public String toString () { + return animation == null ? "" : animation.name; + } + } + + static public interface AnimationStateListener { + /** Invoked when the current animation triggers an event. */ + public void event (int trackIndex, Event event); + + /** Invoked when the current animation has completed. + * @param loopCount The number of times the animation reached the end. */ + public void complete (int trackIndex, int loopCount); + + /** Invoked just after the current animation is set. */ + public void start (int trackIndex); + + /** Invoked just before the current animation is replaced. */ + public void end (int trackIndex); + } + + static public abstract class AnimationStateAdapter implements AnimationStateListener { + public void event (int trackIndex, Event event) { + } + + public void complete (int trackIndex, int loopCount) { + } + + public void start (int trackIndex) { + } + + public void end (int trackIndex) { + } + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationStateData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationStateData.java index d0a8067266..01ef058bdb 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationStateData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationStateData.java @@ -1,103 +1,102 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.utils.ObjectFloatMap; - -/** Stores mixing times between animations. */ -public class AnimationStateData { - private final SkeletonData skeletonData; - final ObjectFloatMap animationToMixTime = new ObjectFloatMap(); - final Key tempKey = new Key(); - float defaultMix; - - public AnimationStateData (SkeletonData skeletonData) { - if (skeletonData == null) throw new IllegalArgumentException("skeletonData cannot be null."); - this.skeletonData = skeletonData; - } - - public SkeletonData getSkeletonData () { - return skeletonData; - } - - public void setMix (String fromName, String toName, float duration) { - Animation from = skeletonData.findAnimation(fromName); - if (from == null) throw new IllegalArgumentException("Animation not found: " + fromName); - Animation to = skeletonData.findAnimation(toName); - if (to == null) throw new IllegalArgumentException("Animation not found: " + toName); - setMix(from, to, duration); - } - - public void setMix (Animation from, Animation to, float duration) { - if (from == null) throw new IllegalArgumentException("from cannot be null."); - if (to == null) throw new IllegalArgumentException("to cannot be null."); - Key key = new Key(); - key.a1 = from; - key.a2 = to; - animationToMixTime.put(key, duration); - } - - public float getMix (Animation from, Animation to) { - tempKey.a1 = from; - tempKey.a2 = to; - return animationToMixTime.get(tempKey, defaultMix); - } - - public float getDefaultMix () { - return defaultMix; - } - - public void setDefaultMix (float defaultMix) { - this.defaultMix = defaultMix; - } - - static class Key { - Animation a1, a2; - - public int hashCode () { - return 31 * (31 + a1.hashCode()) + a2.hashCode(); - } - - public boolean equals (Object obj) { - if (this == obj) return true; - if (obj == null) return false; - Key other = (Key)obj; - if (a1 == null) { - if (other.a1 != null) return false; - } else if (!a1.equals(other.a1)) return false; - if (a2 == null) { - if (other.a2 != null) return false; - } else if (!a2.equals(other.a2)) return false; - return true; - } - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.utils.ObjectFloatMap; + +/** Stores mixing times between animations. */ +public class AnimationStateData { + private final SkeletonData skeletonData; + final ObjectFloatMap animationToMixTime = new ObjectFloatMap(); + final Key tempKey = new Key(); + float defaultMix; + + public AnimationStateData (SkeletonData skeletonData) { + if (skeletonData == null) throw new IllegalArgumentException("skeletonData cannot be null."); + this.skeletonData = skeletonData; + } + + public SkeletonData getSkeletonData () { + return skeletonData; + } + + public void setMix (String fromName, String toName, float duration) { + Animation from = skeletonData.findAnimation(fromName); + if (from == null) throw new IllegalArgumentException("Animation not found: " + fromName); + Animation to = skeletonData.findAnimation(toName); + if (to == null) throw new IllegalArgumentException("Animation not found: " + toName); + setMix(from, to, duration); + } + + public void setMix (Animation from, Animation to, float duration) { + if (from == null) throw new IllegalArgumentException("from cannot be null."); + if (to == null) throw new IllegalArgumentException("to cannot be null."); + Key key = new Key(); + key.a1 = from; + key.a2 = to; + animationToMixTime.put(key, duration); + } + + public float getMix (Animation from, Animation to) { + tempKey.a1 = from; + tempKey.a2 = to; + return animationToMixTime.get(tempKey, defaultMix); + } + + public float getDefaultMix () { + return defaultMix; + } + + public void setDefaultMix (float defaultMix) { + this.defaultMix = defaultMix; + } + + static class Key { + Animation a1, a2; + + public int hashCode () { + return 31 * (31 + a1.hashCode()) + a2.hashCode(); + } + + public boolean equals (Object obj) { + if (this == obj) return true; + if (obj == null) return false; + Key other = (Key)obj; + if (a1 == null) { + if (other.a1 != null) return false; + } else if (!a1.equals(other.a1)) return false; + if (a2 == null) { + if (other.a2 != null) return false; + } else if (!a2.equals(other.a2)) return false; + return true; + } + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BlendMode.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BlendMode.java index f4a32197d9..f37a2eec03 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BlendMode.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BlendMode.java @@ -1,60 +1,59 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.graphics.GL20; - -public enum BlendMode { - normal(GL20.GL_SRC_ALPHA, GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA), // - additive(GL20.GL_SRC_ALPHA, GL20.GL_ONE, GL20.GL_ONE), // - multiply(GL20.GL_DST_COLOR, GL20.GL_DST_COLOR, GL20.GL_ONE_MINUS_SRC_ALPHA), // - screen(GL20.GL_ONE, GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_COLOR), // - ; - - int source, sourcePMA, dest; - - BlendMode (int source, int sourcePremultipledAlpha, int dest) { - this.source = source; - this.sourcePMA = sourcePremultipledAlpha; - this.dest = dest; - } - - public int getSource (boolean premultipliedAlpha) { - return premultipliedAlpha ? sourcePMA : source; - } - - public int getDest () { - return dest; - } - - static public BlendMode[] values = values(); +package com.esotericsoftware.spine; + +import com.badlogic.gdx.graphics.GL20; + +public enum BlendMode { + normal(GL20.GL_SRC_ALPHA, GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA), // + additive(GL20.GL_SRC_ALPHA, GL20.GL_ONE, GL20.GL_ONE), // + multiply(GL20.GL_DST_COLOR, GL20.GL_DST_COLOR, GL20.GL_ONE_MINUS_SRC_ALPHA), // + screen(GL20.GL_ONE, GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_COLOR), // + ; + + int source, sourcePMA, dest; + + BlendMode (int source, int sourcePremultipledAlpha, int dest) { + this.source = source; + this.sourcePMA = sourcePremultipledAlpha; + this.dest = dest; + } + + public int getSource (boolean premultipliedAlpha) { + return premultipliedAlpha ? sourcePMA : source; + } + + public int getDest () { + return dest; + } + + static public BlendMode[] values = values(); } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java index 076a4b2d69..3549a9b6e0 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java @@ -1,455 +1,454 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import static com.badlogic.gdx.math.MathUtils.*; -import static com.badlogic.gdx.math.Matrix3.*; - -import com.badlogic.gdx.math.Matrix3; -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.utils.Array; - -public class Bone implements Updatable { - final BoneData data; - final Skeleton skeleton; - final Bone parent; - final Array children = new Array(); - float x, y, rotation, scaleX, scaleY, shearX, shearY; - float appliedRotation; - - float a, b, worldX; - float c, d, worldY; - float worldSignX, worldSignY; - - boolean sorted; - - /** @param parent May be null. */ - public Bone (BoneData data, Skeleton skeleton, Bone parent) { - if (data == null) throw new IllegalArgumentException("data cannot be null."); - if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); - this.data = data; - this.skeleton = skeleton; - this.parent = parent; - setToSetupPose(); - } - - /** Copy constructor. Does not copy the children bones. - * @param parent May be null. */ - public Bone (Bone bone, Skeleton skeleton, Bone parent) { - if (bone == null) throw new IllegalArgumentException("bone cannot be null."); - if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); - this.skeleton = skeleton; - this.parent = parent; - data = bone.data; - x = bone.x; - y = bone.y; - rotation = bone.rotation; - scaleX = bone.scaleX; - scaleY = bone.scaleY; - shearX = bone.shearX; - shearY = bone.shearY; - } - - /** Same as {@link #updateWorldTransform()}. This method exists for Bone to implement {@link Updatable}. */ - public void update () { - updateWorldTransform(x, y, rotation, scaleX, scaleY, shearX, shearY); - } - - /** Computes the world transform using the parent bone and this bone's local transform. */ - public void updateWorldTransform () { - updateWorldTransform(x, y, rotation, scaleX, scaleY, shearX, shearY); - } - - /** Computes the world transform using the parent bone and the specified local transform. */ - public void updateWorldTransform (float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY) { - appliedRotation = rotation; - - float rotationY = rotation + 90 + shearY; - float la = cosDeg(rotation + shearX) * scaleX, lb = cosDeg(rotationY) * scaleY; - float lc = sinDeg(rotation + shearX) * scaleX, ld = sinDeg(rotationY) * scaleY; - - Bone parent = this.parent; - if (parent == null) { // Root bone. - Skeleton skeleton = this.skeleton; - if (skeleton.flipX) { - x = -x; - la = -la; - lb = -lb; - } - if (skeleton.flipY) { - y = -y; - lc = -lc; - ld = -ld; - } - a = la; - b = lb; - c = lc; - d = ld; - worldX = x; - worldY = y; - worldSignX = Math.signum(scaleX); - worldSignY = Math.signum(scaleY); - return; - } - - float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; - worldX = pa * x + pb * y + parent.worldX; - worldY = pc * x + pd * y + parent.worldY; - worldSignX = parent.worldSignX * Math.signum(scaleX); - worldSignY = parent.worldSignY * Math.signum(scaleY); - - if (data.inheritRotation && data.inheritScale) { - a = pa * la + pb * lc; - b = pa * lb + pb * ld; - c = pc * la + pd * lc; - d = pc * lb + pd * ld; - } else { - if (data.inheritRotation) { // No scale inheritance. - pa = 1; - pb = 0; - pc = 0; - pd = 1; - do { - float cos = cosDeg(parent.appliedRotation), sin = sinDeg(parent.appliedRotation); - float temp = pa * cos + pb * sin; - pb = pb * cos - pa * sin; - pa = temp; - temp = pc * cos + pd * sin; - pd = pd * cos - pc * sin; - pc = temp; - - if (!parent.data.inheritRotation) break; - parent = parent.parent; - } while (parent != null); - a = pa * la + pb * lc; - b = pa * lb + pb * ld; - c = pc * la + pd * lc; - d = pc * lb + pd * ld; - } else if (data.inheritScale) { // No rotation inheritance. - pa = 1; - pb = 0; - pc = 0; - pd = 1; - do { - float cos = cosDeg(parent.appliedRotation), sin = sinDeg(parent.appliedRotation); - float psx = parent.scaleX, psy = parent.scaleY; - float za = cos * psx, zb = sin * psy, zc = sin * psx, zd = cos * psy; - float temp = pa * za + pb * zc; - pb = pb * zd - pa * zb; - pa = temp; - temp = pc * za + pd * zc; - pd = pd * zd - pc * zb; - pc = temp; - - if (psx >= 0) sin = -sin; - temp = pa * cos + pb * sin; - pb = pb * cos - pa * sin; - pa = temp; - temp = pc * cos + pd * sin; - pd = pd * cos - pc * sin; - pc = temp; - - if (!parent.data.inheritScale) break; - parent = parent.parent; - } while (parent != null); - a = pa * la + pb * lc; - b = pa * lb + pb * ld; - c = pc * la + pd * lc; - d = pc * lb + pd * ld; - } else { - a = la; - b = lb; - c = lc; - d = ld; - } - if (skeleton.flipX) { - a = -a; - b = -b; - } - if (skeleton.flipY) { - c = -c; - d = -d; - } - } - } - - public void setToSetupPose () { - BoneData data = this.data; - x = data.x; - y = data.y; - rotation = data.rotation; - scaleX = data.scaleX; - scaleY = data.scaleY; - shearX = data.shearX; - shearY = data.shearY; - } - - public BoneData getData () { - return data; - } - - public Skeleton getSkeleton () { - return skeleton; - } - - public Bone getParent () { - return parent; - } - - public Array getChildren () { - return children; - } - - public float getX () { - return x; - } - - public void setX (float x) { - this.x = x; - } - - public float getY () { - return y; - } - - public void setY (float y) { - this.y = y; - } - - public void setPosition (float x, float y) { - this.x = x; - this.y = y; - } - - public float getRotation () { - return rotation; - } - - public void setRotation (float rotation) { - this.rotation = rotation; - } - - public float getScaleX () { - return scaleX; - } - - public void setScaleX (float scaleX) { - this.scaleX = scaleX; - } - - public float getScaleY () { - return scaleY; - } - - public void setScaleY (float scaleY) { - this.scaleY = scaleY; - } - - public void setScale (float scaleX, float scaleY) { - this.scaleX = scaleX; - this.scaleY = scaleY; - } - - public void setScale (float scale) { - scaleX = scale; - scaleY = scale; - } - - public float getShearX () { - return shearX; - } - - public void setShearX (float shearX) { - this.shearX = shearX; - } - - public float getShearY () { - return shearY; - } - - public void setShearY (float shearY) { - this.shearY = shearY; - } - - public float getA () { - return a; - } - - public float getB () { - return b; - } - - public float getC () { - return c; - } - - public float getD () { - return d; - } - - public float getWorldX () { - return worldX; - } - - public float getWorldY () { - return worldY; - } - - public float getWorldSignX () { - return worldSignX; - } - - public float getWorldSignY () { - return worldSignY; - } - - public float getWorldRotationX () { - return atan2(c, a) * radDeg; - } - - public float getWorldRotationY () { - return atan2(d, b) * radDeg; - } - - public float getWorldScaleX () { - return (float)Math.sqrt(a * a + b * b) * worldSignX; - } - - public float getWorldScaleY () { - return (float)Math.sqrt(c * c + d * d) * worldSignY; - } - - public float worldToLocalRotationX () { - Bone parent = this.parent; - if (parent == null) return rotation; - float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, a = this.a, c = this.c; - return atan2(pa * c - pc * a, pd * a - pb * c) * radDeg; - } - - public float worldToLocalRotationY () { - Bone parent = this.parent; - if (parent == null) return rotation; - float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, b = this.b, d = this.d; - return atan2(pa * d - pc * b, pd * b - pb * d) * radDeg; - } - - public void rotateWorld (float degrees) { - float a = this.a, b = this.b, c = this.c, d = this.d; - float cos = cosDeg(degrees), sin = sinDeg(degrees); - this.a = cos * a - sin * c; - this.b = cos * b - sin * d; - this.c = sin * a + cos * c; - this.d = sin * b + cos * d; - } - - /** Computes the local transform from the world transform. This can be useful to perform processing on the local transform - * after the world transform has been modified directly (eg, by a constraint). - *

- * Some redundant information is lost by the world transform, such as -1,-1 scale versus 180 rotation. The computed local - * transform values may differ from the original values but are functionally the same. */ - public void updateLocalTransform () { - Bone parent = this.parent; - if (parent == null) { - x = worldX; - y = worldY; - rotation = atan2(c, a) * radDeg; - scaleX = (float)Math.sqrt(a * a + c * c); - scaleY = (float)Math.sqrt(b * b + d * d); - float det = a * d - b * c; - shearX = 0; - shearY = atan2(a * b + c * d, det) * radDeg; - return; - } - float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; - float pid = 1 / (pa * pd - pb * pc); - float dx = worldX - parent.worldX, dy = worldY - parent.worldY; - x = (dx * pd * pid - dy * pb * pid); - y = (dy * pa * pid - dx * pc * pid); - float ia = pid * pd; - float id = pid * pa; - float ib = pid * pb; - float ic = pid * pc; - float ra = ia * a - ib * c; - float rb = ia * b - ib * d; - float rc = id * c - ic * a; - float rd = id * d - ic * b; - shearX = 0; - scaleX = (float)Math.sqrt(ra * ra + rc * rc); - if (scaleX > 0.0001f) { - float det = ra * rd - rb * rc; - scaleY = det / scaleX; - shearY = atan2(ra * rb + rc * rd, det) * radDeg; - rotation = atan2(rc, ra) * radDeg; - } else { - scaleX = 0; - scaleY = (float)Math.sqrt(rb * rb + rd * rd); - shearY = 0; - rotation = 90 - atan2(rd, rb) * radDeg; - } - appliedRotation = rotation; - } - - public Matrix3 getWorldTransform (Matrix3 worldTransform) { - if (worldTransform == null) throw new IllegalArgumentException("worldTransform cannot be null."); - float[] val = worldTransform.val; - val[M00] = a; - val[M01] = b; - val[M10] = c; - val[M11] = d; - val[M02] = worldX; - val[M12] = worldY; - val[M20] = 0; - val[M21] = 0; - val[M22] = 1; - return worldTransform; - } - - public Vector2 worldToLocal (Vector2 world) { - float a = this.a, b = this.b, c = this.c, d = this.d; - float invDet = 1 / (a * d - b * c); - float x = world.x - worldX, y = world.y - worldY; - world.x = (x * d * invDet - y * b * invDet); - world.y = (y * a * invDet - x * c * invDet); - return world; - } - - public Vector2 localToWorld (Vector2 local) { - float x = local.x, y = local.y; - local.x = x * a + y * b + worldX; - local.y = x * c + y * d + worldY; - return local; - } - - public String toString () { - return data.name; - } +package com.esotericsoftware.spine; + +import static com.badlogic.gdx.math.MathUtils.*; +import static com.badlogic.gdx.math.Matrix3.*; + +import com.badlogic.gdx.math.Matrix3; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; + +public class Bone implements Updatable { + final BoneData data; + final Skeleton skeleton; + final Bone parent; + final Array children = new Array(); + float x, y, rotation, scaleX, scaleY, shearX, shearY; + float appliedRotation; + + float a, b, worldX; + float c, d, worldY; + float worldSignX, worldSignY; + + boolean sorted; + + /** @param parent May be null. */ + public Bone (BoneData data, Skeleton skeleton, Bone parent) { + if (data == null) throw new IllegalArgumentException("data cannot be null."); + if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); + this.data = data; + this.skeleton = skeleton; + this.parent = parent; + setToSetupPose(); + } + + /** Copy constructor. Does not copy the children bones. + * @param parent May be null. */ + public Bone (Bone bone, Skeleton skeleton, Bone parent) { + if (bone == null) throw new IllegalArgumentException("bone cannot be null."); + if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); + this.skeleton = skeleton; + this.parent = parent; + data = bone.data; + x = bone.x; + y = bone.y; + rotation = bone.rotation; + scaleX = bone.scaleX; + scaleY = bone.scaleY; + shearX = bone.shearX; + shearY = bone.shearY; + } + + /** Same as {@link #updateWorldTransform()}. This method exists for Bone to implement {@link Updatable}. */ + public void update () { + updateWorldTransform(x, y, rotation, scaleX, scaleY, shearX, shearY); + } + + /** Computes the world transform using the parent bone and this bone's local transform. */ + public void updateWorldTransform () { + updateWorldTransform(x, y, rotation, scaleX, scaleY, shearX, shearY); + } + + /** Computes the world transform using the parent bone and the specified local transform. */ + public void updateWorldTransform (float x, float y, float rotation, float scaleX, float scaleY, float shearX, float shearY) { + appliedRotation = rotation; + + float rotationY = rotation + 90 + shearY; + float la = cosDeg(rotation + shearX) * scaleX, lb = cosDeg(rotationY) * scaleY; + float lc = sinDeg(rotation + shearX) * scaleX, ld = sinDeg(rotationY) * scaleY; + + Bone parent = this.parent; + if (parent == null) { // Root bone. + Skeleton skeleton = this.skeleton; + if (skeleton.flipX) { + x = -x; + la = -la; + lb = -lb; + } + if (skeleton.flipY) { + y = -y; + lc = -lc; + ld = -ld; + } + a = la; + b = lb; + c = lc; + d = ld; + worldX = x; + worldY = y; + worldSignX = Math.signum(scaleX); + worldSignY = Math.signum(scaleY); + return; + } + + float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + worldX = pa * x + pb * y + parent.worldX; + worldY = pc * x + pd * y + parent.worldY; + worldSignX = parent.worldSignX * Math.signum(scaleX); + worldSignY = parent.worldSignY * Math.signum(scaleY); + + if (data.inheritRotation && data.inheritScale) { + a = pa * la + pb * lc; + b = pa * lb + pb * ld; + c = pc * la + pd * lc; + d = pc * lb + pd * ld; + } else { + if (data.inheritRotation) { // No scale inheritance. + pa = 1; + pb = 0; + pc = 0; + pd = 1; + do { + float cos = cosDeg(parent.appliedRotation), sin = sinDeg(parent.appliedRotation); + float temp = pa * cos + pb * sin; + pb = pb * cos - pa * sin; + pa = temp; + temp = pc * cos + pd * sin; + pd = pd * cos - pc * sin; + pc = temp; + + if (!parent.data.inheritRotation) break; + parent = parent.parent; + } while (parent != null); + a = pa * la + pb * lc; + b = pa * lb + pb * ld; + c = pc * la + pd * lc; + d = pc * lb + pd * ld; + } else if (data.inheritScale) { // No rotation inheritance. + pa = 1; + pb = 0; + pc = 0; + pd = 1; + do { + float cos = cosDeg(parent.appliedRotation), sin = sinDeg(parent.appliedRotation); + float psx = parent.scaleX, psy = parent.scaleY; + float za = cos * psx, zb = sin * psy, zc = sin * psx, zd = cos * psy; + float temp = pa * za + pb * zc; + pb = pb * zd - pa * zb; + pa = temp; + temp = pc * za + pd * zc; + pd = pd * zd - pc * zb; + pc = temp; + + if (psx >= 0) sin = -sin; + temp = pa * cos + pb * sin; + pb = pb * cos - pa * sin; + pa = temp; + temp = pc * cos + pd * sin; + pd = pd * cos - pc * sin; + pc = temp; + + if (!parent.data.inheritScale) break; + parent = parent.parent; + } while (parent != null); + a = pa * la + pb * lc; + b = pa * lb + pb * ld; + c = pc * la + pd * lc; + d = pc * lb + pd * ld; + } else { + a = la; + b = lb; + c = lc; + d = ld; + } + if (skeleton.flipX) { + a = -a; + b = -b; + } + if (skeleton.flipY) { + c = -c; + d = -d; + } + } + } + + public void setToSetupPose () { + BoneData data = this.data; + x = data.x; + y = data.y; + rotation = data.rotation; + scaleX = data.scaleX; + scaleY = data.scaleY; + shearX = data.shearX; + shearY = data.shearY; + } + + public BoneData getData () { + return data; + } + + public Skeleton getSkeleton () { + return skeleton; + } + + public Bone getParent () { + return parent; + } + + public Array getChildren () { + return children; + } + + public float getX () { + return x; + } + + public void setX (float x) { + this.x = x; + } + + public float getY () { + return y; + } + + public void setY (float y) { + this.y = y; + } + + public void setPosition (float x, float y) { + this.x = x; + this.y = y; + } + + public float getRotation () { + return rotation; + } + + public void setRotation (float rotation) { + this.rotation = rotation; + } + + public float getScaleX () { + return scaleX; + } + + public void setScaleX (float scaleX) { + this.scaleX = scaleX; + } + + public float getScaleY () { + return scaleY; + } + + public void setScaleY (float scaleY) { + this.scaleY = scaleY; + } + + public void setScale (float scaleX, float scaleY) { + this.scaleX = scaleX; + this.scaleY = scaleY; + } + + public void setScale (float scale) { + scaleX = scale; + scaleY = scale; + } + + public float getShearX () { + return shearX; + } + + public void setShearX (float shearX) { + this.shearX = shearX; + } + + public float getShearY () { + return shearY; + } + + public void setShearY (float shearY) { + this.shearY = shearY; + } + + public float getA () { + return a; + } + + public float getB () { + return b; + } + + public float getC () { + return c; + } + + public float getD () { + return d; + } + + public float getWorldX () { + return worldX; + } + + public float getWorldY () { + return worldY; + } + + public float getWorldSignX () { + return worldSignX; + } + + public float getWorldSignY () { + return worldSignY; + } + + public float getWorldRotationX () { + return atan2(c, a) * radDeg; + } + + public float getWorldRotationY () { + return atan2(d, b) * radDeg; + } + + public float getWorldScaleX () { + return (float)Math.sqrt(a * a + b * b) * worldSignX; + } + + public float getWorldScaleY () { + return (float)Math.sqrt(c * c + d * d) * worldSignY; + } + + public float worldToLocalRotationX () { + Bone parent = this.parent; + if (parent == null) return rotation; + float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, a = this.a, c = this.c; + return atan2(pa * c - pc * a, pd * a - pb * c) * radDeg; + } + + public float worldToLocalRotationY () { + Bone parent = this.parent; + if (parent == null) return rotation; + float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, b = this.b, d = this.d; + return atan2(pa * d - pc * b, pd * b - pb * d) * radDeg; + } + + public void rotateWorld (float degrees) { + float a = this.a, b = this.b, c = this.c, d = this.d; + float cos = cosDeg(degrees), sin = sinDeg(degrees); + this.a = cos * a - sin * c; + this.b = cos * b - sin * d; + this.c = sin * a + cos * c; + this.d = sin * b + cos * d; + } + + /** Computes the local transform from the world transform. This can be useful to perform processing on the local transform + * after the world transform has been modified directly (eg, by a constraint). + *

+ * Some redundant information is lost by the world transform, such as -1,-1 scale versus 180 rotation. The computed local + * transform values may differ from the original values but are functionally the same. */ + public void updateLocalTransform () { + Bone parent = this.parent; + if (parent == null) { + x = worldX; + y = worldY; + rotation = atan2(c, a) * radDeg; + scaleX = (float)Math.sqrt(a * a + c * c); + scaleY = (float)Math.sqrt(b * b + d * d); + float det = a * d - b * c; + shearX = 0; + shearY = atan2(a * b + c * d, det) * radDeg; + return; + } + float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + float pid = 1 / (pa * pd - pb * pc); + float dx = worldX - parent.worldX, dy = worldY - parent.worldY; + x = (dx * pd * pid - dy * pb * pid); + y = (dy * pa * pid - dx * pc * pid); + float ia = pid * pd; + float id = pid * pa; + float ib = pid * pb; + float ic = pid * pc; + float ra = ia * a - ib * c; + float rb = ia * b - ib * d; + float rc = id * c - ic * a; + float rd = id * d - ic * b; + shearX = 0; + scaleX = (float)Math.sqrt(ra * ra + rc * rc); + if (scaleX > 0.0001f) { + float det = ra * rd - rb * rc; + scaleY = det / scaleX; + shearY = atan2(ra * rb + rc * rd, det) * radDeg; + rotation = atan2(rc, ra) * radDeg; + } else { + scaleX = 0; + scaleY = (float)Math.sqrt(rb * rb + rd * rd); + shearY = 0; + rotation = 90 - atan2(rd, rb) * radDeg; + } + appliedRotation = rotation; + } + + public Matrix3 getWorldTransform (Matrix3 worldTransform) { + if (worldTransform == null) throw new IllegalArgumentException("worldTransform cannot be null."); + float[] val = worldTransform.val; + val[M00] = a; + val[M01] = b; + val[M10] = c; + val[M11] = d; + val[M02] = worldX; + val[M12] = worldY; + val[M20] = 0; + val[M21] = 0; + val[M22] = 1; + return worldTransform; + } + + public Vector2 worldToLocal (Vector2 world) { + float a = this.a, b = this.b, c = this.c, d = this.d; + float invDet = 1 / (a * d - b * c); + float x = world.x - worldX, y = world.y - worldY; + world.x = (x * d * invDet - y * b * invDet); + world.y = (y * a * invDet - x * c * invDet); + return world; + } + + public Vector2 localToWorld (Vector2 local) { + float x = local.x, y = local.y; + local.x = x * a + y * b + worldX; + local.y = x * c + y * d + worldY; + return local; + } + + public String toString () { + return data.name; + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BoneData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BoneData.java index 821403b953..460aa7b74a 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BoneData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BoneData.java @@ -1,183 +1,182 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.graphics.Color; - -public class BoneData { - final int index; - final String name; - final BoneData parent; - float length; - float x, y, rotation, scaleX = 1, scaleY = 1, shearX, shearY; - boolean inheritRotation = true, inheritScale = true; - - // Nonessential. - final Color color = new Color(0.61f, 0.61f, 0.61f, 1); - - /** @param parent May be null. */ - public BoneData (int index, String name, BoneData parent) { - if (index < 0) throw new IllegalArgumentException("index must be >= 0."); - if (name == null) throw new IllegalArgumentException("name cannot be null."); - this.index = index; - this.name = name; - this.parent = parent; - } - - /** Copy constructor. - * @param parent May be null. */ - public BoneData (BoneData bone, BoneData parent) { - if (bone == null) throw new IllegalArgumentException("bone cannot be null."); - index = bone.index; - name = bone.name; - this.parent = parent; - length = bone.length; - x = bone.x; - y = bone.y; - rotation = bone.rotation; - scaleX = bone.scaleX; - scaleY = bone.scaleY; - shearX = bone.shearX; - shearY = bone.shearY; - } - - public int getIndex () { - return index; - } - - public String getName () { - return name; - } - - /** @return May be null. */ - public BoneData getParent () { - return parent; - } - - public float getLength () { - return length; - } - - public void setLength (float length) { - this.length = length; - } - - public float getX () { - return x; - } - - public void setX (float x) { - this.x = x; - } - - public float getY () { - return y; - } - - public void setY (float y) { - this.y = y; - } - - public void setPosition (float x, float y) { - this.x = x; - this.y = y; - } - - public float getRotation () { - return rotation; - } - - public void setRotation (float rotation) { - this.rotation = rotation; - } - - public float getScaleX () { - return scaleX; - } - - public void setScaleX (float scaleX) { - this.scaleX = scaleX; - } - - public float getScaleY () { - return scaleY; - } - - public void setScaleY (float scaleY) { - this.scaleY = scaleY; - } - - public void setScale (float scaleX, float scaleY) { - this.scaleX = scaleX; - this.scaleY = scaleY; - } - - public float getShearX () { - return shearX; - } - - public void setShearX (float shearX) { - this.shearX = shearX; - } - - public float getShearY () { - return shearY; - } - - public void setShearY (float shearY) { - this.shearY = shearY; - } - - public boolean getInheritRotation () { - return inheritRotation; - } - - public void setInheritRotation (boolean inheritRotation) { - this.inheritRotation = inheritRotation; - } - - public boolean getInheritScale () { - return inheritScale; - } - - public void setInheritScale (boolean inheritScale) { - this.inheritScale = inheritScale; - } - - public Color getColor () { - return color; - } - - public String toString () { - return name; - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.graphics.Color; + +public class BoneData { + final int index; + final String name; + final BoneData parent; + float length; + float x, y, rotation, scaleX = 1, scaleY = 1, shearX, shearY; + boolean inheritRotation = true, inheritScale = true; + + // Nonessential. + final Color color = new Color(0.61f, 0.61f, 0.61f, 1); + + /** @param parent May be null. */ + public BoneData (int index, String name, BoneData parent) { + if (index < 0) throw new IllegalArgumentException("index must be >= 0."); + if (name == null) throw new IllegalArgumentException("name cannot be null."); + this.index = index; + this.name = name; + this.parent = parent; + } + + /** Copy constructor. + * @param parent May be null. */ + public BoneData (BoneData bone, BoneData parent) { + if (bone == null) throw new IllegalArgumentException("bone cannot be null."); + index = bone.index; + name = bone.name; + this.parent = parent; + length = bone.length; + x = bone.x; + y = bone.y; + rotation = bone.rotation; + scaleX = bone.scaleX; + scaleY = bone.scaleY; + shearX = bone.shearX; + shearY = bone.shearY; + } + + public int getIndex () { + return index; + } + + public String getName () { + return name; + } + + /** @return May be null. */ + public BoneData getParent () { + return parent; + } + + public float getLength () { + return length; + } + + public void setLength (float length) { + this.length = length; + } + + public float getX () { + return x; + } + + public void setX (float x) { + this.x = x; + } + + public float getY () { + return y; + } + + public void setY (float y) { + this.y = y; + } + + public void setPosition (float x, float y) { + this.x = x; + this.y = y; + } + + public float getRotation () { + return rotation; + } + + public void setRotation (float rotation) { + this.rotation = rotation; + } + + public float getScaleX () { + return scaleX; + } + + public void setScaleX (float scaleX) { + this.scaleX = scaleX; + } + + public float getScaleY () { + return scaleY; + } + + public void setScaleY (float scaleY) { + this.scaleY = scaleY; + } + + public void setScale (float scaleX, float scaleY) { + this.scaleX = scaleX; + this.scaleY = scaleY; + } + + public float getShearX () { + return shearX; + } + + public void setShearX (float shearX) { + this.shearX = shearX; + } + + public float getShearY () { + return shearY; + } + + public void setShearY (float shearY) { + this.shearY = shearY; + } + + public boolean getInheritRotation () { + return inheritRotation; + } + + public void setInheritRotation (boolean inheritRotation) { + this.inheritRotation = inheritRotation; + } + + public boolean getInheritScale () { + return inheritScale; + } + + public void setInheritScale (boolean inheritScale) { + this.inheritScale = inheritScale; + } + + public Color getColor () { + return color; + } + + public String toString () { + return name; + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Event.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Event.java index e4730fbc91..625ce94e21 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Event.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Event.java @@ -1,82 +1,81 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -public class Event { - final private EventData data; - int intValue; - float floatValue; - String stringValue; - final float time; - - public Event (float time, EventData data) { - if (data == null) throw new IllegalArgumentException("data cannot be null."); - this.time = time; - this.data = data; - } - - public int getInt () { - return intValue; - } - - public void setInt (int intValue) { - this.intValue = intValue; - } - - public float getFloat () { - return floatValue; - } - - public void setFloat (float floatValue) { - this.floatValue = floatValue; - } - - public String getString () { - return stringValue; - } - - public void setString (String stringValue) { - this.stringValue = stringValue; - } - - public float getTime () { - return time; - } - - public EventData getData () { - return data; - } - - public String toString () { - return data.name; - } +package com.esotericsoftware.spine; + +public class Event { + final private EventData data; + int intValue; + float floatValue; + String stringValue; + final float time; + + public Event (float time, EventData data) { + if (data == null) throw new IllegalArgumentException("data cannot be null."); + this.time = time; + this.data = data; + } + + public int getInt () { + return intValue; + } + + public void setInt (int intValue) { + this.intValue = intValue; + } + + public float getFloat () { + return floatValue; + } + + public void setFloat (float floatValue) { + this.floatValue = floatValue; + } + + public String getString () { + return stringValue; + } + + public void setString (String stringValue) { + this.stringValue = stringValue; + } + + public float getTime () { + return time; + } + + public EventData getData () { + return data; + } + + public String toString () { + return data.name; + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/EventData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/EventData.java index 8bd6b61dc8..75ffce872b 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/EventData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/EventData.java @@ -1,76 +1,75 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -public class EventData { - final String name; - int intValue; - float floatValue; - String stringValue; - - public EventData (String name) { - if (name == null) throw new IllegalArgumentException("name cannot be null."); - this.name = name; - } - - public int getInt () { - return intValue; - } - - public void setInt (int intValue) { - this.intValue = intValue; - } - - public float getFloat () { - return floatValue; - } - - public void setFloat (float floatValue) { - this.floatValue = floatValue; - } - - public String getString () { - return stringValue; - } - - public void setString (String stringValue) { - this.stringValue = stringValue; - } - - public String getName () { - return name; - } - - public String toString () { - return name; - } +package com.esotericsoftware.spine; + +public class EventData { + final String name; + int intValue; + float floatValue; + String stringValue; + + public EventData (String name) { + if (name == null) throw new IllegalArgumentException("name cannot be null."); + this.name = name; + } + + public int getInt () { + return intValue; + } + + public void setInt (int intValue) { + this.intValue = intValue; + } + + public float getFloat () { + return floatValue; + } + + public void setFloat (float floatValue) { + this.floatValue = floatValue; + } + + public String getString () { + return stringValue; + } + + public void setString (String stringValue) { + this.stringValue = stringValue; + } + + public String getName () { + return name; + } + + public String toString () { + return name; + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java index 58e99dd182..33e1a2eb5f 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java @@ -1,276 +1,275 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import static com.badlogic.gdx.math.MathUtils.*; - -import com.badlogic.gdx.utils.Array; - -public class IkConstraint implements Updatable { - final IkConstraintData data; - final Array bones; - Bone target; - float mix = 1; - int bendDirection; - - int level; - - public IkConstraint (IkConstraintData data, Skeleton skeleton) { - if (data == null) throw new IllegalArgumentException("data cannot be null."); - if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); - this.data = data; - mix = data.mix; - bendDirection = data.bendDirection; - - bones = new Array(data.bones.size); - for (BoneData boneData : data.bones) - bones.add(skeleton.findBone(boneData.name)); - target = skeleton.findBone(data.target.name); - } - - /** Copy constructor. */ - public IkConstraint (IkConstraint constraint, Skeleton skeleton) { - if (constraint == null) throw new IllegalArgumentException("constraint cannot be null."); - if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); - data = constraint.data; - bones = new Array(constraint.bones.size); - for (Bone bone : constraint.bones) - bones.add(skeleton.bones.get(bone.data.index)); - target = skeleton.bones.get(constraint.target.data.index); - mix = constraint.mix; - bendDirection = constraint.bendDirection; - } - - public void apply () { - update(); - } - - public void update () { - Bone target = this.target; - Array bones = this.bones; - switch (bones.size) { - case 1: - apply(bones.first(), target.worldX, target.worldY, mix); - break; - case 2: - apply(bones.first(), bones.get(1), target.worldX, target.worldY, bendDirection, mix); - break; - } - } - - public Array getBones () { - return bones; - } - - public Bone getTarget () { - return target; - } - - public void setTarget (Bone target) { - this.target = target; - } - - public float getMix () { - return mix; - } - - public void setMix (float mix) { - this.mix = mix; - } - - public int getBendDirection () { - return bendDirection; - } - - public void setBendDirection (int bendDirection) { - this.bendDirection = bendDirection; - } - - public IkConstraintData getData () { - return data; - } - - public String toString () { - return data.name; - } - - /** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world - * coordinate system. */ - static public void apply (Bone bone, float targetX, float targetY, float alpha) { - Bone pp = bone.parent; - float id = 1 / (pp.a * pp.d - pp.b * pp.c); - float x = targetX - pp.worldX, y = targetY - pp.worldY; - float tx = (x * pp.d - y * pp.b) * id - bone.x, ty = (y * pp.a - x * pp.c) * id - bone.y; - float rotationIK = atan2(ty, tx) * radDeg - bone.shearX - bone.rotation; - if (bone.scaleX < 0) rotationIK += 180; - if (rotationIK > 180) - rotationIK -= 360; - else if (rotationIK < -180) rotationIK += 360; - bone.updateWorldTransform(bone.x, bone.y, bone.rotation + rotationIK * alpha, bone.scaleX, bone.scaleY, bone.shearX, - bone.shearY); - } - - /** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The - * target is specified in the world coordinate system. - * @param child A direct descendant of the parent bone. */ - static public void apply (Bone parent, Bone child, float targetX, float targetY, int bendDir, float alpha) { - if (alpha == 0) { - child.updateWorldTransform(); - return; - } - float px = parent.x, py = parent.y, psx = parent.scaleX, psy = parent.scaleY, csx = child.scaleX; - int os1, os2, s2; - if (psx < 0) { - psx = -psx; - os1 = 180; - s2 = -1; - } else { - os1 = 0; - s2 = 1; - } - if (psy < 0) { - psy = -psy; - s2 = -s2; - } - if (csx < 0) { - csx = -csx; - os2 = 180; - } else - os2 = 0; - float cx = child.x, cy, cwx, cwy, a = parent.a, b = parent.b, c = parent.c, d = parent.d; - boolean u = Math.abs(psx - psy) <= 0.0001f; - if (!u) { - cy = 0; - cwx = a * cx + parent.worldX; - cwy = c * cx + parent.worldY; - } else { - cy = child.y; - cwx = a * cx + b * cy + parent.worldX; - cwy = c * cx + d * cy + parent.worldY; - } - Bone pp = parent.parent; - a = pp.a; - b = pp.b; - c = pp.c; - d = pp.d; - float id = 1 / (a * d - b * c), x = targetX - pp.worldX, y = targetY - pp.worldY; - float tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py; - x = cwx - pp.worldX; - y = cwy - pp.worldY; - float dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; - float l1 = (float)Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2; - outer: - if (u) { - l2 *= psx; - float cos = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2); - if (cos < -1) - cos = -1; - else if (cos > 1) cos = 1; - a2 = (float)Math.acos(cos) * bendDir; - a = l1 + l2 * cos; - b = l2 * sin(a2); - a1 = atan2(ty * a - tx * b, tx * a + ty * b); - } else { - a = psx * l2; - b = psy * l2; - float aa = a * a, bb = b * b, dd = tx * tx + ty * ty, ta = atan2(ty, tx); - c = bb * l1 * l1 + aa * dd - aa * bb; - float c1 = -2 * bb * l1, c2 = bb - aa; - d = c1 * c1 - 4 * c2 * c; - if (d >= 0) { - float q = (float)Math.sqrt(d); - if (c1 < 0) q = -q; - q = -(c1 + q) / 2; - float r0 = q / c2, r1 = c / q; - float r = Math.abs(r0) < Math.abs(r1) ? r0 : r1; - if (r * r <= dd) { - y = (float)Math.sqrt(dd - r * r) * bendDir; - a1 = ta - atan2(y, r); - a2 = atan2(y / psy, (r - l1) / psx); - break outer; - } - } - float minAngle = 0, minDist = Float.MAX_VALUE, minX = 0, minY = 0; - float maxAngle = 0, maxDist = 0, maxX = 0, maxY = 0; - x = l1 + a; - d = x * x; - if (d > maxDist) { - maxAngle = 0; - maxDist = d; - maxX = x; - } - x = l1 - a; - d = x * x; - if (d < minDist) { - minAngle = PI; - minDist = d; - minX = x; - } - float angle = (float)Math.acos(-a * l1 / (aa - bb)); - x = a * cos(angle) + l1; - y = b * sin(angle); - d = x * x + y * y; - if (d < minDist) { - minAngle = angle; - minDist = d; - minX = x; - minY = y; - } - if (d > maxDist) { - maxAngle = angle; - maxDist = d; - maxX = x; - maxY = y; - } - if (dd <= (minDist + maxDist) / 2) { - a1 = ta - atan2(minY * bendDir, minX); - a2 = minAngle * bendDir; - } else { - a1 = ta - atan2(maxY * bendDir, maxX); - a2 = maxAngle * bendDir; - } - } - float os = atan2(cy, cx) * s2; - float rotation = parent.rotation; - a1 = (a1 - os) * radDeg + os1 - rotation; - if (a1 > 180) - a1 -= 360; - else if (a1 < -180) a1 += 360; - parent.updateWorldTransform(px, py, rotation + a1 * alpha, parent.scaleX, parent.scaleY, 0, 0); - rotation = child.rotation; - a2 = ((a2 + os) * radDeg - child.shearX) * s2 + os2 - rotation; - if (a2 > 180) - a2 -= 360; - else if (a2 < -180) a2 += 360; - child.updateWorldTransform(cx, cy, rotation + a2 * alpha, child.scaleX, child.scaleY, child.shearX, child.shearY); - } +package com.esotericsoftware.spine; + +import static com.badlogic.gdx.math.MathUtils.*; + +import com.badlogic.gdx.utils.Array; + +public class IkConstraint implements Updatable { + final IkConstraintData data; + final Array bones; + Bone target; + float mix = 1; + int bendDirection; + + int level; + + public IkConstraint (IkConstraintData data, Skeleton skeleton) { + if (data == null) throw new IllegalArgumentException("data cannot be null."); + if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); + this.data = data; + mix = data.mix; + bendDirection = data.bendDirection; + + bones = new Array(data.bones.size); + for (BoneData boneData : data.bones) + bones.add(skeleton.findBone(boneData.name)); + target = skeleton.findBone(data.target.name); + } + + /** Copy constructor. */ + public IkConstraint (IkConstraint constraint, Skeleton skeleton) { + if (constraint == null) throw new IllegalArgumentException("constraint cannot be null."); + if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); + data = constraint.data; + bones = new Array(constraint.bones.size); + for (Bone bone : constraint.bones) + bones.add(skeleton.bones.get(bone.data.index)); + target = skeleton.bones.get(constraint.target.data.index); + mix = constraint.mix; + bendDirection = constraint.bendDirection; + } + + public void apply () { + update(); + } + + public void update () { + Bone target = this.target; + Array bones = this.bones; + switch (bones.size) { + case 1: + apply(bones.first(), target.worldX, target.worldY, mix); + break; + case 2: + apply(bones.first(), bones.get(1), target.worldX, target.worldY, bendDirection, mix); + break; + } + } + + public Array getBones () { + return bones; + } + + public Bone getTarget () { + return target; + } + + public void setTarget (Bone target) { + this.target = target; + } + + public float getMix () { + return mix; + } + + public void setMix (float mix) { + this.mix = mix; + } + + public int getBendDirection () { + return bendDirection; + } + + public void setBendDirection (int bendDirection) { + this.bendDirection = bendDirection; + } + + public IkConstraintData getData () { + return data; + } + + public String toString () { + return data.name; + } + + /** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world + * coordinate system. */ + static public void apply (Bone bone, float targetX, float targetY, float alpha) { + Bone pp = bone.parent; + float id = 1 / (pp.a * pp.d - pp.b * pp.c); + float x = targetX - pp.worldX, y = targetY - pp.worldY; + float tx = (x * pp.d - y * pp.b) * id - bone.x, ty = (y * pp.a - x * pp.c) * id - bone.y; + float rotationIK = atan2(ty, tx) * radDeg - bone.shearX - bone.rotation; + if (bone.scaleX < 0) rotationIK += 180; + if (rotationIK > 180) + rotationIK -= 360; + else if (rotationIK < -180) rotationIK += 360; + bone.updateWorldTransform(bone.x, bone.y, bone.rotation + rotationIK * alpha, bone.scaleX, bone.scaleY, bone.shearX, + bone.shearY); + } + + /** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The + * target is specified in the world coordinate system. + * @param child A direct descendant of the parent bone. */ + static public void apply (Bone parent, Bone child, float targetX, float targetY, int bendDir, float alpha) { + if (alpha == 0) { + child.updateWorldTransform(); + return; + } + float px = parent.x, py = parent.y, psx = parent.scaleX, psy = parent.scaleY, csx = child.scaleX; + int os1, os2, s2; + if (psx < 0) { + psx = -psx; + os1 = 180; + s2 = -1; + } else { + os1 = 0; + s2 = 1; + } + if (psy < 0) { + psy = -psy; + s2 = -s2; + } + if (csx < 0) { + csx = -csx; + os2 = 180; + } else + os2 = 0; + float cx = child.x, cy, cwx, cwy, a = parent.a, b = parent.b, c = parent.c, d = parent.d; + boolean u = Math.abs(psx - psy) <= 0.0001f; + if (!u) { + cy = 0; + cwx = a * cx + parent.worldX; + cwy = c * cx + parent.worldY; + } else { + cy = child.y; + cwx = a * cx + b * cy + parent.worldX; + cwy = c * cx + d * cy + parent.worldY; + } + Bone pp = parent.parent; + a = pp.a; + b = pp.b; + c = pp.c; + d = pp.d; + float id = 1 / (a * d - b * c), x = targetX - pp.worldX, y = targetY - pp.worldY; + float tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py; + x = cwx - pp.worldX; + y = cwy - pp.worldY; + float dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; + float l1 = (float)Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2; + outer: + if (u) { + l2 *= psx; + float cos = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2); + if (cos < -1) + cos = -1; + else if (cos > 1) cos = 1; + a2 = (float)Math.acos(cos) * bendDir; + a = l1 + l2 * cos; + b = l2 * sin(a2); + a1 = atan2(ty * a - tx * b, tx * a + ty * b); + } else { + a = psx * l2; + b = psy * l2; + float aa = a * a, bb = b * b, dd = tx * tx + ty * ty, ta = atan2(ty, tx); + c = bb * l1 * l1 + aa * dd - aa * bb; + float c1 = -2 * bb * l1, c2 = bb - aa; + d = c1 * c1 - 4 * c2 * c; + if (d >= 0) { + float q = (float)Math.sqrt(d); + if (c1 < 0) q = -q; + q = -(c1 + q) / 2; + float r0 = q / c2, r1 = c / q; + float r = Math.abs(r0) < Math.abs(r1) ? r0 : r1; + if (r * r <= dd) { + y = (float)Math.sqrt(dd - r * r) * bendDir; + a1 = ta - atan2(y, r); + a2 = atan2(y / psy, (r - l1) / psx); + break outer; + } + } + float minAngle = 0, minDist = Float.MAX_VALUE, minX = 0, minY = 0; + float maxAngle = 0, maxDist = 0, maxX = 0, maxY = 0; + x = l1 + a; + d = x * x; + if (d > maxDist) { + maxAngle = 0; + maxDist = d; + maxX = x; + } + x = l1 - a; + d = x * x; + if (d < minDist) { + minAngle = PI; + minDist = d; + minX = x; + } + float angle = (float)Math.acos(-a * l1 / (aa - bb)); + x = a * cos(angle) + l1; + y = b * sin(angle); + d = x * x + y * y; + if (d < minDist) { + minAngle = angle; + minDist = d; + minX = x; + minY = y; + } + if (d > maxDist) { + maxAngle = angle; + maxDist = d; + maxX = x; + maxY = y; + } + if (dd <= (minDist + maxDist) / 2) { + a1 = ta - atan2(minY * bendDir, minX); + a2 = minAngle * bendDir; + } else { + a1 = ta - atan2(maxY * bendDir, maxX); + a2 = maxAngle * bendDir; + } + } + float os = atan2(cy, cx) * s2; + float rotation = parent.rotation; + a1 = (a1 - os) * radDeg + os1 - rotation; + if (a1 > 180) + a1 -= 360; + else if (a1 < -180) a1 += 360; + parent.updateWorldTransform(px, py, rotation + a1 * alpha, parent.scaleX, parent.scaleY, 0, 0); + rotation = child.rotation; + a2 = ((a2 + os) * radDeg - child.shearX) * s2 + os2 - rotation; + if (a2 > 180) + a2 -= 360; + else if (a2 < -180) a2 += 360; + child.updateWorldTransform(cx, cy, rotation + a2 * alpha, child.scaleX, child.scaleY, child.shearX, child.shearY); + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java index dfced65cc4..5de6610198 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java @@ -1,84 +1,83 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.utils.Array; - -public class IkConstraintData { - final String name; - final Array bones = new Array(); - BoneData target; - int bendDirection = 1; - float mix = 1; - - public IkConstraintData (String name) { - if (name == null) throw new IllegalArgumentException("name cannot be null."); - this.name = name; - } - - public String getName () { - return name; - } - - public Array getBones () { - return bones; - } - - public BoneData getTarget () { - return target; - } - - public void setTarget (BoneData target) { - if (target == null) throw new IllegalArgumentException("target cannot be null."); - this.target = target; - } - - public int getBendDirection () { - return bendDirection; - } - - public void setBendDirection (int bendDirection) { - this.bendDirection = bendDirection; - } - - public float getMix () { - return mix; - } - - public void setMix (float mix) { - this.mix = mix; - } - - public String toString () { - return name; - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.utils.Array; + +public class IkConstraintData { + final String name; + final Array bones = new Array(); + BoneData target; + int bendDirection = 1; + float mix = 1; + + public IkConstraintData (String name) { + if (name == null) throw new IllegalArgumentException("name cannot be null."); + this.name = name; + } + + public String getName () { + return name; + } + + public Array getBones () { + return bones; + } + + public BoneData getTarget () { + return target; + } + + public void setTarget (BoneData target) { + if (target == null) throw new IllegalArgumentException("target cannot be null."); + this.target = target; + } + + public int getBendDirection () { + return bendDirection; + } + + public void setBendDirection (int bendDirection) { + this.bendDirection = bendDirection; + } + + public float getMix () { + return mix; + } + + public void setMix (float mix) { + this.mix = mix; + } + + public String toString () { + return name; + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java index b83e363161..ceb2bbbd3f 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,13 +21,13 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + package com.esotericsoftware.spine; import static com.badlogic.gdx.math.MathUtils.*; @@ -463,4 +462,4 @@ public PathConstraintData getData () { public String toString () { return data.name; } -} +} diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintData.java index 15e159d85e..df768fb550 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintData.java @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ package com.esotericsoftware.spine; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java index 913720b6d3..6389acdbb2 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java @@ -1,630 +1,629 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.ObjectMap.Entry; -import com.esotericsoftware.spine.Skin.Key; -import com.esotericsoftware.spine.attachments.Attachment; -import com.esotericsoftware.spine.attachments.MeshAttachment; -import com.esotericsoftware.spine.attachments.PathAttachment; -import com.esotericsoftware.spine.attachments.RegionAttachment; - -public class Skeleton { - final SkeletonData data; - final Array bones; - final Array slots; - Array drawOrder; - final Array ikConstraints, ikConstraintsSorted; - final Array transformConstraints; - final Array pathConstraints; - final Array updateCache = new Array(); - Skin skin; - final Color color; - float time; - boolean flipX, flipY; - float x, y; - - public Skeleton (SkeletonData data) { - if (data == null) throw new IllegalArgumentException("data cannot be null."); - this.data = data; - - bones = new Array(data.bones.size); - for (BoneData boneData : data.bones) { - Bone bone; - if (boneData.parent == null) - bone = new Bone(boneData, this, null); - else { - Bone parent = bones.get(boneData.parent.index); - bone = new Bone(boneData, this, parent); - parent.children.add(bone); - } - bones.add(bone); - } - - slots = new Array(data.slots.size); - drawOrder = new Array(data.slots.size); - for (SlotData slotData : data.slots) { - Bone bone = bones.get(slotData.boneData.index); - Slot slot = new Slot(slotData, bone); - slots.add(slot); - drawOrder.add(slot); - } - - ikConstraints = new Array(data.ikConstraints.size); - ikConstraintsSorted = new Array(ikConstraints.size); - for (IkConstraintData ikConstraintData : data.ikConstraints) - ikConstraints.add(new IkConstraint(ikConstraintData, this)); - - transformConstraints = new Array(data.transformConstraints.size); - for (TransformConstraintData transformConstraintData : data.transformConstraints) - transformConstraints.add(new TransformConstraint(transformConstraintData, this)); - - pathConstraints = new Array(data.pathConstraints.size); - for (PathConstraintData pathConstraintData : data.pathConstraints) - pathConstraints.add(new PathConstraint(pathConstraintData, this)); - - color = new Color(1, 1, 1, 1); - - updateCache(); - } - - /** Copy constructor. */ - public Skeleton (Skeleton skeleton) { - if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); - data = skeleton.data; - - bones = new Array(skeleton.bones.size); - for (Bone bone : skeleton.bones) { - Bone copy; - if (bone.parent == null) - copy = new Bone(bone, this, null); - else { - Bone parent = bones.get(bone.parent.data.index); - copy = new Bone(bone, this, parent); - parent.children.add(copy); - } - bones.add(copy); - } - - slots = new Array(skeleton.slots.size); - for (Slot slot : skeleton.slots) { - Bone bone = bones.get(slot.bone.data.index); - slots.add(new Slot(slot, bone)); - } - - drawOrder = new Array(slots.size); - for (Slot slot : skeleton.drawOrder) - drawOrder.add(slots.get(slot.data.index)); - - ikConstraints = new Array(skeleton.ikConstraints.size); - ikConstraintsSorted = new Array(ikConstraints.size); - for (IkConstraint ikConstraint : skeleton.ikConstraints) - ikConstraints.add(new IkConstraint(ikConstraint, this)); - - transformConstraints = new Array(skeleton.transformConstraints.size); - for (TransformConstraint transformConstraint : skeleton.transformConstraints) - transformConstraints.add(new TransformConstraint(transformConstraint, this)); - - pathConstraints = new Array(skeleton.pathConstraints.size); - for (PathConstraint pathConstraint : skeleton.pathConstraints) - pathConstraints.add(new PathConstraint(pathConstraint, this)); - - skin = skeleton.skin; - color = new Color(skeleton.color); - time = skeleton.time; - flipX = skeleton.flipX; - flipY = skeleton.flipY; - - updateCache(); - } - - /** Caches information about bones and constraints. Must be called if bones, constraints, or weighted path attachments are - * added or removed. */ - public void updateCache () { - Array updateCache = this.updateCache; - updateCache.clear(); - - Array bones = this.bones; - for (int i = 0, n = bones.size; i < n; i++) - bones.get(i).sorted = false; - - // IK first, lowest hierarchy depth first. - Array ikConstraints = this.ikConstraintsSorted; - ikConstraints.clear(); - ikConstraints.addAll(this.ikConstraints); - int ikCount = ikConstraints.size; - for (int i = 0, level, n = ikCount; i < n; i++) { - IkConstraint ik = ikConstraints.get(i); - Bone bone = ik.bones.first().parent; - for (level = 0; bone != null; level++) - bone = bone.parent; - ik.level = level; - } - for (int i = 1, ii; i < ikCount; i++) { - IkConstraint ik = ikConstraints.get(i); - int level = ik.level; - for (ii = i - 1; ii >= 0; ii--) { - IkConstraint other = ikConstraints.get(ii); - if (other.level < level) break; - ikConstraints.set(ii + 1, other); - } - ikConstraints.set(ii + 1, ik); - } - for (int i = 0, n = ikConstraints.size; i < n; i++) { - IkConstraint constraint = ikConstraints.get(i); - Bone target = constraint.target; - sortBone(target); - - Array constrained = constraint.bones; - Bone parent = constrained.first(); - sortBone(parent); - - updateCache.add(constraint); - - sortReset(parent.children); - constrained.peek().sorted = true; - } - - Array pathConstraints = this.pathConstraints; - for (int i = 0, n = pathConstraints.size; i < n; i++) { - PathConstraint constraint = pathConstraints.get(i); - - Slot slot = constraint.target; - int slotIndex = slot.getData().index; - Bone slotBone = slot.bone; - if (skin != null) sortPathConstraintAttachment(skin, slotIndex, slotBone); - if (data.defaultSkin != null && data.defaultSkin != skin) - sortPathConstraintAttachment(data.defaultSkin, slotIndex, slotBone); - for (int ii = 0, nn = data.skins.size; ii < nn; ii++) - sortPathConstraintAttachment(data.skins.get(ii), slotIndex, slotBone); - - Attachment attachment = slot.attachment; - if (attachment instanceof PathAttachment) sortPathConstraintAttachment(attachment, slotBone); - - Array constrained = constraint.bones; - int boneCount = constrained.size; - for (int ii = 0; ii < boneCount; ii++) - sortBone(constrained.get(ii)); - - updateCache.add(constraint); - - for (int ii = 0; ii < boneCount; ii++) - sortReset(constrained.get(ii).children); - for (int ii = 0; ii < boneCount; ii++) - constrained.get(ii).sorted = true; - } - - Array transformConstraints = this.transformConstraints; - for (int i = 0, n = transformConstraints.size; i < n; i++) { - TransformConstraint constraint = transformConstraints.get(i); - - sortBone(constraint.target); - - Array constrained = constraint.bones; - int boneCount = constrained.size; - for (int ii = 0; ii < boneCount; ii++) - sortBone(constrained.get(ii)); - - updateCache.add(constraint); - - for (int ii = 0; ii < boneCount; ii++) - sortReset(constrained.get(ii).children); - for (int ii = 0; ii < boneCount; ii++) - constrained.get(ii).sorted = true; - } - - for (int i = 0, n = bones.size; i < n; i++) - sortBone(bones.get(i)); - } - - private void sortPathConstraintAttachment (Skin skin, int slotIndex, Bone slotBone) { - for (Entry entry : skin.attachments.entries()) - if (entry.key.slotIndex == slotIndex) sortPathConstraintAttachment(entry.value, slotBone); - } - - private void sortPathConstraintAttachment (Attachment attachment, Bone slotBone) { - if (!(attachment instanceof PathAttachment)) return; - int[] pathBones = ((PathAttachment)attachment).getBones(); - if (pathBones == null) - sortBone(slotBone); - else { - Array bones = this.bones; - for (int i = 0, n = pathBones.length; i < n;) { - int nn = pathBones[i++]; - nn += i; - while (i < nn) - sortBone(bones.get(pathBones[i++])); - } - } - } - - private void sortBone (Bone bone) { - if (bone.sorted) return; - Bone parent = bone.parent; - if (parent != null) sortBone(parent); - bone.sorted = true; - updateCache.add(bone); - } - - private void sortReset (Array bones) { - for (int i = 0, n = bones.size; i < n; i++) { - Bone bone = bones.get(i); - if (bone.sorted) sortReset(bone.children); - bone.sorted = false; - } - } - - /** Updates the world transform for each bone and applies constraints. */ - public void updateWorldTransform () { - Array updateCache = this.updateCache; - for (int i = 0, n = updateCache.size; i < n; i++) - updateCache.get(i).update(); - } - - /** Sets the bones, constraints, and slots to their setup pose values. */ - public void setToSetupPose () { - setBonesToSetupPose(); - setSlotsToSetupPose(); - } - - /** Sets the bones and constraints to their setup pose values. */ - public void setBonesToSetupPose () { - Array bones = this.bones; - for (int i = 0, n = bones.size; i < n; i++) - bones.get(i).setToSetupPose(); - - Array ikConstraints = this.ikConstraints; - for (int i = 0, n = ikConstraints.size; i < n; i++) { - IkConstraint constraint = ikConstraints.get(i); - constraint.bendDirection = constraint.data.bendDirection; - constraint.mix = constraint.data.mix; - } - - Array transformConstraints = this.transformConstraints; - for (int i = 0, n = transformConstraints.size; i < n; i++) { - TransformConstraint constraint = transformConstraints.get(i); - TransformConstraintData data = constraint.data; - constraint.rotateMix = data.rotateMix; - constraint.translateMix = data.translateMix; - constraint.scaleMix = data.scaleMix; - constraint.shearMix = data.shearMix; - } - - Array pathConstraints = this.pathConstraints; - for (int i = 0, n = pathConstraints.size; i < n; i++) { - PathConstraint constraint = pathConstraints.get(i); - PathConstraintData data = constraint.data; - constraint.position = data.position; - constraint.spacing = data.spacing; - constraint.rotateMix = data.rotateMix; - constraint.translateMix = data.translateMix; - } - } - - public void setSlotsToSetupPose () { - Array slots = this.slots; - System.arraycopy(slots.items, 0, drawOrder.items, 0, slots.size); - for (int i = 0, n = slots.size; i < n; i++) - slots.get(i).setToSetupPose(); - } - - public SkeletonData getData () { - return data; - } - - public Array getBones () { - return bones; - } - - public Array getUpdateCache () { - return updateCache; - } - - /** @return May return null. */ - public Bone getRootBone () { - if (bones.size == 0) return null; - return bones.first(); - } - - /** @return May be null. */ - public Bone findBone (String boneName) { - if (boneName == null) throw new IllegalArgumentException("boneName cannot be null."); - Array bones = this.bones; - for (int i = 0, n = bones.size; i < n; i++) { - Bone bone = bones.get(i); - if (bone.data.name.equals(boneName)) return bone; - } - return null; - } - - /** @return -1 if the bone was not found. */ - public int findBoneIndex (String boneName) { - if (boneName == null) throw new IllegalArgumentException("boneName cannot be null."); - Array bones = this.bones; - for (int i = 0, n = bones.size; i < n; i++) - if (bones.get(i).data.name.equals(boneName)) return i; - return -1; - } - - public Array getSlots () { - return slots; - } - - /** @return May be null. */ - public Slot findSlot (String slotName) { - if (slotName == null) throw new IllegalArgumentException("slotName cannot be null."); - Array slots = this.slots; - for (int i = 0, n = slots.size; i < n; i++) { - Slot slot = slots.get(i); - if (slot.data.name.equals(slotName)) return slot; - } - return null; - } - - /** @return -1 if the bone was not found. */ - public int findSlotIndex (String slotName) { - if (slotName == null) throw new IllegalArgumentException("slotName cannot be null."); - Array slots = this.slots; - for (int i = 0, n = slots.size; i < n; i++) - if (slots.get(i).data.name.equals(slotName)) return i; - return -1; - } - - /** Returns the slots in the order they will be drawn. The returned array may be modified to change the draw order. */ - public Array getDrawOrder () { - return drawOrder; - } - - /** Sets the slots and the order they will be drawn. */ - public void setDrawOrder (Array drawOrder) { - if (drawOrder == null) throw new IllegalArgumentException("drawOrder cannot be null."); - this.drawOrder = drawOrder; - } - - /** @return May be null. */ - public Skin getSkin () { - return skin; - } - - /** Sets a skin by name. - * @see #setSkin(Skin) */ - public void setSkin (String skinName) { - Skin skin = data.findSkin(skinName); - if (skin == null) throw new IllegalArgumentException("Skin not found: " + skinName); - setSkin(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. */ - public void setSkin (Skin newSkin) { - if (newSkin != null) { - if (skin != null) - newSkin.attachAll(this, skin); - else { - Array slots = this.slots; - for (int i = 0, n = slots.size; i < n; i++) { - Slot slot = slots.get(i); - String name = slot.data.attachmentName; - if (name != null) { - Attachment attachment = newSkin.getAttachment(i, name); - if (attachment != null) slot.setAttachment(attachment); - } - } - } - } - skin = newSkin; - } - - /** @return May be null. */ - public Attachment getAttachment (String slotName, String attachmentName) { - return getAttachment(data.findSlotIndex(slotName), attachmentName); - } - - /** @return May be null. */ - public Attachment getAttachment (int slotIndex, String attachmentName) { - if (attachmentName == null) throw new IllegalArgumentException("attachmentName cannot be null."); - if (skin != null) { - Attachment attachment = skin.getAttachment(slotIndex, attachmentName); - if (attachment != null) return attachment; - } - if (data.defaultSkin != null) return data.defaultSkin.getAttachment(slotIndex, attachmentName); - return null; - } - - /** @param attachmentName May be null. */ - public void setAttachment (String slotName, String attachmentName) { - if (slotName == null) throw new IllegalArgumentException("slotName cannot be null."); - Array slots = this.slots; - for (int i = 0, n = slots.size; i < n; i++) { - Slot slot = slots.get(i); - if (slot.data.name.equals(slotName)) { - Attachment attachment = null; - if (attachmentName != null) { - attachment = getAttachment(i, attachmentName); - if (attachment == null) - throw new IllegalArgumentException("Attachment not found: " + attachmentName + ", for slot: " + slotName); - } - slot.setAttachment(attachment); - return; - } - } - throw new IllegalArgumentException("Slot not found: " + slotName); - } - - public Array getIkConstraints () { - return ikConstraints; - } - - /** @return May be null. */ - public IkConstraint findIkConstraint (String constraintName) { - if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); - Array ikConstraints = this.ikConstraints; - for (int i = 0, n = ikConstraints.size; i < n; i++) { - IkConstraint ikConstraint = ikConstraints.get(i); - if (ikConstraint.data.name.equals(constraintName)) return ikConstraint; - } - return null; - } - - public Array getTransformConstraints () { - return transformConstraints; - } - - /** @return May be null. */ - public TransformConstraint findTransformConstraint (String constraintName) { - if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); - Array transformConstraints = this.transformConstraints; - for (int i = 0, n = transformConstraints.size; i < n; i++) { - TransformConstraint constraint = transformConstraints.get(i); - if (constraint.data.name.equals(constraintName)) return constraint; - } - return null; - } - - public Array getPathConstraints () { - return pathConstraints; - } - - /** @return May be null. */ - public PathConstraint findPathConstraint (String constraintName) { - if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); - Array pathConstraints = this.pathConstraints; - for (int i = 0, n = pathConstraints.size; i < n; i++) { - PathConstraint constraint = pathConstraints.get(i); - if (constraint.data.name.equals(constraintName)) return constraint; - } - return null; - } - - /** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose. - * @param offset The distance from the skeleton origin to the bottom left corner of the AABB. - * @param size The width and height of the AABB. */ - public void getBounds (Vector2 offset, Vector2 size) { - if (offset == null) throw new IllegalArgumentException("offset cannot be null."); - if (size == null) throw new IllegalArgumentException("size cannot be null."); - Array drawOrder = this.drawOrder; - float minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE; - for (int i = 0, n = drawOrder.size; i < n; i++) { - Slot slot = drawOrder.get(i); - float[] vertices = null; - Attachment attachment = slot.attachment; - if (attachment instanceof RegionAttachment) - vertices = ((RegionAttachment)attachment).updateWorldVertices(slot, false); - else if (attachment instanceof MeshAttachment) // - vertices = ((MeshAttachment)attachment).updateWorldVertices(slot, true); - if (vertices != null) { - for (int ii = 0, nn = vertices.length; ii < nn; ii += 5) { - float x = vertices[ii], y = vertices[ii + 1]; - minX = Math.min(minX, x); - minY = Math.min(minY, y); - maxX = Math.max(maxX, x); - maxY = Math.max(maxY, y); - } - } - } - offset.set(minX, minY); - size.set(maxX - minX, maxY - minY); - } - - public Color getColor () { - return color; - } - - /** A convenience method for setting the skeleton color. The color can also be set by modifying {@link #getColor()}. */ - public void setColor (Color color) { - if (color == null) throw new IllegalArgumentException("color cannot be null."); - this.color.set(color); - } - - public boolean getFlipX () { - return flipX; - } - - public void setFlipX (boolean flipX) { - this.flipX = flipX; - } - - public boolean getFlipY () { - return flipY; - } - - public void setFlipY (boolean flipY) { - this.flipY = flipY; - } - - public void setFlip (boolean flipX, boolean flipY) { - this.flipX = flipX; - this.flipY = flipY; - } - - public float getX () { - return x; - } - - public void setX (float x) { - this.x = x; - } - - public float getY () { - return y; - } - - public void setY (float y) { - this.y = y; - } - - public void setPosition (float x, float y) { - this.x = x; - this.y = y; - } - - public float getTime () { - return time; - } - - public void setTime (float time) { - this.time = time; - } - - public void update (float delta) { - time += delta; - } - - public String toString () { - return data.name != null ? data.name : super.toString(); - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.ObjectMap.Entry; +import com.esotericsoftware.spine.Skin.Key; +import com.esotericsoftware.spine.attachments.Attachment; +import com.esotericsoftware.spine.attachments.MeshAttachment; +import com.esotericsoftware.spine.attachments.PathAttachment; +import com.esotericsoftware.spine.attachments.RegionAttachment; + +public class Skeleton { + final SkeletonData data; + final Array bones; + final Array slots; + Array drawOrder; + final Array ikConstraints, ikConstraintsSorted; + final Array transformConstraints; + final Array pathConstraints; + final Array updateCache = new Array(); + Skin skin; + final Color color; + float time; + boolean flipX, flipY; + float x, y; + + public Skeleton (SkeletonData data) { + if (data == null) throw new IllegalArgumentException("data cannot be null."); + this.data = data; + + bones = new Array(data.bones.size); + for (BoneData boneData : data.bones) { + Bone bone; + if (boneData.parent == null) + bone = new Bone(boneData, this, null); + else { + Bone parent = bones.get(boneData.parent.index); + bone = new Bone(boneData, this, parent); + parent.children.add(bone); + } + bones.add(bone); + } + + slots = new Array(data.slots.size); + drawOrder = new Array(data.slots.size); + for (SlotData slotData : data.slots) { + Bone bone = bones.get(slotData.boneData.index); + Slot slot = new Slot(slotData, bone); + slots.add(slot); + drawOrder.add(slot); + } + + ikConstraints = new Array(data.ikConstraints.size); + ikConstraintsSorted = new Array(ikConstraints.size); + for (IkConstraintData ikConstraintData : data.ikConstraints) + ikConstraints.add(new IkConstraint(ikConstraintData, this)); + + transformConstraints = new Array(data.transformConstraints.size); + for (TransformConstraintData transformConstraintData : data.transformConstraints) + transformConstraints.add(new TransformConstraint(transformConstraintData, this)); + + pathConstraints = new Array(data.pathConstraints.size); + for (PathConstraintData pathConstraintData : data.pathConstraints) + pathConstraints.add(new PathConstraint(pathConstraintData, this)); + + color = new Color(1, 1, 1, 1); + + updateCache(); + } + + /** Copy constructor. */ + public Skeleton (Skeleton skeleton) { + if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); + data = skeleton.data; + + bones = new Array(skeleton.bones.size); + for (Bone bone : skeleton.bones) { + Bone copy; + if (bone.parent == null) + copy = new Bone(bone, this, null); + else { + Bone parent = bones.get(bone.parent.data.index); + copy = new Bone(bone, this, parent); + parent.children.add(copy); + } + bones.add(copy); + } + + slots = new Array(skeleton.slots.size); + for (Slot slot : skeleton.slots) { + Bone bone = bones.get(slot.bone.data.index); + slots.add(new Slot(slot, bone)); + } + + drawOrder = new Array(slots.size); + for (Slot slot : skeleton.drawOrder) + drawOrder.add(slots.get(slot.data.index)); + + ikConstraints = new Array(skeleton.ikConstraints.size); + ikConstraintsSorted = new Array(ikConstraints.size); + for (IkConstraint ikConstraint : skeleton.ikConstraints) + ikConstraints.add(new IkConstraint(ikConstraint, this)); + + transformConstraints = new Array(skeleton.transformConstraints.size); + for (TransformConstraint transformConstraint : skeleton.transformConstraints) + transformConstraints.add(new TransformConstraint(transformConstraint, this)); + + pathConstraints = new Array(skeleton.pathConstraints.size); + for (PathConstraint pathConstraint : skeleton.pathConstraints) + pathConstraints.add(new PathConstraint(pathConstraint, this)); + + skin = skeleton.skin; + color = new Color(skeleton.color); + time = skeleton.time; + flipX = skeleton.flipX; + flipY = skeleton.flipY; + + updateCache(); + } + + /** Caches information about bones and constraints. Must be called if bones, constraints, or weighted path attachments are + * added or removed. */ + public void updateCache () { + Array updateCache = this.updateCache; + updateCache.clear(); + + Array bones = this.bones; + for (int i = 0, n = bones.size; i < n; i++) + bones.get(i).sorted = false; + + // IK first, lowest hierarchy depth first. + Array ikConstraints = this.ikConstraintsSorted; + ikConstraints.clear(); + ikConstraints.addAll(this.ikConstraints); + int ikCount = ikConstraints.size; + for (int i = 0, level, n = ikCount; i < n; i++) { + IkConstraint ik = ikConstraints.get(i); + Bone bone = ik.bones.first().parent; + for (level = 0; bone != null; level++) + bone = bone.parent; + ik.level = level; + } + for (int i = 1, ii; i < ikCount; i++) { + IkConstraint ik = ikConstraints.get(i); + int level = ik.level; + for (ii = i - 1; ii >= 0; ii--) { + IkConstraint other = ikConstraints.get(ii); + if (other.level < level) break; + ikConstraints.set(ii + 1, other); + } + ikConstraints.set(ii + 1, ik); + } + for (int i = 0, n = ikConstraints.size; i < n; i++) { + IkConstraint constraint = ikConstraints.get(i); + Bone target = constraint.target; + sortBone(target); + + Array constrained = constraint.bones; + Bone parent = constrained.first(); + sortBone(parent); + + updateCache.add(constraint); + + sortReset(parent.children); + constrained.peek().sorted = true; + } + + Array pathConstraints = this.pathConstraints; + for (int i = 0, n = pathConstraints.size; i < n; i++) { + PathConstraint constraint = pathConstraints.get(i); + + Slot slot = constraint.target; + int slotIndex = slot.getData().index; + Bone slotBone = slot.bone; + if (skin != null) sortPathConstraintAttachment(skin, slotIndex, slotBone); + if (data.defaultSkin != null && data.defaultSkin != skin) + sortPathConstraintAttachment(data.defaultSkin, slotIndex, slotBone); + for (int ii = 0, nn = data.skins.size; ii < nn; ii++) + sortPathConstraintAttachment(data.skins.get(ii), slotIndex, slotBone); + + Attachment attachment = slot.attachment; + if (attachment instanceof PathAttachment) sortPathConstraintAttachment(attachment, slotBone); + + Array constrained = constraint.bones; + int boneCount = constrained.size; + for (int ii = 0; ii < boneCount; ii++) + sortBone(constrained.get(ii)); + + updateCache.add(constraint); + + for (int ii = 0; ii < boneCount; ii++) + sortReset(constrained.get(ii).children); + for (int ii = 0; ii < boneCount; ii++) + constrained.get(ii).sorted = true; + } + + Array transformConstraints = this.transformConstraints; + for (int i = 0, n = transformConstraints.size; i < n; i++) { + TransformConstraint constraint = transformConstraints.get(i); + + sortBone(constraint.target); + + Array constrained = constraint.bones; + int boneCount = constrained.size; + for (int ii = 0; ii < boneCount; ii++) + sortBone(constrained.get(ii)); + + updateCache.add(constraint); + + for (int ii = 0; ii < boneCount; ii++) + sortReset(constrained.get(ii).children); + for (int ii = 0; ii < boneCount; ii++) + constrained.get(ii).sorted = true; + } + + for (int i = 0, n = bones.size; i < n; i++) + sortBone(bones.get(i)); + } + + private void sortPathConstraintAttachment (Skin skin, int slotIndex, Bone slotBone) { + for (Entry entry : skin.attachments.entries()) + if (entry.key.slotIndex == slotIndex) sortPathConstraintAttachment(entry.value, slotBone); + } + + private void sortPathConstraintAttachment (Attachment attachment, Bone slotBone) { + if (!(attachment instanceof PathAttachment)) return; + int[] pathBones = ((PathAttachment)attachment).getBones(); + if (pathBones == null) + sortBone(slotBone); + else { + Array bones = this.bones; + for (int i = 0, n = pathBones.length; i < n;) { + int nn = pathBones[i++]; + nn += i; + while (i < nn) + sortBone(bones.get(pathBones[i++])); + } + } + } + + private void sortBone (Bone bone) { + if (bone.sorted) return; + Bone parent = bone.parent; + if (parent != null) sortBone(parent); + bone.sorted = true; + updateCache.add(bone); + } + + private void sortReset (Array bones) { + for (int i = 0, n = bones.size; i < n; i++) { + Bone bone = bones.get(i); + if (bone.sorted) sortReset(bone.children); + bone.sorted = false; + } + } + + /** Updates the world transform for each bone and applies constraints. */ + public void updateWorldTransform () { + Array updateCache = this.updateCache; + for (int i = 0, n = updateCache.size; i < n; i++) + updateCache.get(i).update(); + } + + /** Sets the bones, constraints, and slots to their setup pose values. */ + public void setToSetupPose () { + setBonesToSetupPose(); + setSlotsToSetupPose(); + } + + /** Sets the bones and constraints to their setup pose values. */ + public void setBonesToSetupPose () { + Array bones = this.bones; + for (int i = 0, n = bones.size; i < n; i++) + bones.get(i).setToSetupPose(); + + Array ikConstraints = this.ikConstraints; + for (int i = 0, n = ikConstraints.size; i < n; i++) { + IkConstraint constraint = ikConstraints.get(i); + constraint.bendDirection = constraint.data.bendDirection; + constraint.mix = constraint.data.mix; + } + + Array transformConstraints = this.transformConstraints; + for (int i = 0, n = transformConstraints.size; i < n; i++) { + TransformConstraint constraint = transformConstraints.get(i); + TransformConstraintData data = constraint.data; + constraint.rotateMix = data.rotateMix; + constraint.translateMix = data.translateMix; + constraint.scaleMix = data.scaleMix; + constraint.shearMix = data.shearMix; + } + + Array pathConstraints = this.pathConstraints; + for (int i = 0, n = pathConstraints.size; i < n; i++) { + PathConstraint constraint = pathConstraints.get(i); + PathConstraintData data = constraint.data; + constraint.position = data.position; + constraint.spacing = data.spacing; + constraint.rotateMix = data.rotateMix; + constraint.translateMix = data.translateMix; + } + } + + public void setSlotsToSetupPose () { + Array slots = this.slots; + System.arraycopy(slots.items, 0, drawOrder.items, 0, slots.size); + for (int i = 0, n = slots.size; i < n; i++) + slots.get(i).setToSetupPose(); + } + + public SkeletonData getData () { + return data; + } + + public Array getBones () { + return bones; + } + + public Array getUpdateCache () { + return updateCache; + } + + /** @return May return null. */ + public Bone getRootBone () { + if (bones.size == 0) return null; + return bones.first(); + } + + /** @return May be null. */ + public Bone findBone (String boneName) { + if (boneName == null) throw new IllegalArgumentException("boneName cannot be null."); + Array bones = this.bones; + for (int i = 0, n = bones.size; i < n; i++) { + Bone bone = bones.get(i); + if (bone.data.name.equals(boneName)) return bone; + } + return null; + } + + /** @return -1 if the bone was not found. */ + public int findBoneIndex (String boneName) { + if (boneName == null) throw new IllegalArgumentException("boneName cannot be null."); + Array bones = this.bones; + for (int i = 0, n = bones.size; i < n; i++) + if (bones.get(i).data.name.equals(boneName)) return i; + return -1; + } + + public Array getSlots () { + return slots; + } + + /** @return May be null. */ + public Slot findSlot (String slotName) { + if (slotName == null) throw new IllegalArgumentException("slotName cannot be null."); + Array slots = this.slots; + for (int i = 0, n = slots.size; i < n; i++) { + Slot slot = slots.get(i); + if (slot.data.name.equals(slotName)) return slot; + } + return null; + } + + /** @return -1 if the bone was not found. */ + public int findSlotIndex (String slotName) { + if (slotName == null) throw new IllegalArgumentException("slotName cannot be null."); + Array slots = this.slots; + for (int i = 0, n = slots.size; i < n; i++) + if (slots.get(i).data.name.equals(slotName)) return i; + return -1; + } + + /** Returns the slots in the order they will be drawn. The returned array may be modified to change the draw order. */ + public Array getDrawOrder () { + return drawOrder; + } + + /** Sets the slots and the order they will be drawn. */ + public void setDrawOrder (Array drawOrder) { + if (drawOrder == null) throw new IllegalArgumentException("drawOrder cannot be null."); + this.drawOrder = drawOrder; + } + + /** @return May be null. */ + public Skin getSkin () { + return skin; + } + + /** Sets a skin by name. + * @see #setSkin(Skin) */ + public void setSkin (String skinName) { + Skin skin = data.findSkin(skinName); + if (skin == null) throw new IllegalArgumentException("Skin not found: " + skinName); + setSkin(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. */ + public void setSkin (Skin newSkin) { + if (newSkin != null) { + if (skin != null) + newSkin.attachAll(this, skin); + else { + Array slots = this.slots; + for (int i = 0, n = slots.size; i < n; i++) { + Slot slot = slots.get(i); + String name = slot.data.attachmentName; + if (name != null) { + Attachment attachment = newSkin.getAttachment(i, name); + if (attachment != null) slot.setAttachment(attachment); + } + } + } + } + skin = newSkin; + } + + /** @return May be null. */ + public Attachment getAttachment (String slotName, String attachmentName) { + return getAttachment(data.findSlotIndex(slotName), attachmentName); + } + + /** @return May be null. */ + public Attachment getAttachment (int slotIndex, String attachmentName) { + if (attachmentName == null) throw new IllegalArgumentException("attachmentName cannot be null."); + if (skin != null) { + Attachment attachment = skin.getAttachment(slotIndex, attachmentName); + if (attachment != null) return attachment; + } + if (data.defaultSkin != null) return data.defaultSkin.getAttachment(slotIndex, attachmentName); + return null; + } + + /** @param attachmentName May be null. */ + public void setAttachment (String slotName, String attachmentName) { + if (slotName == null) throw new IllegalArgumentException("slotName cannot be null."); + Array slots = this.slots; + for (int i = 0, n = slots.size; i < n; i++) { + Slot slot = slots.get(i); + if (slot.data.name.equals(slotName)) { + Attachment attachment = null; + if (attachmentName != null) { + attachment = getAttachment(i, attachmentName); + if (attachment == null) + throw new IllegalArgumentException("Attachment not found: " + attachmentName + ", for slot: " + slotName); + } + slot.setAttachment(attachment); + return; + } + } + throw new IllegalArgumentException("Slot not found: " + slotName); + } + + public Array getIkConstraints () { + return ikConstraints; + } + + /** @return May be null. */ + public IkConstraint findIkConstraint (String constraintName) { + if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); + Array ikConstraints = this.ikConstraints; + for (int i = 0, n = ikConstraints.size; i < n; i++) { + IkConstraint ikConstraint = ikConstraints.get(i); + if (ikConstraint.data.name.equals(constraintName)) return ikConstraint; + } + return null; + } + + public Array getTransformConstraints () { + return transformConstraints; + } + + /** @return May be null. */ + public TransformConstraint findTransformConstraint (String constraintName) { + if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); + Array transformConstraints = this.transformConstraints; + for (int i = 0, n = transformConstraints.size; i < n; i++) { + TransformConstraint constraint = transformConstraints.get(i); + if (constraint.data.name.equals(constraintName)) return constraint; + } + return null; + } + + public Array getPathConstraints () { + return pathConstraints; + } + + /** @return May be null. */ + public PathConstraint findPathConstraint (String constraintName) { + if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); + Array pathConstraints = this.pathConstraints; + for (int i = 0, n = pathConstraints.size; i < n; i++) { + PathConstraint constraint = pathConstraints.get(i); + if (constraint.data.name.equals(constraintName)) return constraint; + } + return null; + } + + /** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose. + * @param offset The distance from the skeleton origin to the bottom left corner of the AABB. + * @param size The width and height of the AABB. */ + public void getBounds (Vector2 offset, Vector2 size) { + if (offset == null) throw new IllegalArgumentException("offset cannot be null."); + if (size == null) throw new IllegalArgumentException("size cannot be null."); + Array drawOrder = this.drawOrder; + float minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE; + for (int i = 0, n = drawOrder.size; i < n; i++) { + Slot slot = drawOrder.get(i); + float[] vertices = null; + Attachment attachment = slot.attachment; + if (attachment instanceof RegionAttachment) + vertices = ((RegionAttachment)attachment).updateWorldVertices(slot, false); + else if (attachment instanceof MeshAttachment) // + vertices = ((MeshAttachment)attachment).updateWorldVertices(slot, true); + if (vertices != null) { + for (int ii = 0, nn = vertices.length; ii < nn; ii += 5) { + float x = vertices[ii], y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + } + offset.set(minX, minY); + size.set(maxX - minX, maxY - minY); + } + + public Color getColor () { + return color; + } + + /** A convenience method for setting the skeleton color. The color can also be set by modifying {@link #getColor()}. */ + public void setColor (Color color) { + if (color == null) throw new IllegalArgumentException("color cannot be null."); + this.color.set(color); + } + + public boolean getFlipX () { + return flipX; + } + + public void setFlipX (boolean flipX) { + this.flipX = flipX; + } + + public boolean getFlipY () { + return flipY; + } + + public void setFlipY (boolean flipY) { + this.flipY = flipY; + } + + public void setFlip (boolean flipX, boolean flipY) { + this.flipX = flipX; + this.flipY = flipY; + } + + public float getX () { + return x; + } + + public void setX (float x) { + this.x = x; + } + + public float getY () { + return y; + } + + public void setY (float y) { + this.y = y; + } + + public void setPosition (float x, float y) { + this.x = x; + this.y = y; + } + + public float getTime () { + return time; + } + + public void setTime (float time) { + this.time = time; + } + + public void update (float delta) { + time += delta; + } + + public String toString () { + return data.name != null ? data.name : super.toString(); + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java index a24fe562f8..17144e96a7 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java @@ -1,781 +1,780 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import java.io.EOFException; -import java.io.IOException; - -import com.badlogic.gdx.files.FileHandle; -import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.DataInput; -import com.badlogic.gdx.utils.FloatArray; -import com.badlogic.gdx.utils.IntArray; -import com.badlogic.gdx.utils.SerializationException; -import com.esotericsoftware.spine.Animation.AttachmentTimeline; -import com.esotericsoftware.spine.Animation.ColorTimeline; -import com.esotericsoftware.spine.Animation.CurveTimeline; -import com.esotericsoftware.spine.Animation.DeformTimeline; -import com.esotericsoftware.spine.Animation.DrawOrderTimeline; -import com.esotericsoftware.spine.Animation.EventTimeline; -import com.esotericsoftware.spine.Animation.IkConstraintTimeline; -import com.esotericsoftware.spine.Animation.PathConstraintMixTimeline; -import com.esotericsoftware.spine.Animation.PathConstraintPositionTimeline; -import com.esotericsoftware.spine.Animation.PathConstraintSpacingTimeline; -import com.esotericsoftware.spine.Animation.RotateTimeline; -import com.esotericsoftware.spine.Animation.ScaleTimeline; -import com.esotericsoftware.spine.Animation.ShearTimeline; -import com.esotericsoftware.spine.Animation.Timeline; -import com.esotericsoftware.spine.Animation.TransformConstraintTimeline; -import com.esotericsoftware.spine.Animation.TranslateTimeline; -import com.esotericsoftware.spine.PathConstraintData.PositionMode; -import com.esotericsoftware.spine.PathConstraintData.RotateMode; -import com.esotericsoftware.spine.PathConstraintData.SpacingMode; -import com.esotericsoftware.spine.SkeletonJson.LinkedMesh; -import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader; -import com.esotericsoftware.spine.attachments.Attachment; -import com.esotericsoftware.spine.attachments.AttachmentLoader; -import com.esotericsoftware.spine.attachments.AttachmentType; -import com.esotericsoftware.spine.attachments.BoundingBoxAttachment; -import com.esotericsoftware.spine.attachments.MeshAttachment; -import com.esotericsoftware.spine.attachments.PathAttachment; -import com.esotericsoftware.spine.attachments.RegionAttachment; -import com.esotericsoftware.spine.attachments.VertexAttachment; - -public class SkeletonBinary { - static public final int BONE_ROTATE = 0; - static public final int BONE_TRANSLATE = 1; - static public final int BONE_SCALE = 2; - static public final int BONE_SHEAR = 3; - - static public final int SLOT_ATTACHMENT = 0; - static public final int SLOT_COLOR = 1; - - static public final int PATH_POSITION = 0; - static public final int PATH_SPACING = 1; - static public final int PATH_MIX = 2; - - static public final int CURVE_LINEAR = 0; - static public final int CURVE_STEPPED = 1; - static public final int CURVE_BEZIER = 2; - - static private final Color tempColor = new Color(); - - private final AttachmentLoader attachmentLoader; - private float scale = 1; - private Array linkedMeshes = new Array(); - - public SkeletonBinary (TextureAtlas atlas) { - attachmentLoader = new AtlasAttachmentLoader(atlas); - } - - public SkeletonBinary (AttachmentLoader attachmentLoader) { - if (attachmentLoader == null) throw new IllegalArgumentException("attachmentLoader cannot be null."); - this.attachmentLoader = attachmentLoader; - } - - public float getScale () { - return scale; - } - - /** Scales the bones, images, and animations as they are loaded. */ - public void setScale (float scale) { - this.scale = scale; - } - - public SkeletonData readSkeletonData (FileHandle file) { - if (file == null) throw new IllegalArgumentException("file cannot be null."); - - float scale = this.scale; - - SkeletonData skeletonData = new SkeletonData(); - skeletonData.name = file.nameWithoutExtension(); - - DataInput input = new DataInput(file.read(512)) { - private char[] chars = new char[32]; - - public String readString () throws IOException { - int byteCount = readInt(true); - switch (byteCount) { - case 0: - return null; - case 1: - return ""; - } - byteCount--; - if (chars.length < byteCount) chars = new char[byteCount]; - char[] chars = this.chars; - int charCount = 0; - for (int i = 0; i < byteCount;) { - int b = read(); - switch (b >> 4) { - case -1: - throw new EOFException(); - case 12: - case 13: - chars[charCount++] = (char)((b & 0x1F) << 6 | read() & 0x3F); - i += 2; - break; - case 14: - chars[charCount++] = (char)((b & 0x0F) << 12 | (read() & 0x3F) << 6 | read() & 0x3F); - i += 3; - break; - default: - chars[charCount++] = (char)b; - i++; - } - } - return new String(chars, 0, charCount); - } - }; - try { - skeletonData.hash = input.readString(); - if (skeletonData.hash.isEmpty()) skeletonData.hash = null; - skeletonData.version = input.readString(); - if (skeletonData.version.isEmpty()) skeletonData.version = null; - skeletonData.width = input.readFloat(); - skeletonData.height = input.readFloat(); - - boolean nonessential = input.readBoolean(); - - if (nonessential) { - skeletonData.imagesPath = input.readString(); - if (skeletonData.imagesPath.isEmpty()) skeletonData.imagesPath = null; - } - - // Bones. - for (int i = 0, n = input.readInt(true); i < n; i++) { - String name = input.readString(); - BoneData parent = i == 0 ? null : skeletonData.bones.get(input.readInt(true)); - BoneData data = new BoneData(i, name, parent); - data.rotation = input.readFloat(); - data.x = input.readFloat() * scale; - data.y = input.readFloat() * scale; - data.scaleX = input.readFloat(); - data.scaleY = input.readFloat(); - data.shearX = input.readFloat(); - data.shearY = input.readFloat(); - data.length = input.readFloat() * scale; - data.inheritRotation = input.readBoolean(); - data.inheritScale = input.readBoolean(); - if (nonessential) Color.rgba8888ToColor(data.color, input.readInt()); - skeletonData.bones.add(data); - } - - // Slots. - for (int i = 0, n = input.readInt(true); i < n; i++) { - String slotName = input.readString(); - BoneData boneData = skeletonData.bones.get(input.readInt(true)); - SlotData data = new SlotData(i, slotName, boneData); - Color.rgba8888ToColor(data.color, input.readInt()); - data.attachmentName = input.readString(); - data.blendMode = BlendMode.values[input.readInt(true)]; - skeletonData.slots.add(data); - } - - // IK constraints. - for (int i = 0, n = input.readInt(true); i < n; i++) { - IkConstraintData data = new IkConstraintData(input.readString()); - for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) - data.bones.add(skeletonData.bones.get(input.readInt(true))); - data.target = skeletonData.bones.get(input.readInt(true)); - data.mix = input.readFloat(); - data.bendDirection = input.readByte(); - skeletonData.ikConstraints.add(data); - } - - // Transform constraints. - for (int i = 0, n = input.readInt(true); i < n; i++) { - TransformConstraintData data = new TransformConstraintData(input.readString()); - for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) - data.bones.add(skeletonData.bones.get(input.readInt(true))); - data.target = skeletonData.bones.get(input.readInt(true)); - data.offsetRotation = input.readFloat(); - data.offsetX = input.readFloat() * scale; - data.offsetY = input.readFloat() * scale; - data.offsetScaleX = input.readFloat(); - data.offsetScaleY = input.readFloat(); - data.offsetShearY = input.readFloat(); - data.rotateMix = input.readFloat(); - data.translateMix = input.readFloat(); - data.scaleMix = input.readFloat(); - data.shearMix = input.readFloat(); - skeletonData.transformConstraints.add(data); - } - - // Path constraints. - for (int i = 0, n = input.readInt(true); i < n; i++) { - PathConstraintData data = new PathConstraintData(input.readString()); - for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) - data.bones.add(skeletonData.bones.get(input.readInt(true))); - data.target = skeletonData.slots.get(input.readInt(true)); - data.positionMode = PositionMode.values[input.readInt(true)]; - data.spacingMode = SpacingMode.values[input.readInt(true)]; - data.rotateMode = RotateMode.values[input.readInt(true)]; - data.offsetRotation = input.readFloat(); - data.position = input.readFloat(); - if (data.positionMode == PositionMode.fixed) data.position *= scale; - data.spacing = input.readFloat(); - if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) data.spacing *= scale; - data.rotateMix = input.readFloat(); - data.translateMix = input.readFloat(); - skeletonData.pathConstraints.add(data); - } - - // Default skin. - Skin defaultSkin = readSkin(input, "default", nonessential); - if (defaultSkin != null) { - skeletonData.defaultSkin = defaultSkin; - skeletonData.skins.add(defaultSkin); - } - - // Skins. - for (int i = 0, n = input.readInt(true); i < n; i++) - skeletonData.skins.add(readSkin(input, input.readString(), nonessential)); - - // Linked meshes. - for (int i = 0, n = linkedMeshes.size; i < n; i++) { - LinkedMesh linkedMesh = linkedMeshes.get(i); - Skin skin = linkedMesh.skin == null ? skeletonData.getDefaultSkin() : skeletonData.findSkin(linkedMesh.skin); - if (skin == null) throw new SerializationException("Skin not found: " + linkedMesh.skin); - Attachment parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); - if (parent == null) throw new SerializationException("Parent mesh not found: " + linkedMesh.parent); - linkedMesh.mesh.setParentMesh((MeshAttachment)parent); - linkedMesh.mesh.updateUVs(); - } - linkedMeshes.clear(); - - // Events. - for (int i = 0, n = input.readInt(true); i < n; i++) { - EventData data = new EventData(input.readString()); - data.intValue = input.readInt(false); - data.floatValue = input.readFloat(); - data.stringValue = input.readString(); - skeletonData.events.add(data); - } - - // Animations. - for (int i = 0, n = input.readInt(true); i < n; i++) - readAnimation(input.readString(), input, skeletonData); - - } catch (IOException ex) { - throw new SerializationException("Error reading skeleton file.", ex); - } finally { - try { - input.close(); - } catch (IOException ignored) { - } - } - - skeletonData.bones.shrink(); - skeletonData.slots.shrink(); - skeletonData.skins.shrink(); - skeletonData.events.shrink(); - skeletonData.animations.shrink(); - skeletonData.ikConstraints.shrink(); - return skeletonData; - } - - /** @return May be null. */ - private Skin readSkin (DataInput input, String skinName, boolean nonessential) throws IOException { - int slotCount = input.readInt(true); - if (slotCount == 0) return null; - Skin skin = new Skin(skinName); - for (int i = 0; i < slotCount; i++) { - int slotIndex = input.readInt(true); - for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) { - String name = input.readString(); - skin.addAttachment(slotIndex, name, readAttachment(input, skin, slotIndex, name, nonessential)); - } - } - return skin; - } - - private Attachment readAttachment (DataInput input, Skin skin, int slotIndex, String attachmentName, boolean nonessential) - throws IOException { - float scale = this.scale; - - String name = input.readString(); - if (name == null) name = attachmentName; - - AttachmentType type = AttachmentType.values[input.readByte()]; - switch (type) { - case region: { - String path = input.readString(); - float rotation = input.readFloat(); - float x = input.readFloat(); - float y = input.readFloat(); - float scaleX = input.readFloat(); - float scaleY = input.readFloat(); - float width = input.readFloat(); - float height = input.readFloat(); - int color = input.readInt(); - - if (path == null) path = name; - RegionAttachment region = attachmentLoader.newRegionAttachment(skin, name, path); - if (region == null) return null; - region.setPath(path); - region.setX(x * scale); - region.setY(y * scale); - region.setScaleX(scaleX); - region.setScaleY(scaleY); - region.setRotation(rotation); - region.setWidth(width * scale); - region.setHeight(height * scale); - Color.rgba8888ToColor(region.getColor(), color); - region.updateOffset(); - return region; - } - case boundingbox: { - int vertexCount = input.readInt(true); - Vertices vertices = readVertices(input, vertexCount); - int color = nonessential ? input.readInt() : 0; - - BoundingBoxAttachment box = attachmentLoader.newBoundingBoxAttachment(skin, name); - if (box == null) return null; - box.setWorldVerticesLength(vertexCount << 1); - box.setVertices(vertices.vertices); - box.setBones(vertices.bones); - if (nonessential) Color.rgba8888ToColor(box.getColor(), color); - return box; - } - case mesh: { - String path = input.readString(); - int color = input.readInt(); - int vertexCount = input.readInt(true); - float[] uvs = readFloatArray(input, vertexCount << 1, 1); - short[] triangles = readShortArray(input); - Vertices vertices = readVertices(input, vertexCount); - int hullLength = input.readInt(true); - short[] edges = null; - float width = 0, height = 0; - if (nonessential) { - edges = readShortArray(input); - width = input.readFloat(); - height = input.readFloat(); - } - - if (path == null) path = name; - MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path); - if (mesh == null) return null; - mesh.setPath(path); - Color.rgba8888ToColor(mesh.getColor(), color); - mesh.setBones(vertices.bones); - mesh.setVertices(vertices.vertices); - mesh.setWorldVerticesLength(vertexCount << 1); - mesh.setTriangles(triangles); - mesh.setRegionUVs(uvs); - mesh.updateUVs(); - mesh.setHullLength(hullLength << 1); - if (nonessential) { - mesh.setEdges(edges); - mesh.setWidth(width * scale); - mesh.setHeight(height * scale); - } - return mesh; - } - case linkedmesh: { - String path = input.readString(); - int color = input.readInt(); - String skinName = input.readString(); - String parent = input.readString(); - boolean inheritDeform = input.readBoolean(); - float width = 0, height = 0; - if (nonessential) { - width = input.readFloat(); - height = input.readFloat(); - } - - if (path == null) path = name; - MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path); - if (mesh == null) return null; - mesh.setPath(path); - Color.rgba8888ToColor(mesh.getColor(), color); - mesh.setInheritDeform(inheritDeform); - if (nonessential) { - mesh.setWidth(width * scale); - mesh.setHeight(height * scale); - } - linkedMeshes.add(new LinkedMesh(mesh, skinName, slotIndex, parent)); - return mesh; - } - case path: { - boolean closed = input.readBoolean(); - boolean constantSpeed = input.readBoolean(); - int vertexCount = input.readInt(true); - Vertices vertices = readVertices(input, vertexCount); - float[] lengths = new float[vertexCount / 3]; - for (int i = 0, n = lengths.length; i < n; i++) - lengths[i] = input.readFloat() * scale; - int color = nonessential ? input.readInt() : 0; - - PathAttachment path = attachmentLoader.newPathAttachment(skin, name); - if (path == null) return null; - path.setClosed(closed); - path.setConstantSpeed(constantSpeed); - path.setWorldVerticesLength(vertexCount << 1); - path.setVertices(vertices.vertices); - path.setBones(vertices.bones); - path.setLengths(lengths); - if (nonessential) Color.rgba8888ToColor(path.getColor(), color); - return path; - } - } - return null; - } - - private Vertices readVertices (DataInput input, int vertexCount) throws IOException { - int verticesLength = vertexCount << 1; - Vertices vertices = new Vertices(); - if (!input.readBoolean()) { - vertices.vertices = readFloatArray(input, verticesLength, scale); - return vertices; - } - FloatArray weights = new FloatArray(verticesLength * 3 * 3); - IntArray bonesArray = new IntArray(verticesLength * 3); - for (int i = 0; i < vertexCount; i++) { - int boneCount = input.readInt(true); - bonesArray.add(boneCount); - for (int ii = 0; ii < boneCount; ii++) { - bonesArray.add(input.readInt(true)); - weights.add(input.readFloat() * scale); - weights.add(input.readFloat() * scale); - weights.add(input.readFloat()); - } - } - vertices.vertices = weights.toArray(); - vertices.bones = bonesArray.toArray(); - return vertices; - } - - private float[] readFloatArray (DataInput input, int n, float scale) throws IOException { - float[] array = new float[n]; - if (scale == 1) { - for (int i = 0; i < n; i++) - array[i] = input.readFloat(); - } else { - for (int i = 0; i < n; i++) - array[i] = input.readFloat() * scale; - } - return array; - } - - private short[] readShortArray (DataInput input) throws IOException { - int n = input.readInt(true); - short[] array = new short[n]; - for (int i = 0; i < n; i++) - array[i] = input.readShort(); - return array; - } - - private void readAnimation (String name, DataInput input, SkeletonData skeletonData) { - Array timelines = new Array(); - float scale = this.scale; - float duration = 0; - - try { - // Slot timelines. - for (int i = 0, n = input.readInt(true); i < n; i++) { - int slotIndex = input.readInt(true); - for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) { - int timelineType = input.readByte(); - int frameCount = input.readInt(true); - switch (timelineType) { - case SLOT_COLOR: { - ColorTimeline timeline = new ColorTimeline(frameCount); - timeline.slotIndex = slotIndex; - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { - float time = input.readFloat(); - Color.rgba8888ToColor(tempColor, input.readInt()); - timeline.setFrame(frameIndex, time, tempColor.r, tempColor.g, tempColor.b, tempColor.a); - if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); - } - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * ColorTimeline.ENTRIES]); - break; - } - case SLOT_ATTACHMENT: - AttachmentTimeline timeline = new AttachmentTimeline(frameCount); - timeline.slotIndex = slotIndex; - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) - timeline.setFrame(frameIndex, input.readFloat(), input.readString()); - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[frameCount - 1]); - break; - } - } - } - - // Bone timelines. - for (int i = 0, n = input.readInt(true); i < n; i++) { - int boneIndex = input.readInt(true); - for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) { - int timelineType = input.readByte(); - int frameCount = input.readInt(true); - switch (timelineType) { - case BONE_ROTATE: { - RotateTimeline timeline = new RotateTimeline(frameCount); - timeline.boneIndex = boneIndex; - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { - timeline.setFrame(frameIndex, input.readFloat(), input.readFloat()); - if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); - } - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * RotateTimeline.ENTRIES]); - break; - } - case BONE_TRANSLATE: - case BONE_SCALE: - case BONE_SHEAR: { - TranslateTimeline timeline; - float timelineScale = 1; - if (timelineType == BONE_SCALE) - timeline = new ScaleTimeline(frameCount); - else if (timelineType == BONE_SHEAR) - timeline = new ShearTimeline(frameCount); - else { - timeline = new TranslateTimeline(frameCount); - timelineScale = scale; - } - timeline.boneIndex = boneIndex; - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { - timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale, - input.readFloat() * timelineScale); - if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); - } - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * TranslateTimeline.ENTRIES]); - break; - } - } - } - } - - // IK constraint timelines. - for (int i = 0, n = input.readInt(true); i < n; i++) { - int index = input.readInt(true); - int frameCount = input.readInt(true); - IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount); - timeline.ikConstraintIndex = index; - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { - timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readByte()); - if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); - } - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * IkConstraintTimeline.ENTRIES]); - } - - // Transform constraint timelines. - for (int i = 0, n = input.readInt(true); i < n; i++) { - int index = input.readInt(true); - int frameCount = input.readInt(true); - TransformConstraintTimeline timeline = new TransformConstraintTimeline(frameCount); - timeline.transformConstraintIndex = index; - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { - timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat(), - input.readFloat()); - if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); - } - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * TransformConstraintTimeline.ENTRIES]); - } - - // Path constraint timelines. - for (int i = 0, n = input.readInt(true); i < n; i++) { - int index = input.readInt(true); - PathConstraintData data = skeletonData.getPathConstraints().get(index); - for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) { - int timelineType = input.readByte(); - int frameCount = input.readInt(true); - switch (timelineType) { - case PATH_POSITION: - case PATH_SPACING: { - PathConstraintPositionTimeline timeline; - float timelineScale = 1; - if (timelineType == PATH_SPACING) { - timeline = new PathConstraintSpacingTimeline(frameCount); - if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) timelineScale = scale; - } else { - timeline = new PathConstraintPositionTimeline(frameCount); - if (data.positionMode == PositionMode.fixed) timelineScale = scale; - } - timeline.pathConstraintIndex = index; - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { - timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale); - if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); - } - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * PathConstraintPositionTimeline.ENTRIES]); - break; - } - case PATH_MIX: { - PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(frameCount); - timeline.pathConstraintIndex = index; - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { - timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat()); - if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); - } - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * PathConstraintMixTimeline.ENTRIES]); - break; - } - } - } - } - - // Deform timelines. - for (int i = 0, n = input.readInt(true); i < n; i++) { - Skin skin = skeletonData.skins.get(input.readInt(true)); - for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) { - int slotIndex = input.readInt(true); - for (int iii = 0, nnn = input.readInt(true); iii < nnn; iii++) { - VertexAttachment attachment = (VertexAttachment)skin.getAttachment(slotIndex, input.readString()); - boolean weighted = attachment.getBones() != null; - float[] vertices = attachment.getVertices(); - int deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; - - int frameCount = input.readInt(true); - DeformTimeline timeline = new DeformTimeline(frameCount); - timeline.slotIndex = slotIndex; - timeline.attachment = attachment; - - for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { - float time = input.readFloat(); - float[] deform; - int end = input.readInt(true); - if (end == 0) - deform = weighted ? new float[deformLength] : vertices; - else { - deform = new float[deformLength]; - int start = input.readInt(true); - end += start; - if (scale == 1) { - for (int v = start; v < end; v++) - deform[v] = input.readFloat(); - } else { - for (int v = start; v < end; v++) - deform[v] = input.readFloat() * scale; - } - if (!weighted) { - for (int v = 0, vn = deform.length; v < vn; v++) - deform[v] += vertices[v]; - } - } - - timeline.setFrame(frameIndex, time, deform); - if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); - } - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[frameCount - 1]); - } - } - } - - // Draw order timeline. - int drawOrderCount = input.readInt(true); - if (drawOrderCount > 0) { - DrawOrderTimeline timeline = new DrawOrderTimeline(drawOrderCount); - int slotCount = skeletonData.slots.size; - for (int i = 0; i < drawOrderCount; i++) { - float time = input.readFloat(); - int offsetCount = input.readInt(true); - int[] drawOrder = new int[slotCount]; - for (int ii = slotCount - 1; ii >= 0; ii--) - drawOrder[ii] = -1; - int[] unchanged = new int[slotCount - offsetCount]; - int originalIndex = 0, unchangedIndex = 0; - for (int ii = 0; ii < offsetCount; ii++) { - int slotIndex = input.readInt(true); - // Collect unchanged items. - while (originalIndex != slotIndex) - unchanged[unchangedIndex++] = originalIndex++; - // Set changed items. - drawOrder[originalIndex + input.readInt(true)] = originalIndex++; - } - // Collect remaining unchanged items. - while (originalIndex < slotCount) - unchanged[unchangedIndex++] = originalIndex++; - // Fill in unchanged items. - for (int ii = slotCount - 1; ii >= 0; ii--) - if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex]; - timeline.setFrame(i, time, drawOrder); - } - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[drawOrderCount - 1]); - } - - // Event timeline. - int eventCount = input.readInt(true); - if (eventCount > 0) { - EventTimeline timeline = new EventTimeline(eventCount); - for (int i = 0; i < eventCount; i++) { - float time = input.readFloat(); - EventData eventData = skeletonData.events.get(input.readInt(true)); - Event event = new Event(time, eventData); - event.intValue = input.readInt(false); - event.floatValue = input.readFloat(); - event.stringValue = input.readBoolean() ? input.readString() : eventData.stringValue; - timeline.setFrame(i, event); - } - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[eventCount - 1]); - } - } catch (IOException ex) { - throw new SerializationException("Error reading skeleton file.", ex); - } - - timelines.shrink(); - skeletonData.animations.add(new Animation(name, timelines, duration)); - - } - - private void readCurve (DataInput input, int frameIndex, CurveTimeline timeline) throws IOException { - switch (input.readByte()) { - case CURVE_STEPPED: - timeline.setStepped(frameIndex); - break; - case CURVE_BEZIER: - setCurve(timeline, frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat()); - break; - } - } - - void setCurve (CurveTimeline timeline, int frameIndex, float cx1, float cy1, float cx2, float cy2) { - timeline.setCurve(frameIndex, cx1, cy1, cx2, cy2); - } - - static class Vertices { - int[] bones; - float[] vertices; - } +package com.esotericsoftware.spine; + +import java.io.EOFException; +import java.io.IOException; + +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.DataInput; +import com.badlogic.gdx.utils.FloatArray; +import com.badlogic.gdx.utils.IntArray; +import com.badlogic.gdx.utils.SerializationException; +import com.esotericsoftware.spine.Animation.AttachmentTimeline; +import com.esotericsoftware.spine.Animation.ColorTimeline; +import com.esotericsoftware.spine.Animation.CurveTimeline; +import com.esotericsoftware.spine.Animation.DeformTimeline; +import com.esotericsoftware.spine.Animation.DrawOrderTimeline; +import com.esotericsoftware.spine.Animation.EventTimeline; +import com.esotericsoftware.spine.Animation.IkConstraintTimeline; +import com.esotericsoftware.spine.Animation.PathConstraintMixTimeline; +import com.esotericsoftware.spine.Animation.PathConstraintPositionTimeline; +import com.esotericsoftware.spine.Animation.PathConstraintSpacingTimeline; +import com.esotericsoftware.spine.Animation.RotateTimeline; +import com.esotericsoftware.spine.Animation.ScaleTimeline; +import com.esotericsoftware.spine.Animation.ShearTimeline; +import com.esotericsoftware.spine.Animation.Timeline; +import com.esotericsoftware.spine.Animation.TransformConstraintTimeline; +import com.esotericsoftware.spine.Animation.TranslateTimeline; +import com.esotericsoftware.spine.PathConstraintData.PositionMode; +import com.esotericsoftware.spine.PathConstraintData.RotateMode; +import com.esotericsoftware.spine.PathConstraintData.SpacingMode; +import com.esotericsoftware.spine.SkeletonJson.LinkedMesh; +import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader; +import com.esotericsoftware.spine.attachments.Attachment; +import com.esotericsoftware.spine.attachments.AttachmentLoader; +import com.esotericsoftware.spine.attachments.AttachmentType; +import com.esotericsoftware.spine.attachments.BoundingBoxAttachment; +import com.esotericsoftware.spine.attachments.MeshAttachment; +import com.esotericsoftware.spine.attachments.PathAttachment; +import com.esotericsoftware.spine.attachments.RegionAttachment; +import com.esotericsoftware.spine.attachments.VertexAttachment; + +public class SkeletonBinary { + static public final int BONE_ROTATE = 0; + static public final int BONE_TRANSLATE = 1; + static public final int BONE_SCALE = 2; + static public final int BONE_SHEAR = 3; + + static public final int SLOT_ATTACHMENT = 0; + static public final int SLOT_COLOR = 1; + + static public final int PATH_POSITION = 0; + static public final int PATH_SPACING = 1; + static public final int PATH_MIX = 2; + + static public final int CURVE_LINEAR = 0; + static public final int CURVE_STEPPED = 1; + static public final int CURVE_BEZIER = 2; + + static private final Color tempColor = new Color(); + + private final AttachmentLoader attachmentLoader; + private float scale = 1; + private Array linkedMeshes = new Array(); + + public SkeletonBinary (TextureAtlas atlas) { + attachmentLoader = new AtlasAttachmentLoader(atlas); + } + + public SkeletonBinary (AttachmentLoader attachmentLoader) { + if (attachmentLoader == null) throw new IllegalArgumentException("attachmentLoader cannot be null."); + this.attachmentLoader = attachmentLoader; + } + + public float getScale () { + return scale; + } + + /** Scales the bones, images, and animations as they are loaded. */ + public void setScale (float scale) { + this.scale = scale; + } + + public SkeletonData readSkeletonData (FileHandle file) { + if (file == null) throw new IllegalArgumentException("file cannot be null."); + + float scale = this.scale; + + SkeletonData skeletonData = new SkeletonData(); + skeletonData.name = file.nameWithoutExtension(); + + DataInput input = new DataInput(file.read(512)) { + private char[] chars = new char[32]; + + public String readString () throws IOException { + int byteCount = readInt(true); + switch (byteCount) { + case 0: + return null; + case 1: + return ""; + } + byteCount--; + if (chars.length < byteCount) chars = new char[byteCount]; + char[] chars = this.chars; + int charCount = 0; + for (int i = 0; i < byteCount;) { + int b = read(); + switch (b >> 4) { + case -1: + throw new EOFException(); + case 12: + case 13: + chars[charCount++] = (char)((b & 0x1F) << 6 | read() & 0x3F); + i += 2; + break; + case 14: + chars[charCount++] = (char)((b & 0x0F) << 12 | (read() & 0x3F) << 6 | read() & 0x3F); + i += 3; + break; + default: + chars[charCount++] = (char)b; + i++; + } + } + return new String(chars, 0, charCount); + } + }; + try { + skeletonData.hash = input.readString(); + if (skeletonData.hash.isEmpty()) skeletonData.hash = null; + skeletonData.version = input.readString(); + if (skeletonData.version.isEmpty()) skeletonData.version = null; + skeletonData.width = input.readFloat(); + skeletonData.height = input.readFloat(); + + boolean nonessential = input.readBoolean(); + + if (nonessential) { + skeletonData.imagesPath = input.readString(); + if (skeletonData.imagesPath.isEmpty()) skeletonData.imagesPath = null; + } + + // Bones. + for (int i = 0, n = input.readInt(true); i < n; i++) { + String name = input.readString(); + BoneData parent = i == 0 ? null : skeletonData.bones.get(input.readInt(true)); + BoneData data = new BoneData(i, name, parent); + data.rotation = input.readFloat(); + data.x = input.readFloat() * scale; + data.y = input.readFloat() * scale; + data.scaleX = input.readFloat(); + data.scaleY = input.readFloat(); + data.shearX = input.readFloat(); + data.shearY = input.readFloat(); + data.length = input.readFloat() * scale; + data.inheritRotation = input.readBoolean(); + data.inheritScale = input.readBoolean(); + if (nonessential) Color.rgba8888ToColor(data.color, input.readInt()); + skeletonData.bones.add(data); + } + + // Slots. + for (int i = 0, n = input.readInt(true); i < n; i++) { + String slotName = input.readString(); + BoneData boneData = skeletonData.bones.get(input.readInt(true)); + SlotData data = new SlotData(i, slotName, boneData); + Color.rgba8888ToColor(data.color, input.readInt()); + data.attachmentName = input.readString(); + data.blendMode = BlendMode.values[input.readInt(true)]; + skeletonData.slots.add(data); + } + + // IK constraints. + for (int i = 0, n = input.readInt(true); i < n; i++) { + IkConstraintData data = new IkConstraintData(input.readString()); + for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) + data.bones.add(skeletonData.bones.get(input.readInt(true))); + data.target = skeletonData.bones.get(input.readInt(true)); + data.mix = input.readFloat(); + data.bendDirection = input.readByte(); + skeletonData.ikConstraints.add(data); + } + + // Transform constraints. + for (int i = 0, n = input.readInt(true); i < n; i++) { + TransformConstraintData data = new TransformConstraintData(input.readString()); + for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) + data.bones.add(skeletonData.bones.get(input.readInt(true))); + data.target = skeletonData.bones.get(input.readInt(true)); + data.offsetRotation = input.readFloat(); + data.offsetX = input.readFloat() * scale; + data.offsetY = input.readFloat() * scale; + data.offsetScaleX = input.readFloat(); + data.offsetScaleY = input.readFloat(); + data.offsetShearY = input.readFloat(); + data.rotateMix = input.readFloat(); + data.translateMix = input.readFloat(); + data.scaleMix = input.readFloat(); + data.shearMix = input.readFloat(); + skeletonData.transformConstraints.add(data); + } + + // Path constraints. + for (int i = 0, n = input.readInt(true); i < n; i++) { + PathConstraintData data = new PathConstraintData(input.readString()); + for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) + data.bones.add(skeletonData.bones.get(input.readInt(true))); + data.target = skeletonData.slots.get(input.readInt(true)); + data.positionMode = PositionMode.values[input.readInt(true)]; + data.spacingMode = SpacingMode.values[input.readInt(true)]; + data.rotateMode = RotateMode.values[input.readInt(true)]; + data.offsetRotation = input.readFloat(); + data.position = input.readFloat(); + if (data.positionMode == PositionMode.fixed) data.position *= scale; + data.spacing = input.readFloat(); + if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) data.spacing *= scale; + data.rotateMix = input.readFloat(); + data.translateMix = input.readFloat(); + skeletonData.pathConstraints.add(data); + } + + // Default skin. + Skin defaultSkin = readSkin(input, "default", nonessential); + if (defaultSkin != null) { + skeletonData.defaultSkin = defaultSkin; + skeletonData.skins.add(defaultSkin); + } + + // Skins. + for (int i = 0, n = input.readInt(true); i < n; i++) + skeletonData.skins.add(readSkin(input, input.readString(), nonessential)); + + // Linked meshes. + for (int i = 0, n = linkedMeshes.size; i < n; i++) { + LinkedMesh linkedMesh = linkedMeshes.get(i); + Skin skin = linkedMesh.skin == null ? skeletonData.getDefaultSkin() : skeletonData.findSkin(linkedMesh.skin); + if (skin == null) throw new SerializationException("Skin not found: " + linkedMesh.skin); + Attachment parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); + if (parent == null) throw new SerializationException("Parent mesh not found: " + linkedMesh.parent); + linkedMesh.mesh.setParentMesh((MeshAttachment)parent); + linkedMesh.mesh.updateUVs(); + } + linkedMeshes.clear(); + + // Events. + for (int i = 0, n = input.readInt(true); i < n; i++) { + EventData data = new EventData(input.readString()); + data.intValue = input.readInt(false); + data.floatValue = input.readFloat(); + data.stringValue = input.readString(); + skeletonData.events.add(data); + } + + // Animations. + for (int i = 0, n = input.readInt(true); i < n; i++) + readAnimation(input.readString(), input, skeletonData); + + } catch (IOException ex) { + throw new SerializationException("Error reading skeleton file.", ex); + } finally { + try { + input.close(); + } catch (IOException ignored) { + } + } + + skeletonData.bones.shrink(); + skeletonData.slots.shrink(); + skeletonData.skins.shrink(); + skeletonData.events.shrink(); + skeletonData.animations.shrink(); + skeletonData.ikConstraints.shrink(); + return skeletonData; + } + + /** @return May be null. */ + private Skin readSkin (DataInput input, String skinName, boolean nonessential) throws IOException { + int slotCount = input.readInt(true); + if (slotCount == 0) return null; + Skin skin = new Skin(skinName); + for (int i = 0; i < slotCount; i++) { + int slotIndex = input.readInt(true); + for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) { + String name = input.readString(); + skin.addAttachment(slotIndex, name, readAttachment(input, skin, slotIndex, name, nonessential)); + } + } + return skin; + } + + private Attachment readAttachment (DataInput input, Skin skin, int slotIndex, String attachmentName, boolean nonessential) + throws IOException { + float scale = this.scale; + + String name = input.readString(); + if (name == null) name = attachmentName; + + AttachmentType type = AttachmentType.values[input.readByte()]; + switch (type) { + case region: { + String path = input.readString(); + float rotation = input.readFloat(); + float x = input.readFloat(); + float y = input.readFloat(); + float scaleX = input.readFloat(); + float scaleY = input.readFloat(); + float width = input.readFloat(); + float height = input.readFloat(); + int color = input.readInt(); + + if (path == null) path = name; + RegionAttachment region = attachmentLoader.newRegionAttachment(skin, name, path); + if (region == null) return null; + region.setPath(path); + region.setX(x * scale); + region.setY(y * scale); + region.setScaleX(scaleX); + region.setScaleY(scaleY); + region.setRotation(rotation); + region.setWidth(width * scale); + region.setHeight(height * scale); + Color.rgba8888ToColor(region.getColor(), color); + region.updateOffset(); + return region; + } + case boundingbox: { + int vertexCount = input.readInt(true); + Vertices vertices = readVertices(input, vertexCount); + int color = nonessential ? input.readInt() : 0; + + BoundingBoxAttachment box = attachmentLoader.newBoundingBoxAttachment(skin, name); + if (box == null) return null; + box.setWorldVerticesLength(vertexCount << 1); + box.setVertices(vertices.vertices); + box.setBones(vertices.bones); + if (nonessential) Color.rgba8888ToColor(box.getColor(), color); + return box; + } + case mesh: { + String path = input.readString(); + int color = input.readInt(); + int vertexCount = input.readInt(true); + float[] uvs = readFloatArray(input, vertexCount << 1, 1); + short[] triangles = readShortArray(input); + Vertices vertices = readVertices(input, vertexCount); + int hullLength = input.readInt(true); + short[] edges = null; + float width = 0, height = 0; + if (nonessential) { + edges = readShortArray(input); + width = input.readFloat(); + height = input.readFloat(); + } + + if (path == null) path = name; + MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path); + if (mesh == null) return null; + mesh.setPath(path); + Color.rgba8888ToColor(mesh.getColor(), color); + mesh.setBones(vertices.bones); + mesh.setVertices(vertices.vertices); + mesh.setWorldVerticesLength(vertexCount << 1); + mesh.setTriangles(triangles); + mesh.setRegionUVs(uvs); + mesh.updateUVs(); + mesh.setHullLength(hullLength << 1); + if (nonessential) { + mesh.setEdges(edges); + mesh.setWidth(width * scale); + mesh.setHeight(height * scale); + } + return mesh; + } + case linkedmesh: { + String path = input.readString(); + int color = input.readInt(); + String skinName = input.readString(); + String parent = input.readString(); + boolean inheritDeform = input.readBoolean(); + float width = 0, height = 0; + if (nonessential) { + width = input.readFloat(); + height = input.readFloat(); + } + + if (path == null) path = name; + MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path); + if (mesh == null) return null; + mesh.setPath(path); + Color.rgba8888ToColor(mesh.getColor(), color); + mesh.setInheritDeform(inheritDeform); + if (nonessential) { + mesh.setWidth(width * scale); + mesh.setHeight(height * scale); + } + linkedMeshes.add(new LinkedMesh(mesh, skinName, slotIndex, parent)); + return mesh; + } + case path: { + boolean closed = input.readBoolean(); + boolean constantSpeed = input.readBoolean(); + int vertexCount = input.readInt(true); + Vertices vertices = readVertices(input, vertexCount); + float[] lengths = new float[vertexCount / 3]; + for (int i = 0, n = lengths.length; i < n; i++) + lengths[i] = input.readFloat() * scale; + int color = nonessential ? input.readInt() : 0; + + PathAttachment path = attachmentLoader.newPathAttachment(skin, name); + if (path == null) return null; + path.setClosed(closed); + path.setConstantSpeed(constantSpeed); + path.setWorldVerticesLength(vertexCount << 1); + path.setVertices(vertices.vertices); + path.setBones(vertices.bones); + path.setLengths(lengths); + if (nonessential) Color.rgba8888ToColor(path.getColor(), color); + return path; + } + } + return null; + } + + private Vertices readVertices (DataInput input, int vertexCount) throws IOException { + int verticesLength = vertexCount << 1; + Vertices vertices = new Vertices(); + if (!input.readBoolean()) { + vertices.vertices = readFloatArray(input, verticesLength, scale); + return vertices; + } + FloatArray weights = new FloatArray(verticesLength * 3 * 3); + IntArray bonesArray = new IntArray(verticesLength * 3); + for (int i = 0; i < vertexCount; i++) { + int boneCount = input.readInt(true); + bonesArray.add(boneCount); + for (int ii = 0; ii < boneCount; ii++) { + bonesArray.add(input.readInt(true)); + weights.add(input.readFloat() * scale); + weights.add(input.readFloat() * scale); + weights.add(input.readFloat()); + } + } + vertices.vertices = weights.toArray(); + vertices.bones = bonesArray.toArray(); + return vertices; + } + + private float[] readFloatArray (DataInput input, int n, float scale) throws IOException { + float[] array = new float[n]; + if (scale == 1) { + for (int i = 0; i < n; i++) + array[i] = input.readFloat(); + } else { + for (int i = 0; i < n; i++) + array[i] = input.readFloat() * scale; + } + return array; + } + + private short[] readShortArray (DataInput input) throws IOException { + int n = input.readInt(true); + short[] array = new short[n]; + for (int i = 0; i < n; i++) + array[i] = input.readShort(); + return array; + } + + private void readAnimation (String name, DataInput input, SkeletonData skeletonData) { + Array timelines = new Array(); + float scale = this.scale; + float duration = 0; + + try { + // Slot timelines. + for (int i = 0, n = input.readInt(true); i < n; i++) { + int slotIndex = input.readInt(true); + for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) { + int timelineType = input.readByte(); + int frameCount = input.readInt(true); + switch (timelineType) { + case SLOT_COLOR: { + ColorTimeline timeline = new ColorTimeline(frameCount); + timeline.slotIndex = slotIndex; + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { + float time = input.readFloat(); + Color.rgba8888ToColor(tempColor, input.readInt()); + timeline.setFrame(frameIndex, time, tempColor.r, tempColor.g, tempColor.b, tempColor.a); + if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * ColorTimeline.ENTRIES]); + break; + } + case SLOT_ATTACHMENT: + AttachmentTimeline timeline = new AttachmentTimeline(frameCount); + timeline.slotIndex = slotIndex; + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) + timeline.setFrame(frameIndex, input.readFloat(), input.readString()); + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[frameCount - 1]); + break; + } + } + } + + // Bone timelines. + for (int i = 0, n = input.readInt(true); i < n; i++) { + int boneIndex = input.readInt(true); + for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) { + int timelineType = input.readByte(); + int frameCount = input.readInt(true); + switch (timelineType) { + case BONE_ROTATE: { + RotateTimeline timeline = new RotateTimeline(frameCount); + timeline.boneIndex = boneIndex; + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat()); + if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * RotateTimeline.ENTRIES]); + break; + } + case BONE_TRANSLATE: + case BONE_SCALE: + case BONE_SHEAR: { + TranslateTimeline timeline; + float timelineScale = 1; + if (timelineType == BONE_SCALE) + timeline = new ScaleTimeline(frameCount); + else if (timelineType == BONE_SHEAR) + timeline = new ShearTimeline(frameCount); + else { + timeline = new TranslateTimeline(frameCount); + timelineScale = scale; + } + timeline.boneIndex = boneIndex; + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale, + input.readFloat() * timelineScale); + if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * TranslateTimeline.ENTRIES]); + break; + } + } + } + } + + // IK constraint timelines. + for (int i = 0, n = input.readInt(true); i < n; i++) { + int index = input.readInt(true); + int frameCount = input.readInt(true); + IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount); + timeline.ikConstraintIndex = index; + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readByte()); + if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * IkConstraintTimeline.ENTRIES]); + } + + // Transform constraint timelines. + for (int i = 0, n = input.readInt(true); i < n; i++) { + int index = input.readInt(true); + int frameCount = input.readInt(true); + TransformConstraintTimeline timeline = new TransformConstraintTimeline(frameCount); + timeline.transformConstraintIndex = index; + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat(), + input.readFloat()); + if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * TransformConstraintTimeline.ENTRIES]); + } + + // Path constraint timelines. + for (int i = 0, n = input.readInt(true); i < n; i++) { + int index = input.readInt(true); + PathConstraintData data = skeletonData.getPathConstraints().get(index); + for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) { + int timelineType = input.readByte(); + int frameCount = input.readInt(true); + switch (timelineType) { + case PATH_POSITION: + case PATH_SPACING: { + PathConstraintPositionTimeline timeline; + float timelineScale = 1; + if (timelineType == PATH_SPACING) { + timeline = new PathConstraintSpacingTimeline(frameCount); + if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) timelineScale = scale; + } else { + timeline = new PathConstraintPositionTimeline(frameCount); + if (data.positionMode == PositionMode.fixed) timelineScale = scale; + } + timeline.pathConstraintIndex = index; + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale); + if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * PathConstraintPositionTimeline.ENTRIES]); + break; + } + case PATH_MIX: { + PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(frameCount); + timeline.pathConstraintIndex = index; + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat()); + if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[(frameCount - 1) * PathConstraintMixTimeline.ENTRIES]); + break; + } + } + } + } + + // Deform timelines. + for (int i = 0, n = input.readInt(true); i < n; i++) { + Skin skin = skeletonData.skins.get(input.readInt(true)); + for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) { + int slotIndex = input.readInt(true); + for (int iii = 0, nnn = input.readInt(true); iii < nnn; iii++) { + VertexAttachment attachment = (VertexAttachment)skin.getAttachment(slotIndex, input.readString()); + boolean weighted = attachment.getBones() != null; + float[] vertices = attachment.getVertices(); + int deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; + + int frameCount = input.readInt(true); + DeformTimeline timeline = new DeformTimeline(frameCount); + timeline.slotIndex = slotIndex; + timeline.attachment = attachment; + + for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { + float time = input.readFloat(); + float[] deform; + int end = input.readInt(true); + if (end == 0) + deform = weighted ? new float[deformLength] : vertices; + else { + deform = new float[deformLength]; + int start = input.readInt(true); + end += start; + if (scale == 1) { + for (int v = start; v < end; v++) + deform[v] = input.readFloat(); + } else { + for (int v = start; v < end; v++) + deform[v] = input.readFloat() * scale; + } + if (!weighted) { + for (int v = 0, vn = deform.length; v < vn; v++) + deform[v] += vertices[v]; + } + } + + timeline.setFrame(frameIndex, time, deform); + if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[frameCount - 1]); + } + } + } + + // Draw order timeline. + int drawOrderCount = input.readInt(true); + if (drawOrderCount > 0) { + DrawOrderTimeline timeline = new DrawOrderTimeline(drawOrderCount); + int slotCount = skeletonData.slots.size; + for (int i = 0; i < drawOrderCount; i++) { + float time = input.readFloat(); + int offsetCount = input.readInt(true); + int[] drawOrder = new int[slotCount]; + for (int ii = slotCount - 1; ii >= 0; ii--) + drawOrder[ii] = -1; + int[] unchanged = new int[slotCount - offsetCount]; + int originalIndex = 0, unchangedIndex = 0; + for (int ii = 0; ii < offsetCount; ii++) { + int slotIndex = input.readInt(true); + // Collect unchanged items. + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + // Set changed items. + drawOrder[originalIndex + input.readInt(true)] = originalIndex++; + } + // Collect remaining unchanged items. + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + // Fill in unchanged items. + for (int ii = slotCount - 1; ii >= 0; ii--) + if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex]; + timeline.setFrame(i, time, drawOrder); + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[drawOrderCount - 1]); + } + + // Event timeline. + int eventCount = input.readInt(true); + if (eventCount > 0) { + EventTimeline timeline = new EventTimeline(eventCount); + for (int i = 0; i < eventCount; i++) { + float time = input.readFloat(); + EventData eventData = skeletonData.events.get(input.readInt(true)); + Event event = new Event(time, eventData); + event.intValue = input.readInt(false); + event.floatValue = input.readFloat(); + event.stringValue = input.readBoolean() ? input.readString() : eventData.stringValue; + timeline.setFrame(i, event); + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[eventCount - 1]); + } + } catch (IOException ex) { + throw new SerializationException("Error reading skeleton file.", ex); + } + + timelines.shrink(); + skeletonData.animations.add(new Animation(name, timelines, duration)); + + } + + private void readCurve (DataInput input, int frameIndex, CurveTimeline timeline) throws IOException { + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frameIndex); + break; + case CURVE_BEZIER: + setCurve(timeline, frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat()); + break; + } + } + + void setCurve (CurveTimeline timeline, int frameIndex, float cx1, float cy1, float cx2, float cy2) { + timeline.setCurve(frameIndex, cx1, cy1, cx2, cy2); + } + + static class Vertices { + int[] bones; + float[] vertices; + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBounds.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBounds.java index 7ff9d0f865..8ebaf50443 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBounds.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBounds.java @@ -1,229 +1,228 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.esotericsoftware.spine.attachments.Attachment; -import com.esotericsoftware.spine.attachments.BoundingBoxAttachment; - -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.FloatArray; -import com.badlogic.gdx.utils.Pool; - -public class SkeletonBounds { - private float minX, minY, maxX, maxY; - private Array boundingBoxes = new Array(); - private Array polygons = new Array(); - private Pool polygonPool = new Pool() { - protected Object newObject () { - return new FloatArray(); - } - }; - - public void update (Skeleton skeleton, boolean updateAabb) { - if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); - Array boundingBoxes = this.boundingBoxes; - Array polygons = this.polygons; - Array slots = skeleton.slots; - int slotCount = slots.size; - - boundingBoxes.clear(); - polygonPool.freeAll(polygons); - polygons.clear(); - - for (int i = 0; i < slotCount; i++) { - Slot slot = slots.get(i); - Attachment attachment = slot.attachment; - if (attachment instanceof BoundingBoxAttachment) { - BoundingBoxAttachment boundingBox = (BoundingBoxAttachment)attachment; - boundingBoxes.add(boundingBox); - - FloatArray polygon = polygonPool.obtain(); - polygons.add(polygon); - boundingBox.computeWorldVertices(slot, polygon.setSize(boundingBox.getWorldVerticesLength())); - } - } - - if (updateAabb) aabbCompute(); - } - - private void aabbCompute () { - float minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE; - Array polygons = this.polygons; - for (int i = 0, n = polygons.size; i < n; i++) { - FloatArray polygon = polygons.get(i); - float[] vertices = polygon.items; - for (int ii = 0, nn = polygon.size; ii < nn; ii += 2) { - float x = vertices[ii]; - float y = vertices[ii + 1]; - minX = Math.min(minX, x); - minY = Math.min(minY, y); - maxX = Math.max(maxX, x); - maxY = Math.max(maxY, y); - } - } - this.minX = minX; - this.minY = minY; - this.maxX = maxX; - this.maxY = maxY; - } - - /** Returns true if the axis aligned bounding box contains the point. */ - public boolean aabbContainsPoint (float x, float y) { - return x >= minX && x <= maxX && y >= minY && y <= maxY; - } - - /** Returns true if the axis aligned bounding box intersects the line segment. */ - public boolean aabbIntersectsSegment (float x1, float y1, float x2, float y2) { - float minX = this.minX; - float minY = this.minY; - float maxX = this.maxX; - float maxY = this.maxY; - if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) - return false; - float m = (y2 - y1) / (x2 - x1); - float y = m * (minX - x1) + y1; - if (y > minY && y < maxY) return true; - y = m * (maxX - x1) + y1; - if (y > minY && y < maxY) return true; - float x = (minY - y1) / m + x1; - if (x > minX && x < maxX) return true; - x = (maxY - y1) / m + x1; - if (x > minX && x < maxX) return true; - return false; - } - - /** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */ - public boolean aabbIntersectsSkeleton (SkeletonBounds bounds) { - return minX < bounds.maxX && maxX > bounds.minX && minY < bounds.maxY && maxY > bounds.minY; - } - - /** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more - * efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. */ - public BoundingBoxAttachment containsPoint (float x, float y) { - Array polygons = this.polygons; - for (int i = 0, n = polygons.size; i < n; i++) - if (containsPoint(polygons.get(i), x, y)) return boundingBoxes.get(i); - return null; - } - - /** Returns true if the polygon contains the point. */ - public boolean containsPoint (FloatArray polygon, float x, float y) { - float[] vertices = polygon.items; - int nn = polygon.size; - - int prevIndex = nn - 2; - boolean inside = false; - for (int ii = 0; ii < nn; ii += 2) { - float vertexY = vertices[ii + 1]; - float prevY = vertices[prevIndex + 1]; - if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { - float vertexX = vertices[ii]; - if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside; - } - prevIndex = ii; - } - return inside; - } - - /** Returns the first bounding box attachment that contains any part of the line segment, or null. When doing many checks, it - * is usually more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns - * true. */ - public BoundingBoxAttachment intersectsSegment (float x1, float y1, float x2, float y2) { - Array polygons = this.polygons; - for (int i = 0, n = polygons.size; i < n; i++) - if (intersectsSegment(polygons.get(i), x1, y1, x2, y2)) return boundingBoxes.get(i); - return null; - } - - /** Returns true if the polygon contains any part of the line segment. */ - public boolean intersectsSegment (FloatArray polygon, float x1, float y1, float x2, float y2) { - float[] vertices = polygon.items; - int nn = polygon.size; - - float width12 = x1 - x2, height12 = y1 - y2; - float det1 = x1 * y2 - y1 * x2; - float x3 = vertices[nn - 2], y3 = vertices[nn - 1]; - for (int ii = 0; ii < nn; ii += 2) { - float x4 = vertices[ii], y4 = vertices[ii + 1]; - float det2 = x3 * y4 - y3 * x4; - float width34 = x3 - x4, height34 = y3 - y4; - float det3 = width12 * height34 - height12 * width34; - float x = (det1 * width34 - width12 * det2) / det3; - if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { - float y = (det1 * height34 - height12 * det2) / det3; - if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; - } - x3 = x4; - y3 = y4; - } - return false; - } - - public float getMinX () { - return minX; - } - - public float getMinY () { - return minY; - } - - public float getMaxX () { - return maxX; - } - - public float getMaxY () { - return maxY; - } - - public float getWidth () { - return maxX - minX; - } - - public float getHeight () { - return maxY - minY; - } - - public Array getBoundingBoxes () { - return boundingBoxes; - } - - public Array getPolygons () { - return polygons; - } - - /** Returns the polygon for the specified bounding box, or null. */ - public FloatArray getPolygon (BoundingBoxAttachment boundingBox) { - if (boundingBox == null) throw new IllegalArgumentException("boundingBox cannot be null."); - int index = boundingBoxes.indexOf(boundingBox, true); - return index == -1 ? null : polygons.get(index); - } +package com.esotericsoftware.spine; + +import com.esotericsoftware.spine.attachments.Attachment; +import com.esotericsoftware.spine.attachments.BoundingBoxAttachment; + +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.FloatArray; +import com.badlogic.gdx.utils.Pool; + +public class SkeletonBounds { + private float minX, minY, maxX, maxY; + private Array boundingBoxes = new Array(); + private Array polygons = new Array(); + private Pool polygonPool = new Pool() { + protected Object newObject () { + return new FloatArray(); + } + }; + + public void update (Skeleton skeleton, boolean updateAabb) { + if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); + Array boundingBoxes = this.boundingBoxes; + Array polygons = this.polygons; + Array slots = skeleton.slots; + int slotCount = slots.size; + + boundingBoxes.clear(); + polygonPool.freeAll(polygons); + polygons.clear(); + + for (int i = 0; i < slotCount; i++) { + Slot slot = slots.get(i); + Attachment attachment = slot.attachment; + if (attachment instanceof BoundingBoxAttachment) { + BoundingBoxAttachment boundingBox = (BoundingBoxAttachment)attachment; + boundingBoxes.add(boundingBox); + + FloatArray polygon = polygonPool.obtain(); + polygons.add(polygon); + boundingBox.computeWorldVertices(slot, polygon.setSize(boundingBox.getWorldVerticesLength())); + } + } + + if (updateAabb) aabbCompute(); + } + + private void aabbCompute () { + float minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE; + Array polygons = this.polygons; + for (int i = 0, n = polygons.size; i < n; i++) { + FloatArray polygon = polygons.get(i); + float[] vertices = polygon.items; + for (int ii = 0, nn = polygon.size; ii < nn; ii += 2) { + float x = vertices[ii]; + float y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } + + /** Returns true if the axis aligned bounding box contains the point. */ + public boolean aabbContainsPoint (float x, float y) { + return x >= minX && x <= maxX && y >= minY && y <= maxY; + } + + /** Returns true if the axis aligned bounding box intersects the line segment. */ + public boolean aabbIntersectsSegment (float x1, float y1, float x2, float y2) { + float minX = this.minX; + float minY = this.minY; + float maxX = this.maxX; + float maxY = this.maxY; + if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) + return false; + float m = (y2 - y1) / (x2 - x1); + float y = m * (minX - x1) + y1; + if (y > minY && y < maxY) return true; + y = m * (maxX - x1) + y1; + if (y > minY && y < maxY) return true; + float x = (minY - y1) / m + x1; + if (x > minX && x < maxX) return true; + x = (maxY - y1) / m + x1; + if (x > minX && x < maxX) return true; + return false; + } + + /** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */ + public boolean aabbIntersectsSkeleton (SkeletonBounds bounds) { + return minX < bounds.maxX && maxX > bounds.minX && minY < bounds.maxY && maxY > bounds.minY; + } + + /** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more + * efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. */ + public BoundingBoxAttachment containsPoint (float x, float y) { + Array polygons = this.polygons; + for (int i = 0, n = polygons.size; i < n; i++) + if (containsPoint(polygons.get(i), x, y)) return boundingBoxes.get(i); + return null; + } + + /** Returns true if the polygon contains the point. */ + public boolean containsPoint (FloatArray polygon, float x, float y) { + float[] vertices = polygon.items; + int nn = polygon.size; + + int prevIndex = nn - 2; + boolean inside = false; + for (int ii = 0; ii < nn; ii += 2) { + float vertexY = vertices[ii + 1]; + float prevY = vertices[prevIndex + 1]; + if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { + float vertexX = vertices[ii]; + if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside; + } + prevIndex = ii; + } + return inside; + } + + /** Returns the first bounding box attachment that contains any part of the line segment, or null. When doing many checks, it + * is usually more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns + * true. */ + public BoundingBoxAttachment intersectsSegment (float x1, float y1, float x2, float y2) { + Array polygons = this.polygons; + for (int i = 0, n = polygons.size; i < n; i++) + if (intersectsSegment(polygons.get(i), x1, y1, x2, y2)) return boundingBoxes.get(i); + return null; + } + + /** Returns true if the polygon contains any part of the line segment. */ + public boolean intersectsSegment (FloatArray polygon, float x1, float y1, float x2, float y2) { + float[] vertices = polygon.items; + int nn = polygon.size; + + float width12 = x1 - x2, height12 = y1 - y2; + float det1 = x1 * y2 - y1 * x2; + float x3 = vertices[nn - 2], y3 = vertices[nn - 1]; + for (int ii = 0; ii < nn; ii += 2) { + float x4 = vertices[ii], y4 = vertices[ii + 1]; + float det2 = x3 * y4 - y3 * x4; + float width34 = x3 - x4, height34 = y3 - y4; + float det3 = width12 * height34 - height12 * width34; + float x = (det1 * width34 - width12 * det2) / det3; + if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { + float y = (det1 * height34 - height12 * det2) / det3; + if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; + } + x3 = x4; + y3 = y4; + } + return false; + } + + public float getMinX () { + return minX; + } + + public float getMinY () { + return minY; + } + + public float getMaxX () { + return maxX; + } + + public float getMaxY () { + return maxY; + } + + public float getWidth () { + return maxX - minX; + } + + public float getHeight () { + return maxY - minY; + } + + public Array getBoundingBoxes () { + return boundingBoxes; + } + + public Array getPolygons () { + return polygons; + } + + /** Returns the polygon for the specified bounding box, or null. */ + public FloatArray getPolygon (BoundingBoxAttachment boundingBox) { + if (boundingBox == null) throw new IllegalArgumentException("boundingBox cannot be null."); + int index = boundingBoxes.indexOf(boundingBox, true); + return index == -1 ? null : polygons.get(index); + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonData.java index 9b90d213ff..bcef7bcd7f 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonData.java @@ -1,279 +1,278 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.utils.Array; - -public class SkeletonData { - String name; - final Array bones = new Array(); // Ordered parents first. - final Array slots = new Array(); // Setup pose draw order. - final Array skins = new Array(); - Skin defaultSkin; - final Array events = new Array(); - final Array animations = new Array(); - final Array ikConstraints = new Array(); - final Array transformConstraints = new Array(); - final Array pathConstraints = new Array(); - float width, height; - String version, hash, imagesPath; - - // --- Bones. - - public Array getBones () { - return bones; - } - - /** @return May be null. */ - public BoneData findBone (String boneName) { - if (boneName == null) throw new IllegalArgumentException("boneName cannot be null."); - Array bones = this.bones; - for (int i = 0, n = bones.size; i < n; i++) { - BoneData bone = bones.get(i); - if (bone.name.equals(boneName)) return bone; - } - return null; - } - - /** @return -1 if the bone was not found. */ - public int findBoneIndex (String boneName) { - if (boneName == null) throw new IllegalArgumentException("boneName cannot be null."); - Array bones = this.bones; - for (int i = 0, n = bones.size; i < n; i++) - if (bones.get(i).name.equals(boneName)) return i; - return -1; - } - - // --- Slots. - - public Array getSlots () { - return slots; - } - - /** @return May be null. */ - public SlotData findSlot (String slotName) { - if (slotName == null) throw new IllegalArgumentException("slotName cannot be null."); - Array slots = this.slots; - for (int i = 0, n = slots.size; i < n; i++) { - SlotData slot = slots.get(i); - if (slot.name.equals(slotName)) return slot; - } - return null; - } - - /** @return -1 if the slot was not found. */ - public int findSlotIndex (String slotName) { - if (slotName == null) throw new IllegalArgumentException("slotName cannot be null."); - Array slots = this.slots; - for (int i = 0, n = slots.size; i < n; i++) - if (slots.get(i).name.equals(slotName)) return i; - return -1; - } - - // --- Skins. - - /** @return May be null. */ - public Skin getDefaultSkin () { - return defaultSkin; - } - - /** @param defaultSkin May be null. */ - public void setDefaultSkin (Skin defaultSkin) { - this.defaultSkin = defaultSkin; - } - - /** @return May be null. */ - public Skin findSkin (String skinName) { - if (skinName == null) throw new IllegalArgumentException("skinName cannot be null."); - for (Skin skin : skins) - if (skin.name.equals(skinName)) return skin; - return null; - } - - /** Returns all skins, including the default skin. */ - public Array getSkins () { - return skins; - } - - // --- Events. - - /** @return May be null. */ - public EventData findEvent (String eventDataName) { - if (eventDataName == null) throw new IllegalArgumentException("eventDataName cannot be null."); - for (EventData eventData : events) - if (eventData.name.equals(eventDataName)) return eventData; - return null; - } - - public Array getEvents () { - return events; - } - - // --- Animations. - - public Array getAnimations () { - return animations; - } - - /** @return May be null. */ - public Animation findAnimation (String animationName) { - if (animationName == null) throw new IllegalArgumentException("animationName cannot be null."); - Array animations = this.animations; - for (int i = 0, n = animations.size; i < n; i++) { - Animation animation = animations.get(i); - if (animation.name.equals(animationName)) return animation; - } - return null; - } - - // --- IK constraints - - public Array getIkConstraints () { - return ikConstraints; - } - - /** @return May be null. */ - public IkConstraintData findIkConstraint (String constraintName) { - if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); - Array ikConstraints = this.ikConstraints; - for (int i = 0, n = ikConstraints.size; i < n; i++) { - IkConstraintData constraint = ikConstraints.get(i); - if (constraint.name.equals(constraintName)) return constraint; - } - return null; - } - - // --- Transform constraints - - public Array getTransformConstraints () { - return transformConstraints; - } - - /** @return May be null. */ - public TransformConstraintData findTransformConstraint (String constraintName) { - if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); - Array transformConstraints = this.transformConstraints; - for (int i = 0, n = transformConstraints.size; i < n; i++) { - TransformConstraintData constraint = transformConstraints.get(i); - if (constraint.name.equals(constraintName)) return constraint; - } - return null; - } - - // --- Path constraints - - public Array getPathConstraints () { - return pathConstraints; - } - - /** @return May be null. */ - public PathConstraintData findPathConstraint (String constraintName) { - if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); - Array pathConstraints = this.pathConstraints; - for (int i = 0, n = pathConstraints.size; i < n; i++) { - PathConstraintData constraint = pathConstraints.get(i); - if (constraint.name.equals(constraintName)) return constraint; - } - return null; - } - - /** @return -1 if the path constraint was not found. */ - public int findPathConstraintIndex (String pathConstraintName) { - if (pathConstraintName == null) throw new IllegalArgumentException("pathConstraintName cannot be null."); - Array pathConstraints = this.pathConstraints; - for (int i = 0, n = pathConstraints.size; i < n; i++) - if (pathConstraints.get(i).name.equals(pathConstraintName)) return i; - return -1; - } - - // --- - - /** @return May be null. */ - public String getName () { - return name; - } - - /** @param name May be null. */ - public void setName (String name) { - this.name = name; - } - - public float getWidth () { - return width; - } - - public void setWidth (float width) { - this.width = width; - } - - public float getHeight () { - return height; - } - - public void setHeight (float height) { - this.height = height; - } - - /** Returns the Spine version used to export this data, or null. */ - public String getVersion () { - return version; - } - - /** @param version May be null. */ - public void setVersion (String version) { - this.version = version; - } - - /** @return May be null. */ - public String getHash () { - return hash; - } - - /** @param hash May be null. */ - public void setHash (String hash) { - this.hash = hash; - } - - /** @return May be null. */ - public String getImagesPath () { - return imagesPath; - } - - /** @param imagesPath May be null. */ - public void setImagesPath (String imagesPath) { - this.imagesPath = imagesPath; - } - - public String toString () { - return name != null ? name : super.toString(); - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.utils.Array; + +public class SkeletonData { + String name; + final Array bones = new Array(); // Ordered parents first. + final Array slots = new Array(); // Setup pose draw order. + final Array skins = new Array(); + Skin defaultSkin; + final Array events = new Array(); + final Array animations = new Array(); + final Array ikConstraints = new Array(); + final Array transformConstraints = new Array(); + final Array pathConstraints = new Array(); + float width, height; + String version, hash, imagesPath; + + // --- Bones. + + public Array getBones () { + return bones; + } + + /** @return May be null. */ + public BoneData findBone (String boneName) { + if (boneName == null) throw new IllegalArgumentException("boneName cannot be null."); + Array bones = this.bones; + for (int i = 0, n = bones.size; i < n; i++) { + BoneData bone = bones.get(i); + if (bone.name.equals(boneName)) return bone; + } + return null; + } + + /** @return -1 if the bone was not found. */ + public int findBoneIndex (String boneName) { + if (boneName == null) throw new IllegalArgumentException("boneName cannot be null."); + Array bones = this.bones; + for (int i = 0, n = bones.size; i < n; i++) + if (bones.get(i).name.equals(boneName)) return i; + return -1; + } + + // --- Slots. + + public Array getSlots () { + return slots; + } + + /** @return May be null. */ + public SlotData findSlot (String slotName) { + if (slotName == null) throw new IllegalArgumentException("slotName cannot be null."); + Array slots = this.slots; + for (int i = 0, n = slots.size; i < n; i++) { + SlotData slot = slots.get(i); + if (slot.name.equals(slotName)) return slot; + } + return null; + } + + /** @return -1 if the slot was not found. */ + public int findSlotIndex (String slotName) { + if (slotName == null) throw new IllegalArgumentException("slotName cannot be null."); + Array slots = this.slots; + for (int i = 0, n = slots.size; i < n; i++) + if (slots.get(i).name.equals(slotName)) return i; + return -1; + } + + // --- Skins. + + /** @return May be null. */ + public Skin getDefaultSkin () { + return defaultSkin; + } + + /** @param defaultSkin May be null. */ + public void setDefaultSkin (Skin defaultSkin) { + this.defaultSkin = defaultSkin; + } + + /** @return May be null. */ + public Skin findSkin (String skinName) { + if (skinName == null) throw new IllegalArgumentException("skinName cannot be null."); + for (Skin skin : skins) + if (skin.name.equals(skinName)) return skin; + return null; + } + + /** Returns all skins, including the default skin. */ + public Array getSkins () { + return skins; + } + + // --- Events. + + /** @return May be null. */ + public EventData findEvent (String eventDataName) { + if (eventDataName == null) throw new IllegalArgumentException("eventDataName cannot be null."); + for (EventData eventData : events) + if (eventData.name.equals(eventDataName)) return eventData; + return null; + } + + public Array getEvents () { + return events; + } + + // --- Animations. + + public Array getAnimations () { + return animations; + } + + /** @return May be null. */ + public Animation findAnimation (String animationName) { + if (animationName == null) throw new IllegalArgumentException("animationName cannot be null."); + Array animations = this.animations; + for (int i = 0, n = animations.size; i < n; i++) { + Animation animation = animations.get(i); + if (animation.name.equals(animationName)) return animation; + } + return null; + } + + // --- IK constraints + + public Array getIkConstraints () { + return ikConstraints; + } + + /** @return May be null. */ + public IkConstraintData findIkConstraint (String constraintName) { + if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); + Array ikConstraints = this.ikConstraints; + for (int i = 0, n = ikConstraints.size; i < n; i++) { + IkConstraintData constraint = ikConstraints.get(i); + if (constraint.name.equals(constraintName)) return constraint; + } + return null; + } + + // --- Transform constraints + + public Array getTransformConstraints () { + return transformConstraints; + } + + /** @return May be null. */ + public TransformConstraintData findTransformConstraint (String constraintName) { + if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); + Array transformConstraints = this.transformConstraints; + for (int i = 0, n = transformConstraints.size; i < n; i++) { + TransformConstraintData constraint = transformConstraints.get(i); + if (constraint.name.equals(constraintName)) return constraint; + } + return null; + } + + // --- Path constraints + + public Array getPathConstraints () { + return pathConstraints; + } + + /** @return May be null. */ + public PathConstraintData findPathConstraint (String constraintName) { + if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); + Array pathConstraints = this.pathConstraints; + for (int i = 0, n = pathConstraints.size; i < n; i++) { + PathConstraintData constraint = pathConstraints.get(i); + if (constraint.name.equals(constraintName)) return constraint; + } + return null; + } + + /** @return -1 if the path constraint was not found. */ + public int findPathConstraintIndex (String pathConstraintName) { + if (pathConstraintName == null) throw new IllegalArgumentException("pathConstraintName cannot be null."); + Array pathConstraints = this.pathConstraints; + for (int i = 0, n = pathConstraints.size; i < n; i++) + if (pathConstraints.get(i).name.equals(pathConstraintName)) return i; + return -1; + } + + // --- + + /** @return May be null. */ + public String getName () { + return name; + } + + /** @param name May be null. */ + public void setName (String name) { + this.name = name; + } + + public float getWidth () { + return width; + } + + public void setWidth (float width) { + this.width = width; + } + + public float getHeight () { + return height; + } + + public void setHeight (float height) { + this.height = height; + } + + /** Returns the Spine version used to export this data, or null. */ + public String getVersion () { + return version; + } + + /** @param version May be null. */ + public void setVersion (String version) { + this.version = version; + } + + /** @return May be null. */ + public String getHash () { + return hash; + } + + /** @param hash May be null. */ + public void setHash (String hash) { + this.hash = hash; + } + + /** @return May be null. */ + public String getImagesPath () { + return imagesPath; + } + + /** @param imagesPath May be null. */ + public void setImagesPath (String imagesPath) { + this.imagesPath = imagesPath; + } + + public String toString () { + return name != null ? name : super.toString(); + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java index f737f54e53..ddb2c965cf 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java @@ -1,703 +1,702 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.files.FileHandle; -import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.FloatArray; -import com.badlogic.gdx.utils.IntArray; -import com.badlogic.gdx.utils.JsonReader; -import com.badlogic.gdx.utils.JsonValue; -import com.badlogic.gdx.utils.SerializationException; -import com.esotericsoftware.spine.Animation.AttachmentTimeline; -import com.esotericsoftware.spine.Animation.ColorTimeline; -import com.esotericsoftware.spine.Animation.CurveTimeline; -import com.esotericsoftware.spine.Animation.DeformTimeline; -import com.esotericsoftware.spine.Animation.DrawOrderTimeline; -import com.esotericsoftware.spine.Animation.EventTimeline; -import com.esotericsoftware.spine.Animation.IkConstraintTimeline; -import com.esotericsoftware.spine.Animation.PathConstraintMixTimeline; -import com.esotericsoftware.spine.Animation.PathConstraintPositionTimeline; -import com.esotericsoftware.spine.Animation.PathConstraintSpacingTimeline; -import com.esotericsoftware.spine.Animation.RotateTimeline; -import com.esotericsoftware.spine.Animation.ScaleTimeline; -import com.esotericsoftware.spine.Animation.ShearTimeline; -import com.esotericsoftware.spine.Animation.Timeline; -import com.esotericsoftware.spine.Animation.TransformConstraintTimeline; -import com.esotericsoftware.spine.Animation.TranslateTimeline; -import com.esotericsoftware.spine.PathConstraintData.PositionMode; -import com.esotericsoftware.spine.PathConstraintData.RotateMode; -import com.esotericsoftware.spine.PathConstraintData.SpacingMode; -import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader; -import com.esotericsoftware.spine.attachments.Attachment; -import com.esotericsoftware.spine.attachments.AttachmentLoader; -import com.esotericsoftware.spine.attachments.AttachmentType; -import com.esotericsoftware.spine.attachments.BoundingBoxAttachment; -import com.esotericsoftware.spine.attachments.MeshAttachment; -import com.esotericsoftware.spine.attachments.PathAttachment; -import com.esotericsoftware.spine.attachments.RegionAttachment; -import com.esotericsoftware.spine.attachments.VertexAttachment; - -public class SkeletonJson { - private final AttachmentLoader attachmentLoader; - private float scale = 1; - private Array linkedMeshes = new Array(); - - public SkeletonJson (TextureAtlas atlas) { - attachmentLoader = new AtlasAttachmentLoader(atlas); - } - - public SkeletonJson (AttachmentLoader attachmentLoader) { - if (attachmentLoader == null) throw new IllegalArgumentException("attachmentLoader cannot be null."); - this.attachmentLoader = attachmentLoader; - } - - public float getScale () { - return scale; - } - - /** Scales the bones, images, and animations as they are loaded. */ - public void setScale (float scale) { - this.scale = scale; - } - - public SkeletonData readSkeletonData (FileHandle file) { - if (file == null) throw new IllegalArgumentException("file cannot be null."); - - float scale = this.scale; - - SkeletonData skeletonData = new SkeletonData(); - skeletonData.name = file.nameWithoutExtension(); - - JsonValue root = new JsonReader().parse(file); - - // Skeleton. - JsonValue skeletonMap = root.get("skeleton"); - if (skeletonMap != null) { - skeletonData.hash = skeletonMap.getString("hash", null); - skeletonData.version = skeletonMap.getString("spine", null); - skeletonData.width = skeletonMap.getFloat("width", 0); - skeletonData.height = skeletonMap.getFloat("height", 0); - skeletonData.imagesPath = skeletonMap.getString("images", null); - } - - // Bones. - for (JsonValue boneMap = root.getChild("bones"); boneMap != null; boneMap = boneMap.next) { - BoneData parent = null; - String parentName = boneMap.getString("parent", null); - if (parentName != null) { - parent = skeletonData.findBone(parentName); - if (parent == null) throw new SerializationException("Parent bone not found: " + parentName); - } - BoneData data = new BoneData(skeletonData.bones.size, boneMap.getString("name"), parent); - data.length = boneMap.getFloat("length", 0) * scale; - data.x = boneMap.getFloat("x", 0) * scale; - data.y = boneMap.getFloat("y", 0) * scale; - data.rotation = boneMap.getFloat("rotation", 0); - data.scaleX = boneMap.getFloat("scaleX", 1); - data.scaleY = boneMap.getFloat("scaleY", 1); - data.shearX = boneMap.getFloat("shearX", 0); - data.shearY = boneMap.getFloat("shearY", 0); - data.inheritRotation = boneMap.getBoolean("inheritRotation", true); - data.inheritScale = boneMap.getBoolean("inheritScale", true); - - String color = boneMap.getString("color", null); - if (color != null) data.getColor().set(Color.valueOf(color)); - - skeletonData.bones.add(data); - } - - // Slots. - for (JsonValue slotMap = root.getChild("slots"); slotMap != null; slotMap = slotMap.next) { - String slotName = slotMap.getString("name"); - String boneName = slotMap.getString("bone"); - BoneData boneData = skeletonData.findBone(boneName); - if (boneData == null) throw new SerializationException("Slot bone not found: " + boneName); - SlotData data = new SlotData(skeletonData.slots.size, slotName, boneData); - - String color = slotMap.getString("color", null); - if (color != null) data.getColor().set(Color.valueOf(color)); - - data.attachmentName = slotMap.getString("attachment", null); - data.blendMode = BlendMode.valueOf(slotMap.getString("blend", BlendMode.normal.name())); - skeletonData.slots.add(data); - } - - // IK constraints. - for (JsonValue constraintMap = root.getChild("ik"); constraintMap != null; constraintMap = constraintMap.next) { - IkConstraintData data = new IkConstraintData(constraintMap.getString("name")); - - for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) { - String boneName = boneMap.asString(); - BoneData bone = skeletonData.findBone(boneName); - if (bone == null) throw new SerializationException("IK bone not found: " + boneName); - data.bones.add(bone); - } - - String targetName = constraintMap.getString("target"); - data.target = skeletonData.findBone(targetName); - if (data.target == null) throw new SerializationException("IK target bone not found: " + targetName); - - data.bendDirection = constraintMap.getBoolean("bendPositive", true) ? 1 : -1; - data.mix = constraintMap.getFloat("mix", 1); - - skeletonData.ikConstraints.add(data); - } - - // Transform constraints. - for (JsonValue constraintMap = root.getChild("transform"); constraintMap != null; constraintMap = constraintMap.next) { - TransformConstraintData data = new TransformConstraintData(constraintMap.getString("name")); - - for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) { - String boneName = boneMap.asString(); - BoneData bone = skeletonData.findBone(boneName); - if (bone == null) throw new SerializationException("Transform constraint bone not found: " + boneName); - data.bones.add(bone); - } - - String targetName = constraintMap.getString("target"); - data.target = skeletonData.findBone(targetName); - if (data.target == null) throw new SerializationException("Transform constraint target bone not found: " + targetName); - - data.offsetRotation = constraintMap.getFloat("rotation", 0); - data.offsetX = constraintMap.getFloat("x", 0) * scale; - data.offsetY = constraintMap.getFloat("y", 0) * scale; - data.offsetScaleX = constraintMap.getFloat("scaleX", 0); - data.offsetScaleY = constraintMap.getFloat("scaleY", 0); - data.offsetShearY = constraintMap.getFloat("shearY", 0); - - data.rotateMix = constraintMap.getFloat("rotateMix", 1); - data.translateMix = constraintMap.getFloat("translateMix", 1); - data.scaleMix = constraintMap.getFloat("scaleMix", 1); - data.shearMix = constraintMap.getFloat("shearMix", 1); - - skeletonData.transformConstraints.add(data); - } - - // Path constraints. - for (JsonValue constraintMap = root.getChild("path"); constraintMap != null; constraintMap = constraintMap.next) { - PathConstraintData data = new PathConstraintData(constraintMap.getString("name")); - - for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) { - String boneName = boneMap.asString(); - BoneData bone = skeletonData.findBone(boneName); - if (bone == null) throw new SerializationException("Path bone not found: " + boneName); - data.bones.add(bone); - } - - String targetName = constraintMap.getString("target"); - data.target = skeletonData.findSlot(targetName); - if (data.target == null) throw new SerializationException("Path target slot not found: " + targetName); - - data.positionMode = PositionMode.valueOf(constraintMap.getString("positionMode", "percent")); - data.spacingMode = SpacingMode.valueOf(constraintMap.getString("spacingMode", "length")); - data.rotateMode = RotateMode.valueOf(constraintMap.getString("rotateMode", "tangent")); - data.offsetRotation = constraintMap.getFloat("rotation", 0); - data.position = constraintMap.getFloat("position", 0); - if (data.positionMode == PositionMode.fixed) data.position *= scale; - data.spacing = constraintMap.getFloat("spacing", 0); - if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) data.spacing *= scale; - data.rotateMix = constraintMap.getFloat("rotateMix", 1); - data.translateMix = constraintMap.getFloat("translateMix", 1); - - skeletonData.pathConstraints.add(data); - } - - // Skins. - for (JsonValue skinMap = root.getChild("skins"); skinMap != null; skinMap = skinMap.next) { - Skin skin = new Skin(skinMap.name); - for (JsonValue slotEntry = skinMap.child; slotEntry != null; slotEntry = slotEntry.next) { - int slotIndex = skeletonData.findSlotIndex(slotEntry.name); - if (slotIndex == -1) throw new SerializationException("Slot not found: " + slotEntry.name); - for (JsonValue entry = slotEntry.child; entry != null; entry = entry.next) { - try { - Attachment attachment = readAttachment(entry, skin, slotIndex, entry.name); - if (attachment != null) skin.addAttachment(slotIndex, entry.name, attachment); - } catch (Exception ex) { - throw new SerializationException("Error reading attachment: " + entry.name + ", skin: " + skin, ex); - } - } - } - skeletonData.skins.add(skin); - if (skin.name.equals("default")) skeletonData.defaultSkin = skin; - } - - // Linked meshes. - for (int i = 0, n = linkedMeshes.size; i < n; i++) { - LinkedMesh linkedMesh = linkedMeshes.get(i); - Skin skin = linkedMesh.skin == null ? skeletonData.getDefaultSkin() : skeletonData.findSkin(linkedMesh.skin); - if (skin == null) throw new SerializationException("Skin not found: " + linkedMesh.skin); - Attachment parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); - if (parent == null) throw new SerializationException("Parent mesh not found: " + linkedMesh.parent); - linkedMesh.mesh.setParentMesh((MeshAttachment)parent); - linkedMesh.mesh.updateUVs(); - } - linkedMeshes.clear(); - - // Events. - for (JsonValue eventMap = root.getChild("events"); eventMap != null; eventMap = eventMap.next) { - EventData data = new EventData(eventMap.name); - data.intValue = eventMap.getInt("int", 0); - data.floatValue = eventMap.getFloat("float", 0f); - data.stringValue = eventMap.getString("string", null); - skeletonData.events.add(data); - } - - // Animations. - for (JsonValue animationMap = root.getChild("animations"); animationMap != null; animationMap = animationMap.next) { - try { - readAnimation(animationMap, animationMap.name, skeletonData); - } catch (Exception ex) { - throw new SerializationException("Error reading animation: " + animationMap.name, ex); - } - } - - skeletonData.bones.shrink(); - skeletonData.slots.shrink(); - skeletonData.skins.shrink(); - skeletonData.events.shrink(); - skeletonData.animations.shrink(); - skeletonData.ikConstraints.shrink(); - return skeletonData; - } - - private Attachment readAttachment (JsonValue map, Skin skin, int slotIndex, String name) { - float scale = this.scale; - name = map.getString("name", name); - - String type = map.getString("type", AttachmentType.region.name()); - - switch (AttachmentType.valueOf(type)) { - case region: { - String path = map.getString("path", name); - RegionAttachment region = attachmentLoader.newRegionAttachment(skin, name, path); - if (region == null) return null; - region.setPath(path); - region.setX(map.getFloat("x", 0) * scale); - region.setY(map.getFloat("y", 0) * scale); - region.setScaleX(map.getFloat("scaleX", 1)); - region.setScaleY(map.getFloat("scaleY", 1)); - region.setRotation(map.getFloat("rotation", 0)); - region.setWidth(map.getFloat("width") * scale); - region.setHeight(map.getFloat("height") * scale); - - String color = map.getString("color", null); - if (color != null) region.getColor().set(Color.valueOf(color)); - - region.updateOffset(); - return region; - } - case boundingbox: { - BoundingBoxAttachment box = attachmentLoader.newBoundingBoxAttachment(skin, name); - if (box == null) return null; - readVertices(map, box, map.getInt("vertexCount") << 1); - - String color = map.getString("color", null); - if (color != null) box.getColor().set(Color.valueOf(color)); - return box; - } - case mesh: - case linkedmesh: { - String path = map.getString("path", name); - MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path); - if (mesh == null) return null; - mesh.setPath(path); - - String color = map.getString("color", null); - if (color != null) mesh.getColor().set(Color.valueOf(color)); - - mesh.setWidth(map.getFloat("width", 0) * scale); - mesh.setHeight(map.getFloat("height", 0) * scale); - - String parent = map.getString("parent", null); - if (parent != null) { - mesh.setInheritDeform(map.getBoolean("deform", true)); - linkedMeshes.add(new LinkedMesh(mesh, map.getString("skin", null), slotIndex, parent)); - return mesh; - } - - float[] uvs = map.require("uvs").asFloatArray(); - readVertices(map, mesh, uvs.length); - mesh.setTriangles(map.require("triangles").asShortArray()); - mesh.setRegionUVs(uvs); - mesh.updateUVs(); - - if (map.has("hull")) mesh.setHullLength(map.require("hull").asInt() * 2); - if (map.has("edges")) mesh.setEdges(map.require("edges").asShortArray()); - return mesh; - } - case path: { - PathAttachment path = attachmentLoader.newPathAttachment(skin, name); - if (path == null) return null; - path.setClosed(map.getBoolean("closed", false)); - path.setConstantSpeed(map.getBoolean("constantSpeed", true)); - - int vertexCount = map.getInt("vertexCount"); - readVertices(map, path, vertexCount << 1); - - float[] lengths = new float[vertexCount / 3]; - int i = 0; - for (JsonValue curves = map.require("lengths").child; curves != null; curves = curves.next) - lengths[i++] = curves.asFloat() * scale; - path.setLengths(lengths); - - String color = map.getString("color", null); - if (color != null) path.getColor().set(Color.valueOf(color)); - return path; - } - } - return null; - } - - private void readVertices (JsonValue map, VertexAttachment attachment, int verticesLength) { - attachment.setWorldVerticesLength(verticesLength); - float[] vertices = map.require("vertices").asFloatArray(); - if (verticesLength == vertices.length) { - if (scale != 1) { - for (int i = 0, n = vertices.length; i < n; i++) - vertices[i] *= scale; - } - attachment.setVertices(vertices); - return; - } - FloatArray weights = new FloatArray(verticesLength * 3 * 3); - IntArray bones = new IntArray(verticesLength * 3); - for (int i = 0, n = vertices.length; i < n;) { - int boneCount = (int)vertices[i++]; - bones.add(boneCount); - for (int nn = i + boneCount * 4; i < nn; i += 4) { - bones.add((int)vertices[i]); - weights.add(vertices[i + 1] * scale); - weights.add(vertices[i + 2] * scale); - weights.add(vertices[i + 3]); - } - } - attachment.setBones(bones.toArray()); - attachment.setVertices(weights.toArray()); - } - - private void readAnimation (JsonValue map, String name, SkeletonData skeletonData) { - float scale = this.scale; - Array timelines = new Array(); - float duration = 0; - - // Slot timelines. - for (JsonValue slotMap = map.getChild("slots"); slotMap != null; slotMap = slotMap.next) { - int slotIndex = skeletonData.findSlotIndex(slotMap.name); - if (slotIndex == -1) throw new SerializationException("Slot not found: " + slotMap.name); - for (JsonValue timelineMap = slotMap.child; timelineMap != null; timelineMap = timelineMap.next) { - String timelineName = timelineMap.name; - if (timelineName.equals("color")) { - ColorTimeline timeline = new ColorTimeline(timelineMap.size); - timeline.slotIndex = slotIndex; - - int frameIndex = 0; - for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) { - Color color = Color.valueOf(valueMap.getString("color")); - timeline.setFrame(frameIndex, valueMap.getFloat("time"), color.r, color.g, color.b, color.a); - readCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[(timeline.getFrameCount() - 1) * ColorTimeline.ENTRIES]); - - } else if (timelineName.equals("attachment")) { - AttachmentTimeline timeline = new AttachmentTimeline(timelineMap.size); - timeline.slotIndex = slotIndex; - - int frameIndex = 0; - for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) - timeline.setFrame(frameIndex++, valueMap.getFloat("time"), valueMap.getString("name")); - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() - 1]); - } else - throw new RuntimeException("Invalid timeline type for a slot: " + timelineName + " (" + slotMap.name + ")"); - } - } - - // Bone timelines. - for (JsonValue boneMap = map.getChild("bones"); boneMap != null; boneMap = boneMap.next) { - int boneIndex = skeletonData.findBoneIndex(boneMap.name); - if (boneIndex == -1) throw new SerializationException("Bone not found: " + boneMap.name); - for (JsonValue timelineMap = boneMap.child; timelineMap != null; timelineMap = timelineMap.next) { - String timelineName = timelineMap.name; - if (timelineName.equals("rotate")) { - RotateTimeline timeline = new RotateTimeline(timelineMap.size); - timeline.boneIndex = boneIndex; - - int frameIndex = 0; - for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) { - timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat("angle")); - readCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[(timeline.getFrameCount() - 1) * RotateTimeline.ENTRIES]); - - } else if (timelineName.equals("translate") || timelineName.equals("scale") || timelineName.equals("shear")) { - TranslateTimeline timeline; - float timelineScale = 1; - if (timelineName.equals("scale")) - timeline = new ScaleTimeline(timelineMap.size); - else if (timelineName.equals("shear")) - timeline = new ShearTimeline(timelineMap.size); - else { - timeline = new TranslateTimeline(timelineMap.size); - timelineScale = scale; - } - timeline.boneIndex = boneIndex; - - int frameIndex = 0; - for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) { - float x = valueMap.getFloat("x", 0), y = valueMap.getFloat("y", 0); - timeline.setFrame(frameIndex, valueMap.getFloat("time"), x * timelineScale, y * timelineScale); - readCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[(timeline.getFrameCount() - 1) * TranslateTimeline.ENTRIES]); - - } else - throw new RuntimeException("Invalid timeline type for a bone: " + timelineName + " (" + boneMap.name + ")"); - } - } - - // IK constraint timelines. - for (JsonValue constraintMap = map.getChild("ik"); constraintMap != null; constraintMap = constraintMap.next) { - IkConstraintData constraint = skeletonData.findIkConstraint(constraintMap.name); - IkConstraintTimeline timeline = new IkConstraintTimeline(constraintMap.size); - timeline.ikConstraintIndex = skeletonData.getIkConstraints().indexOf(constraint, true); - int frameIndex = 0; - for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next) { - timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat("mix", 1), - valueMap.getBoolean("bendPositive", true) ? 1 : -1); - readCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[(timeline.getFrameCount() - 1) * IkConstraintTimeline.ENTRIES]); - } - - // Transform constraint timelines. - for (JsonValue constraintMap = map.getChild("transform"); constraintMap != null; constraintMap = constraintMap.next) { - TransformConstraintData constraint = skeletonData.findTransformConstraint(constraintMap.name); - TransformConstraintTimeline timeline = new TransformConstraintTimeline(constraintMap.size); - timeline.transformConstraintIndex = skeletonData.getTransformConstraints().indexOf(constraint, true); - int frameIndex = 0; - for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next) { - timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat("rotateMix", 1), - valueMap.getFloat("translateMix", 1), valueMap.getFloat("scaleMix", 1), valueMap.getFloat("shearMix", 1)); - readCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.add(timeline); - duration = Math.max(duration, - timeline.getFrames()[(timeline.getFrameCount() - 1) * TransformConstraintTimeline.ENTRIES]); - } - - // Path constraint timelines. - for (JsonValue constraintMap = map.getChild("paths"); constraintMap != null; constraintMap = constraintMap.next) { - int index = skeletonData.findPathConstraintIndex(constraintMap.name); - if (index == -1) throw new SerializationException("Path constraint not found: " + constraintMap.name); - PathConstraintData data = skeletonData.getPathConstraints().get(index); - for (JsonValue timelineMap = constraintMap.child; timelineMap != null; timelineMap = timelineMap.next) { - String timelineName = timelineMap.name; - if (timelineName.equals("position") || timelineName.equals("spacing")) { - PathConstraintPositionTimeline timeline; - float timelineScale = 1; - if (timelineName.equals("spacing")) { - timeline = new PathConstraintSpacingTimeline(timelineMap.size); - if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) timelineScale = scale; - } else { - timeline = new PathConstraintPositionTimeline(timelineMap.size); - if (data.positionMode == PositionMode.fixed) timelineScale = scale; - } - timeline.pathConstraintIndex = index; - int frameIndex = 0; - for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) { - timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat(timelineName, 0) * timelineScale); - readCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.add(timeline); - duration = Math.max(duration, - timeline.getFrames()[(timeline.getFrameCount() - 1) * PathConstraintPositionTimeline.ENTRIES]); - } else if (timelineName.equals("mix")) { - PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(timelineMap.size); - timeline.pathConstraintIndex = index; - int frameIndex = 0; - for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) { - timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat("rotateMix", 1), - valueMap.getFloat("translateMix", 1)); - readCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.add(timeline); - duration = Math.max(duration, - timeline.getFrames()[(timeline.getFrameCount() - 1) * PathConstraintMixTimeline.ENTRIES]); - } - } - } - - // Deform timelines. - for (JsonValue deformMap = map.getChild("deform"); deformMap != null; deformMap = deformMap.next) { - Skin skin = skeletonData.findSkin(deformMap.name); - if (skin == null) throw new SerializationException("Skin not found: " + deformMap.name); - for (JsonValue slotMap = deformMap.child; slotMap != null; slotMap = slotMap.next) { - int slotIndex = skeletonData.findSlotIndex(slotMap.name); - if (slotIndex == -1) throw new SerializationException("Slot not found: " + slotMap.name); - for (JsonValue timelineMap = slotMap.child; timelineMap != null; timelineMap = timelineMap.next) { - VertexAttachment attachment = (VertexAttachment)skin.getAttachment(slotIndex, timelineMap.name); - if (attachment == null) throw new SerializationException("Deform attachment not found: " + timelineMap.name); - boolean weighted = attachment.getBones() != null; - float[] vertices = attachment.getVertices(); - int deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; - - DeformTimeline timeline = new DeformTimeline(timelineMap.size); - timeline.slotIndex = slotIndex; - timeline.attachment = attachment; - - int frameIndex = 0; - for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) { - float[] deform; - JsonValue verticesValue = valueMap.get("vertices"); - if (verticesValue == null) - deform = weighted ? new float[deformLength] : vertices; - else { - deform = new float[deformLength]; - int start = valueMap.getInt("offset", 0); - System.arraycopy(verticesValue.asFloatArray(), 0, deform, start, verticesValue.size); - if (scale != 1) { - for (int i = start, n = i + verticesValue.size; i < n; i++) - deform[i] *= scale; - } - if (!weighted) { - for (int i = 0; i < deformLength; i++) - deform[i] += vertices[i]; - } - } - - timeline.setFrame(frameIndex, valueMap.getFloat("time"), deform); - readCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() - 1]); - } - } - } - - // Draw order timeline. - JsonValue drawOrdersMap = map.get("drawOrder"); - if (drawOrdersMap == null) drawOrdersMap = map.get("draworder"); - if (drawOrdersMap != null) { - DrawOrderTimeline timeline = new DrawOrderTimeline(drawOrdersMap.size); - int slotCount = skeletonData.slots.size; - int frameIndex = 0; - for (JsonValue drawOrderMap = drawOrdersMap.child; drawOrderMap != null; drawOrderMap = drawOrderMap.next) { - int[] drawOrder = null; - JsonValue offsets = drawOrderMap.get("offsets"); - if (offsets != null) { - drawOrder = new int[slotCount]; - for (int i = slotCount - 1; i >= 0; i--) - drawOrder[i] = -1; - int[] unchanged = new int[slotCount - offsets.size]; - int originalIndex = 0, unchangedIndex = 0; - for (JsonValue offsetMap = offsets.child; offsetMap != null; offsetMap = offsetMap.next) { - int slotIndex = skeletonData.findSlotIndex(offsetMap.getString("slot")); - if (slotIndex == -1) throw new SerializationException("Slot not found: " + offsetMap.getString("slot")); - // Collect unchanged items. - while (originalIndex != slotIndex) - unchanged[unchangedIndex++] = originalIndex++; - // Set changed items. - drawOrder[originalIndex + offsetMap.getInt("offset")] = originalIndex++; - } - // Collect remaining unchanged items. - while (originalIndex < slotCount) - unchanged[unchangedIndex++] = originalIndex++; - // Fill in unchanged items. - for (int i = slotCount - 1; i >= 0; i--) - if (drawOrder[i] == -1) drawOrder[i] = unchanged[--unchangedIndex]; - } - timeline.setFrame(frameIndex++, drawOrderMap.getFloat("time"), drawOrder); - } - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() - 1]); - } - - // Event timeline. - JsonValue eventsMap = map.get("events"); - if (eventsMap != null) { - EventTimeline timeline = new EventTimeline(eventsMap.size); - int frameIndex = 0; - for (JsonValue eventMap = eventsMap.child; eventMap != null; eventMap = eventMap.next) { - EventData eventData = skeletonData.findEvent(eventMap.getString("name")); - if (eventData == null) throw new SerializationException("Event not found: " + eventMap.getString("name")); - Event event = new Event(eventMap.getFloat("time"), eventData); - event.intValue = eventMap.getInt("int", eventData.getInt()); - event.floatValue = eventMap.getFloat("float", eventData.getFloat()); - event.stringValue = eventMap.getString("string", eventData.getString()); - timeline.setFrame(frameIndex++, event); - } - timelines.add(timeline); - duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() - 1]); - } - - timelines.shrink(); - skeletonData.animations.add(new Animation(name, timelines, duration)); - } - - void readCurve (JsonValue map, CurveTimeline timeline, int frameIndex) { - JsonValue curve = map.get("curve"); - if (curve == null) return; - if (curve.isString() && curve.asString().equals("stepped")) - timeline.setStepped(frameIndex); - else if (curve.isArray()) { - timeline.setCurve(frameIndex, curve.getFloat(0), curve.getFloat(1), curve.getFloat(2), curve.getFloat(3)); - } - } - - static class LinkedMesh { - String parent, skin; - int slotIndex; - MeshAttachment mesh; - - public LinkedMesh (MeshAttachment mesh, String skin, int slotIndex, String parent) { - this.mesh = mesh; - this.skin = skin; - this.slotIndex = slotIndex; - this.parent = parent; - } - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.FloatArray; +import com.badlogic.gdx.utils.IntArray; +import com.badlogic.gdx.utils.JsonReader; +import com.badlogic.gdx.utils.JsonValue; +import com.badlogic.gdx.utils.SerializationException; +import com.esotericsoftware.spine.Animation.AttachmentTimeline; +import com.esotericsoftware.spine.Animation.ColorTimeline; +import com.esotericsoftware.spine.Animation.CurveTimeline; +import com.esotericsoftware.spine.Animation.DeformTimeline; +import com.esotericsoftware.spine.Animation.DrawOrderTimeline; +import com.esotericsoftware.spine.Animation.EventTimeline; +import com.esotericsoftware.spine.Animation.IkConstraintTimeline; +import com.esotericsoftware.spine.Animation.PathConstraintMixTimeline; +import com.esotericsoftware.spine.Animation.PathConstraintPositionTimeline; +import com.esotericsoftware.spine.Animation.PathConstraintSpacingTimeline; +import com.esotericsoftware.spine.Animation.RotateTimeline; +import com.esotericsoftware.spine.Animation.ScaleTimeline; +import com.esotericsoftware.spine.Animation.ShearTimeline; +import com.esotericsoftware.spine.Animation.Timeline; +import com.esotericsoftware.spine.Animation.TransformConstraintTimeline; +import com.esotericsoftware.spine.Animation.TranslateTimeline; +import com.esotericsoftware.spine.PathConstraintData.PositionMode; +import com.esotericsoftware.spine.PathConstraintData.RotateMode; +import com.esotericsoftware.spine.PathConstraintData.SpacingMode; +import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader; +import com.esotericsoftware.spine.attachments.Attachment; +import com.esotericsoftware.spine.attachments.AttachmentLoader; +import com.esotericsoftware.spine.attachments.AttachmentType; +import com.esotericsoftware.spine.attachments.BoundingBoxAttachment; +import com.esotericsoftware.spine.attachments.MeshAttachment; +import com.esotericsoftware.spine.attachments.PathAttachment; +import com.esotericsoftware.spine.attachments.RegionAttachment; +import com.esotericsoftware.spine.attachments.VertexAttachment; + +public class SkeletonJson { + private final AttachmentLoader attachmentLoader; + private float scale = 1; + private Array linkedMeshes = new Array(); + + public SkeletonJson (TextureAtlas atlas) { + attachmentLoader = new AtlasAttachmentLoader(atlas); + } + + public SkeletonJson (AttachmentLoader attachmentLoader) { + if (attachmentLoader == null) throw new IllegalArgumentException("attachmentLoader cannot be null."); + this.attachmentLoader = attachmentLoader; + } + + public float getScale () { + return scale; + } + + /** Scales the bones, images, and animations as they are loaded. */ + public void setScale (float scale) { + this.scale = scale; + } + + public SkeletonData readSkeletonData (FileHandle file) { + if (file == null) throw new IllegalArgumentException("file cannot be null."); + + float scale = this.scale; + + SkeletonData skeletonData = new SkeletonData(); + skeletonData.name = file.nameWithoutExtension(); + + JsonValue root = new JsonReader().parse(file); + + // Skeleton. + JsonValue skeletonMap = root.get("skeleton"); + if (skeletonMap != null) { + skeletonData.hash = skeletonMap.getString("hash", null); + skeletonData.version = skeletonMap.getString("spine", null); + skeletonData.width = skeletonMap.getFloat("width", 0); + skeletonData.height = skeletonMap.getFloat("height", 0); + skeletonData.imagesPath = skeletonMap.getString("images", null); + } + + // Bones. + for (JsonValue boneMap = root.getChild("bones"); boneMap != null; boneMap = boneMap.next) { + BoneData parent = null; + String parentName = boneMap.getString("parent", null); + if (parentName != null) { + parent = skeletonData.findBone(parentName); + if (parent == null) throw new SerializationException("Parent bone not found: " + parentName); + } + BoneData data = new BoneData(skeletonData.bones.size, boneMap.getString("name"), parent); + data.length = boneMap.getFloat("length", 0) * scale; + data.x = boneMap.getFloat("x", 0) * scale; + data.y = boneMap.getFloat("y", 0) * scale; + data.rotation = boneMap.getFloat("rotation", 0); + data.scaleX = boneMap.getFloat("scaleX", 1); + data.scaleY = boneMap.getFloat("scaleY", 1); + data.shearX = boneMap.getFloat("shearX", 0); + data.shearY = boneMap.getFloat("shearY", 0); + data.inheritRotation = boneMap.getBoolean("inheritRotation", true); + data.inheritScale = boneMap.getBoolean("inheritScale", true); + + String color = boneMap.getString("color", null); + if (color != null) data.getColor().set(Color.valueOf(color)); + + skeletonData.bones.add(data); + } + + // Slots. + for (JsonValue slotMap = root.getChild("slots"); slotMap != null; slotMap = slotMap.next) { + String slotName = slotMap.getString("name"); + String boneName = slotMap.getString("bone"); + BoneData boneData = skeletonData.findBone(boneName); + if (boneData == null) throw new SerializationException("Slot bone not found: " + boneName); + SlotData data = new SlotData(skeletonData.slots.size, slotName, boneData); + + String color = slotMap.getString("color", null); + if (color != null) data.getColor().set(Color.valueOf(color)); + + data.attachmentName = slotMap.getString("attachment", null); + data.blendMode = BlendMode.valueOf(slotMap.getString("blend", BlendMode.normal.name())); + skeletonData.slots.add(data); + } + + // IK constraints. + for (JsonValue constraintMap = root.getChild("ik"); constraintMap != null; constraintMap = constraintMap.next) { + IkConstraintData data = new IkConstraintData(constraintMap.getString("name")); + + for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) { + String boneName = boneMap.asString(); + BoneData bone = skeletonData.findBone(boneName); + if (bone == null) throw new SerializationException("IK bone not found: " + boneName); + data.bones.add(bone); + } + + String targetName = constraintMap.getString("target"); + data.target = skeletonData.findBone(targetName); + if (data.target == null) throw new SerializationException("IK target bone not found: " + targetName); + + data.bendDirection = constraintMap.getBoolean("bendPositive", true) ? 1 : -1; + data.mix = constraintMap.getFloat("mix", 1); + + skeletonData.ikConstraints.add(data); + } + + // Transform constraints. + for (JsonValue constraintMap = root.getChild("transform"); constraintMap != null; constraintMap = constraintMap.next) { + TransformConstraintData data = new TransformConstraintData(constraintMap.getString("name")); + + for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) { + String boneName = boneMap.asString(); + BoneData bone = skeletonData.findBone(boneName); + if (bone == null) throw new SerializationException("Transform constraint bone not found: " + boneName); + data.bones.add(bone); + } + + String targetName = constraintMap.getString("target"); + data.target = skeletonData.findBone(targetName); + if (data.target == null) throw new SerializationException("Transform constraint target bone not found: " + targetName); + + data.offsetRotation = constraintMap.getFloat("rotation", 0); + data.offsetX = constraintMap.getFloat("x", 0) * scale; + data.offsetY = constraintMap.getFloat("y", 0) * scale; + data.offsetScaleX = constraintMap.getFloat("scaleX", 0); + data.offsetScaleY = constraintMap.getFloat("scaleY", 0); + data.offsetShearY = constraintMap.getFloat("shearY", 0); + + data.rotateMix = constraintMap.getFloat("rotateMix", 1); + data.translateMix = constraintMap.getFloat("translateMix", 1); + data.scaleMix = constraintMap.getFloat("scaleMix", 1); + data.shearMix = constraintMap.getFloat("shearMix", 1); + + skeletonData.transformConstraints.add(data); + } + + // Path constraints. + for (JsonValue constraintMap = root.getChild("path"); constraintMap != null; constraintMap = constraintMap.next) { + PathConstraintData data = new PathConstraintData(constraintMap.getString("name")); + + for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) { + String boneName = boneMap.asString(); + BoneData bone = skeletonData.findBone(boneName); + if (bone == null) throw new SerializationException("Path bone not found: " + boneName); + data.bones.add(bone); + } + + String targetName = constraintMap.getString("target"); + data.target = skeletonData.findSlot(targetName); + if (data.target == null) throw new SerializationException("Path target slot not found: " + targetName); + + data.positionMode = PositionMode.valueOf(constraintMap.getString("positionMode", "percent")); + data.spacingMode = SpacingMode.valueOf(constraintMap.getString("spacingMode", "length")); + data.rotateMode = RotateMode.valueOf(constraintMap.getString("rotateMode", "tangent")); + data.offsetRotation = constraintMap.getFloat("rotation", 0); + data.position = constraintMap.getFloat("position", 0); + if (data.positionMode == PositionMode.fixed) data.position *= scale; + data.spacing = constraintMap.getFloat("spacing", 0); + if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) data.spacing *= scale; + data.rotateMix = constraintMap.getFloat("rotateMix", 1); + data.translateMix = constraintMap.getFloat("translateMix", 1); + + skeletonData.pathConstraints.add(data); + } + + // Skins. + for (JsonValue skinMap = root.getChild("skins"); skinMap != null; skinMap = skinMap.next) { + Skin skin = new Skin(skinMap.name); + for (JsonValue slotEntry = skinMap.child; slotEntry != null; slotEntry = slotEntry.next) { + int slotIndex = skeletonData.findSlotIndex(slotEntry.name); + if (slotIndex == -1) throw new SerializationException("Slot not found: " + slotEntry.name); + for (JsonValue entry = slotEntry.child; entry != null; entry = entry.next) { + try { + Attachment attachment = readAttachment(entry, skin, slotIndex, entry.name); + if (attachment != null) skin.addAttachment(slotIndex, entry.name, attachment); + } catch (Exception ex) { + throw new SerializationException("Error reading attachment: " + entry.name + ", skin: " + skin, ex); + } + } + } + skeletonData.skins.add(skin); + if (skin.name.equals("default")) skeletonData.defaultSkin = skin; + } + + // Linked meshes. + for (int i = 0, n = linkedMeshes.size; i < n; i++) { + LinkedMesh linkedMesh = linkedMeshes.get(i); + Skin skin = linkedMesh.skin == null ? skeletonData.getDefaultSkin() : skeletonData.findSkin(linkedMesh.skin); + if (skin == null) throw new SerializationException("Skin not found: " + linkedMesh.skin); + Attachment parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); + if (parent == null) throw new SerializationException("Parent mesh not found: " + linkedMesh.parent); + linkedMesh.mesh.setParentMesh((MeshAttachment)parent); + linkedMesh.mesh.updateUVs(); + } + linkedMeshes.clear(); + + // Events. + for (JsonValue eventMap = root.getChild("events"); eventMap != null; eventMap = eventMap.next) { + EventData data = new EventData(eventMap.name); + data.intValue = eventMap.getInt("int", 0); + data.floatValue = eventMap.getFloat("float", 0f); + data.stringValue = eventMap.getString("string", null); + skeletonData.events.add(data); + } + + // Animations. + for (JsonValue animationMap = root.getChild("animations"); animationMap != null; animationMap = animationMap.next) { + try { + readAnimation(animationMap, animationMap.name, skeletonData); + } catch (Exception ex) { + throw new SerializationException("Error reading animation: " + animationMap.name, ex); + } + } + + skeletonData.bones.shrink(); + skeletonData.slots.shrink(); + skeletonData.skins.shrink(); + skeletonData.events.shrink(); + skeletonData.animations.shrink(); + skeletonData.ikConstraints.shrink(); + return skeletonData; + } + + private Attachment readAttachment (JsonValue map, Skin skin, int slotIndex, String name) { + float scale = this.scale; + name = map.getString("name", name); + + String type = map.getString("type", AttachmentType.region.name()); + + switch (AttachmentType.valueOf(type)) { + case region: { + String path = map.getString("path", name); + RegionAttachment region = attachmentLoader.newRegionAttachment(skin, name, path); + if (region == null) return null; + region.setPath(path); + region.setX(map.getFloat("x", 0) * scale); + region.setY(map.getFloat("y", 0) * scale); + region.setScaleX(map.getFloat("scaleX", 1)); + region.setScaleY(map.getFloat("scaleY", 1)); + region.setRotation(map.getFloat("rotation", 0)); + region.setWidth(map.getFloat("width") * scale); + region.setHeight(map.getFloat("height") * scale); + + String color = map.getString("color", null); + if (color != null) region.getColor().set(Color.valueOf(color)); + + region.updateOffset(); + return region; + } + case boundingbox: { + BoundingBoxAttachment box = attachmentLoader.newBoundingBoxAttachment(skin, name); + if (box == null) return null; + readVertices(map, box, map.getInt("vertexCount") << 1); + + String color = map.getString("color", null); + if (color != null) box.getColor().set(Color.valueOf(color)); + return box; + } + case mesh: + case linkedmesh: { + String path = map.getString("path", name); + MeshAttachment mesh = attachmentLoader.newMeshAttachment(skin, name, path); + if (mesh == null) return null; + mesh.setPath(path); + + String color = map.getString("color", null); + if (color != null) mesh.getColor().set(Color.valueOf(color)); + + mesh.setWidth(map.getFloat("width", 0) * scale); + mesh.setHeight(map.getFloat("height", 0) * scale); + + String parent = map.getString("parent", null); + if (parent != null) { + mesh.setInheritDeform(map.getBoolean("deform", true)); + linkedMeshes.add(new LinkedMesh(mesh, map.getString("skin", null), slotIndex, parent)); + return mesh; + } + + float[] uvs = map.require("uvs").asFloatArray(); + readVertices(map, mesh, uvs.length); + mesh.setTriangles(map.require("triangles").asShortArray()); + mesh.setRegionUVs(uvs); + mesh.updateUVs(); + + if (map.has("hull")) mesh.setHullLength(map.require("hull").asInt() * 2); + if (map.has("edges")) mesh.setEdges(map.require("edges").asShortArray()); + return mesh; + } + case path: { + PathAttachment path = attachmentLoader.newPathAttachment(skin, name); + if (path == null) return null; + path.setClosed(map.getBoolean("closed", false)); + path.setConstantSpeed(map.getBoolean("constantSpeed", true)); + + int vertexCount = map.getInt("vertexCount"); + readVertices(map, path, vertexCount << 1); + + float[] lengths = new float[vertexCount / 3]; + int i = 0; + for (JsonValue curves = map.require("lengths").child; curves != null; curves = curves.next) + lengths[i++] = curves.asFloat() * scale; + path.setLengths(lengths); + + String color = map.getString("color", null); + if (color != null) path.getColor().set(Color.valueOf(color)); + return path; + } + } + return null; + } + + private void readVertices (JsonValue map, VertexAttachment attachment, int verticesLength) { + attachment.setWorldVerticesLength(verticesLength); + float[] vertices = map.require("vertices").asFloatArray(); + if (verticesLength == vertices.length) { + if (scale != 1) { + for (int i = 0, n = vertices.length; i < n; i++) + vertices[i] *= scale; + } + attachment.setVertices(vertices); + return; + } + FloatArray weights = new FloatArray(verticesLength * 3 * 3); + IntArray bones = new IntArray(verticesLength * 3); + for (int i = 0, n = vertices.length; i < n;) { + int boneCount = (int)vertices[i++]; + bones.add(boneCount); + for (int nn = i + boneCount * 4; i < nn; i += 4) { + bones.add((int)vertices[i]); + weights.add(vertices[i + 1] * scale); + weights.add(vertices[i + 2] * scale); + weights.add(vertices[i + 3]); + } + } + attachment.setBones(bones.toArray()); + attachment.setVertices(weights.toArray()); + } + + private void readAnimation (JsonValue map, String name, SkeletonData skeletonData) { + float scale = this.scale; + Array timelines = new Array(); + float duration = 0; + + // Slot timelines. + for (JsonValue slotMap = map.getChild("slots"); slotMap != null; slotMap = slotMap.next) { + int slotIndex = skeletonData.findSlotIndex(slotMap.name); + if (slotIndex == -1) throw new SerializationException("Slot not found: " + slotMap.name); + for (JsonValue timelineMap = slotMap.child; timelineMap != null; timelineMap = timelineMap.next) { + String timelineName = timelineMap.name; + if (timelineName.equals("color")) { + ColorTimeline timeline = new ColorTimeline(timelineMap.size); + timeline.slotIndex = slotIndex; + + int frameIndex = 0; + for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) { + Color color = Color.valueOf(valueMap.getString("color")); + timeline.setFrame(frameIndex, valueMap.getFloat("time"), color.r, color.g, color.b, color.a); + readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[(timeline.getFrameCount() - 1) * ColorTimeline.ENTRIES]); + + } else if (timelineName.equals("attachment")) { + AttachmentTimeline timeline = new AttachmentTimeline(timelineMap.size); + timeline.slotIndex = slotIndex; + + int frameIndex = 0; + for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) + timeline.setFrame(frameIndex++, valueMap.getFloat("time"), valueMap.getString("name")); + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() - 1]); + } else + throw new RuntimeException("Invalid timeline type for a slot: " + timelineName + " (" + slotMap.name + ")"); + } + } + + // Bone timelines. + for (JsonValue boneMap = map.getChild("bones"); boneMap != null; boneMap = boneMap.next) { + int boneIndex = skeletonData.findBoneIndex(boneMap.name); + if (boneIndex == -1) throw new SerializationException("Bone not found: " + boneMap.name); + for (JsonValue timelineMap = boneMap.child; timelineMap != null; timelineMap = timelineMap.next) { + String timelineName = timelineMap.name; + if (timelineName.equals("rotate")) { + RotateTimeline timeline = new RotateTimeline(timelineMap.size); + timeline.boneIndex = boneIndex; + + int frameIndex = 0; + for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) { + timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat("angle")); + readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[(timeline.getFrameCount() - 1) * RotateTimeline.ENTRIES]); + + } else if (timelineName.equals("translate") || timelineName.equals("scale") || timelineName.equals("shear")) { + TranslateTimeline timeline; + float timelineScale = 1; + if (timelineName.equals("scale")) + timeline = new ScaleTimeline(timelineMap.size); + else if (timelineName.equals("shear")) + timeline = new ShearTimeline(timelineMap.size); + else { + timeline = new TranslateTimeline(timelineMap.size); + timelineScale = scale; + } + timeline.boneIndex = boneIndex; + + int frameIndex = 0; + for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) { + float x = valueMap.getFloat("x", 0), y = valueMap.getFloat("y", 0); + timeline.setFrame(frameIndex, valueMap.getFloat("time"), x * timelineScale, y * timelineScale); + readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[(timeline.getFrameCount() - 1) * TranslateTimeline.ENTRIES]); + + } else + throw new RuntimeException("Invalid timeline type for a bone: " + timelineName + " (" + boneMap.name + ")"); + } + } + + // IK constraint timelines. + for (JsonValue constraintMap = map.getChild("ik"); constraintMap != null; constraintMap = constraintMap.next) { + IkConstraintData constraint = skeletonData.findIkConstraint(constraintMap.name); + IkConstraintTimeline timeline = new IkConstraintTimeline(constraintMap.size); + timeline.ikConstraintIndex = skeletonData.getIkConstraints().indexOf(constraint, true); + int frameIndex = 0; + for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next) { + timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat("mix", 1), + valueMap.getBoolean("bendPositive", true) ? 1 : -1); + readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[(timeline.getFrameCount() - 1) * IkConstraintTimeline.ENTRIES]); + } + + // Transform constraint timelines. + for (JsonValue constraintMap = map.getChild("transform"); constraintMap != null; constraintMap = constraintMap.next) { + TransformConstraintData constraint = skeletonData.findTransformConstraint(constraintMap.name); + TransformConstraintTimeline timeline = new TransformConstraintTimeline(constraintMap.size); + timeline.transformConstraintIndex = skeletonData.getTransformConstraints().indexOf(constraint, true); + int frameIndex = 0; + for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next) { + timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat("rotateMix", 1), + valueMap.getFloat("translateMix", 1), valueMap.getFloat("scaleMix", 1), valueMap.getFloat("shearMix", 1)); + readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.add(timeline); + duration = Math.max(duration, + timeline.getFrames()[(timeline.getFrameCount() - 1) * TransformConstraintTimeline.ENTRIES]); + } + + // Path constraint timelines. + for (JsonValue constraintMap = map.getChild("paths"); constraintMap != null; constraintMap = constraintMap.next) { + int index = skeletonData.findPathConstraintIndex(constraintMap.name); + if (index == -1) throw new SerializationException("Path constraint not found: " + constraintMap.name); + PathConstraintData data = skeletonData.getPathConstraints().get(index); + for (JsonValue timelineMap = constraintMap.child; timelineMap != null; timelineMap = timelineMap.next) { + String timelineName = timelineMap.name; + if (timelineName.equals("position") || timelineName.equals("spacing")) { + PathConstraintPositionTimeline timeline; + float timelineScale = 1; + if (timelineName.equals("spacing")) { + timeline = new PathConstraintSpacingTimeline(timelineMap.size); + if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) timelineScale = scale; + } else { + timeline = new PathConstraintPositionTimeline(timelineMap.size); + if (data.positionMode == PositionMode.fixed) timelineScale = scale; + } + timeline.pathConstraintIndex = index; + int frameIndex = 0; + for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) { + timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat(timelineName, 0) * timelineScale); + readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.add(timeline); + duration = Math.max(duration, + timeline.getFrames()[(timeline.getFrameCount() - 1) * PathConstraintPositionTimeline.ENTRIES]); + } else if (timelineName.equals("mix")) { + PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(timelineMap.size); + timeline.pathConstraintIndex = index; + int frameIndex = 0; + for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) { + timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat("rotateMix", 1), + valueMap.getFloat("translateMix", 1)); + readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.add(timeline); + duration = Math.max(duration, + timeline.getFrames()[(timeline.getFrameCount() - 1) * PathConstraintMixTimeline.ENTRIES]); + } + } + } + + // Deform timelines. + for (JsonValue deformMap = map.getChild("deform"); deformMap != null; deformMap = deformMap.next) { + Skin skin = skeletonData.findSkin(deformMap.name); + if (skin == null) throw new SerializationException("Skin not found: " + deformMap.name); + for (JsonValue slotMap = deformMap.child; slotMap != null; slotMap = slotMap.next) { + int slotIndex = skeletonData.findSlotIndex(slotMap.name); + if (slotIndex == -1) throw new SerializationException("Slot not found: " + slotMap.name); + for (JsonValue timelineMap = slotMap.child; timelineMap != null; timelineMap = timelineMap.next) { + VertexAttachment attachment = (VertexAttachment)skin.getAttachment(slotIndex, timelineMap.name); + if (attachment == null) throw new SerializationException("Deform attachment not found: " + timelineMap.name); + boolean weighted = attachment.getBones() != null; + float[] vertices = attachment.getVertices(); + int deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; + + DeformTimeline timeline = new DeformTimeline(timelineMap.size); + timeline.slotIndex = slotIndex; + timeline.attachment = attachment; + + int frameIndex = 0; + for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) { + float[] deform; + JsonValue verticesValue = valueMap.get("vertices"); + if (verticesValue == null) + deform = weighted ? new float[deformLength] : vertices; + else { + deform = new float[deformLength]; + int start = valueMap.getInt("offset", 0); + System.arraycopy(verticesValue.asFloatArray(), 0, deform, start, verticesValue.size); + if (scale != 1) { + for (int i = start, n = i + verticesValue.size; i < n; i++) + deform[i] *= scale; + } + if (!weighted) { + for (int i = 0; i < deformLength; i++) + deform[i] += vertices[i]; + } + } + + timeline.setFrame(frameIndex, valueMap.getFloat("time"), deform); + readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() - 1]); + } + } + } + + // Draw order timeline. + JsonValue drawOrdersMap = map.get("drawOrder"); + if (drawOrdersMap == null) drawOrdersMap = map.get("draworder"); + if (drawOrdersMap != null) { + DrawOrderTimeline timeline = new DrawOrderTimeline(drawOrdersMap.size); + int slotCount = skeletonData.slots.size; + int frameIndex = 0; + for (JsonValue drawOrderMap = drawOrdersMap.child; drawOrderMap != null; drawOrderMap = drawOrderMap.next) { + int[] drawOrder = null; + JsonValue offsets = drawOrderMap.get("offsets"); + if (offsets != null) { + drawOrder = new int[slotCount]; + for (int i = slotCount - 1; i >= 0; i--) + drawOrder[i] = -1; + int[] unchanged = new int[slotCount - offsets.size]; + int originalIndex = 0, unchangedIndex = 0; + for (JsonValue offsetMap = offsets.child; offsetMap != null; offsetMap = offsetMap.next) { + int slotIndex = skeletonData.findSlotIndex(offsetMap.getString("slot")); + if (slotIndex == -1) throw new SerializationException("Slot not found: " + offsetMap.getString("slot")); + // Collect unchanged items. + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + // Set changed items. + drawOrder[originalIndex + offsetMap.getInt("offset")] = originalIndex++; + } + // Collect remaining unchanged items. + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + // Fill in unchanged items. + for (int i = slotCount - 1; i >= 0; i--) + if (drawOrder[i] == -1) drawOrder[i] = unchanged[--unchangedIndex]; + } + timeline.setFrame(frameIndex++, drawOrderMap.getFloat("time"), drawOrder); + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() - 1]); + } + + // Event timeline. + JsonValue eventsMap = map.get("events"); + if (eventsMap != null) { + EventTimeline timeline = new EventTimeline(eventsMap.size); + int frameIndex = 0; + for (JsonValue eventMap = eventsMap.child; eventMap != null; eventMap = eventMap.next) { + EventData eventData = skeletonData.findEvent(eventMap.getString("name")); + if (eventData == null) throw new SerializationException("Event not found: " + eventMap.getString("name")); + Event event = new Event(eventMap.getFloat("time"), eventData); + event.intValue = eventMap.getInt("int", eventData.getInt()); + event.floatValue = eventMap.getFloat("float", eventData.getFloat()); + event.stringValue = eventMap.getString("string", eventData.getString()); + timeline.setFrame(frameIndex++, event); + } + timelines.add(timeline); + duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() - 1]); + } + + timelines.shrink(); + skeletonData.animations.add(new Animation(name, timelines, duration)); + } + + void readCurve (JsonValue map, CurveTimeline timeline, int frameIndex) { + JsonValue curve = map.get("curve"); + if (curve == null) return; + if (curve.isString() && curve.asString().equals("stepped")) + timeline.setStepped(frameIndex); + else if (curve.isArray()) { + timeline.setCurve(frameIndex, curve.getFloat(0), curve.getFloat(1), curve.getFloat(2), curve.getFloat(3)); + } + } + + static class LinkedMesh { + String parent, skin; + int slotIndex; + MeshAttachment mesh; + + public LinkedMesh (MeshAttachment mesh, String skin, int slotIndex, String parent) { + this.mesh = mesh; + this.skin = skin; + this.slotIndex = slotIndex; + this.parent = parent; + } + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonMeshRenderer.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonMeshRenderer.java index dcd7c02856..03f17b898f 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonMeshRenderer.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonMeshRenderer.java @@ -1,98 +1,97 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch; -import com.badlogic.gdx.utils.Array; -import com.esotericsoftware.spine.attachments.Attachment; -import com.esotericsoftware.spine.attachments.MeshAttachment; -import com.esotericsoftware.spine.attachments.RegionAttachment; -import com.esotericsoftware.spine.attachments.SkeletonAttachment; - -public class SkeletonMeshRenderer extends SkeletonRenderer { - static private final short[] quadTriangles = {0, 1, 2, 2, 3, 0}; - - @SuppressWarnings("null") - public void draw (PolygonSpriteBatch batch, Skeleton skeleton) { - boolean premultipliedAlpha = this.premultipliedAlpha; - - float[] vertices = null; - short[] triangles = null; - Array drawOrder = skeleton.drawOrder; - for (int i = 0, n = drawOrder.size; i < n; i++) { - Slot slot = drawOrder.get(i); - Attachment attachment = slot.attachment; - Texture texture = null; - if (attachment instanceof RegionAttachment) { - RegionAttachment region = (RegionAttachment)attachment; - vertices = region.updateWorldVertices(slot, premultipliedAlpha); - triangles = quadTriangles; - texture = region.getRegion().getTexture(); - - } else if (attachment instanceof MeshAttachment) { - MeshAttachment mesh = (MeshAttachment)attachment; - vertices = mesh.updateWorldVertices(slot, premultipliedAlpha); - triangles = mesh.getTriangles(); - texture = mesh.getRegion().getTexture(); - - } else if (attachment instanceof SkeletonAttachment) { - Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton(); - if (attachmentSkeleton == null) continue; - Bone bone = slot.getBone(); - Bone rootBone = attachmentSkeleton.getRootBone(); - float oldScaleX = rootBone.getScaleX(); - float oldScaleY = rootBone.getScaleY(); - float oldRotation = rootBone.getRotation(); - attachmentSkeleton.setPosition(skeleton.getX() + bone.getWorldX(), skeleton.getY() + bone.getWorldY()); - // rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX); - // rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY); - // Set shear. - rootBone.setRotation(oldRotation + bone.getWorldRotationX()); - attachmentSkeleton.updateWorldTransform(); - - draw(batch, attachmentSkeleton); - - attachmentSkeleton.setPosition(0, 0); - rootBone.setScaleX(oldScaleX); - rootBone.setScaleY(oldScaleY); - rootBone.setRotation(oldRotation); - } - - if (texture != null) { - BlendMode blendMode = slot.data.getBlendMode(); - batch.setBlendFunction(blendMode.getSource(premultipliedAlpha), blendMode.getDest()); - batch.draw(texture, vertices, 0, vertices.length, triangles, 0, triangles.length); - } - } - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch; +import com.badlogic.gdx.utils.Array; +import com.esotericsoftware.spine.attachments.Attachment; +import com.esotericsoftware.spine.attachments.MeshAttachment; +import com.esotericsoftware.spine.attachments.RegionAttachment; +import com.esotericsoftware.spine.attachments.SkeletonAttachment; + +public class SkeletonMeshRenderer extends SkeletonRenderer { + static private final short[] quadTriangles = {0, 1, 2, 2, 3, 0}; + + @SuppressWarnings("null") + public void draw (PolygonSpriteBatch batch, Skeleton skeleton) { + boolean premultipliedAlpha = this.premultipliedAlpha; + + float[] vertices = null; + short[] triangles = null; + Array drawOrder = skeleton.drawOrder; + for (int i = 0, n = drawOrder.size; i < n; i++) { + Slot slot = drawOrder.get(i); + Attachment attachment = slot.attachment; + Texture texture = null; + if (attachment instanceof RegionAttachment) { + RegionAttachment region = (RegionAttachment)attachment; + vertices = region.updateWorldVertices(slot, premultipliedAlpha); + triangles = quadTriangles; + texture = region.getRegion().getTexture(); + + } else if (attachment instanceof MeshAttachment) { + MeshAttachment mesh = (MeshAttachment)attachment; + vertices = mesh.updateWorldVertices(slot, premultipliedAlpha); + triangles = mesh.getTriangles(); + texture = mesh.getRegion().getTexture(); + + } else if (attachment instanceof SkeletonAttachment) { + Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton(); + if (attachmentSkeleton == null) continue; + Bone bone = slot.getBone(); + Bone rootBone = attachmentSkeleton.getRootBone(); + float oldScaleX = rootBone.getScaleX(); + float oldScaleY = rootBone.getScaleY(); + float oldRotation = rootBone.getRotation(); + attachmentSkeleton.setPosition(skeleton.getX() + bone.getWorldX(), skeleton.getY() + bone.getWorldY()); + // rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX); + // rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY); + // Set shear. + rootBone.setRotation(oldRotation + bone.getWorldRotationX()); + attachmentSkeleton.updateWorldTransform(); + + draw(batch, attachmentSkeleton); + + attachmentSkeleton.setPosition(0, 0); + rootBone.setScaleX(oldScaleX); + rootBone.setScaleY(oldScaleY); + rootBone.setRotation(oldRotation); + } + + if (texture != null) { + BlendMode blendMode = slot.data.getBlendMode(); + batch.setBlendFunction(blendMode.getSource(premultipliedAlpha), blendMode.getDest()); + batch.draw(texture, vertices, 0, vertices.length, triangles, 0, triangles.length); + } + } + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java index a26715590a..5b6bd0c626 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java @@ -1,90 +1,89 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.graphics.g2d.Batch; -import com.badlogic.gdx.utils.Array; -import com.esotericsoftware.spine.attachments.Attachment; -import com.esotericsoftware.spine.attachments.RegionAttachment; -import com.esotericsoftware.spine.attachments.SkeletonAttachment; -import com.esotericsoftware.spine.attachments.MeshAttachment; - -public class SkeletonRenderer { - boolean premultipliedAlpha; - - public void draw (T batch, Skeleton skeleton) { - boolean premultipliedAlpha = this.premultipliedAlpha; - - Array drawOrder = skeleton.drawOrder; - for (int i = 0, n = drawOrder.size; i < n; i++) { - Slot slot = drawOrder.get(i); - Attachment attachment = slot.attachment; - if (attachment instanceof RegionAttachment) { - RegionAttachment regionAttachment = (RegionAttachment)attachment; - float[] vertices = regionAttachment.updateWorldVertices(slot, premultipliedAlpha); - BlendMode blendMode = slot.data.getBlendMode(); - batch.setBlendFunction(blendMode.getSource(premultipliedAlpha), blendMode.getDest()); - batch.draw(regionAttachment.getRegion().getTexture(), vertices, 0, 20); - - } else if (attachment instanceof MeshAttachment) { - throw new RuntimeException("SkeletonMeshRenderer is required to render meshes."); - - } else if (attachment instanceof SkeletonAttachment) { - Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton(); - if (attachmentSkeleton == null) continue; - Bone bone = slot.getBone(); - Bone rootBone = attachmentSkeleton.getRootBone(); - float oldScaleX = rootBone.getScaleX(); - float oldScaleY = rootBone.getScaleY(); - float oldRotation = rootBone.getRotation(); - attachmentSkeleton.setPosition(skeleton.getX() + bone.getWorldX(), skeleton.getY() + bone.getWorldY()); - // rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX); - // rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY); - // Set shear. - rootBone.setRotation(oldRotation + bone.getWorldRotationX()); - attachmentSkeleton.updateWorldTransform(); - - draw(batch, attachmentSkeleton); - - attachmentSkeleton.setX(0); - attachmentSkeleton.setY(0); - rootBone.setScaleX(oldScaleX); - rootBone.setScaleY(oldScaleY); - rootBone.setRotation(oldRotation); - } - } - } - - public void setPremultipliedAlpha (boolean premultipliedAlpha) { - this.premultipliedAlpha = premultipliedAlpha; - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.utils.Array; +import com.esotericsoftware.spine.attachments.Attachment; +import com.esotericsoftware.spine.attachments.RegionAttachment; +import com.esotericsoftware.spine.attachments.SkeletonAttachment; +import com.esotericsoftware.spine.attachments.MeshAttachment; + +public class SkeletonRenderer { + boolean premultipliedAlpha; + + public void draw (T batch, Skeleton skeleton) { + boolean premultipliedAlpha = this.premultipliedAlpha; + + Array drawOrder = skeleton.drawOrder; + for (int i = 0, n = drawOrder.size; i < n; i++) { + Slot slot = drawOrder.get(i); + Attachment attachment = slot.attachment; + if (attachment instanceof RegionAttachment) { + RegionAttachment regionAttachment = (RegionAttachment)attachment; + float[] vertices = regionAttachment.updateWorldVertices(slot, premultipliedAlpha); + BlendMode blendMode = slot.data.getBlendMode(); + batch.setBlendFunction(blendMode.getSource(premultipliedAlpha), blendMode.getDest()); + batch.draw(regionAttachment.getRegion().getTexture(), vertices, 0, 20); + + } else if (attachment instanceof MeshAttachment) { + throw new RuntimeException("SkeletonMeshRenderer is required to render meshes."); + + } else if (attachment instanceof SkeletonAttachment) { + Skeleton attachmentSkeleton = ((SkeletonAttachment)attachment).getSkeleton(); + if (attachmentSkeleton == null) continue; + Bone bone = slot.getBone(); + Bone rootBone = attachmentSkeleton.getRootBone(); + float oldScaleX = rootBone.getScaleX(); + float oldScaleY = rootBone.getScaleY(); + float oldRotation = rootBone.getRotation(); + attachmentSkeleton.setPosition(skeleton.getX() + bone.getWorldX(), skeleton.getY() + bone.getWorldY()); + // rootBone.setScaleX(1 + bone.getWorldScaleX() - oldScaleX); + // rootBone.setScaleY(1 + bone.getWorldScaleY() - oldScaleY); + // Set shear. + rootBone.setRotation(oldRotation + bone.getWorldRotationX()); + attachmentSkeleton.updateWorldTransform(); + + draw(batch, attachmentSkeleton); + + attachmentSkeleton.setX(0); + attachmentSkeleton.setY(0); + rootBone.setScaleX(oldScaleX); + rootBone.setScaleY(oldScaleY); + rootBone.setRotation(oldRotation); + } + } + } + + public void setPremultipliedAlpha (boolean premultipliedAlpha) { + this.premultipliedAlpha = premultipliedAlpha; + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRendererDebug.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRendererDebug.java index 9aabd2662f..390a59208b 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRendererDebug.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRendererDebug.java @@ -1,255 +1,254 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import static com.badlogic.gdx.graphics.g2d.Batch.*; - -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.glutils.ShapeRenderer; -import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.FloatArray; -import com.esotericsoftware.spine.attachments.Attachment; -import com.esotericsoftware.spine.attachments.BoundingBoxAttachment; -import com.esotericsoftware.spine.attachments.MeshAttachment; -import com.esotericsoftware.spine.attachments.PathAttachment; -import com.esotericsoftware.spine.attachments.RegionAttachment; - -public class SkeletonRendererDebug { - static private final Color boneLineColor = Color.RED; - static private final Color boneOriginColor = Color.GREEN; - static private final Color attachmentLineColor = new Color(0, 0, 1, 0.5f); - static private final Color triangleLineColor = new Color(1, 0.64f, 0, 0.5f); - static private final Color aabbColor = new Color(0, 1, 0, 0.5f); - - private final ShapeRenderer shapes; - private boolean drawBones = true, drawRegionAttachments = true, drawBoundingBoxes = true; - private boolean drawMeshHull = true, drawMeshTriangles = true, drawPaths = true; - private final SkeletonBounds bounds = new SkeletonBounds(); - private final FloatArray temp = new FloatArray(); - private float scale = 1; - private float boneWidth = 2; - private boolean premultipliedAlpha; - - public SkeletonRendererDebug () { - shapes = new ShapeRenderer(); - } - - public SkeletonRendererDebug (ShapeRenderer shapes) { - this.shapes = shapes; - } - - public void draw (Skeleton skeleton) { - float skeletonX = skeleton.getX(); - float skeletonY = skeleton.getY(); - - Gdx.gl.glEnable(GL20.GL_BLEND); - int srcFunc = premultipliedAlpha ? GL20.GL_ONE : GL20.GL_SRC_ALPHA; - Gdx.gl.glBlendFunc(srcFunc, GL20.GL_ONE_MINUS_SRC_ALPHA); - - ShapeRenderer shapes = this.shapes; - - Array bones = skeleton.getBones(); - if (drawBones) { - shapes.setColor(boneLineColor); - shapes.begin(ShapeType.Filled); - for (int i = 0, n = bones.size; i < n; i++) { - Bone bone = bones.get(i); - if (bone.parent == null) continue; - float x = skeletonX + bone.data.length * bone.a + bone.worldX; - float y = skeletonY + bone.data.length * bone.c + bone.worldY; - shapes.rectLine(skeletonX + bone.worldX, skeletonY + bone.worldY, x, y, boneWidth * scale); - } - shapes.end(); - shapes.begin(ShapeType.Line); - shapes.x(skeletonX, skeletonY, 4 * scale); - } else - shapes.begin(ShapeType.Line); - - if (drawRegionAttachments) { - shapes.setColor(attachmentLineColor); - Array slots = skeleton.getSlots(); - for (int i = 0, n = slots.size; i < n; i++) { - Slot slot = slots.get(i); - Attachment attachment = slot.attachment; - if (attachment instanceof RegionAttachment) { - RegionAttachment regionAttachment = (RegionAttachment)attachment; - float[] vertices = regionAttachment.updateWorldVertices(slot, false); - shapes.line(vertices[X1], vertices[Y1], vertices[X2], vertices[Y2]); - shapes.line(vertices[X2], vertices[Y2], vertices[X3], vertices[Y3]); - shapes.line(vertices[X3], vertices[Y3], vertices[X4], vertices[Y4]); - shapes.line(vertices[X4], vertices[Y4], vertices[X1], vertices[Y1]); - } - } - } - - if (drawMeshHull || drawMeshTriangles) { - Array slots = skeleton.getSlots(); - for (int i = 0, n = slots.size; i < n; i++) { - Slot slot = slots.get(i); - Attachment attachment = slot.attachment; - if (!(attachment instanceof MeshAttachment)) continue; - MeshAttachment mesh = (MeshAttachment)attachment; - mesh.updateWorldVertices(slot, false); - float[] vertices = mesh.getWorldVertices(); - short[] triangles = mesh.getTriangles(); - int hullLength = mesh.getHullLength(); - if (drawMeshTriangles) { - shapes.setColor(triangleLineColor); - for (int ii = 0, nn = triangles.length; ii < nn; ii += 3) { - int v1 = triangles[ii] * 5, v2 = triangles[ii + 1] * 5, v3 = triangles[ii + 2] * 5; - shapes.triangle(vertices[v1], vertices[v1 + 1], // - vertices[v2], vertices[v2 + 1], // - vertices[v3], vertices[v3 + 1] // - ); - } - } - if (drawMeshHull && hullLength > 0) { - shapes.setColor(attachmentLineColor); - hullLength = (hullLength >> 1) * 5; - float lastX = vertices[hullLength - 5], lastY = vertices[hullLength - 4]; - for (int ii = 0, nn = hullLength; ii < nn; ii += 5) { - float x = vertices[ii], y = vertices[ii + 1]; - shapes.line(x, y, lastX, lastY); - lastX = x; - lastY = y; - } - } - } - } - - if (drawBoundingBoxes) { - SkeletonBounds bounds = this.bounds; - bounds.update(skeleton, true); - shapes.setColor(aabbColor); - shapes.rect(bounds.getMinX(), bounds.getMinY(), bounds.getWidth(), bounds.getHeight()); - Array polygons = bounds.getPolygons(); - Array boxes = bounds.getBoundingBoxes(); - for (int i = 0, n = polygons.size; i < n; i++) { - FloatArray polygon = polygons.get(i); - shapes.setColor(boxes.get(i).getColor()); - shapes.polygon(polygon.items, 0, polygon.size); - } - } - - if (drawPaths) { - Array slots = skeleton.getSlots(); - for (int i = 0, n = slots.size; i < n; i++) { - Slot slot = slots.get(i); - Attachment attachment = slot.attachment; - if (!(attachment instanceof PathAttachment)) continue; - PathAttachment path = (PathAttachment)attachment; - int nn = path.getWorldVerticesLength(); - float[] world = temp.setSize(nn); - path.computeWorldVertices(slot, world); - Color color = path.getColor(); - float x1 = world[2], y1 = world[3], x2 = 0, y2 = 0; - if (path.getClosed()) { - shapes.setColor(color); - float cx1 = world[0], cy1 = world[1], cx2 = world[nn - 2], cy2 = world[nn - 1]; - x2 = world[nn - 4]; - y2 = world[nn - 3]; - shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, 32); - shapes.setColor(Color.LIGHT_GRAY); - shapes.line(x1, y1, cx1, cy1); - shapes.line(x2, y2, cx2, cy2); - } - nn -= 4; - for (int ii = 4; ii < nn; ii += 6) { - float cx1 = world[ii], cy1 = world[ii + 1], cx2 = world[ii + 2], cy2 = world[ii + 3]; - x2 = world[ii + 4]; - y2 = world[ii + 5]; - shapes.setColor(color); - shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, 32); - shapes.setColor(Color.LIGHT_GRAY); - shapes.line(x1, y1, cx1, cy1); - shapes.line(x2, y2, cx2, cy2); - x1 = x2; - y1 = y2; - } - } - } - - shapes.end(); - shapes.begin(ShapeType.Filled); - - if (drawBones) { - shapes.setColor(boneOriginColor); - for (int i = 0, n = bones.size; i < n; i++) { - Bone bone = bones.get(i); - shapes.setColor(Color.GREEN); - shapes.circle(skeletonX + bone.worldX, skeletonY + bone.worldY, 3 * scale, 8); - } - } - - shapes.end(); - - } - - public ShapeRenderer getShapeRenderer () { - return shapes; - } - - public void setBones (boolean bones) { - this.drawBones = bones; - } - - public void setScale (float scale) { - this.scale = scale; - } - - public void setRegionAttachments (boolean regionAttachments) { - this.drawRegionAttachments = regionAttachments; - } - - public void setBoundingBoxes (boolean boundingBoxes) { - this.drawBoundingBoxes = boundingBoxes; - } - - public void setMeshHull (boolean meshHull) { - this.drawMeshHull = meshHull; - } - - public void setMeshTriangles (boolean meshTriangles) { - this.drawMeshTriangles = meshTriangles; - } - - public void setPaths (boolean paths) { - this.drawPaths = paths; - } - - public void setPremultipliedAlpha (boolean premultipliedAlpha) { - this.premultipliedAlpha = premultipliedAlpha; - } +package com.esotericsoftware.spine; + +import static com.badlogic.gdx.graphics.g2d.Batch.*; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.FloatArray; +import com.esotericsoftware.spine.attachments.Attachment; +import com.esotericsoftware.spine.attachments.BoundingBoxAttachment; +import com.esotericsoftware.spine.attachments.MeshAttachment; +import com.esotericsoftware.spine.attachments.PathAttachment; +import com.esotericsoftware.spine.attachments.RegionAttachment; + +public class SkeletonRendererDebug { + static private final Color boneLineColor = Color.RED; + static private final Color boneOriginColor = Color.GREEN; + static private final Color attachmentLineColor = new Color(0, 0, 1, 0.5f); + static private final Color triangleLineColor = new Color(1, 0.64f, 0, 0.5f); + static private final Color aabbColor = new Color(0, 1, 0, 0.5f); + + private final ShapeRenderer shapes; + private boolean drawBones = true, drawRegionAttachments = true, drawBoundingBoxes = true; + private boolean drawMeshHull = true, drawMeshTriangles = true, drawPaths = true; + private final SkeletonBounds bounds = new SkeletonBounds(); + private final FloatArray temp = new FloatArray(); + private float scale = 1; + private float boneWidth = 2; + private boolean premultipliedAlpha; + + public SkeletonRendererDebug () { + shapes = new ShapeRenderer(); + } + + public SkeletonRendererDebug (ShapeRenderer shapes) { + this.shapes = shapes; + } + + public void draw (Skeleton skeleton) { + float skeletonX = skeleton.getX(); + float skeletonY = skeleton.getY(); + + Gdx.gl.glEnable(GL20.GL_BLEND); + int srcFunc = premultipliedAlpha ? GL20.GL_ONE : GL20.GL_SRC_ALPHA; + Gdx.gl.glBlendFunc(srcFunc, GL20.GL_ONE_MINUS_SRC_ALPHA); + + ShapeRenderer shapes = this.shapes; + + Array bones = skeleton.getBones(); + if (drawBones) { + shapes.setColor(boneLineColor); + shapes.begin(ShapeType.Filled); + for (int i = 0, n = bones.size; i < n; i++) { + Bone bone = bones.get(i); + if (bone.parent == null) continue; + float x = skeletonX + bone.data.length * bone.a + bone.worldX; + float y = skeletonY + bone.data.length * bone.c + bone.worldY; + shapes.rectLine(skeletonX + bone.worldX, skeletonY + bone.worldY, x, y, boneWidth * scale); + } + shapes.end(); + shapes.begin(ShapeType.Line); + shapes.x(skeletonX, skeletonY, 4 * scale); + } else + shapes.begin(ShapeType.Line); + + if (drawRegionAttachments) { + shapes.setColor(attachmentLineColor); + Array slots = skeleton.getSlots(); + for (int i = 0, n = slots.size; i < n; i++) { + Slot slot = slots.get(i); + Attachment attachment = slot.attachment; + if (attachment instanceof RegionAttachment) { + RegionAttachment regionAttachment = (RegionAttachment)attachment; + float[] vertices = regionAttachment.updateWorldVertices(slot, false); + shapes.line(vertices[X1], vertices[Y1], vertices[X2], vertices[Y2]); + shapes.line(vertices[X2], vertices[Y2], vertices[X3], vertices[Y3]); + shapes.line(vertices[X3], vertices[Y3], vertices[X4], vertices[Y4]); + shapes.line(vertices[X4], vertices[Y4], vertices[X1], vertices[Y1]); + } + } + } + + if (drawMeshHull || drawMeshTriangles) { + Array slots = skeleton.getSlots(); + for (int i = 0, n = slots.size; i < n; i++) { + Slot slot = slots.get(i); + Attachment attachment = slot.attachment; + if (!(attachment instanceof MeshAttachment)) continue; + MeshAttachment mesh = (MeshAttachment)attachment; + mesh.updateWorldVertices(slot, false); + float[] vertices = mesh.getWorldVertices(); + short[] triangles = mesh.getTriangles(); + int hullLength = mesh.getHullLength(); + if (drawMeshTriangles) { + shapes.setColor(triangleLineColor); + for (int ii = 0, nn = triangles.length; ii < nn; ii += 3) { + int v1 = triangles[ii] * 5, v2 = triangles[ii + 1] * 5, v3 = triangles[ii + 2] * 5; + shapes.triangle(vertices[v1], vertices[v1 + 1], // + vertices[v2], vertices[v2 + 1], // + vertices[v3], vertices[v3 + 1] // + ); + } + } + if (drawMeshHull && hullLength > 0) { + shapes.setColor(attachmentLineColor); + hullLength = (hullLength >> 1) * 5; + float lastX = vertices[hullLength - 5], lastY = vertices[hullLength - 4]; + for (int ii = 0, nn = hullLength; ii < nn; ii += 5) { + float x = vertices[ii], y = vertices[ii + 1]; + shapes.line(x, y, lastX, lastY); + lastX = x; + lastY = y; + } + } + } + } + + if (drawBoundingBoxes) { + SkeletonBounds bounds = this.bounds; + bounds.update(skeleton, true); + shapes.setColor(aabbColor); + shapes.rect(bounds.getMinX(), bounds.getMinY(), bounds.getWidth(), bounds.getHeight()); + Array polygons = bounds.getPolygons(); + Array boxes = bounds.getBoundingBoxes(); + for (int i = 0, n = polygons.size; i < n; i++) { + FloatArray polygon = polygons.get(i); + shapes.setColor(boxes.get(i).getColor()); + shapes.polygon(polygon.items, 0, polygon.size); + } + } + + if (drawPaths) { + Array slots = skeleton.getSlots(); + for (int i = 0, n = slots.size; i < n; i++) { + Slot slot = slots.get(i); + Attachment attachment = slot.attachment; + if (!(attachment instanceof PathAttachment)) continue; + PathAttachment path = (PathAttachment)attachment; + int nn = path.getWorldVerticesLength(); + float[] world = temp.setSize(nn); + path.computeWorldVertices(slot, world); + Color color = path.getColor(); + float x1 = world[2], y1 = world[3], x2 = 0, y2 = 0; + if (path.getClosed()) { + shapes.setColor(color); + float cx1 = world[0], cy1 = world[1], cx2 = world[nn - 2], cy2 = world[nn - 1]; + x2 = world[nn - 4]; + y2 = world[nn - 3]; + shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, 32); + shapes.setColor(Color.LIGHT_GRAY); + shapes.line(x1, y1, cx1, cy1); + shapes.line(x2, y2, cx2, cy2); + } + nn -= 4; + for (int ii = 4; ii < nn; ii += 6) { + float cx1 = world[ii], cy1 = world[ii + 1], cx2 = world[ii + 2], cy2 = world[ii + 3]; + x2 = world[ii + 4]; + y2 = world[ii + 5]; + shapes.setColor(color); + shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, 32); + shapes.setColor(Color.LIGHT_GRAY); + shapes.line(x1, y1, cx1, cy1); + shapes.line(x2, y2, cx2, cy2); + x1 = x2; + y1 = y2; + } + } + } + + shapes.end(); + shapes.begin(ShapeType.Filled); + + if (drawBones) { + shapes.setColor(boneOriginColor); + for (int i = 0, n = bones.size; i < n; i++) { + Bone bone = bones.get(i); + shapes.setColor(Color.GREEN); + shapes.circle(skeletonX + bone.worldX, skeletonY + bone.worldY, 3 * scale, 8); + } + } + + shapes.end(); + + } + + public ShapeRenderer getShapeRenderer () { + return shapes; + } + + public void setBones (boolean bones) { + this.drawBones = bones; + } + + public void setScale (float scale) { + this.scale = scale; + } + + public void setRegionAttachments (boolean regionAttachments) { + this.drawRegionAttachments = regionAttachments; + } + + public void setBoundingBoxes (boolean boundingBoxes) { + this.drawBoundingBoxes = boundingBoxes; + } + + public void setMeshHull (boolean meshHull) { + this.drawMeshHull = meshHull; + } + + public void setMeshTriangles (boolean meshTriangles) { + this.drawMeshTriangles = meshTriangles; + } + + public void setPaths (boolean paths) { + this.drawPaths = paths; + } + + public void setPremultipliedAlpha (boolean premultipliedAlpha) { + this.premultipliedAlpha = premultipliedAlpha; + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skin.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skin.java index 048de25486..3316f63a61 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skin.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skin.java @@ -1,146 +1,145 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import java.util.Iterator; - -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.ObjectMap; -import com.badlogic.gdx.utils.ObjectMap.Entry; -import com.badlogic.gdx.utils.Pool; -import com.esotericsoftware.spine.attachments.Attachment; - -/** Stores attachments by slot index and attachment name. */ -public class Skin { - static private final Key lookup = new Key(); - - final String name; - final ObjectMap attachments = new ObjectMap(); - final Pool keyPool = new Pool(64) { - protected Object newObject () { - return new Key(); - } - }; - - public Skin (String name) { - if (name == null) throw new IllegalArgumentException("name cannot be null."); - this.name = name; - } - - public void addAttachment (int slotIndex, String name, Attachment attachment) { - if (attachment == null) throw new IllegalArgumentException("attachment cannot be null."); - if (slotIndex < 0) throw new IllegalArgumentException("slotIndex must be >= 0."); - Key key = keyPool.obtain(); - key.set(slotIndex, name); - attachments.put(key, attachment); - } - - /** @return May be null. */ - public Attachment getAttachment (int slotIndex, String name) { - if (slotIndex < 0) throw new IllegalArgumentException("slotIndex must be >= 0."); - lookup.set(slotIndex, name); - return attachments.get(lookup); - } - - public void findNamesForSlot (int slotIndex, Array names) { - if (names == null) throw new IllegalArgumentException("names cannot be null."); - if (slotIndex < 0) throw new IllegalArgumentException("slotIndex must be >= 0."); - for (Key key : attachments.keys()) - if (key.slotIndex == slotIndex) names.add(key.name); - } - - public void findAttachmentsForSlot (int slotIndex, Array attachments) { - if (attachments == null) throw new IllegalArgumentException("attachments cannot be null."); - if (slotIndex < 0) throw new IllegalArgumentException("slotIndex must be >= 0."); - for (Entry entry : this.attachments.entries()) - if (entry.key.slotIndex == slotIndex) attachments.add(entry.value); - } - - public void clear () { - for (Key key : attachments.keys()) - keyPool.free(key); - attachments.clear(); - } - - public String getName () { - return name; - } - - public Iterator attachments () { - return attachments.values().iterator(); - } - - public String toString () { - return name; - } - - /** Attach each attachment in this skin if the corresponding attachment in the old skin is currently attached. */ - void attachAll (Skeleton skeleton, Skin oldSkin) { - for (Entry entry : oldSkin.attachments.entries()) { - int slotIndex = entry.key.slotIndex; - Slot slot = skeleton.slots.get(slotIndex); - if (slot.attachment == entry.value) { - Attachment attachment = getAttachment(slotIndex, entry.key.name); - if (attachment != null) slot.setAttachment(attachment); - } - } - } - - static class Key { - int slotIndex; - String name; - int hashCode; - - public void set (int slotIndex, String name) { - if (name == null) throw new IllegalArgumentException("name cannot be null."); - this.slotIndex = slotIndex; - this.name = name; - hashCode = 31 * (31 + name.hashCode()) + slotIndex; - } - - public int hashCode () { - return hashCode; - } - - public boolean equals (Object object) { - if (object == null) return false; - Key other = (Key)object; - if (slotIndex != other.slotIndex) return false; - if (!name.equals(other.name)) return false; - return true; - } - - public String toString () { - return slotIndex + ":" + name; - } - } +package com.esotericsoftware.spine; + +import java.util.Iterator; + +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.ObjectMap; +import com.badlogic.gdx.utils.ObjectMap.Entry; +import com.badlogic.gdx.utils.Pool; +import com.esotericsoftware.spine.attachments.Attachment; + +/** Stores attachments by slot index and attachment name. */ +public class Skin { + static private final Key lookup = new Key(); + + final String name; + final ObjectMap attachments = new ObjectMap(); + final Pool keyPool = new Pool(64) { + protected Object newObject () { + return new Key(); + } + }; + + public Skin (String name) { + if (name == null) throw new IllegalArgumentException("name cannot be null."); + this.name = name; + } + + public void addAttachment (int slotIndex, String name, Attachment attachment) { + if (attachment == null) throw new IllegalArgumentException("attachment cannot be null."); + if (slotIndex < 0) throw new IllegalArgumentException("slotIndex must be >= 0."); + Key key = keyPool.obtain(); + key.set(slotIndex, name); + attachments.put(key, attachment); + } + + /** @return May be null. */ + public Attachment getAttachment (int slotIndex, String name) { + if (slotIndex < 0) throw new IllegalArgumentException("slotIndex must be >= 0."); + lookup.set(slotIndex, name); + return attachments.get(lookup); + } + + public void findNamesForSlot (int slotIndex, Array names) { + if (names == null) throw new IllegalArgumentException("names cannot be null."); + if (slotIndex < 0) throw new IllegalArgumentException("slotIndex must be >= 0."); + for (Key key : attachments.keys()) + if (key.slotIndex == slotIndex) names.add(key.name); + } + + public void findAttachmentsForSlot (int slotIndex, Array attachments) { + if (attachments == null) throw new IllegalArgumentException("attachments cannot be null."); + if (slotIndex < 0) throw new IllegalArgumentException("slotIndex must be >= 0."); + for (Entry entry : this.attachments.entries()) + if (entry.key.slotIndex == slotIndex) attachments.add(entry.value); + } + + public void clear () { + for (Key key : attachments.keys()) + keyPool.free(key); + attachments.clear(); + } + + public String getName () { + return name; + } + + public Iterator attachments () { + return attachments.values().iterator(); + } + + public String toString () { + return name; + } + + /** Attach each attachment in this skin if the corresponding attachment in the old skin is currently attached. */ + void attachAll (Skeleton skeleton, Skin oldSkin) { + for (Entry entry : oldSkin.attachments.entries()) { + int slotIndex = entry.key.slotIndex; + Slot slot = skeleton.slots.get(slotIndex); + if (slot.attachment == entry.value) { + Attachment attachment = getAttachment(slotIndex, entry.key.name); + if (attachment != null) slot.setAttachment(attachment); + } + } + } + + static class Key { + int slotIndex; + String name; + int hashCode; + + public void set (int slotIndex, String name) { + if (name == null) throw new IllegalArgumentException("name cannot be null."); + this.slotIndex = slotIndex; + this.name = name; + hashCode = 31 * (31 + name.hashCode()) + slotIndex; + } + + public int hashCode () { + return hashCode; + } + + public boolean equals (Object object) { + if (object == null) return false; + Key other = (Key)object; + if (slotIndex != other.slotIndex) return false; + if (!name.equals(other.name)) return false; + return true; + } + + public String toString () { + return slotIndex + ":" + name; + } + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slot.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slot.java index c74a9ec2da..4ff2184ed9 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slot.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slot.java @@ -1,127 +1,126 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.utils.FloatArray; -import com.esotericsoftware.spine.attachments.Attachment; - -public class Slot { - final SlotData data; - final Bone bone; - final Color color; - Attachment attachment; - private float attachmentTime; - private FloatArray attachmentVertices = new FloatArray(); - - public Slot (SlotData data, Bone bone) { - if (data == null) throw new IllegalArgumentException("data cannot be null."); - if (bone == null) throw new IllegalArgumentException("bone cannot be null."); - this.data = data; - this.bone = bone; - color = new Color(); - setToSetupPose(); - } - - /** Copy constructor. */ - public Slot (Slot slot, Bone bone) { - if (slot == null) throw new IllegalArgumentException("slot cannot be null."); - if (bone == null) throw new IllegalArgumentException("bone cannot be null."); - data = slot.data; - this.bone = bone; - color = new Color(slot.color); - attachment = slot.attachment; - attachmentTime = slot.attachmentTime; - } - - public SlotData getData () { - return data; - } - - public Bone getBone () { - return bone; - } - - public Skeleton getSkeleton () { - return bone.skeleton; - } - - public Color getColor () { - return color; - } - - /** @return May be null. */ - public Attachment getAttachment () { - return attachment; - } - - /** Sets the attachment and if it changed, resets {@link #getAttachmentTime()} and clears {@link #getAttachmentVertices()}. - * @param attachment May be null. */ - public void setAttachment (Attachment attachment) { - if (this.attachment == attachment) return; - this.attachment = attachment; - attachmentTime = bone.skeleton.time; - attachmentVertices.clear(); - } - - public void setAttachmentTime (float time) { - attachmentTime = bone.skeleton.time - time; - } - - /** Returns the time since the attachment was set. */ - public float getAttachmentTime () { - return bone.skeleton.time - attachmentTime; - } - - public void setAttachmentVertices (FloatArray attachmentVertices) { - if (attachmentVertices == null) throw new IllegalArgumentException("attachmentVertices cannot be null."); - this.attachmentVertices = attachmentVertices; - } - - public FloatArray getAttachmentVertices () { - return attachmentVertices; - } - - public void setToSetupPose () { - color.set(data.color); - if (data.attachmentName == null) - setAttachment(null); - else { - attachment = null; - setAttachment(bone.skeleton.getAttachment(data.index, data.attachmentName)); - } - } - - public String toString () { - return data.name; - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.utils.FloatArray; +import com.esotericsoftware.spine.attachments.Attachment; + +public class Slot { + final SlotData data; + final Bone bone; + final Color color; + Attachment attachment; + private float attachmentTime; + private FloatArray attachmentVertices = new FloatArray(); + + public Slot (SlotData data, Bone bone) { + if (data == null) throw new IllegalArgumentException("data cannot be null."); + if (bone == null) throw new IllegalArgumentException("bone cannot be null."); + this.data = data; + this.bone = bone; + color = new Color(); + setToSetupPose(); + } + + /** Copy constructor. */ + public Slot (Slot slot, Bone bone) { + if (slot == null) throw new IllegalArgumentException("slot cannot be null."); + if (bone == null) throw new IllegalArgumentException("bone cannot be null."); + data = slot.data; + this.bone = bone; + color = new Color(slot.color); + attachment = slot.attachment; + attachmentTime = slot.attachmentTime; + } + + public SlotData getData () { + return data; + } + + public Bone getBone () { + return bone; + } + + public Skeleton getSkeleton () { + return bone.skeleton; + } + + public Color getColor () { + return color; + } + + /** @return May be null. */ + public Attachment getAttachment () { + return attachment; + } + + /** Sets the attachment and if it changed, resets {@link #getAttachmentTime()} and clears {@link #getAttachmentVertices()}. + * @param attachment May be null. */ + public void setAttachment (Attachment attachment) { + if (this.attachment == attachment) return; + this.attachment = attachment; + attachmentTime = bone.skeleton.time; + attachmentVertices.clear(); + } + + public void setAttachmentTime (float time) { + attachmentTime = bone.skeleton.time - time; + } + + /** Returns the time since the attachment was set. */ + public float getAttachmentTime () { + return bone.skeleton.time - attachmentTime; + } + + public void setAttachmentVertices (FloatArray attachmentVertices) { + if (attachmentVertices == null) throw new IllegalArgumentException("attachmentVertices cannot be null."); + this.attachmentVertices = attachmentVertices; + } + + public FloatArray getAttachmentVertices () { + return attachmentVertices; + } + + public void setToSetupPose () { + color.set(data.color); + if (data.attachmentName == null) + setAttachment(null); + else { + attachment = null; + setAttachment(bone.skeleton.getAttachment(data.index, data.attachmentName)); + } + } + + public String toString () { + return data.name; + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SlotData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SlotData.java index 5625b1b7d8..a993b8531e 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SlotData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SlotData.java @@ -1,90 +1,89 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import com.badlogic.gdx.graphics.Color; - -public class SlotData { - final int index; - final String name; - final BoneData boneData; - final Color color = new Color(1, 1, 1, 1); - String attachmentName; - BlendMode blendMode; - - public SlotData (int index, String name, BoneData boneData) { - if (index < 0) throw new IllegalArgumentException("index must be >= 0."); - if (name == null) throw new IllegalArgumentException("name cannot be null."); - if (boneData == null) throw new IllegalArgumentException("boneData cannot be null."); - this.index = index; - this.name = name; - this.boneData = boneData; - } - - public int getIndex () { - return index; - } - - public String getName () { - return name; - } - - public BoneData getBoneData () { - return boneData; - } - - public Color getColor () { - return color; - } - - /** @param attachmentName May be null. */ - public void setAttachmentName (String attachmentName) { - this.attachmentName = attachmentName; - } - - /** @return May be null. */ - public String getAttachmentName () { - return attachmentName; - } - - public BlendMode getBlendMode () { - return blendMode; - } - - public void setBlendMode (BlendMode blendMode) { - this.blendMode = blendMode; - } - - public String toString () { - return name; - } +package com.esotericsoftware.spine; + +import com.badlogic.gdx.graphics.Color; + +public class SlotData { + final int index; + final String name; + final BoneData boneData; + final Color color = new Color(1, 1, 1, 1); + String attachmentName; + BlendMode blendMode; + + public SlotData (int index, String name, BoneData boneData) { + if (index < 0) throw new IllegalArgumentException("index must be >= 0."); + if (name == null) throw new IllegalArgumentException("name cannot be null."); + if (boneData == null) throw new IllegalArgumentException("boneData cannot be null."); + this.index = index; + this.name = name; + this.boneData = boneData; + } + + public int getIndex () { + return index; + } + + public String getName () { + return name; + } + + public BoneData getBoneData () { + return boneData; + } + + public Color getColor () { + return color; + } + + /** @param attachmentName May be null. */ + public void setAttachmentName (String attachmentName) { + this.attachmentName = attachmentName; + } + + /** @return May be null. */ + public String getAttachmentName () { + return attachmentName; + } + + public BlendMode getBlendMode () { + return blendMode; + } + + public void setBlendMode (BlendMode blendMode) { + this.blendMode = blendMode; + } + + public String toString () { + return name; + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java index 27e972a440..e353d38c9b 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ package com.esotericsoftware.spine; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintData.java index 5fe3adcbc5..5bc0013e58 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintData.java @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ package com.esotericsoftware.spine; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Updatable.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Updatable.java index 1b68393c9d..15a4e3d031 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Updatable.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Updatable.java @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ package com.esotericsoftware.spine; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/AtlasAttachmentLoader.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/AtlasAttachmentLoader.java index a667c9b3de..566c8a8ee4 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/AtlasAttachmentLoader.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/AtlasAttachmentLoader.java @@ -1,70 +1,69 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine.attachments; - -import com.esotericsoftware.spine.Skin; - -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion; - -public class AtlasAttachmentLoader implements AttachmentLoader { - private TextureAtlas atlas; - - public AtlasAttachmentLoader (TextureAtlas atlas) { - if (atlas == null) throw new IllegalArgumentException("atlas cannot be null."); - this.atlas = atlas; - } - - public RegionAttachment newRegionAttachment (Skin skin, String name, String path) { - AtlasRegion region = atlas.findRegion(path); - if (region == null) throw new RuntimeException("Region not found in atlas: " + path + " (region attachment: " + name + ")"); - RegionAttachment attachment = new RegionAttachment(name); - attachment.setRegion(region); - return attachment; - } - - public MeshAttachment newMeshAttachment (Skin skin, String name, String path) { - AtlasRegion region = atlas.findRegion(path); - if (region == null) throw new RuntimeException("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); - MeshAttachment attachment = new MeshAttachment(name); - attachment.setRegion(region); - return attachment; - } - - public BoundingBoxAttachment newBoundingBoxAttachment (Skin skin, String name) { - return new BoundingBoxAttachment(name); - } - - public PathAttachment newPathAttachment (Skin skin, String name) { - return new PathAttachment(name); - } +package com.esotericsoftware.spine.attachments; + +import com.esotericsoftware.spine.Skin; + +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion; + +public class AtlasAttachmentLoader implements AttachmentLoader { + private TextureAtlas atlas; + + public AtlasAttachmentLoader (TextureAtlas atlas) { + if (atlas == null) throw new IllegalArgumentException("atlas cannot be null."); + this.atlas = atlas; + } + + public RegionAttachment newRegionAttachment (Skin skin, String name, String path) { + AtlasRegion region = atlas.findRegion(path); + if (region == null) throw new RuntimeException("Region not found in atlas: " + path + " (region attachment: " + name + ")"); + RegionAttachment attachment = new RegionAttachment(name); + attachment.setRegion(region); + return attachment; + } + + public MeshAttachment newMeshAttachment (Skin skin, String name, String path) { + AtlasRegion region = atlas.findRegion(path); + if (region == null) throw new RuntimeException("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); + MeshAttachment attachment = new MeshAttachment(name); + attachment.setRegion(region); + return attachment; + } + + public BoundingBoxAttachment newBoundingBoxAttachment (Skin skin, String name) { + return new BoundingBoxAttachment(name); + } + + public PathAttachment newPathAttachment (Skin skin, String name) { + return new PathAttachment(name); + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/Attachment.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/Attachment.java index d01b24d848..0b963bb1e7 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/Attachment.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/Attachment.java @@ -1,49 +1,48 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine.attachments; - -abstract public class Attachment { - String name; - - public Attachment (String name) { - if (name == null) throw new IllegalArgumentException("name cannot be null."); - this.name = name; - } - - public String getName () { - return name; - } - - public String toString () { - return getName(); - } +package com.esotericsoftware.spine.attachments; + +abstract public class Attachment { + String name; + + public Attachment (String name) { + if (name == null) throw new IllegalArgumentException("name cannot be null."); + this.name = name; + } + + public String getName () { + return name; + } + + public String toString () { + return getName(); + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/AttachmentLoader.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/AttachmentLoader.java index 6081e7d378..210665dd96 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/AttachmentLoader.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/AttachmentLoader.java @@ -1,48 +1,47 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine.attachments; - -import com.esotericsoftware.spine.Skin; - -public interface AttachmentLoader { - /** @return May be null to not load any attachment. */ - public RegionAttachment newRegionAttachment (Skin skin, String name, String path); - - /** @return May be null to not load any attachment. */ - public MeshAttachment newMeshAttachment (Skin skin, String name, String path); - - /** @return May be null to not load any attachment. */ - public BoundingBoxAttachment newBoundingBoxAttachment (Skin skin, String name); - - /** @return May be null to not load any attachment. */ - public PathAttachment newPathAttachment (Skin skin, String name); +package com.esotericsoftware.spine.attachments; + +import com.esotericsoftware.spine.Skin; + +public interface AttachmentLoader { + /** @return May be null to not load any attachment. */ + public RegionAttachment newRegionAttachment (Skin skin, String name, String path); + + /** @return May be null to not load any attachment. */ + public MeshAttachment newMeshAttachment (Skin skin, String name, String path); + + /** @return May be null to not load any attachment. */ + public BoundingBoxAttachment newBoundingBoxAttachment (Skin skin, String name); + + /** @return May be null to not load any attachment. */ + public PathAttachment newPathAttachment (Skin skin, String name); } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/AttachmentType.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/AttachmentType.java index 6e8e5f303e..6ed9fb502f 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/AttachmentType.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/AttachmentType.java @@ -1,38 +1,37 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine.attachments; - -public enum AttachmentType { - region, boundingbox, mesh, linkedmesh, path; - - static public AttachmentType[] values = values(); +package com.esotericsoftware.spine.attachments; + +public enum AttachmentType { + region, boundingbox, mesh, linkedmesh, path; + + static public AttachmentType[] values = values(); } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/BoundingBoxAttachment.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/BoundingBoxAttachment.java index 867b2906d2..4f7f6976b9 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/BoundingBoxAttachment.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/BoundingBoxAttachment.java @@ -1,52 +1,51 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine.attachments; - -import com.badlogic.gdx.graphics.Color; -import com.esotericsoftware.spine.Slot; - -public class BoundingBoxAttachment extends VertexAttachment { - // Nonessential. - final Color color = new Color(0.38f, 0.94f, 0, 1); - - public BoundingBoxAttachment (String name) { - super(name); - } - - public void computeWorldVertices (Slot slot, float[] worldVertices) { - computeWorldVertices(slot, 0, worldVerticesLength, worldVertices, 0); - } - - public Color getColor () { - return color; - } +package com.esotericsoftware.spine.attachments; + +import com.badlogic.gdx.graphics.Color; +import com.esotericsoftware.spine.Slot; + +public class BoundingBoxAttachment extends VertexAttachment { + // Nonessential. + final Color color = new Color(0.38f, 0.94f, 0, 1); + + public BoundingBoxAttachment (String name) { + super(name); + } + + public void computeWorldVertices (Slot slot, float[] worldVertices) { + computeWorldVertices(slot, 0, worldVerticesLength, worldVertices, 0); + } + + public Color getColor () { + return color; + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/MeshAttachment.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/MeshAttachment.java index 23c94ea17a..f2f8a6ec80 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/MeshAttachment.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/MeshAttachment.java @@ -1,263 +1,262 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine.attachments; - -import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion; -import com.badlogic.gdx.graphics.g2d.TextureRegion; -import com.badlogic.gdx.utils.FloatArray; -import com.badlogic.gdx.utils.NumberUtils; -import com.esotericsoftware.spine.Bone; -import com.esotericsoftware.spine.Skeleton; -import com.esotericsoftware.spine.Slot; - -/** Attachment that displays a texture region. */ -public class MeshAttachment extends VertexAttachment { - private TextureRegion region; - private String path; - private float[] regionUVs, worldVertices; - private short[] triangles; - private final Color color = new Color(1, 1, 1, 1); - private int hullLength; - private MeshAttachment parentMesh; - private boolean inheritDeform; - - // Nonessential. - private short[] edges; - private float width, height; - - public MeshAttachment (String name) { - super(name); - } - - public void setRegion (TextureRegion region) { - if (region == null) throw new IllegalArgumentException("region cannot be null."); - this.region = region; - } - - public TextureRegion getRegion () { - if (region == null) throw new IllegalStateException("Region has not been set: " + this); - return region; - } - - public void updateUVs () { - float[] regionUVs = this.regionUVs; - int verticesLength = regionUVs.length; - int worldVerticesLength = (verticesLength >> 1) * 5; - if (worldVertices == null || worldVertices.length != worldVerticesLength) worldVertices = new float[worldVerticesLength]; - - float u, v, width, height; - if (region == null) { - u = v = 0; - width = height = 1; - } else { - u = region.getU(); - v = region.getV(); - width = region.getU2() - u; - height = region.getV2() - v; - } - if (region instanceof AtlasRegion && ((AtlasRegion)region).rotate) { - for (int i = 0, w = 3; i < verticesLength; i += 2, w += 5) { - worldVertices[w] = u + regionUVs[i + 1] * width; - worldVertices[w + 1] = v + height - regionUVs[i] * height; - } - } else { - for (int i = 0, w = 3; i < verticesLength; i += 2, w += 5) { - worldVertices[w] = u + regionUVs[i] * width; - worldVertices[w + 1] = v + regionUVs[i + 1] * height; - } - } - } - - /** @return The updated world vertices. */ - public float[] updateWorldVertices (Slot slot, boolean premultipliedAlpha) { - Skeleton skeleton = slot.getSkeleton(); - Color skeletonColor = skeleton.getColor(), slotColor = slot.getColor(), meshColor = color; - float alpha = skeletonColor.a * slotColor.a * meshColor.a * 255; - float multiplier = premultipliedAlpha ? alpha : 255; - float color = NumberUtils.intToFloatColor( // - ((int)alpha << 24) // - | ((int)(skeletonColor.b * slotColor.b * meshColor.b * multiplier) << 16) // - | ((int)(skeletonColor.g * slotColor.g * meshColor.g * multiplier) << 8) // - | (int)(skeletonColor.r * slotColor.r * meshColor.r * multiplier)); - - float x = skeleton.getX(), y = skeleton.getY(); - FloatArray deformArray = slot.getAttachmentVertices(); - float[] vertices = this.vertices, worldVertices = this.worldVertices; - int[] bones = this.bones; - if (bones == null) { - int verticesLength = vertices.length; - if (deformArray.size > 0) vertices = deformArray.items; - Bone bone = slot.getBone(); - x += bone.getWorldX(); - y += bone.getWorldY(); - float a = bone.getA(), b = bone.getB(), c = bone.getC(), d = bone.getD(); - for (int v = 0, w = 0; v < verticesLength; v += 2, w += 5) { - float vx = vertices[v], vy = vertices[v + 1]; - worldVertices[w] = vx * a + vy * b + x; - worldVertices[w + 1] = vx * c + vy * d + y; - worldVertices[w + 2] = color; - } - return worldVertices; - } - Object[] skeletonBones = skeleton.getBones().items; - if (deformArray.size == 0) { - for (int w = 0, v = 0, b = 0, n = bones.length; v < n; w += 5) { - float wx = x, wy = y; - int nn = bones[v++] + v; - for (; v < nn; v++, b += 3) { - Bone bone = (Bone)skeletonBones[bones[v]]; - float vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; - wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight; - wy += (vx * bone.getC() + vy * bone.getD() + bone.getWorldY()) * weight; - } - worldVertices[w] = wx; - worldVertices[w + 1] = wy; - worldVertices[w + 2] = color; - } - } else { - float[] deform = deformArray.items; - for (int w = 0, v = 0, b = 0, f = 0, n = bones.length; v < n; w += 5) { - float wx = x, wy = y; - int nn = bones[v++] + v; - for (; v < nn; v++, b += 3, f += 2) { - Bone bone = (Bone)skeletonBones[bones[v]]; - float vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; - wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight; - wy += (vx * bone.getC() + vy * bone.getD() + bone.getWorldY()) * weight; - } - worldVertices[w] = wx; - worldVertices[w + 1] = wy; - worldVertices[w + 2] = color; - } - } - return worldVertices; - } - - public boolean applyDeform (VertexAttachment sourceAttachment) { - return this == sourceAttachment || (inheritDeform && parentMesh == sourceAttachment); - } - - public float[] getWorldVertices () { - return worldVertices; - } - - public short[] getTriangles () { - return triangles; - } - - /** Vertex number triplets which describe the mesh's triangulation. */ - public void setTriangles (short[] triangles) { - this.triangles = triangles; - } - - public float[] getRegionUVs () { - return regionUVs; - } - - /** Sets the texture coordinates for the region. The values are u,v pairs for each vertex. */ - public void setRegionUVs (float[] regionUVs) { - this.regionUVs = regionUVs; - } - - public Color getColor () { - return color; - } - - public String getPath () { - return path; - } - - public void setPath (String path) { - this.path = path; - } - - public int getHullLength () { - return hullLength; - } - - public void setHullLength (int hullLength) { - this.hullLength = hullLength; - } - - public void setEdges (short[] edges) { - this.edges = edges; - } - - public short[] getEdges () { - return edges; - } - - public float getWidth () { - return width; - } - - public void setWidth (float width) { - this.width = width; - } - - public float getHeight () { - return height; - } - - public void setHeight (float height) { - this.height = height; - } - - /** Returns the source mesh if this is a linked mesh, else returns null. */ - public MeshAttachment getParentMesh () { - return parentMesh; - } - - /** @param parentMesh May be null. */ - public void setParentMesh (MeshAttachment parentMesh) { - this.parentMesh = parentMesh; - if (parentMesh != null) { - bones = parentMesh.bones; - vertices = parentMesh.vertices; - regionUVs = parentMesh.regionUVs; - triangles = parentMesh.triangles; - hullLength = parentMesh.hullLength; - edges = parentMesh.edges; - width = parentMesh.width; - height = parentMesh.height; - } - } - - public boolean getInheritDeform () { - return inheritDeform; - } - - public void setInheritDeform (boolean inheritDeform) { - this.inheritDeform = inheritDeform; - } +package com.esotericsoftware.spine.attachments; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.utils.FloatArray; +import com.badlogic.gdx.utils.NumberUtils; +import com.esotericsoftware.spine.Bone; +import com.esotericsoftware.spine.Skeleton; +import com.esotericsoftware.spine.Slot; + +/** Attachment that displays a texture region. */ +public class MeshAttachment extends VertexAttachment { + private TextureRegion region; + private String path; + private float[] regionUVs, worldVertices; + private short[] triangles; + private final Color color = new Color(1, 1, 1, 1); + private int hullLength; + private MeshAttachment parentMesh; + private boolean inheritDeform; + + // Nonessential. + private short[] edges; + private float width, height; + + public MeshAttachment (String name) { + super(name); + } + + public void setRegion (TextureRegion region) { + if (region == null) throw new IllegalArgumentException("region cannot be null."); + this.region = region; + } + + public TextureRegion getRegion () { + if (region == null) throw new IllegalStateException("Region has not been set: " + this); + return region; + } + + public void updateUVs () { + float[] regionUVs = this.regionUVs; + int verticesLength = regionUVs.length; + int worldVerticesLength = (verticesLength >> 1) * 5; + if (worldVertices == null || worldVertices.length != worldVerticesLength) worldVertices = new float[worldVerticesLength]; + + float u, v, width, height; + if (region == null) { + u = v = 0; + width = height = 1; + } else { + u = region.getU(); + v = region.getV(); + width = region.getU2() - u; + height = region.getV2() - v; + } + if (region instanceof AtlasRegion && ((AtlasRegion)region).rotate) { + for (int i = 0, w = 3; i < verticesLength; i += 2, w += 5) { + worldVertices[w] = u + regionUVs[i + 1] * width; + worldVertices[w + 1] = v + height - regionUVs[i] * height; + } + } else { + for (int i = 0, w = 3; i < verticesLength; i += 2, w += 5) { + worldVertices[w] = u + regionUVs[i] * width; + worldVertices[w + 1] = v + regionUVs[i + 1] * height; + } + } + } + + /** @return The updated world vertices. */ + public float[] updateWorldVertices (Slot slot, boolean premultipliedAlpha) { + Skeleton skeleton = slot.getSkeleton(); + Color skeletonColor = skeleton.getColor(), slotColor = slot.getColor(), meshColor = color; + float alpha = skeletonColor.a * slotColor.a * meshColor.a * 255; + float multiplier = premultipliedAlpha ? alpha : 255; + float color = NumberUtils.intToFloatColor( // + ((int)alpha << 24) // + | ((int)(skeletonColor.b * slotColor.b * meshColor.b * multiplier) << 16) // + | ((int)(skeletonColor.g * slotColor.g * meshColor.g * multiplier) << 8) // + | (int)(skeletonColor.r * slotColor.r * meshColor.r * multiplier)); + + float x = skeleton.getX(), y = skeleton.getY(); + FloatArray deformArray = slot.getAttachmentVertices(); + float[] vertices = this.vertices, worldVertices = this.worldVertices; + int[] bones = this.bones; + if (bones == null) { + int verticesLength = vertices.length; + if (deformArray.size > 0) vertices = deformArray.items; + Bone bone = slot.getBone(); + x += bone.getWorldX(); + y += bone.getWorldY(); + float a = bone.getA(), b = bone.getB(), c = bone.getC(), d = bone.getD(); + for (int v = 0, w = 0; v < verticesLength; v += 2, w += 5) { + float vx = vertices[v], vy = vertices[v + 1]; + worldVertices[w] = vx * a + vy * b + x; + worldVertices[w + 1] = vx * c + vy * d + y; + worldVertices[w + 2] = color; + } + return worldVertices; + } + Object[] skeletonBones = skeleton.getBones().items; + if (deformArray.size == 0) { + for (int w = 0, v = 0, b = 0, n = bones.length; v < n; w += 5) { + float wx = x, wy = y; + int nn = bones[v++] + v; + for (; v < nn; v++, b += 3) { + Bone bone = (Bone)skeletonBones[bones[v]]; + float vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; + wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight; + wy += (vx * bone.getC() + vy * bone.getD() + bone.getWorldY()) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + worldVertices[w + 2] = color; + } + } else { + float[] deform = deformArray.items; + for (int w = 0, v = 0, b = 0, f = 0, n = bones.length; v < n; w += 5) { + float wx = x, wy = y; + int nn = bones[v++] + v; + for (; v < nn; v++, b += 3, f += 2) { + Bone bone = (Bone)skeletonBones[bones[v]]; + float vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; + wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight; + wy += (vx * bone.getC() + vy * bone.getD() + bone.getWorldY()) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + worldVertices[w + 2] = color; + } + } + return worldVertices; + } + + public boolean applyDeform (VertexAttachment sourceAttachment) { + return this == sourceAttachment || (inheritDeform && parentMesh == sourceAttachment); + } + + public float[] getWorldVertices () { + return worldVertices; + } + + public short[] getTriangles () { + return triangles; + } + + /** Vertex number triplets which describe the mesh's triangulation. */ + public void setTriangles (short[] triangles) { + this.triangles = triangles; + } + + public float[] getRegionUVs () { + return regionUVs; + } + + /** Sets the texture coordinates for the region. The values are u,v pairs for each vertex. */ + public void setRegionUVs (float[] regionUVs) { + this.regionUVs = regionUVs; + } + + public Color getColor () { + return color; + } + + public String getPath () { + return path; + } + + public void setPath (String path) { + this.path = path; + } + + public int getHullLength () { + return hullLength; + } + + public void setHullLength (int hullLength) { + this.hullLength = hullLength; + } + + public void setEdges (short[] edges) { + this.edges = edges; + } + + public short[] getEdges () { + return edges; + } + + public float getWidth () { + return width; + } + + public void setWidth (float width) { + this.width = width; + } + + public float getHeight () { + return height; + } + + public void setHeight (float height) { + this.height = height; + } + + /** Returns the source mesh if this is a linked mesh, else returns null. */ + public MeshAttachment getParentMesh () { + return parentMesh; + } + + /** @param parentMesh May be null. */ + public void setParentMesh (MeshAttachment parentMesh) { + this.parentMesh = parentMesh; + if (parentMesh != null) { + bones = parentMesh.bones; + vertices = parentMesh.vertices; + regionUVs = parentMesh.regionUVs; + triangles = parentMesh.triangles; + hullLength = parentMesh.hullLength; + edges = parentMesh.edges; + width = parentMesh.width; + height = parentMesh.height; + } + } + + public boolean getInheritDeform () { + return inheritDeform; + } + + public void setInheritDeform (boolean inheritDeform) { + this.inheritDeform = inheritDeform; + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/PathAttachment.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/PathAttachment.java index 229be6d47f..f81443f36a 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/PathAttachment.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/PathAttachment.java @@ -1,84 +1,83 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine.attachments; - -import com.badlogic.gdx.graphics.Color; -import com.esotericsoftware.spine.Slot; - -public class PathAttachment extends VertexAttachment { - float[] lengths; - boolean closed, constantSpeed; - - // Nonessential. - final Color color = new Color(1, 0.5f, 0, 1); - - public PathAttachment (String name) { - super(name); - } - - public void computeWorldVertices (Slot slot, float[] worldVertices) { - super.computeWorldVertices(slot, worldVertices); - } - - public void computeWorldVertices (Slot slot, int start, int count, float[] worldVertices, int offset) { - super.computeWorldVertices(slot, start, count, worldVertices, offset); - } - - public boolean getClosed () { - return closed; - } - - public void setClosed (boolean closed) { - this.closed = closed; - } - - public boolean getConstantSpeed () { - return constantSpeed; - } - - public void setConstantSpeed (boolean constantSpeed) { - this.constantSpeed = constantSpeed; - } - - /** Returns the length in the setup pose from the start of the path to the end of each curve. */ - public float[] getLengths () { - return lengths; - } - - public void setLengths (float[] lengths) { - this.lengths = lengths; - } - - public Color getColor () { - return color; - } +package com.esotericsoftware.spine.attachments; + +import com.badlogic.gdx.graphics.Color; +import com.esotericsoftware.spine.Slot; + +public class PathAttachment extends VertexAttachment { + float[] lengths; + boolean closed, constantSpeed; + + // Nonessential. + final Color color = new Color(1, 0.5f, 0, 1); + + public PathAttachment (String name) { + super(name); + } + + public void computeWorldVertices (Slot slot, float[] worldVertices) { + super.computeWorldVertices(slot, worldVertices); + } + + public void computeWorldVertices (Slot slot, int start, int count, float[] worldVertices, int offset) { + super.computeWorldVertices(slot, start, count, worldVertices, offset); + } + + public boolean getClosed () { + return closed; + } + + public void setClosed (boolean closed) { + this.closed = closed; + } + + public boolean getConstantSpeed () { + return constantSpeed; + } + + public void setConstantSpeed (boolean constantSpeed) { + this.constantSpeed = constantSpeed; + } + + /** Returns the length in the setup pose from the start of the path to the end of each curve. */ + public float[] getLengths () { + return lengths; + } + + public void setLengths (float[] lengths) { + this.lengths = lengths; + } + + public Color getColor () { + return color; + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionAttachment.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionAttachment.java index cc5a362426..72d6ab293e 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionAttachment.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionAttachment.java @@ -1,271 +1,270 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine.attachments; - -import com.esotericsoftware.spine.Bone; -import com.esotericsoftware.spine.Skeleton; -import com.esotericsoftware.spine.Slot; - -import static com.badlogic.gdx.graphics.g2d.Batch.*; - -import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion; -import com.badlogic.gdx.graphics.g2d.TextureRegion; -import com.badlogic.gdx.math.MathUtils; -import com.badlogic.gdx.utils.NumberUtils; - -/** Attachment that displays a texture region. */ -public class RegionAttachment extends Attachment { - static public final int BLX = 0; - static public final int BLY = 1; - static public final int ULX = 2; - static public final int ULY = 3; - static public final int URX = 4; - static public final int URY = 5; - static public final int BRX = 6; - static public final int BRY = 7; - - private TextureRegion region; - private String path; - private float x, y, scaleX = 1, scaleY = 1, rotation, width, height; - private final float[] vertices = new float[20]; - private final float[] offset = new float[8]; - private final Color color = new Color(1, 1, 1, 1); - - public RegionAttachment (String name) { - super(name); - } - - public void updateOffset () { - float width = getWidth(); - float height = getHeight(); - float localX2 = width / 2; - float localY2 = height / 2; - float localX = -localX2; - float localY = -localY2; - if (region instanceof AtlasRegion) { - AtlasRegion region = (AtlasRegion)this.region; - if (region.rotate) { - localX += region.offsetX / region.originalWidth * width; - localY += region.offsetY / region.originalHeight * height; - localX2 -= (region.originalWidth - region.offsetX - region.packedHeight) / region.originalWidth * width; - localY2 -= (region.originalHeight - region.offsetY - region.packedWidth) / region.originalHeight * height; - } else { - localX += region.offsetX / region.originalWidth * width; - localY += region.offsetY / region.originalHeight * height; - localX2 -= (region.originalWidth - region.offsetX - region.packedWidth) / region.originalWidth * width; - localY2 -= (region.originalHeight - region.offsetY - region.packedHeight) / region.originalHeight * height; - } - } - float scaleX = getScaleX(); - float scaleY = getScaleY(); - localX *= scaleX; - localY *= scaleY; - localX2 *= scaleX; - localY2 *= scaleY; - float rotation = getRotation(); - float cos = MathUtils.cosDeg(rotation); - float sin = MathUtils.sinDeg(rotation); - float x = getX(); - float y = getY(); - float localXCos = localX * cos + x; - float localXSin = localX * sin; - float localYCos = localY * cos + y; - float localYSin = localY * sin; - float localX2Cos = localX2 * cos + x; - float localX2Sin = localX2 * sin; - float localY2Cos = localY2 * cos + y; - float localY2Sin = localY2 * sin; - float[] offset = this.offset; - offset[BLX] = localXCos - localYSin; - offset[BLY] = localYCos + localXSin; - offset[ULX] = localXCos - localY2Sin; - offset[ULY] = localY2Cos + localXSin; - offset[URX] = localX2Cos - localY2Sin; - offset[URY] = localY2Cos + localX2Sin; - offset[BRX] = localX2Cos - localYSin; - offset[BRY] = localYCos + localX2Sin; - } - - public void setRegion (TextureRegion region) { - if (region == null) throw new IllegalArgumentException("region cannot be null."); - this.region = region; - float[] vertices = this.vertices; - if (region instanceof AtlasRegion && ((AtlasRegion)region).rotate) { - vertices[U3] = region.getU(); - vertices[V3] = region.getV2(); - vertices[U4] = region.getU(); - vertices[V4] = region.getV(); - vertices[U1] = region.getU2(); - vertices[V1] = region.getV(); - vertices[U2] = region.getU2(); - vertices[V2] = region.getV2(); - } else { - vertices[U2] = region.getU(); - vertices[V2] = region.getV2(); - vertices[U3] = region.getU(); - vertices[V3] = region.getV(); - vertices[U4] = region.getU2(); - vertices[V4] = region.getV(); - vertices[U1] = region.getU2(); - vertices[V1] = region.getV2(); - } - } - - public TextureRegion getRegion () { - if (region == null) throw new IllegalStateException("Region has not been set: " + this); - return region; - } - - /** @return The updated world vertices. */ - public float[] updateWorldVertices (Slot slot, boolean premultipliedAlpha) { - Skeleton skeleton = slot.getSkeleton(); - Color skeletonColor = skeleton.getColor(); - Color slotColor = slot.getColor(); - Color regionColor = color; - float alpha = skeletonColor.a * slotColor.a * regionColor.a * 255; - float multiplier = premultipliedAlpha ? alpha : 255; - float color = NumberUtils.intToFloatColor( // - ((int)alpha << 24) // - | ((int)(skeletonColor.b * slotColor.b * regionColor.b * multiplier) << 16) // - | ((int)(skeletonColor.g * slotColor.g * regionColor.g * multiplier) << 8) // - | (int)(skeletonColor.r * slotColor.r * regionColor.r * multiplier)); - - float[] vertices = this.vertices; - float[] offset = this.offset; - Bone bone = slot.getBone(); - float x = skeleton.getX() + bone.getWorldX(), y = skeleton.getY() + bone.getWorldY(); - float a = bone.getA(), b = bone.getB(), c = bone.getC(), d = bone.getD(); - float offsetX, offsetY; - - offsetX = offset[BRX]; - offsetY = offset[BRY]; - vertices[X1] = offsetX * a + offsetY * b + x; // br - vertices[Y1] = offsetX * c + offsetY * d + y; - vertices[C1] = color; - - offsetX = offset[BLX]; - offsetY = offset[BLY]; - vertices[X2] = offsetX * a + offsetY * b + x; // bl - vertices[Y2] = offsetX * c + offsetY * d + y; - vertices[C2] = color; - - offsetX = offset[ULX]; - offsetY = offset[ULY]; - vertices[X3] = offsetX * a + offsetY * b + x; // ul - vertices[Y3] = offsetX * c + offsetY * d + y; - vertices[C3] = color; - - offsetX = offset[URX]; - offsetY = offset[URY]; - vertices[X4] = offsetX * a + offsetY * b + x; // ur - vertices[Y4] = offsetX * c + offsetY * d + y; - vertices[C4] = color; - return vertices; - } - - public float[] getWorldVertices () { - return vertices; - } - - public float[] getOffset () { - return offset; - } - - public float getX () { - return x; - } - - public void setX (float x) { - this.x = x; - } - - public float getY () { - return y; - } - - public void setY (float y) { - this.y = y; - } - - public float getScaleX () { - return scaleX; - } - - public void setScaleX (float scaleX) { - this.scaleX = scaleX; - } - - public float getScaleY () { - return scaleY; - } - - public void setScaleY (float scaleY) { - this.scaleY = scaleY; - } - - public float getRotation () { - return rotation; - } - - public void setRotation (float rotation) { - this.rotation = rotation; - } - - public float getWidth () { - return width; - } - - public void setWidth (float width) { - this.width = width; - } - - public float getHeight () { - return height; - } - - public void setHeight (float height) { - this.height = height; - } - - public Color getColor () { - return color; - } - - public String getPath () { - return path; - } - - public void setPath (String path) { - this.path = path; - } +package com.esotericsoftware.spine.attachments; + +import com.esotericsoftware.spine.Bone; +import com.esotericsoftware.spine.Skeleton; +import com.esotericsoftware.spine.Slot; + +import static com.badlogic.gdx.graphics.g2d.Batch.*; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.math.MathUtils; +import com.badlogic.gdx.utils.NumberUtils; + +/** Attachment that displays a texture region. */ +public class RegionAttachment extends Attachment { + static public final int BLX = 0; + static public final int BLY = 1; + static public final int ULX = 2; + static public final int ULY = 3; + static public final int URX = 4; + static public final int URY = 5; + static public final int BRX = 6; + static public final int BRY = 7; + + private TextureRegion region; + private String path; + private float x, y, scaleX = 1, scaleY = 1, rotation, width, height; + private final float[] vertices = new float[20]; + private final float[] offset = new float[8]; + private final Color color = new Color(1, 1, 1, 1); + + public RegionAttachment (String name) { + super(name); + } + + public void updateOffset () { + float width = getWidth(); + float height = getHeight(); + float localX2 = width / 2; + float localY2 = height / 2; + float localX = -localX2; + float localY = -localY2; + if (region instanceof AtlasRegion) { + AtlasRegion region = (AtlasRegion)this.region; + if (region.rotate) { + localX += region.offsetX / region.originalWidth * width; + localY += region.offsetY / region.originalHeight * height; + localX2 -= (region.originalWidth - region.offsetX - region.packedHeight) / region.originalWidth * width; + localY2 -= (region.originalHeight - region.offsetY - region.packedWidth) / region.originalHeight * height; + } else { + localX += region.offsetX / region.originalWidth * width; + localY += region.offsetY / region.originalHeight * height; + localX2 -= (region.originalWidth - region.offsetX - region.packedWidth) / region.originalWidth * width; + localY2 -= (region.originalHeight - region.offsetY - region.packedHeight) / region.originalHeight * height; + } + } + float scaleX = getScaleX(); + float scaleY = getScaleY(); + localX *= scaleX; + localY *= scaleY; + localX2 *= scaleX; + localY2 *= scaleY; + float rotation = getRotation(); + float cos = MathUtils.cosDeg(rotation); + float sin = MathUtils.sinDeg(rotation); + float x = getX(); + float y = getY(); + float localXCos = localX * cos + x; + float localXSin = localX * sin; + float localYCos = localY * cos + y; + float localYSin = localY * sin; + float localX2Cos = localX2 * cos + x; + float localX2Sin = localX2 * sin; + float localY2Cos = localY2 * cos + y; + float localY2Sin = localY2 * sin; + float[] offset = this.offset; + offset[BLX] = localXCos - localYSin; + offset[BLY] = localYCos + localXSin; + offset[ULX] = localXCos - localY2Sin; + offset[ULY] = localY2Cos + localXSin; + offset[URX] = localX2Cos - localY2Sin; + offset[URY] = localY2Cos + localX2Sin; + offset[BRX] = localX2Cos - localYSin; + offset[BRY] = localYCos + localX2Sin; + } + + public void setRegion (TextureRegion region) { + if (region == null) throw new IllegalArgumentException("region cannot be null."); + this.region = region; + float[] vertices = this.vertices; + if (region instanceof AtlasRegion && ((AtlasRegion)region).rotate) { + vertices[U3] = region.getU(); + vertices[V3] = region.getV2(); + vertices[U4] = region.getU(); + vertices[V4] = region.getV(); + vertices[U1] = region.getU2(); + vertices[V1] = region.getV(); + vertices[U2] = region.getU2(); + vertices[V2] = region.getV2(); + } else { + vertices[U2] = region.getU(); + vertices[V2] = region.getV2(); + vertices[U3] = region.getU(); + vertices[V3] = region.getV(); + vertices[U4] = region.getU2(); + vertices[V4] = region.getV(); + vertices[U1] = region.getU2(); + vertices[V1] = region.getV2(); + } + } + + public TextureRegion getRegion () { + if (region == null) throw new IllegalStateException("Region has not been set: " + this); + return region; + } + + /** @return The updated world vertices. */ + public float[] updateWorldVertices (Slot slot, boolean premultipliedAlpha) { + Skeleton skeleton = slot.getSkeleton(); + Color skeletonColor = skeleton.getColor(); + Color slotColor = slot.getColor(); + Color regionColor = color; + float alpha = skeletonColor.a * slotColor.a * regionColor.a * 255; + float multiplier = premultipliedAlpha ? alpha : 255; + float color = NumberUtils.intToFloatColor( // + ((int)alpha << 24) // + | ((int)(skeletonColor.b * slotColor.b * regionColor.b * multiplier) << 16) // + | ((int)(skeletonColor.g * slotColor.g * regionColor.g * multiplier) << 8) // + | (int)(skeletonColor.r * slotColor.r * regionColor.r * multiplier)); + + float[] vertices = this.vertices; + float[] offset = this.offset; + Bone bone = slot.getBone(); + float x = skeleton.getX() + bone.getWorldX(), y = skeleton.getY() + bone.getWorldY(); + float a = bone.getA(), b = bone.getB(), c = bone.getC(), d = bone.getD(); + float offsetX, offsetY; + + offsetX = offset[BRX]; + offsetY = offset[BRY]; + vertices[X1] = offsetX * a + offsetY * b + x; // br + vertices[Y1] = offsetX * c + offsetY * d + y; + vertices[C1] = color; + + offsetX = offset[BLX]; + offsetY = offset[BLY]; + vertices[X2] = offsetX * a + offsetY * b + x; // bl + vertices[Y2] = offsetX * c + offsetY * d + y; + vertices[C2] = color; + + offsetX = offset[ULX]; + offsetY = offset[ULY]; + vertices[X3] = offsetX * a + offsetY * b + x; // ul + vertices[Y3] = offsetX * c + offsetY * d + y; + vertices[C3] = color; + + offsetX = offset[URX]; + offsetY = offset[URY]; + vertices[X4] = offsetX * a + offsetY * b + x; // ur + vertices[Y4] = offsetX * c + offsetY * d + y; + vertices[C4] = color; + return vertices; + } + + public float[] getWorldVertices () { + return vertices; + } + + public float[] getOffset () { + return offset; + } + + public float getX () { + return x; + } + + public void setX (float x) { + this.x = x; + } + + public float getY () { + return y; + } + + public void setY (float y) { + this.y = y; + } + + public float getScaleX () { + return scaleX; + } + + public void setScaleX (float scaleX) { + this.scaleX = scaleX; + } + + public float getScaleY () { + return scaleY; + } + + public void setScaleY (float scaleY) { + this.scaleY = scaleY; + } + + public float getRotation () { + return rotation; + } + + public void setRotation (float rotation) { + this.rotation = rotation; + } + + public float getWidth () { + return width; + } + + public void setWidth (float width) { + this.width = width; + } + + public float getHeight () { + return height; + } + + public void setHeight (float height) { + this.height = height; + } + + public Color getColor () { + return color; + } + + public String getPath () { + return path; + } + + public void setPath (String path) { + this.path = path; + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionSequenceAttachment.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionSequenceAttachment.java index 53f0f00602..61d08c1360 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionSequenceAttachment.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/RegionSequenceAttachment.java @@ -1,101 +1,100 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine.attachments; - -import com.esotericsoftware.spine.Slot; - -import com.badlogic.gdx.graphics.g2d.TextureRegion; -import com.badlogic.gdx.math.MathUtils; - -/** Attachment that displays various texture regions over time. */ -public class RegionSequenceAttachment extends RegionAttachment { - private Mode mode; - private float frameTime; - private TextureRegion[] regions; - - public RegionSequenceAttachment (String name) { - super(name); - } - - public float[] updateWorldVertices (Slot slot, boolean premultipliedAlpha) { - if (regions == null) throw new IllegalStateException("Regions have not been set: " + this); - - int frameIndex = (int)(slot.getAttachmentTime() / frameTime); - switch (mode) { - case forward: - frameIndex = Math.min(regions.length - 1, frameIndex); - break; - case forwardLoop: - frameIndex = frameIndex % regions.length; - break; - case pingPong: - frameIndex = frameIndex % (regions.length << 1); - if (frameIndex >= regions.length) frameIndex = regions.length - 1 - (frameIndex - regions.length); - break; - case random: - frameIndex = MathUtils.random(regions.length - 1); - break; - case backward: - frameIndex = Math.max(regions.length - frameIndex - 1, 0); - break; - case backwardLoop: - frameIndex = frameIndex % regions.length; - frameIndex = regions.length - frameIndex - 1; - break; - } - setRegion(regions[frameIndex]); - - return super.updateWorldVertices(slot, premultipliedAlpha); - } - - public TextureRegion[] getRegions () { - if (regions == null) throw new IllegalStateException("Regions have not been set: " + this); - return regions; - } - - public void setRegions (TextureRegion[] regions) { - this.regions = regions; - } - - /** Sets the time in seconds each frame is shown. */ - public void setFrameTime (float frameTime) { - this.frameTime = frameTime; - } - - public void setMode (Mode mode) { - this.mode = mode; - } - - static public enum Mode { - forward, backward, forwardLoop, backwardLoop, pingPong, random - } +package com.esotericsoftware.spine.attachments; + +import com.esotericsoftware.spine.Slot; + +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.math.MathUtils; + +/** Attachment that displays various texture regions over time. */ +public class RegionSequenceAttachment extends RegionAttachment { + private Mode mode; + private float frameTime; + private TextureRegion[] regions; + + public RegionSequenceAttachment (String name) { + super(name); + } + + public float[] updateWorldVertices (Slot slot, boolean premultipliedAlpha) { + if (regions == null) throw new IllegalStateException("Regions have not been set: " + this); + + int frameIndex = (int)(slot.getAttachmentTime() / frameTime); + switch (mode) { + case forward: + frameIndex = Math.min(regions.length - 1, frameIndex); + break; + case forwardLoop: + frameIndex = frameIndex % regions.length; + break; + case pingPong: + frameIndex = frameIndex % (regions.length << 1); + if (frameIndex >= regions.length) frameIndex = regions.length - 1 - (frameIndex - regions.length); + break; + case random: + frameIndex = MathUtils.random(regions.length - 1); + break; + case backward: + frameIndex = Math.max(regions.length - frameIndex - 1, 0); + break; + case backwardLoop: + frameIndex = frameIndex % regions.length; + frameIndex = regions.length - frameIndex - 1; + break; + } + setRegion(regions[frameIndex]); + + return super.updateWorldVertices(slot, premultipliedAlpha); + } + + public TextureRegion[] getRegions () { + if (regions == null) throw new IllegalStateException("Regions have not been set: " + this); + return regions; + } + + public void setRegions (TextureRegion[] regions) { + this.regions = regions; + } + + /** Sets the time in seconds each frame is shown. */ + public void setFrameTime (float frameTime) { + this.frameTime = frameTime; + } + + public void setMode (Mode mode) { + this.mode = mode; + } + + static public enum Mode { + forward, backward, forwardLoop, backwardLoop, pingPong, random + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/SkeletonAttachment.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/SkeletonAttachment.java index 7d39fcdad4..e50b58671a 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/SkeletonAttachment.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/SkeletonAttachment.java @@ -1,53 +1,52 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine.attachments; - -import com.esotericsoftware.spine.Skeleton; - -/** Attachment that displays a skeleton. */ -public class SkeletonAttachment extends Attachment { - private Skeleton skeleton; - - public SkeletonAttachment (String name) { - super(name); - } - - /** @return May return null. */ - public Skeleton getSkeleton () { - return skeleton; - } - - /** @param skeleton May be null. */ - public void setSkeleton (Skeleton skeleton) { - this.skeleton = skeleton; - } +package com.esotericsoftware.spine.attachments; + +import com.esotericsoftware.spine.Skeleton; + +/** Attachment that displays a skeleton. */ +public class SkeletonAttachment extends Attachment { + private Skeleton skeleton; + + public SkeletonAttachment (String name) { + super(name); + } + + /** @return May return null. */ + public Skeleton getSkeleton () { + return skeleton; + } + + /** @param skeleton May be null. */ + public void setSkeleton (Skeleton skeleton) { + this.skeleton = skeleton; + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/VertexAttachment.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/VertexAttachment.java index 51829d38d1..51a3e444eb 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/VertexAttachment.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/attachments/VertexAttachment.java @@ -1,150 +1,149 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine.attachments; - -import com.badlogic.gdx.utils.FloatArray; -import com.esotericsoftware.spine.Bone; -import com.esotericsoftware.spine.Skeleton; -import com.esotericsoftware.spine.Slot; - -/** An attachment with vertices that are transformed by one or more bones and can be deformed by a slot's vertices. */ -public class VertexAttachment extends Attachment { - int[] bones; - float[] vertices; - int worldVerticesLength; - - public VertexAttachment (String name) { - super(name); - } - - protected void computeWorldVertices (Slot slot, float[] worldVertices) { - computeWorldVertices(slot, 0, worldVerticesLength, worldVertices, 0); - } - - /** Transforms local vertices to world coordinates. - * @param start The index of the first local vertex value to transform. Each vertex has 2 values, x and y. - * @param count The number of world vertex values to output. Must be <= {@link #getWorldVerticesLength()} - start. - * @param worldVertices The output world vertices. Must have a length >= offset + count. - * @param offset The worldVertices index to begin writing values. */ - protected void computeWorldVertices (Slot slot, int start, int count, float[] worldVertices, int offset) { - count += offset; - Skeleton skeleton = slot.getSkeleton(); - float x = skeleton.getX(), y = skeleton.getY(); - FloatArray deformArray = slot.getAttachmentVertices(); - float[] vertices = this.vertices; - int[] bones = this.bones; - if (bones == null) { - if (deformArray.size > 0) vertices = deformArray.items; - Bone bone = slot.getBone(); - x += bone.getWorldX(); - y += bone.getWorldY(); - float a = bone.getA(), b = bone.getB(), c = bone.getC(), d = bone.getD(); - for (int v = start, w = offset; w < count; v += 2, w += 2) { - float vx = vertices[v], vy = vertices[v + 1]; - worldVertices[w] = vx * a + vy * b + x; - worldVertices[w + 1] = vx * c + vy * d + y; - } - return; - } - int v = 0, skip = 0; - for (int i = 0; i < start; i += 2) { - int n = bones[v]; - v += n + 1; - skip += n; - } - Object[] skeletonBones = skeleton.getBones().items; - if (deformArray.size == 0) { - for (int w = offset, b = skip * 3; w < count; w += 2) { - float wx = x, wy = y; - int n = bones[v++]; - n += v; - for (; v < n; v++, b += 3) { - Bone bone = (Bone)skeletonBones[bones[v]]; - float vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; - wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight; - wy += (vx * bone.getC() + vy * bone.getD() + bone.getWorldY()) * weight; - } - worldVertices[w] = wx; - worldVertices[w + 1] = wy; - } - } else { - float[] deform = deformArray.items; - for (int w = offset, b = skip * 3, f = skip << 1; w < count; w += 2) { - float wx = x, wy = y; - int n = bones[v++]; - n += v; - for (; v < n; v++, b += 3, f += 2) { - Bone bone = (Bone)skeletonBones[bones[v]]; - float vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; - wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight; - wy += (vx * bone.getC() + vy * bone.getD() + bone.getWorldY()) * weight; - } - worldVertices[w] = wx; - worldVertices[w + 1] = wy; - } - } - } - - /** Returns true if a deform originally applied to the specified attachment should be applied to this attachment. */ - public boolean applyDeform (VertexAttachment sourceAttachment) { - return this == sourceAttachment; - } - - /** @return May be null if this attachment has no weights. */ - public int[] getBones () { - return bones; - } - - /** For each vertex, the number of bones affecting the vertex followed by that many bone indices. Ie: count, boneIndex, ... - * @param bones May be null if this attachment has no weights. */ - public void setBones (int[] bones) { - this.bones = bones; - } - - public float[] getVertices () { - return vertices; - } - - /** Sets the vertex position in the bone's coordinate system. For a non-weighted attachment, the values are x,y entries for - * each vertex. For a weighted attachment, the values are x,y,weight entries for each bone affecting each vertex. */ - public void setVertices (float[] vertices) { - this.vertices = vertices; - } - - public int getWorldVerticesLength () { - return worldVerticesLength; - } - - public void setWorldVerticesLength (int worldVerticesLength) { - this.worldVerticesLength = worldVerticesLength; - } +package com.esotericsoftware.spine.attachments; + +import com.badlogic.gdx.utils.FloatArray; +import com.esotericsoftware.spine.Bone; +import com.esotericsoftware.spine.Skeleton; +import com.esotericsoftware.spine.Slot; + +/** An attachment with vertices that are transformed by one or more bones and can be deformed by a slot's vertices. */ +public class VertexAttachment extends Attachment { + int[] bones; + float[] vertices; + int worldVerticesLength; + + public VertexAttachment (String name) { + super(name); + } + + protected void computeWorldVertices (Slot slot, float[] worldVertices) { + computeWorldVertices(slot, 0, worldVerticesLength, worldVertices, 0); + } + + /** Transforms local vertices to world coordinates. + * @param start The index of the first local vertex value to transform. Each vertex has 2 values, x and y. + * @param count The number of world vertex values to output. Must be <= {@link #getWorldVerticesLength()} - start. + * @param worldVertices The output world vertices. Must have a length >= offset + count. + * @param offset The worldVertices index to begin writing values. */ + protected void computeWorldVertices (Slot slot, int start, int count, float[] worldVertices, int offset) { + count += offset; + Skeleton skeleton = slot.getSkeleton(); + float x = skeleton.getX(), y = skeleton.getY(); + FloatArray deformArray = slot.getAttachmentVertices(); + float[] vertices = this.vertices; + int[] bones = this.bones; + if (bones == null) { + if (deformArray.size > 0) vertices = deformArray.items; + Bone bone = slot.getBone(); + x += bone.getWorldX(); + y += bone.getWorldY(); + float a = bone.getA(), b = bone.getB(), c = bone.getC(), d = bone.getD(); + for (int v = start, w = offset; w < count; v += 2, w += 2) { + float vx = vertices[v], vy = vertices[v + 1]; + worldVertices[w] = vx * a + vy * b + x; + worldVertices[w + 1] = vx * c + vy * d + y; + } + return; + } + int v = 0, skip = 0; + for (int i = 0; i < start; i += 2) { + int n = bones[v]; + v += n + 1; + skip += n; + } + Object[] skeletonBones = skeleton.getBones().items; + if (deformArray.size == 0) { + for (int w = offset, b = skip * 3; w < count; w += 2) { + float wx = x, wy = y; + int n = bones[v++]; + n += v; + for (; v < n; v++, b += 3) { + Bone bone = (Bone)skeletonBones[bones[v]]; + float vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; + wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight; + wy += (vx * bone.getC() + vy * bone.getD() + bone.getWorldY()) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } else { + float[] deform = deformArray.items; + for (int w = offset, b = skip * 3, f = skip << 1; w < count; w += 2) { + float wx = x, wy = y; + int n = bones[v++]; + n += v; + for (; v < n; v++, b += 3, f += 2) { + Bone bone = (Bone)skeletonBones[bones[v]]; + float vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; + wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight; + wy += (vx * bone.getC() + vy * bone.getD() + bone.getWorldY()) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } + } + + /** Returns true if a deform originally applied to the specified attachment should be applied to this attachment. */ + public boolean applyDeform (VertexAttachment sourceAttachment) { + return this == sourceAttachment; + } + + /** @return May be null if this attachment has no weights. */ + public int[] getBones () { + return bones; + } + + /** For each vertex, the number of bones affecting the vertex followed by that many bone indices. Ie: count, boneIndex, ... + * @param bones May be null if this attachment has no weights. */ + public void setBones (int[] bones) { + this.bones = bones; + } + + public float[] getVertices () { + return vertices; + } + + /** Sets the vertex position in the bone's coordinate system. For a non-weighted attachment, the values are x,y entries for + * each vertex. For a weighted attachment, the values are x,y,weight entries for each bone affecting each vertex. */ + public void setVertices (float[] vertices) { + this.vertices = vertices; + } + + public int getWorldVerticesLength () { + return worldVerticesLength; + } + + public void setWorldVerticesLength (int worldVerticesLength) { + this.worldVerticesLength = worldVerticesLength; + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonActor.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonActor.java index b8257f5fc3..eab954315c 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonActor.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonActor.java @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ package com.esotericsoftware.spine.utils; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonActorPool.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonActorPool.java index d1bb1f587b..a0416ee851 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonActorPool.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonActorPool.java @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ package com.esotericsoftware.spine.utils; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonPool.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonPool.java index 9b5c4575fe..e7d2bfa9a2 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonPool.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonPool.java @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ package com.esotericsoftware.spine.utils; diff --git a/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/JsonRollback.java b/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/JsonRollback.java index abc2aabf2f..9d609f757c 100644 --- a/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/JsonRollback.java +++ b/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/JsonRollback.java @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ package com.esotericsoftware.spine; diff --git a/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java b/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java index bb3c624325..2b65ddc203 100644 --- a/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java +++ b/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java @@ -1,551 +1,550 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package com.esotericsoftware.spine; - -import static com.badlogic.gdx.scenes.scene2d.actions.Actions.*; - -import java.awt.FileDialog; -import java.awt.Frame; -import java.io.File; -import java.lang.Thread.UncaughtExceptionHandler; - -import com.badlogic.gdx.ApplicationAdapter; -import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.InputAdapter; -import com.badlogic.gdx.InputMultiplexer; -import com.badlogic.gdx.Preferences; -import com.badlogic.gdx.backends.lwjgl.LwjglApplication; -import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration; -import com.badlogic.gdx.files.FileHandle; -import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.Pixmap; -import com.badlogic.gdx.graphics.Pixmap.Format; -import com.badlogic.gdx.graphics.Texture; -import com.badlogic.gdx.graphics.Texture.TextureFilter; -import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch; -import com.badlogic.gdx.graphics.g2d.TextureAtlas; -import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion; -import com.badlogic.gdx.graphics.g2d.TextureAtlas.TextureAtlasData; -import com.badlogic.gdx.graphics.glutils.ShapeRenderer; -import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; -import com.badlogic.gdx.scenes.scene2d.Actor; -import com.badlogic.gdx.scenes.scene2d.InputEvent; -import com.badlogic.gdx.scenes.scene2d.InputListener; -import com.badlogic.gdx.scenes.scene2d.Stage; -import com.badlogic.gdx.scenes.scene2d.Touchable; -import com.badlogic.gdx.scenes.scene2d.ui.CheckBox; -import com.badlogic.gdx.scenes.scene2d.ui.Label; -import com.badlogic.gdx.scenes.scene2d.ui.List; -import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; -import com.badlogic.gdx.scenes.scene2d.ui.Slider; -import com.badlogic.gdx.scenes.scene2d.ui.Table; -import com.badlogic.gdx.scenes.scene2d.ui.TextButton; -import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup; -import com.badlogic.gdx.scenes.scene2d.ui.Window; -import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; -import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; -import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.viewport.ScreenViewport; -import com.esotericsoftware.spine.AnimationState.TrackEntry; - -public class SkeletonViewer extends ApplicationAdapter { - static final float checkModifiedInterval = 0.250f; - static final float reloadDelay = 1; - - UI ui; - - PolygonSpriteBatch batch; - SkeletonMeshRenderer renderer; - SkeletonRendererDebug debugRenderer; - SkeletonData skeletonData; - Skeleton skeleton; - AnimationState state; - int skeletonX, skeletonY; - FileHandle skeletonFile; - long lastModified; - float lastModifiedCheck, reloadTimer; - - public void create () { - Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() { - public void uncaughtException (Thread thread, Throwable ex) { - ex.printStackTrace(); - Runtime.getRuntime().halt(0); // Prevent Swing from keeping JVM alive. - } - }); - - ui = new UI(); - batch = new PolygonSpriteBatch(); - renderer = new SkeletonMeshRenderer(); - debugRenderer = new SkeletonRendererDebug(); - skeletonX = (int)(ui.window.getWidth() + (Gdx.graphics.getWidth() - ui.window.getWidth()) / 2); - skeletonY = Gdx.graphics.getHeight() / 4; - - loadSkeleton( - Gdx.files.internal(Gdx.app.getPreferences("spine-skeletonviewer").getString("lastFile", "spineboy/spineboy.json")), - false); - } - - void loadSkeleton (final FileHandle skeletonFile, boolean reload) { - if (skeletonFile == null) return; - - try { - // A regular texture atlas would normally usually be used. This returns a white image for images not found in the atlas. - Pixmap pixmap = new Pixmap(32, 32, Format.RGBA8888); - pixmap.setColor(new Color(1, 1, 1, 0.33f)); - pixmap.fill(); - final AtlasRegion fake = new AtlasRegion(new Texture(pixmap), 0, 0, 32, 32); - pixmap.dispose(); - - String atlasFileName = skeletonFile.nameWithoutExtension(); - if (atlasFileName.endsWith(".json")) atlasFileName = new FileHandle(atlasFileName).nameWithoutExtension(); - FileHandle atlasFile = skeletonFile.sibling(atlasFileName + ".atlas"); - if (!atlasFile.exists()) atlasFile = skeletonFile.sibling(atlasFileName + ".atlas.txt"); - TextureAtlasData data = !atlasFile.exists() ? null : new TextureAtlasData(atlasFile, atlasFile.parent(), false); - TextureAtlas atlas = new TextureAtlas(data) { - public AtlasRegion findRegion (String name) { - AtlasRegion region = super.findRegion(name); - if (region == null) { - // Look for separate image file. - FileHandle file = skeletonFile.sibling(name + ".png"); - if (file.exists()) { - Texture texture = new Texture(file); - texture.setFilter(TextureFilter.Linear, TextureFilter.Linear); - region = new AtlasRegion(texture, 0, 0, texture.getWidth(), texture.getHeight()); - region.name = name; - } - } - return region != null ? region : fake; - } - }; - - String extension = skeletonFile.extension(); - if (extension.equalsIgnoreCase("json") || extension.equalsIgnoreCase("txt")) { - SkeletonJson json = new SkeletonJson(atlas); - json.setScale(ui.scaleSlider.getValue()); - skeletonData = json.readSkeletonData(skeletonFile); - } else { - SkeletonBinary binary = new SkeletonBinary(atlas); - binary.setScale(ui.scaleSlider.getValue()); - skeletonData = binary.readSkeletonData(skeletonFile); - if (skeletonData.getBones().size == 0) throw new Exception("No bones in skeleton data."); - } - } catch (Exception ex) { - ex.printStackTrace(); - ui.toast("Error loading skeleton: " + skeletonFile.name()); - lastModifiedCheck = 5; - return; - } - - skeleton = new Skeleton(skeletonData); - skeleton.setToSetupPose(); - skeleton = new Skeleton(skeleton); - skeleton.updateWorldTransform(); - - state = new AnimationState(new AnimationStateData(skeletonData)); - - this.skeletonFile = skeletonFile; - Preferences prefs = Gdx.app.getPreferences("spine-skeletonviewer"); - prefs.putString("lastFile", skeletonFile.path()); - prefs.flush(); - lastModified = skeletonFile.lastModified(); - lastModifiedCheck = checkModifiedInterval; - - // Populate UI. - - ui.window.getTitleLabel().setText(skeletonFile.name()); - { - Array items = new Array(); - for (Skin skin : skeletonData.getSkins()) - items.add(skin.getName()); - ui.skinList.setItems(items); - } - { - Array items = new Array(); - for (Animation animation : skeletonData.getAnimations()) - items.add(animation.getName()); - ui.animationList.setItems(items); - } - - // Configure skeleton from UI. - - if (ui.skinList.getSelected() != null) skeleton.setSkin(ui.skinList.getSelected()); - if (ui.animationList.getSelected() != null) - state.setAnimation(0, ui.animationList.getSelected(), ui.loopCheckbox.isChecked()); - - if (reload) ui.toast("Reloaded."); - } - - public void render () { - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); - - float delta = Gdx.graphics.getDeltaTime(); - - if (skeleton != null) { - if (reloadTimer <= 0) { - lastModifiedCheck -= delta; - if (lastModifiedCheck < 0) { - lastModifiedCheck = checkModifiedInterval; - long time = skeletonFile.lastModified(); - if (time != 0 && lastModified != time) reloadTimer = reloadDelay; - } - } else { - reloadTimer -= delta; - if (reloadTimer <= 0) loadSkeleton(skeletonFile, true); - } - - state.getData().setDefaultMix(ui.mixSlider.getValue()); - renderer.setPremultipliedAlpha(ui.premultipliedCheckbox.isChecked()); - - delta = Math.min(delta, 0.032f) * ui.speedSlider.getValue(); - skeleton.update(delta); - skeleton.setFlip(ui.flipXCheckbox.isChecked(), ui.flipYCheckbox.isChecked()); - if (!ui.pauseButton.isChecked()) { - state.update(delta); - state.apply(skeleton); - } - skeleton.setPosition(skeletonX, skeletonY); - skeleton.updateWorldTransform(); - - batch.setColor(Color.WHITE); - batch.begin(); - renderer.draw(batch, skeleton); - batch.end(); - - debugRenderer.setBones(ui.debugBonesCheckbox.isChecked()); - debugRenderer.setRegionAttachments(ui.debugRegionsCheckbox.isChecked()); - debugRenderer.setBoundingBoxes(ui.debugBoundingBoxesCheckbox.isChecked()); - debugRenderer.setMeshHull(ui.debugMeshHullCheckbox.isChecked()); - debugRenderer.setMeshTriangles(ui.debugMeshTrianglesCheckbox.isChecked()); - debugRenderer.setPaths(ui.debugPathsCheckbox.isChecked()); - debugRenderer.draw(skeleton); - } - - ui.stage.act(); - ui.stage.draw(); - - // Draw indicator for timeline position. - if (state != null) { - ShapeRenderer shapes = debugRenderer.getShapeRenderer(); - TrackEntry entry = state.getCurrent(0); - if (entry != null) { - float percent = entry.getTime() / entry.getEndTime(); - if (entry.getLoop()) percent %= 1; - float x = ui.window.getRight() + (Gdx.graphics.getWidth() - ui.window.getRight()) * percent; - shapes.setColor(Color.CYAN); - shapes.begin(ShapeType.Line); - shapes.line(x, 0, x, 20); - shapes.end(); - } - } - } - - public void resize (int width, int height) { - batch.getProjectionMatrix().setToOrtho2D(0, 0, width, height); - debugRenderer.getShapeRenderer().setProjectionMatrix(batch.getProjectionMatrix()); - ui.stage.getViewport().update(width, height, true); - if (!ui.minimizeButton.isChecked()) ui.window.setHeight(height + 8); - } - - class UI { - Stage stage = new Stage(new ScreenViewport()); - com.badlogic.gdx.scenes.scene2d.ui.Skin skin = new com.badlogic.gdx.scenes.scene2d.ui.Skin( - Gdx.files.internal("skin/skin.json")); - - Window window = new Window("Skeleton", skin); - Table root = new Table(skin); - TextButton openButton = new TextButton("Open", skin); - List animationList = new List(skin); - List skinList = new List(skin); - CheckBox loopCheckbox = new CheckBox("Loop", skin); - CheckBox premultipliedCheckbox = new CheckBox("Premultiplied", skin); - Slider mixSlider = new Slider(0f, 2, 0.01f, false, skin); - Label mixLabel = new Label("0.3", skin); - Slider speedSlider = new Slider(0.1f, 3, 0.01f, false, skin); - Label speedLabel = new Label("1.0", skin); - CheckBox flipXCheckbox = new CheckBox("X", skin); - CheckBox flipYCheckbox = new CheckBox("Y", skin); - CheckBox debugBonesCheckbox = new CheckBox("Bones", skin); - CheckBox debugRegionsCheckbox = new CheckBox("Regions", skin); - CheckBox debugBoundingBoxesCheckbox = new CheckBox("Bounds", skin); - CheckBox debugMeshHullCheckbox = new CheckBox("Mesh hull", skin); - CheckBox debugMeshTrianglesCheckbox = new CheckBox("Triangles", skin); - CheckBox debugPathsCheckbox = new CheckBox("Paths", skin); - Slider scaleSlider = new Slider(0.1f, 3, 0.01f, false, skin); - Label scaleLabel = new Label("1.0", skin); - TextButton pauseButton = new TextButton("Pause", skin, "toggle"); - TextButton minimizeButton = new TextButton("-", skin); - TextButton bonesSetupPoseButton = new TextButton("Bones", skin); - TextButton slotsSetupPoseButton = new TextButton("Slots", skin); - TextButton setupPoseButton = new TextButton("Both", skin); - WidgetGroup toasts = new WidgetGroup(); - - public UI () { - // Configure widgets. - - animationList.getSelection().setRequired(false); - - premultipliedCheckbox.setChecked(true); - - loopCheckbox.setChecked(true); - - scaleSlider.setValue(1); - scaleSlider.setSnapToValues(new float[] {1}, 0.1f); - - mixSlider.setValue(0.3f); - - speedSlider.setValue(1); - speedSlider.setSnapToValues(new float[] {1}, 0.1f); - - window.setMovable(false); - window.setResizable(false); - window.setKeepWithinStage(false); - window.setX(-3); - window.setY(-2); - - window.getTitleLabel().setColor(new Color(0.76f, 1, 1, 1)); - window.getTitleTable().add(openButton).space(3); - window.getTitleTable().add(minimizeButton).width(20); - - ScrollPane skinScroll = new ScrollPane(skinList, skin, "bg"); - skinScroll.setFadeScrollBars(false); - - ScrollPane animationScroll = new ScrollPane(animationList, skin, "bg"); - animationScroll.setFadeScrollBars(false); - - // Layout. - - root.defaults().space(6); - root.columnDefaults(0).top().right().padTop(3); - root.columnDefaults(1).left(); - root.add("Scale:"); - { - Table table = table(); - table.add(scaleLabel).width(29); - table.add(scaleSlider).fillX().expandX(); - root.add(table).fill().row(); - } - root.add("Flip:"); - root.add(table(flipXCheckbox, flipYCheckbox)).row(); - root.add("Debug:"); - root.add(table(debugBonesCheckbox, debugRegionsCheckbox, debugBoundingBoxesCheckbox)).row(); - root.add(); - root.add(table(debugMeshHullCheckbox, debugMeshTrianglesCheckbox, debugPathsCheckbox)).row(); - root.add("Alpha:"); - root.add(premultipliedCheckbox).row(); - root.add("Skin:"); - root.add(skinScroll).expand().fill().minHeight(75).row(); - root.add("Setup pose:"); - root.add(table(bonesSetupPoseButton, slotsSetupPoseButton, setupPoseButton)).row(); - root.add("Animation:"); - root.add(animationScroll).expand().fill().minHeight(75).row(); - root.add("Mix:"); - { - Table table = table(); - table.add(mixLabel).width(29); - table.add(mixSlider).fillX().expandX(); - root.add(table).fill().row(); - } - root.add("Speed:"); - { - Table table = table(); - table.add(speedLabel).width(29); - table.add(speedSlider).fillX().expandX(); - root.add(table).fill().row(); - } - root.add("Playback:"); - root.add(table(pauseButton, loopCheckbox)).row(); - - window.add(root).expand().fill(); - window.pack(); - stage.addActor(window); - - { - Table table = new Table(skin); - table.setFillParent(true); - table.setTouchable(Touchable.disabled); - stage.addActor(table); - table.pad(10).bottom().right(); - table.add(toasts); - } - - // Events. - - window.addListener(new InputListener() { - public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { - event.cancel(); - return true; - } - }); - - openButton.addListener(new ChangeListener() { - public void changed (ChangeEvent event, Actor actor) { - FileDialog fileDialog = new FileDialog((Frame)null, "Choose skeleton file"); - fileDialog.setMode(FileDialog.LOAD); - fileDialog.setVisible(true); - String name = fileDialog.getFile(); - String dir = fileDialog.getDirectory(); - if (name == null || dir == null) return; - loadSkeleton(new FileHandle(new File(dir, name).getAbsolutePath()), false); - } - }); - - setupPoseButton.addListener(new ChangeListener() { - public void changed (ChangeEvent event, Actor actor) { - if (skeleton != null) skeleton.setToSetupPose(); - } - }); - bonesSetupPoseButton.addListener(new ChangeListener() { - public void changed (ChangeEvent event, Actor actor) { - if (skeleton != null) skeleton.setBonesToSetupPose(); - } - }); - slotsSetupPoseButton.addListener(new ChangeListener() { - public void changed (ChangeEvent event, Actor actor) { - if (skeleton != null) skeleton.setSlotsToSetupPose(); - } - }); - - minimizeButton.addListener(new ClickListener() { - public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { - event.cancel(); - return super.touchDown(event, x, y, pointer, button); - } - - public void clicked (InputEvent event, float x, float y) { - if (minimizeButton.isChecked()) { - window.getCells().get(0).setActor(null); - window.setHeight(37); - minimizeButton.setText("+"); - } else { - window.getCells().get(0).setActor(root); - ui.window.setHeight(Gdx.graphics.getHeight() + 8); - minimizeButton.setText("-"); - } - } - }); - - scaleSlider.addListener(new ChangeListener() { - public void changed (ChangeEvent event, Actor actor) { - scaleLabel.setText(Float.toString((int)(scaleSlider.getValue() * 100) / 100f)); - if (!scaleSlider.isDragging()) loadSkeleton(skeletonFile, false); - } - }); - - speedSlider.addListener(new ChangeListener() { - public void changed (ChangeEvent event, Actor actor) { - speedLabel.setText(Float.toString((int)(speedSlider.getValue() * 100) / 100f)); - } - }); - - mixSlider.addListener(new ChangeListener() { - public void changed (ChangeEvent event, Actor actor) { - mixLabel.setText(Float.toString((int)(mixSlider.getValue() * 100) / 100f)); - if (state != null) state.getData().setDefaultMix(mixSlider.getValue()); - } - }); - - animationList.addListener(new ChangeListener() { - public void changed (ChangeEvent event, Actor actor) { - if (state != null) { - String name = animationList.getSelected(); - if (name == null) - state.clearTrack(0); - else - state.setAnimation(0, name, loopCheckbox.isChecked()); - } - } - }); - - skinList.addListener(new ChangeListener() { - public void changed (ChangeEvent event, Actor actor) { - if (skeleton != null) { - String skinName = skinList.getSelected(); - if (skinName == null) - skeleton.setSkin((Skin)null); - else - skeleton.setSkin(skinName); - skeleton.setSlotsToSetupPose(); - } - } - }); - - Gdx.input.setInputProcessor(new InputMultiplexer(stage, new InputAdapter() { - public boolean touchDown (int screenX, int screenY, int pointer, int button) { - touchDragged(screenX, screenY, pointer); - return false; - } - - public boolean touchDragged (int screenX, int screenY, int pointer) { - skeletonX = screenX; - skeletonY = Gdx.graphics.getHeight() - screenY; - return false; - } - })); - } - - private Table table (Actor... actors) { - Table table = new Table(); - table.defaults().space(6); - table.add(actors); - return table; - } - - void toast (String text) { - Table table = new Table(); - table.add(new Label(text, skin)); - table.getColor().a = 0; - table.pack(); - table.setPosition(-table.getWidth(), -3 - table.getHeight()); - table.addAction(sequence( // - parallel(moveBy(0, table.getHeight(), 0.3f), fadeIn(0.3f)), // - delay(5f), // - parallel(moveBy(0, table.getHeight(), 0.3f), fadeOut(0.3f)), // - removeActor() // - )); - for (Actor actor : toasts.getChildren()) - actor.addAction(moveBy(0, table.getHeight(), 0.3f)); - toasts.addActor(table); - toasts.getParent().toFront(); - } - } - - static public void main (String[] args) throws Exception { - LwjglApplicationConfiguration.disableAudio = true; - LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); - config.width = 800; - config.height = 600; - config.title = "Skeleton Viewer"; - config.allowSoftwareMode = true; - new LwjglApplication(new SkeletonViewer(), config); - } +package com.esotericsoftware.spine; + +import static com.badlogic.gdx.scenes.scene2d.actions.Actions.*; + +import java.awt.FileDialog; +import java.awt.Frame; +import java.io.File; +import java.lang.Thread.UncaughtExceptionHandler; + +import com.badlogic.gdx.ApplicationAdapter; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.InputAdapter; +import com.badlogic.gdx.InputMultiplexer; +import com.badlogic.gdx.Preferences; +import com.badlogic.gdx.backends.lwjgl.LwjglApplication; +import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Pixmap.Format; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.Texture.TextureFilter; +import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion; +import com.badlogic.gdx.graphics.g2d.TextureAtlas.TextureAtlasData; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.InputListener; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.scenes.scene2d.Touchable; +import com.badlogic.gdx.scenes.scene2d.ui.CheckBox; +import com.badlogic.gdx.scenes.scene2d.ui.Label; +import com.badlogic.gdx.scenes.scene2d.ui.List; +import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; +import com.badlogic.gdx.scenes.scene2d.ui.Slider; +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton; +import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup; +import com.badlogic.gdx.scenes.scene2d.ui.Window; +import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; +import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.viewport.ScreenViewport; +import com.esotericsoftware.spine.AnimationState.TrackEntry; + +public class SkeletonViewer extends ApplicationAdapter { + static final float checkModifiedInterval = 0.250f; + static final float reloadDelay = 1; + + UI ui; + + PolygonSpriteBatch batch; + SkeletonMeshRenderer renderer; + SkeletonRendererDebug debugRenderer; + SkeletonData skeletonData; + Skeleton skeleton; + AnimationState state; + int skeletonX, skeletonY; + FileHandle skeletonFile; + long lastModified; + float lastModifiedCheck, reloadTimer; + + public void create () { + Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() { + public void uncaughtException (Thread thread, Throwable ex) { + ex.printStackTrace(); + Runtime.getRuntime().halt(0); // Prevent Swing from keeping JVM alive. + } + }); + + ui = new UI(); + batch = new PolygonSpriteBatch(); + renderer = new SkeletonMeshRenderer(); + debugRenderer = new SkeletonRendererDebug(); + skeletonX = (int)(ui.window.getWidth() + (Gdx.graphics.getWidth() - ui.window.getWidth()) / 2); + skeletonY = Gdx.graphics.getHeight() / 4; + + loadSkeleton( + Gdx.files.internal(Gdx.app.getPreferences("spine-skeletonviewer").getString("lastFile", "spineboy/spineboy.json")), + false); + } + + void loadSkeleton (final FileHandle skeletonFile, boolean reload) { + if (skeletonFile == null) return; + + try { + // A regular texture atlas would normally usually be used. This returns a white image for images not found in the atlas. + Pixmap pixmap = new Pixmap(32, 32, Format.RGBA8888); + pixmap.setColor(new Color(1, 1, 1, 0.33f)); + pixmap.fill(); + final AtlasRegion fake = new AtlasRegion(new Texture(pixmap), 0, 0, 32, 32); + pixmap.dispose(); + + String atlasFileName = skeletonFile.nameWithoutExtension(); + if (atlasFileName.endsWith(".json")) atlasFileName = new FileHandle(atlasFileName).nameWithoutExtension(); + FileHandle atlasFile = skeletonFile.sibling(atlasFileName + ".atlas"); + if (!atlasFile.exists()) atlasFile = skeletonFile.sibling(atlasFileName + ".atlas.txt"); + TextureAtlasData data = !atlasFile.exists() ? null : new TextureAtlasData(atlasFile, atlasFile.parent(), false); + TextureAtlas atlas = new TextureAtlas(data) { + public AtlasRegion findRegion (String name) { + AtlasRegion region = super.findRegion(name); + if (region == null) { + // Look for separate image file. + FileHandle file = skeletonFile.sibling(name + ".png"); + if (file.exists()) { + Texture texture = new Texture(file); + texture.setFilter(TextureFilter.Linear, TextureFilter.Linear); + region = new AtlasRegion(texture, 0, 0, texture.getWidth(), texture.getHeight()); + region.name = name; + } + } + return region != null ? region : fake; + } + }; + + String extension = skeletonFile.extension(); + if (extension.equalsIgnoreCase("json") || extension.equalsIgnoreCase("txt")) { + SkeletonJson json = new SkeletonJson(atlas); + json.setScale(ui.scaleSlider.getValue()); + skeletonData = json.readSkeletonData(skeletonFile); + } else { + SkeletonBinary binary = new SkeletonBinary(atlas); + binary.setScale(ui.scaleSlider.getValue()); + skeletonData = binary.readSkeletonData(skeletonFile); + if (skeletonData.getBones().size == 0) throw new Exception("No bones in skeleton data."); + } + } catch (Exception ex) { + ex.printStackTrace(); + ui.toast("Error loading skeleton: " + skeletonFile.name()); + lastModifiedCheck = 5; + return; + } + + skeleton = new Skeleton(skeletonData); + skeleton.setToSetupPose(); + skeleton = new Skeleton(skeleton); + skeleton.updateWorldTransform(); + + state = new AnimationState(new AnimationStateData(skeletonData)); + + this.skeletonFile = skeletonFile; + Preferences prefs = Gdx.app.getPreferences("spine-skeletonviewer"); + prefs.putString("lastFile", skeletonFile.path()); + prefs.flush(); + lastModified = skeletonFile.lastModified(); + lastModifiedCheck = checkModifiedInterval; + + // Populate UI. + + ui.window.getTitleLabel().setText(skeletonFile.name()); + { + Array items = new Array(); + for (Skin skin : skeletonData.getSkins()) + items.add(skin.getName()); + ui.skinList.setItems(items); + } + { + Array items = new Array(); + for (Animation animation : skeletonData.getAnimations()) + items.add(animation.getName()); + ui.animationList.setItems(items); + } + + // Configure skeleton from UI. + + if (ui.skinList.getSelected() != null) skeleton.setSkin(ui.skinList.getSelected()); + if (ui.animationList.getSelected() != null) + state.setAnimation(0, ui.animationList.getSelected(), ui.loopCheckbox.isChecked()); + + if (reload) ui.toast("Reloaded."); + } + + public void render () { + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + float delta = Gdx.graphics.getDeltaTime(); + + if (skeleton != null) { + if (reloadTimer <= 0) { + lastModifiedCheck -= delta; + if (lastModifiedCheck < 0) { + lastModifiedCheck = checkModifiedInterval; + long time = skeletonFile.lastModified(); + if (time != 0 && lastModified != time) reloadTimer = reloadDelay; + } + } else { + reloadTimer -= delta; + if (reloadTimer <= 0) loadSkeleton(skeletonFile, true); + } + + state.getData().setDefaultMix(ui.mixSlider.getValue()); + renderer.setPremultipliedAlpha(ui.premultipliedCheckbox.isChecked()); + + delta = Math.min(delta, 0.032f) * ui.speedSlider.getValue(); + skeleton.update(delta); + skeleton.setFlip(ui.flipXCheckbox.isChecked(), ui.flipYCheckbox.isChecked()); + if (!ui.pauseButton.isChecked()) { + state.update(delta); + state.apply(skeleton); + } + skeleton.setPosition(skeletonX, skeletonY); + skeleton.updateWorldTransform(); + + batch.setColor(Color.WHITE); + batch.begin(); + renderer.draw(batch, skeleton); + batch.end(); + + debugRenderer.setBones(ui.debugBonesCheckbox.isChecked()); + debugRenderer.setRegionAttachments(ui.debugRegionsCheckbox.isChecked()); + debugRenderer.setBoundingBoxes(ui.debugBoundingBoxesCheckbox.isChecked()); + debugRenderer.setMeshHull(ui.debugMeshHullCheckbox.isChecked()); + debugRenderer.setMeshTriangles(ui.debugMeshTrianglesCheckbox.isChecked()); + debugRenderer.setPaths(ui.debugPathsCheckbox.isChecked()); + debugRenderer.draw(skeleton); + } + + ui.stage.act(); + ui.stage.draw(); + + // Draw indicator for timeline position. + if (state != null) { + ShapeRenderer shapes = debugRenderer.getShapeRenderer(); + TrackEntry entry = state.getCurrent(0); + if (entry != null) { + float percent = entry.getTime() / entry.getEndTime(); + if (entry.getLoop()) percent %= 1; + float x = ui.window.getRight() + (Gdx.graphics.getWidth() - ui.window.getRight()) * percent; + shapes.setColor(Color.CYAN); + shapes.begin(ShapeType.Line); + shapes.line(x, 0, x, 20); + shapes.end(); + } + } + } + + public void resize (int width, int height) { + batch.getProjectionMatrix().setToOrtho2D(0, 0, width, height); + debugRenderer.getShapeRenderer().setProjectionMatrix(batch.getProjectionMatrix()); + ui.stage.getViewport().update(width, height, true); + if (!ui.minimizeButton.isChecked()) ui.window.setHeight(height + 8); + } + + class UI { + Stage stage = new Stage(new ScreenViewport()); + com.badlogic.gdx.scenes.scene2d.ui.Skin skin = new com.badlogic.gdx.scenes.scene2d.ui.Skin( + Gdx.files.internal("skin/skin.json")); + + Window window = new Window("Skeleton", skin); + Table root = new Table(skin); + TextButton openButton = new TextButton("Open", skin); + List animationList = new List(skin); + List skinList = new List(skin); + CheckBox loopCheckbox = new CheckBox("Loop", skin); + CheckBox premultipliedCheckbox = new CheckBox("Premultiplied", skin); + Slider mixSlider = new Slider(0f, 2, 0.01f, false, skin); + Label mixLabel = new Label("0.3", skin); + Slider speedSlider = new Slider(0.1f, 3, 0.01f, false, skin); + Label speedLabel = new Label("1.0", skin); + CheckBox flipXCheckbox = new CheckBox("X", skin); + CheckBox flipYCheckbox = new CheckBox("Y", skin); + CheckBox debugBonesCheckbox = new CheckBox("Bones", skin); + CheckBox debugRegionsCheckbox = new CheckBox("Regions", skin); + CheckBox debugBoundingBoxesCheckbox = new CheckBox("Bounds", skin); + CheckBox debugMeshHullCheckbox = new CheckBox("Mesh hull", skin); + CheckBox debugMeshTrianglesCheckbox = new CheckBox("Triangles", skin); + CheckBox debugPathsCheckbox = new CheckBox("Paths", skin); + Slider scaleSlider = new Slider(0.1f, 3, 0.01f, false, skin); + Label scaleLabel = new Label("1.0", skin); + TextButton pauseButton = new TextButton("Pause", skin, "toggle"); + TextButton minimizeButton = new TextButton("-", skin); + TextButton bonesSetupPoseButton = new TextButton("Bones", skin); + TextButton slotsSetupPoseButton = new TextButton("Slots", skin); + TextButton setupPoseButton = new TextButton("Both", skin); + WidgetGroup toasts = new WidgetGroup(); + + public UI () { + // Configure widgets. + + animationList.getSelection().setRequired(false); + + premultipliedCheckbox.setChecked(true); + + loopCheckbox.setChecked(true); + + scaleSlider.setValue(1); + scaleSlider.setSnapToValues(new float[] {1}, 0.1f); + + mixSlider.setValue(0.3f); + + speedSlider.setValue(1); + speedSlider.setSnapToValues(new float[] {1}, 0.1f); + + window.setMovable(false); + window.setResizable(false); + window.setKeepWithinStage(false); + window.setX(-3); + window.setY(-2); + + window.getTitleLabel().setColor(new Color(0.76f, 1, 1, 1)); + window.getTitleTable().add(openButton).space(3); + window.getTitleTable().add(minimizeButton).width(20); + + ScrollPane skinScroll = new ScrollPane(skinList, skin, "bg"); + skinScroll.setFadeScrollBars(false); + + ScrollPane animationScroll = new ScrollPane(animationList, skin, "bg"); + animationScroll.setFadeScrollBars(false); + + // Layout. + + root.defaults().space(6); + root.columnDefaults(0).top().right().padTop(3); + root.columnDefaults(1).left(); + root.add("Scale:"); + { + Table table = table(); + table.add(scaleLabel).width(29); + table.add(scaleSlider).fillX().expandX(); + root.add(table).fill().row(); + } + root.add("Flip:"); + root.add(table(flipXCheckbox, flipYCheckbox)).row(); + root.add("Debug:"); + root.add(table(debugBonesCheckbox, debugRegionsCheckbox, debugBoundingBoxesCheckbox)).row(); + root.add(); + root.add(table(debugMeshHullCheckbox, debugMeshTrianglesCheckbox, debugPathsCheckbox)).row(); + root.add("Alpha:"); + root.add(premultipliedCheckbox).row(); + root.add("Skin:"); + root.add(skinScroll).expand().fill().minHeight(75).row(); + root.add("Setup pose:"); + root.add(table(bonesSetupPoseButton, slotsSetupPoseButton, setupPoseButton)).row(); + root.add("Animation:"); + root.add(animationScroll).expand().fill().minHeight(75).row(); + root.add("Mix:"); + { + Table table = table(); + table.add(mixLabel).width(29); + table.add(mixSlider).fillX().expandX(); + root.add(table).fill().row(); + } + root.add("Speed:"); + { + Table table = table(); + table.add(speedLabel).width(29); + table.add(speedSlider).fillX().expandX(); + root.add(table).fill().row(); + } + root.add("Playback:"); + root.add(table(pauseButton, loopCheckbox)).row(); + + window.add(root).expand().fill(); + window.pack(); + stage.addActor(window); + + { + Table table = new Table(skin); + table.setFillParent(true); + table.setTouchable(Touchable.disabled); + stage.addActor(table); + table.pad(10).bottom().right(); + table.add(toasts); + } + + // Events. + + window.addListener(new InputListener() { + public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { + event.cancel(); + return true; + } + }); + + openButton.addListener(new ChangeListener() { + public void changed (ChangeEvent event, Actor actor) { + FileDialog fileDialog = new FileDialog((Frame)null, "Choose skeleton file"); + fileDialog.setMode(FileDialog.LOAD); + fileDialog.setVisible(true); + String name = fileDialog.getFile(); + String dir = fileDialog.getDirectory(); + if (name == null || dir == null) return; + loadSkeleton(new FileHandle(new File(dir, name).getAbsolutePath()), false); + } + }); + + setupPoseButton.addListener(new ChangeListener() { + public void changed (ChangeEvent event, Actor actor) { + if (skeleton != null) skeleton.setToSetupPose(); + } + }); + bonesSetupPoseButton.addListener(new ChangeListener() { + public void changed (ChangeEvent event, Actor actor) { + if (skeleton != null) skeleton.setBonesToSetupPose(); + } + }); + slotsSetupPoseButton.addListener(new ChangeListener() { + public void changed (ChangeEvent event, Actor actor) { + if (skeleton != null) skeleton.setSlotsToSetupPose(); + } + }); + + minimizeButton.addListener(new ClickListener() { + public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { + event.cancel(); + return super.touchDown(event, x, y, pointer, button); + } + + public void clicked (InputEvent event, float x, float y) { + if (minimizeButton.isChecked()) { + window.getCells().get(0).setActor(null); + window.setHeight(37); + minimizeButton.setText("+"); + } else { + window.getCells().get(0).setActor(root); + ui.window.setHeight(Gdx.graphics.getHeight() + 8); + minimizeButton.setText("-"); + } + } + }); + + scaleSlider.addListener(new ChangeListener() { + public void changed (ChangeEvent event, Actor actor) { + scaleLabel.setText(Float.toString((int)(scaleSlider.getValue() * 100) / 100f)); + if (!scaleSlider.isDragging()) loadSkeleton(skeletonFile, false); + } + }); + + speedSlider.addListener(new ChangeListener() { + public void changed (ChangeEvent event, Actor actor) { + speedLabel.setText(Float.toString((int)(speedSlider.getValue() * 100) / 100f)); + } + }); + + mixSlider.addListener(new ChangeListener() { + public void changed (ChangeEvent event, Actor actor) { + mixLabel.setText(Float.toString((int)(mixSlider.getValue() * 100) / 100f)); + if (state != null) state.getData().setDefaultMix(mixSlider.getValue()); + } + }); + + animationList.addListener(new ChangeListener() { + public void changed (ChangeEvent event, Actor actor) { + if (state != null) { + String name = animationList.getSelected(); + if (name == null) + state.clearTrack(0); + else + state.setAnimation(0, name, loopCheckbox.isChecked()); + } + } + }); + + skinList.addListener(new ChangeListener() { + public void changed (ChangeEvent event, Actor actor) { + if (skeleton != null) { + String skinName = skinList.getSelected(); + if (skinName == null) + skeleton.setSkin((Skin)null); + else + skeleton.setSkin(skinName); + skeleton.setSlotsToSetupPose(); + } + } + }); + + Gdx.input.setInputProcessor(new InputMultiplexer(stage, new InputAdapter() { + public boolean touchDown (int screenX, int screenY, int pointer, int button) { + touchDragged(screenX, screenY, pointer); + return false; + } + + public boolean touchDragged (int screenX, int screenY, int pointer) { + skeletonX = screenX; + skeletonY = Gdx.graphics.getHeight() - screenY; + return false; + } + })); + } + + private Table table (Actor... actors) { + Table table = new Table(); + table.defaults().space(6); + table.add(actors); + return table; + } + + void toast (String text) { + Table table = new Table(); + table.add(new Label(text, skin)); + table.getColor().a = 0; + table.pack(); + table.setPosition(-table.getWidth(), -3 - table.getHeight()); + table.addAction(sequence( // + parallel(moveBy(0, table.getHeight(), 0.3f), fadeIn(0.3f)), // + delay(5f), // + parallel(moveBy(0, table.getHeight(), 0.3f), fadeOut(0.3f)), // + removeActor() // + )); + for (Actor actor : toasts.getChildren()) + actor.addAction(moveBy(0, table.getHeight(), 0.3f)); + toasts.addActor(table); + toasts.getParent().toFront(); + } + } + + static public void main (String[] args) throws Exception { + LwjglApplicationConfiguration.disableAudio = true; + LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); + config.width = 800; + config.height = 600; + config.title = "Skeleton Viewer"; + config.allowSoftwareMode = true; + new LwjglApplication(new SkeletonViewer(), config); + } } diff --git a/spine-love/main.lua b/spine-love/main.lua index 6a5c87b577..1144132fc3 100644 --- a/spine-love/main.lua +++ b/spine-love/main.lua @@ -1,108 +1,107 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local spine = require "spine-love.spine" - -local skeletons = {} -local activeSkeleton = 1 - -function loadSkeleton (jsonFile, atlasFile, animation, skin, scale, x, y) - local loader = function (path) return love.graphics.newImage("data/" .. path) end - local atlas = spine.TextureAtlas.new(spine.utils.readFile("data/" .. atlasFile .. ".atlas"), loader) - - local json = spine.SkeletonJson.new(spine.TextureAtlasAttachmentLoader.new(atlas)) - json.scale = scale - local skeletonData = json:readSkeletonDataFile("data/" .. jsonFile .. ".json") - local skeleton = spine.Skeleton.new(skeletonData) - skeleton.x = x - skeleton.y = y - skeleton.flipX = false - skeleton.flipY = true - if skin then - skeleton:setSkin(skin) - end - skeleton:setToSetupPose() - - local stateData = spine.AnimationStateData.new(skeletonData) - local state = spine.AnimationState.new(stateData) - state:setAnimationByName(0, animation, true) - - state.onStart = function (trackIndex) - print(trackIndex.." start: "..state:getCurrent(trackIndex).animation.name) - end - state.onEnd = function (trackIndex) - print(trackIndex.." end: "..state:getCurrent(trackIndex).animation.name) - end - state.onComplete = function (trackIndex, loopCount) - print(trackIndex.." complete: "..state:getCurrent(trackIndex).animation.name..", "..loopCount) - end - state.onEvent = function (trackIndex, event) - print(trackIndex.." event: "..state:getCurrent(trackIndex).animation.name..", "..event.data.name..", "..event.intValue..", "..event.floatValue..", '"..(event.stringValue or "").."'") - end - - state:update(0.5) - state:apply(skeleton) - - return { state = state, skeleton = skeleton } -end - -function love.load(arg) - if arg[#arg] == "-debug" then require("mobdebug").start() end - table.insert(skeletons, loadSkeleton("test", "test", "animation", nil, 0.5, 400, 300)) - table.insert(skeletons, loadSkeleton("spineboy", "spineboy", "walk", nil, 0.5, 400, 500)) - table.insert(skeletons, loadSkeleton("raptor", "raptor", "walk", nil, 0.3, 400, 500)) - table.insert(skeletons, loadSkeleton("goblins-mesh", "goblins", "walk", "goblin", 1, 400, 500)) - table.insert(skeletons, loadSkeleton("tank", "tank", "drive", nil, 0.2, 600, 500)) - table.insert(skeletons, loadSkeleton("vine", "vine", "animation", nil, 0.3, 400, 500)) - table.insert(skeletons, loadSkeleton("stretchyman", "stretchyman", "sneak", nil, 0.3, 200, 500)) - skeletonRenderer = spine.SkeletonRenderer.new() -end - -function love.update (delta) - -- Update the state with the delta time, apply it, and update the world transforms. - local state = skeletons[activeSkeleton].state - local skeleton = skeletons[activeSkeleton].skeleton - state:update(delta) - state:apply(skeleton) - skeleton:updateWorldTransform() -end - -function love.draw () - love.graphics.setBackgroundColor(128, 128, 128, 255) - love.graphics.setColor(255, 255, 255) - local skeleton = skeletons[activeSkeleton].skeleton - skeletonRenderer:draw(skeleton) -end -function love.mousepressed (x, y, button, istouch) - activeSkeleton = activeSkeleton + 1 - if activeSkeleton > #skeletons then activeSkeleton = 1 end +local spine = require "spine-love.spine" + +local skeletons = {} +local activeSkeleton = 1 + +function loadSkeleton (jsonFile, atlasFile, animation, skin, scale, x, y) + local loader = function (path) return love.graphics.newImage("data/" .. path) end + local atlas = spine.TextureAtlas.new(spine.utils.readFile("data/" .. atlasFile .. ".atlas"), loader) + + local json = spine.SkeletonJson.new(spine.TextureAtlasAttachmentLoader.new(atlas)) + json.scale = scale + local skeletonData = json:readSkeletonDataFile("data/" .. jsonFile .. ".json") + local skeleton = spine.Skeleton.new(skeletonData) + skeleton.x = x + skeleton.y = y + skeleton.flipX = false + skeleton.flipY = true + if skin then + skeleton:setSkin(skin) + end + skeleton:setToSetupPose() + + local stateData = spine.AnimationStateData.new(skeletonData) + local state = spine.AnimationState.new(stateData) + state:setAnimationByName(0, animation, true) + + state.onStart = function (trackIndex) + print(trackIndex.." start: "..state:getCurrent(trackIndex).animation.name) + end + state.onEnd = function (trackIndex) + print(trackIndex.." end: "..state:getCurrent(trackIndex).animation.name) + end + state.onComplete = function (trackIndex, loopCount) + print(trackIndex.." complete: "..state:getCurrent(trackIndex).animation.name..", "..loopCount) + end + state.onEvent = function (trackIndex, event) + print(trackIndex.." event: "..state:getCurrent(trackIndex).animation.name..", "..event.data.name..", "..event.intValue..", "..event.floatValue..", '"..(event.stringValue or "").."'") + end + + state:update(0.5) + state:apply(skeleton) + + return { state = state, skeleton = skeleton } +end + +function love.load(arg) + if arg[#arg] == "-debug" then require("mobdebug").start() end + table.insert(skeletons, loadSkeleton("test", "test", "animation", nil, 0.5, 400, 300)) + table.insert(skeletons, loadSkeleton("spineboy", "spineboy", "walk", nil, 0.5, 400, 500)) + table.insert(skeletons, loadSkeleton("raptor", "raptor", "walk", nil, 0.3, 400, 500)) + table.insert(skeletons, loadSkeleton("goblins-mesh", "goblins", "walk", "goblin", 1, 400, 500)) + table.insert(skeletons, loadSkeleton("tank", "tank", "drive", nil, 0.2, 600, 500)) + table.insert(skeletons, loadSkeleton("vine", "vine", "animation", nil, 0.3, 400, 500)) + table.insert(skeletons, loadSkeleton("stretchyman", "stretchyman", "sneak", nil, 0.3, 200, 500)) + skeletonRenderer = spine.SkeletonRenderer.new() +end + +function love.update (delta) + -- Update the state with the delta time, apply it, and update the world transforms. + local state = skeletons[activeSkeleton].state + local skeleton = skeletons[activeSkeleton].skeleton + state:update(delta) + state:apply(skeleton) + skeleton:updateWorldTransform() +end + +function love.draw () + love.graphics.setBackgroundColor(128, 128, 128, 255) + love.graphics.setColor(255, 255, 255) + local skeleton = skeletons[activeSkeleton].skeleton + skeletonRenderer:draw(skeleton) +end + +function love.mousepressed (x, y, button, istouch) + activeSkeleton = activeSkeleton + 1 + if activeSkeleton > #skeletons then activeSkeleton = 1 end end diff --git a/spine-love/spine-love/spine.lua b/spine-love/spine-love/spine.lua index d83458ce74..3bdf6f400b 100644 --- a/spine-love/spine-love/spine.lua +++ b/spine-love/spine-love/spine.lua @@ -1,249 +1,249 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- -local setmetatable = setmetatable - -spine = {} - -spine.utils = require "spine-lua.utils" -spine.SkeletonJson = require "spine-lua.SkeletonJson" -spine.SkeletonData = require "spine-lua.SkeletonData" -spine.BoneData = require "spine-lua.BoneData" -spine.SlotData = require "spine-lua.SlotData" -spine.IkConstraintData = require "spine-lua.IkConstraintData" -spine.Skin = require "spine-lua.Skin" -spine.Attachment = require "spine-lua.attachments.Attachment" -spine.BoundingBoxAttachment = require "spine-lua.attachments.BoundingBoxAttachment" -spine.RegionAttachment = require "spine-lua.attachments.RegionAttachment" -spine.MeshAttachment = require "spine-lua.attachments.MeshAttachment" -spine.VertexAttachment = require "spine-lua.attachments.VertexAttachment" -spine.PathAttachment = require "spine-lua.attachments.PathAttachment" -spine.Skeleton = require "spine-lua.Skeleton" -spine.Bone = require "spine-lua.Bone" -spine.Slot = require "spine-lua.Slot" -spine.IkConstraint = require "spine-lua.IkConstraint" -spine.AttachmentType = require "spine-lua.attachments.AttachmentType" -spine.AttachmentLoader = require "spine-lua.AttachmentLoader" -spine.Animation = require "spine-lua.Animation" -spine.AnimationStateData = require "spine-lua.AnimationStateData" -spine.AnimationState = require "spine-lua.AnimationState" -spine.EventData = require "spine-lua.EventData" -spine.Event = require "spine-lua.Event" -spine.SkeletonBounds = require "spine-lua.SkeletonBounds" -spine.BlendMode = require "spine-lua.BlendMode" -spine.TextureAtlas = require "spine-lua.TextureAtlas" -spine.TextureRegion = require "spine-lua.TextureRegion" -spine.TextureAtlasRegion = require "spine-lua.TextureAtlasRegion" -spine.TextureAtlasAttachmentLoader = require "spine-lua.TextureAtlasAttachmentLoader" -spine.Color = require "spine-lua.Color" - -spine.utils.readFile = function (fileName, base) - local path = fileName - if base then path = base .. '/' .. path end - return love.filesystem.read(path) -end - -local json = require "spine-love.dkjson" -spine.utils.readJSON = function (text) - return json.decode(text) -end - -local PolygonBatcher = {} -PolygonBatcher.__index = PolygonBatcher - -function PolygonBatcher.new(vertexCount) - local self = { - mesh = love.graphics.newMesh(vertexCount, "triangles", "dynamic"), - maxVerticesLength = vertexCount, - maxIndicesLength = vertexCount * 3, - verticesLength = 0, - indicesLength = 0, - lastTexture = nil, - isDrawing = false, - drawCalls = 0, - vertex = { 0, 0, 0, 0, 0, 0, 0, 0 }, - indices = nil - } - - local indices = {} - local i = 1 - local maxIndicesLength = self.maxIndicesLength - while i <= maxIndicesLength do - indices[i] = 1 - i = i + 1 - end - self.indices = indices; - - setmetatable(self, PolygonBatcher) - - return self -end - -function PolygonBatcher:begin () - if self.isDrawing then error("PolygonBatcher is already drawing. Call PolygonBatcher:stop() before calling PolygonBatcher:begin().", 2) end - self.lastTexture = nil - self.isDrawing = true - self.drawCalls = 0 -end - -function PolygonBatcher:draw (texture, vertices, indices) - local numVertices = #vertices / 8 - local numIndices = #indices - local mesh = self.mesh - - if texture ~= self.lastTexture then - self:flush() - self.lastTexture = texture - mesh:setTexture(texture) - elseif self.verticesLength + numVertices >= self.maxVerticesLength or self.indicesLength + numIndices > self.maxIndicesLength then - self:flush() - end - - local i = 1 - local indexStart = self.indicesLength + 1 - local offset = self.verticesLength - local indexEnd = indexStart + numIndices - local meshIndices = self.indices - while indexStart < indexEnd do - meshIndices[indexStart] = indices[i] + offset - indexStart = indexStart + 1 - i = i + 1 - end - self.indicesLength = self.indicesLength + numIndices - - i = 1 - local vertexStart = self.verticesLength + 1 - local vertexEnd = vertexStart + numVertices - local vertex = self.vertex - while vertexStart < vertexEnd do - vertex[1] = vertices[i] - vertex[2] = vertices[i+1] - vertex[3] = vertices[i+2] - vertex[4] = vertices[i+3] - vertex[5] = vertices[i+4] * 255 - vertex[6] = vertices[i+5] * 255 - vertex[7] = vertices[i+6] * 255 - vertex[8] = vertices[i+7] * 255 - mesh:setVertex(vertexStart, vertex) - vertexStart = vertexStart + 1 - i = i + 8 - end - self.verticesLength = self.verticesLength + numVertices -end - -function PolygonBatcher:flush () - if self.verticesLength == 0 then return end - local mesh = self.mesh - mesh:setVertexMap(self.indices) - mesh:setDrawRange(1, self.indicesLength) - love.graphics.draw(mesh, 0, 0) - - self.verticesLength = 0 - self.indicesLength = 0 - self.drawCalls = self.drawCalls + 1 -end - -function PolygonBatcher:stop () - if not self.isDrawing then error("PolygonBatcher is not drawing. Call PolygonBatcher:begin() first.", 2) end - if self.verticesLength > 0 then self:flush() end - - self.lastTexture = nil - self.isDrawing = false -end - -local SkeletonRenderer = {} -SkeletonRenderer.__index = SkeletonRenderer -SkeletonRenderer.QUAD_TRIANGLES = { 1, 2, 3, 3, 4, 1 } - -function SkeletonRenderer.new () - local self = { - batcher = PolygonBatcher.new(3 * 500), - premultipliedAlpha = false - } - - setmetatable(self, SkeletonRenderer) - return self -end - -function SkeletonRenderer:draw (skeleton) - local batcher = self.batcher - local premultipliedAlpha = self.premultipliedAlpha - - local lastLoveBlendMode = love.graphics.getBlendMode() - love.graphics.setBlendMode("alpha") - local lastBlendMode = spine.BlendMode.normal - batcher:begin() - - local drawOrder = skeleton.drawOrder - for i, slot in ipairs(drawOrder) do - local attachment = slot.attachment - local vertices = nil - local indics = nil - local texture = nil - if attachment then - if attachment.type == spine.AttachmentType.region then - vertices = attachment:updateWorldVertices(slot, premultipliedAlpha) - indices = SkeletonRenderer.QUAD_TRIANGLES - texture = attachment.region.renderObject.texture - elseif attachment.type == spine.AttachmentType.mesh then - vertices = attachment:updateWorldVertices(slot, premultipliedAlpha) - indices = attachment.triangles - texture = attachment.region.renderObject.texture - end - - if texture then - local slotBlendMode = slot.data.blendMode - if lastBlendMode ~= slotBlendMode then - if slotBlendMode == spine.BlendMode.normal then - love.graphics.setBlendMode("alpha") - elseif slotBlendMode == spine.BlendMode.additive then - love.graphics.setBlendMode("additive") - elseif slotBlendMode == spine.BlendMode.multiply then - love.graphics.setBlendMode("multiply") - elseif slotBlendMode == spine.BlendMode.screen then - love.graphics.setBlendMode("screen") - end - lastBlendMode = slotBlendMode - batcher:stop() - batcher:begin() - end - batcher:draw(texture, vertices, indices) - end - end - end - - batcher:stop() - love.graphics.setBlendMode(lastLoveBlendMode) -end - -spine.PolygonBatcher = PolygonBatcher -spine.SkeletonRenderer = SkeletonRenderer +local setmetatable = setmetatable + +spine = {} + +spine.utils = require "spine-lua.utils" +spine.SkeletonJson = require "spine-lua.SkeletonJson" +spine.SkeletonData = require "spine-lua.SkeletonData" +spine.BoneData = require "spine-lua.BoneData" +spine.SlotData = require "spine-lua.SlotData" +spine.IkConstraintData = require "spine-lua.IkConstraintData" +spine.Skin = require "spine-lua.Skin" +spine.Attachment = require "spine-lua.attachments.Attachment" +spine.BoundingBoxAttachment = require "spine-lua.attachments.BoundingBoxAttachment" +spine.RegionAttachment = require "spine-lua.attachments.RegionAttachment" +spine.MeshAttachment = require "spine-lua.attachments.MeshAttachment" +spine.VertexAttachment = require "spine-lua.attachments.VertexAttachment" +spine.PathAttachment = require "spine-lua.attachments.PathAttachment" +spine.Skeleton = require "spine-lua.Skeleton" +spine.Bone = require "spine-lua.Bone" +spine.Slot = require "spine-lua.Slot" +spine.IkConstraint = require "spine-lua.IkConstraint" +spine.AttachmentType = require "spine-lua.attachments.AttachmentType" +spine.AttachmentLoader = require "spine-lua.AttachmentLoader" +spine.Animation = require "spine-lua.Animation" +spine.AnimationStateData = require "spine-lua.AnimationStateData" +spine.AnimationState = require "spine-lua.AnimationState" +spine.EventData = require "spine-lua.EventData" +spine.Event = require "spine-lua.Event" +spine.SkeletonBounds = require "spine-lua.SkeletonBounds" +spine.BlendMode = require "spine-lua.BlendMode" +spine.TextureAtlas = require "spine-lua.TextureAtlas" +spine.TextureRegion = require "spine-lua.TextureRegion" +spine.TextureAtlasRegion = require "spine-lua.TextureAtlasRegion" +spine.TextureAtlasAttachmentLoader = require "spine-lua.TextureAtlasAttachmentLoader" +spine.Color = require "spine-lua.Color" + +spine.utils.readFile = function (fileName, base) + local path = fileName + if base then path = base .. '/' .. path end + return love.filesystem.read(path) +end + +local json = require "spine-love.dkjson" +spine.utils.readJSON = function (text) + return json.decode(text) +end + +local PolygonBatcher = {} +PolygonBatcher.__index = PolygonBatcher + +function PolygonBatcher.new(vertexCount) + local self = { + mesh = love.graphics.newMesh(vertexCount, "triangles", "dynamic"), + maxVerticesLength = vertexCount, + maxIndicesLength = vertexCount * 3, + verticesLength = 0, + indicesLength = 0, + lastTexture = nil, + isDrawing = false, + drawCalls = 0, + vertex = { 0, 0, 0, 0, 0, 0, 0, 0 }, + indices = nil + } + + local indices = {} + local i = 1 + local maxIndicesLength = self.maxIndicesLength + while i <= maxIndicesLength do + indices[i] = 1 + i = i + 1 + end + self.indices = indices; + + setmetatable(self, PolygonBatcher) + + return self +end + +function PolygonBatcher:begin () + if self.isDrawing then error("PolygonBatcher is already drawing. Call PolygonBatcher:stop() before calling PolygonBatcher:begin().", 2) end + self.lastTexture = nil + self.isDrawing = true + self.drawCalls = 0 +end + +function PolygonBatcher:draw (texture, vertices, indices) + local numVertices = #vertices / 8 + local numIndices = #indices + local mesh = self.mesh + + if texture ~= self.lastTexture then + self:flush() + self.lastTexture = texture + mesh:setTexture(texture) + elseif self.verticesLength + numVertices >= self.maxVerticesLength or self.indicesLength + numIndices > self.maxIndicesLength then + self:flush() + end + + local i = 1 + local indexStart = self.indicesLength + 1 + local offset = self.verticesLength + local indexEnd = indexStart + numIndices + local meshIndices = self.indices + while indexStart < indexEnd do + meshIndices[indexStart] = indices[i] + offset + indexStart = indexStart + 1 + i = i + 1 + end + self.indicesLength = self.indicesLength + numIndices + + i = 1 + local vertexStart = self.verticesLength + 1 + local vertexEnd = vertexStart + numVertices + local vertex = self.vertex + while vertexStart < vertexEnd do + vertex[1] = vertices[i] + vertex[2] = vertices[i+1] + vertex[3] = vertices[i+2] + vertex[4] = vertices[i+3] + vertex[5] = vertices[i+4] * 255 + vertex[6] = vertices[i+5] * 255 + vertex[7] = vertices[i+6] * 255 + vertex[8] = vertices[i+7] * 255 + mesh:setVertex(vertexStart, vertex) + vertexStart = vertexStart + 1 + i = i + 8 + end + self.verticesLength = self.verticesLength + numVertices +end + +function PolygonBatcher:flush () + if self.verticesLength == 0 then return end + local mesh = self.mesh + mesh:setVertexMap(self.indices) + mesh:setDrawRange(1, self.indicesLength) + love.graphics.draw(mesh, 0, 0) + + self.verticesLength = 0 + self.indicesLength = 0 + self.drawCalls = self.drawCalls + 1 +end + +function PolygonBatcher:stop () + if not self.isDrawing then error("PolygonBatcher is not drawing. Call PolygonBatcher:begin() first.", 2) end + if self.verticesLength > 0 then self:flush() end + + self.lastTexture = nil + self.isDrawing = false +end + +local SkeletonRenderer = {} +SkeletonRenderer.__index = SkeletonRenderer +SkeletonRenderer.QUAD_TRIANGLES = { 1, 2, 3, 3, 4, 1 } + +function SkeletonRenderer.new () + local self = { + batcher = PolygonBatcher.new(3 * 500), + premultipliedAlpha = false + } + + setmetatable(self, SkeletonRenderer) + return self +end + +function SkeletonRenderer:draw (skeleton) + local batcher = self.batcher + local premultipliedAlpha = self.premultipliedAlpha + + local lastLoveBlendMode = love.graphics.getBlendMode() + love.graphics.setBlendMode("alpha") + local lastBlendMode = spine.BlendMode.normal + batcher:begin() + + local drawOrder = skeleton.drawOrder + for i, slot in ipairs(drawOrder) do + local attachment = slot.attachment + local vertices = nil + local indics = nil + local texture = nil + if attachment then + if attachment.type == spine.AttachmentType.region then + vertices = attachment:updateWorldVertices(slot, premultipliedAlpha) + indices = SkeletonRenderer.QUAD_TRIANGLES + texture = attachment.region.renderObject.texture + elseif attachment.type == spine.AttachmentType.mesh then + vertices = attachment:updateWorldVertices(slot, premultipliedAlpha) + indices = attachment.triangles + texture = attachment.region.renderObject.texture + end + + if texture then + local slotBlendMode = slot.data.blendMode + if lastBlendMode ~= slotBlendMode then + if slotBlendMode == spine.BlendMode.normal then + love.graphics.setBlendMode("alpha") + elseif slotBlendMode == spine.BlendMode.additive then + love.graphics.setBlendMode("additive") + elseif slotBlendMode == spine.BlendMode.multiply then + love.graphics.setBlendMode("multiply") + elseif slotBlendMode == spine.BlendMode.screen then + love.graphics.setBlendMode("screen") + end + lastBlendMode = slotBlendMode + batcher:stop() + batcher:begin() + end + batcher:draw(texture, vertices, indices) + end + end + end + + batcher:stop() + love.graphics.setBlendMode(lastLoveBlendMode) +end + +spine.PolygonBatcher = PolygonBatcher +spine.SkeletonRenderer = SkeletonRenderer + return spine diff --git a/spine-lua/Animation.lua b/spine-lua/Animation.lua index bbae6abe88..f805b1ca71 100644 --- a/spine-lua/Animation.lua +++ b/spine-lua/Animation.lua @@ -1,925 +1,924 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - --- FIXME --- All the indexing in this file is zero based. We use zlen() --- instead of the # operator. Initialization of number arrays --- is performed via utils.newNumberArrayZero. This needs --- to be rewritten using one-based indexing for better performance - -local utils = require "spine-lua.utils" -local AttachmentType = require "spine-lua.attachments.AttachmentType" - -local function zlen(array) - return #array + 1 -end - -local Animation = {} -function Animation.new (name, timelines, duration) - if not timelines then error("timelines cannot be nil", 2) end - - local self = { - name = name, - timelines = timelines, - duration = duration - } - - function self:apply (skeleton, lastTime, time, loop, events) - if not skeleton then error("skeleton cannot be nil.", 2) end - - if loop and duration > 0 then - time = time % self.duration - if lastTime > 0 then lastTime = lastTime % self.duration end - end - - for i,timeline in ipairs(self.timelines) do - timeline:apply(skeleton, lastTime, time, events, 1) - end - end - - function self:mix (skeleton, lastTime, time, loop, events, alpha) - if not skeleton then error("skeleton cannot be nil.", 2) end - - if loop and duration > 0 then - time = time % self.duration - if lastTime > 0 then lastTime = lastTime % self.duration end - end - - for i,timeline in ipairs(self.timelines) do - timeline:apply(skeleton, lastTime, time, events, alpha) - end - end - - return self -end - -local function binarySearch (values, target, step) - local low = 0 - local high = math.floor(zlen(values) / step - 2) - if high == 0 then return step end - local current = math.floor(high / 2) - while true do - if values[(current + 1) * step] <= target then - low = current + 1 - else - high = current - end - if low == high then return (low + 1) * step end - current = math.floor((low + high) / 2) - end -end - -local function binarySearch1 (values, target) - local low = 0 - local high = math.floor(zlen(values) - 2) - if high == 0 then return 1 end - local current = math.floor(high / 2) - while true do - if values[current + 1] <= target then - low = current + 1 - else - high = current - end - if low == high then return low + 1 end - current = math.floor((low + high) / 2) - end -end - -local function linearSearch (values, target, step) - local i = 0 - local last = zlen(values) - step - while i <= last do - if (values[i] > target) then return i end - i = i + step - end - return -1 -end - -Animation.CurveTimeline = {} -function Animation.CurveTimeline.new (frameCount) - local LINEAR = 0 - local STEPPED = 1 - local BEZIER = 2 - local BEZIER_SIZE = 10 * 2 - 1 - - local self = { - curves = utils.newNumberArrayZero((frameCount - 1) * BEZIER_SIZE) -- type, x, y, ... - } - - function self:getFrameCount () - return math.floor(zlen(self.curves) / BEZIER_SIZE) + 1 - end - - function self:setStepped (frameIndex) - self.curves[frameIndex * BEZIER_SIZE] = STEPPED - end - - function self:getCurveType (frameIndex) - local index = frameIndex * BEZIER_SIZE - if index == zlen(self.curves) then return LINEAR end - local type = self.curves[index] - if type == LINEAR then return LINEAR end - if type == STEPPED then return STEPPED end - return BEZIER - end - - function self:setCurve (frameIndex, cx1, cy1, cx2, cy2) - local tmpx = (-cx1 * 2 + cx2) * 0.03 - local tmpy = (-cy1 * 2 + cy2) * 0.03 - local dddfx = ((cx1 - cx2) * 3 + 1) * 0.006 - local dddfy = ((cy1 - cy2) * 3 + 1) * 0.006 - local ddfx = tmpx * 2 + dddfx - local ddfy = tmpy * 2 + dddfy - local dfx = cx1 * 0.3 + tmpx + dddfx * 0.16666667 - local dfy = cy1 * 0.3 + tmpy + dddfy * 0.16666667 - - local i = frameIndex * BEZIER_SIZE - local curves = self.curves - curves[i] = BEZIER - i = i + 1 - - local x = dfx - local y = dfy - local n = i + BEZIER_SIZE - 1 - while i < n do - curves[i] = x - curves[i + 1] = y - dfx = dfx + ddfx - dfy = dfy + ddfy - ddfx = ddfx + dddfx - ddfy = ddfy + dddfy - x = x + dfx - y = y + dfy - i = i + 2 - end - end - - function self:getCurvePercent (frameIndex, percent) - percent = utils.clamp(percent, 0, 1) - local curves = self.curves - local i = frameIndex * BEZIER_SIZE - local type = curves[i] - if type == LINEAR then return percent end - if type == STEPPED then return 0 end - i = i + 1 - local x - local n = i + BEZIER_SIZE - 1 - local start = i - while i < n do - x = curves[i] - if x >= percent then - local prevX, prevY - if i == start then - prevX = 0 - prevY = 0 - else - prevX = curves[i - 2] - prevY = curves[i - 1] - end - return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX) - end - i = i + 2 - end - local y = curves[i - 1] - return y + (1 - y) * (percent - x) / (1 - x) -- Last point is 1,1. - end - - return self -end - -Animation.RotateTimeline = {} -Animation.RotateTimeline.ENTRIES = 2 -function Animation.RotateTimeline.new (frameCount) - local ENTRIES = Animation.RotateTimeline.ENTRIES - local PREV_TIME = -2 - local PREV_ROTATION = -1 - local ROTATION = 1 - - local self = Animation.CurveTimeline.new(frameCount) - self.boneIndex = -1 - self.frames = utils.newNumberArrayZero(frameCount * 2) - - function self:setFrame (frameIndex, time, degrees) - frameIndex = frameIndex * 2 - self.frames[frameIndex] = time - self.frames[frameIndex + ROTATION] = degrees - end - - function self:apply (skeleton, lastTime, time, firedEvents, alpha) - local frames = self.frames - if time < frames[0] then return end -- Time is before first frame. - - local bone = skeleton.bones[self.boneIndex] - - if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. - local amount = bone.data.rotation + frames[zlen(frames) + PREV_ROTATION] - bone.rotation - while amount > 180 do - amount = amount - 360 - end - while amount < -180 do - amount = amount + 360 - end - bone.rotation = bone.rotation + amount * alpha - return - end - - -- Interpolate between the last frame and the current frame. - local frame = binarySearch(frames, time, ENTRIES) - local prevRotation = frames[frame + PREV_ROTATION] - local frameTime = frames[frame] - local percent = self:getCurvePercent((math.floor(frame / 2)) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) - - local amount = frames[frame + ROTATION] - prevRotation - while amount > 180 do - amount = amount - 360 - end - while amount < -180 do - amount = amount + 360 - end - amount = bone.data.rotation + (prevRotation + amount * percent) - bone.rotation - while amount > 180 do - amount = amount - 360 - end - while amount < -180 do - amount = amount + 360 - end - bone.rotation = bone.rotation + amount * alpha - end - - return self -end - -Animation.TranslateTimeline = {} -Animation.TranslateTimeline.ENTRIES = 3 -function Animation.TranslateTimeline.new (frameCount) - local ENTRIES = Animation.TranslateTimeline.ENTRIES - local PREV_TIME = -3 - local PREV_X = -2 - local PREV_Y = -1 - local X = 1 - local Y = 2 - - local self = Animation.CurveTimeline.new(frameCount) - self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) - self.boneIndex = -1 - - function self:setFrame (frameIndex, time, x, y) - frameIndex = frameIndex * ENTRIES - self.frames[frameIndex] = time - self.frames[frameIndex + X] = x - self.frames[frameIndex + Y] = y - end - - function self:apply (skeleton, lastTime, time, firedEvents, alpha) - local frames = self.frames - if time < frames[0] then return end -- Time is before first frame. - - local bone = skeleton.bones[self.boneIndex] - - if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. - bone.x = bone.x + (bone.data.x + frames[zlen(frames) + PREV_X] - bone.x) * alpha - bone.y = bone.y + (bone.data.y + frames[zlen(frames) + PREV_Y] - bone.y) * alpha - return - end - - -- Interpolate between the last frame and the current frame. - local frame = binarySearch(frames, time, ENTRIES) - local prevX = frames[frame + PREV_X] - local prevY = frames[frame + PREV_Y] - local frameTime = frames[frame] - local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) - - bone.x = bone.x + (bone.data.x + prevX + (frames[frame + X] - prevX) * percent - bone.x) * alpha - bone.y = bone.y + (bone.data.y + prevY + (frames[frame + Y] - prevY) * percent - bone.y) * alpha - end - - return self -end - -Animation.ScaleTimeline = {} -Animation.ScaleTimeline.ENTRIES = Animation.TranslateTimeline.ENTRIES -function Animation.ScaleTimeline.new (frameCount) - local ENTRIES = Animation.ScaleTimeline.ENTRIES - local PREV_TIME = -3 - local PREV_X = -2 - local PREV_Y = -1 - local X = 1 - local Y = 2 - - local self = Animation.TranslateTimeline.new(frameCount) - - function self:apply (skeleton, lastTime, time, firedEvents, alpha) - local frames = self.frames - if time < frames[0] then return end -- Time is before first frame. - - local bone = skeleton.bones[self.boneIndex] - - if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. - bone.scaleX = bone.scaleX + (bone.data.scaleX * frames[zlen(frames) + PREV_X] - bone.scaleX) * alpha - bone.scaleY = bone.scaleY + (bone.data.scaleY * frames[zlen(frames) + PREV_Y] - bone.scaleY) * alpha - return - end - - -- Interpolate between the last frame and the current frame. - local frame = binarySearch(frames, time, ENTRIES) - local prevX = frames[frame + PREV_X] - local prevY = frames[frame + PREV_Y] - local frameTime = frames[frame] - local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, - 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) - - bone.scaleX = bone.scaleX + (bone.data.scaleX * (prevX + (frames[frame + X] - prevX) * percent) - bone.scaleX) * alpha - bone.scaleY = bone.scaleY + (bone.data.scaleY * (prevY + (frames[frame + Y] - prevY) * percent) - bone.scaleY) * alpha - end - - return self -end - -Animation.ShearTimeline = {} -Animation.ShearTimeline.ENTRIES = Animation.TranslateTimeline.ENTRIES -function Animation.ShearTimeline.new (frameCount) - local ENTRIES = Animation.ShearTimeline.ENTRIES - local PREV_TIME = -3 - local PREV_X = -2 - local PREV_Y = -1 - local X = 1 - local Y = 2 - - local self = Animation.TranslateTimeline.new(frameCount) - - function self:apply (skeleton, lastTime, time, firedEvents, alpha) - local frames = self.frames - if time < frames[0] then return end -- Time is before first frame. - - local bone = skeleton.bones[self.boneIndex] - - if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. - bone.shearX = bone.shearX + (bone.data.shearX * frames[zlen(frames) + PREV_X] - bone.shearX) * alpha - bone.shearY = bone.shearY + (bone.data.shearY * frames[zlen(frames) + PREV_Y] - bone.shearY) * alpha - return - end - - -- Interpolate between the last frame and the current frame. - local frame = binarySearch(frames, time, ENTRIES) - local prevX = frames[frame + PREV_X] - local prevY = frames[frame + PREV_Y] - local frameTime = frames[frame] - local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, - 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) - - bone.shearX = bone.shearX + (bone.data.shearX + (prevX + (frames[frame + X] - prevX) * percent) - bone.shearX) * alpha - bone.shearY = bone.shearY + (bone.data.shearY + (prevY + (frames[frame + Y] - prevY) * percent) - bone.shearY) * alpha - end - - return self -end - -Animation.ColorTimeline = {} -Animation.ColorTimeline.ENTRIES = 5 -function Animation.ColorTimeline.new (frameCount) - local ENTRIES = Animation.ColorTimeline.ENTRIES - local PREV_TIME = -5 - local PREV_R = -4 - local PREV_G = -3 - local PREV_B = -2 - local PREV_A = -1 - local R = 1 - local G = 2 - local B = 3 - local A = 4 - - local self = Animation.CurveTimeline.new(frameCount) - self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) - self.slotIndex = -1 - - function self:setFrame (frameIndex, time, r, g, b, a) - frameIndex = frameIndex * ENTRIES - self.frames[frameIndex] = time - self.frames[frameIndex + R] = r - self.frames[frameIndex + G] = g - self.frames[frameIndex + B] = b - self.frames[frameIndex + A] = a - end - - function self:apply (skeleton, lastTime, time, firedEvents, alpha) - local frames = self.frames - if time < frames[0] then return end -- Time is before first frame. - - local r, g, b, a - if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. - local i = zlen(frames) - r = frames[i + PREV_R] - g = frames[i + PREV_G] - b = frames[i + PREV_B] - a = frames[i + PREV_A] - else - -- Interpolate between the last frame and the current frame. - local frame = binarySearch(frames, time, ENTRIES) - r = frames[frame + PREV_R] - g = frames[frame + PREV_G] - b = frames[frame + PREV_B] - a = frames[frame + PREV_A] - local frameTime = frames[frame] - local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, - 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) - - r = r + (frames[frame + R] - r) * percent - g = g + (frames[frame + G] - g) * percent - b = b + (frames[frame + B] - b) * percent - a = a + (frames[frame + A] - a) * percent - end - local color = skeleton.slots[self.slotIndex].color - if alpha < 1 then - color:add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha) - else - color:set(r, g, b, a) - end - end - - return self -end - -Animation.AttachmentTimeline = {} -function Animation.AttachmentTimeline.new (frameCount) - local self = { - frames = utils.newNumberArrayZero(frameCount), -- time, ... - attachmentNames = {}, - slotName = nil - } - - function self:getFrameCount () - return zlen(self.frames) - end - - function self:setFrame (frameIndex, time, attachmentName) - self.frames[frameIndex] = time - self.attachmentNames[frameIndex] = attachmentName - end - - function self:apply (skeleton, lastTime, time, firedEvents, alpha) - local frames = self.frames - if time < frames[0] then return end - - local frameIndex = 0 - if time >= frames[zlen(frames) - 1] then - frameIndex = zlen(frames) - 1 - else - frameIndex = binarySearch(frames, time, 1) - 1 - end - - local attachmentName = self.attachmentNames[frameIndex] - local slot = skeleton.slotsByName[self.slotName] - if attachmentName then - if not slot.attachment then - slot:setAttachment(skeleton:getAttachment(self.slotName, attachmentName)) - elseif slot.attachment.name ~= attachmentName then - slot:setAttachment(skeleton:getAttachment(self.slotName, attachmentName)) - end - else - slot:setAttachment(nil) - end - end - - return self -end - -Animation.EventTimeline = {} -function Animation.EventTimeline.new (frameCount) - local self = { - frames = utils.newNumberArrayZero(frameCount), - events = {} - } - - function self:getFrameCount () - return zlen(self.frames) - end - - function self:setFrame (frameIndex, event) - self.frames[frameIndex] = event.time - self.events[frameIndex] = event - end - - -- Fires events for frames > lastTime and <= time. - function self:apply (skeleton, lastTime, time, firedEvents, alpha) - if not firedEvents then return end - - local frames = self.frames - local frameCount = zlen(frames) - - if lastTime > time then -- Fire events after last time for looped animations. - self:apply(skeleton, lastTime, 999999, firedEvents, alpha) - lastTime = -1 - elseif lastTime >= frames[frameCount - 1] then -- Last time is after last frame. - return - end - if time < frames[0] then return end -- Time is before first frame. - - local frame - if lastTime < frames[0] then - frame = 0 - else - frame = binarySearch1(frames, lastTime) - local frame = frames[frame] - while frame > 0 do -- Fire multiple events with the same frame. - if frames[frame - 1] ~= frame then break end - frame = frame - 1 - end - end - local events = self.events - while frame < frameCount and time >= frames[frame] do - table.insert(firedEvents, events[frame]) - frame = frame + 1 - end - end - - return self -end - -Animation.DrawOrderTimeline = {} -function Animation.DrawOrderTimeline.new (frameCount) - local self = { - frames = utils.newNumberArrayZero(frameCount), - drawOrders = {} - } - - function self:getFrameCount () - return zlen(self.frames) - end - - function self:setFrame (frameIndex, time, drawOrder) - self.frames[frameIndex] = time - self.drawOrders[frameIndex] = drawOrder - end - - function self:apply (skeleton, lastTime, time, firedEvents, alpha) - local frames = self.frames - if time < frames[0] then return end -- Time is before first frame. - - local frame - if time >= frames[zlen(frames) - 1] then -- Time is after last frame. - frame = zlen(frames) - 1 - else - frame = binarySearch1(frames, time) - 1 - end - - local drawOrder = skeleton.drawOrder - local slots = skeleton.slots - local drawOrderToSetupIndex = self.drawOrders[frame] - if not drawOrderToSetupIndex then - for i,slot in ipairs(slots) do - drawOrder[i] = slots[i] - end - else - for i,setupIndex in ipairs(drawOrderToSetupIndex) do - drawOrder[i] = skeleton.slots[setupIndex] - end - end - end - - return self -end - -Animation.DeformTimeline = {} -function Animation.DeformTimeline.new (frameCount) - - local self = Animation.CurveTimeline.new(frameCount) - self.frames = utils.newNumberArrayZero(frameCount) - self.frameVertices = utils.newNumberArrayZero(frameCount) - self.slotIndex = -1 - self.attachment = nil - - function self:setFrame (frameIndex, time, vertices) - self.frames[frameIndex] = time - self.frameVertices[frameIndex] = vertices - end - - function self:apply (skeleton, lastTime, time, firedEvents, alpha) - local slot = skeleton.slots[self.slotIndex] - local slotAttachment = slot.attachment - if not slotAttachment then return end - if not (slotAttachment.type == AttachmentType.mesh or slotAttachment.type == AttachmentType.linkedmesh or slotAttachment.type == AttachmentType.path) then return end - if not slotAttachment:applyDeform(self.attachment) then return end - - local frames = self.frames - if time < frames[0] then return end -- Time is before first frame. - - local frameVertices = self.frameVertices - local vertexCount = #(frameVertices[0]) - - local verticesArray = slot.attachmentVertices - if (#verticesArray ~= vertexCount) then alpha = 1 end -- Don't mix from uninitialized slot vertices. - local vertices = utils.setArraySize(verticesArray, vertexCount) - - if time >= frames[zlen(frames) - 1] then - local lastVertices = frameVertices[zlen(frames) - 1] - if alpha < 1 then - local i = 1 - while i <= vertexCount do - vertices[i] = vertices[i] + (lastVertices[i] - vertices[i]) * alpha - i = i + 1 - end - else - local i = 1 - while i <= vertexCount do - vertices[i] = lastVertices[i] - i = i + 1 - end - end - return; - end - - -- Interpolate between the previous frame and the current frame. - local frame = binarySearch(frames, time, 1) - local prevVertices = frameVertices[frame - 1] - local nextVertices = frameVertices[frame] - local frameTime = frames[frame] - local percent = self:getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime)) - - if alpha < 1 then - local i = 1 - while i <= vertexCount do - local prev = prevVertices[i] - vertices[i] = vertices[i] + (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha - i = i + 1 - end - else - local i = 1 - while i <= vertexCount do - local prev = prevVertices[i] - vertices[i] = prev + (nextVertices[i] - prev) * percent - i = i + 1 - end - end - end - - return self -end - -Animation.IkConstraintTimeline = {} -Animation.IkConstraintTimeline.ENTRIES = 3 -function Animation.IkConstraintTimeline.new (frameCount) - local ENTRIES = Animation.IkConstraintTimeline.ENTRIES - local PREV_TIME = -3 - local PREV_MIX = -2 - local PREV_BEND_DIRECTION = -1 - local MIX = 1 - local BEND_DIRECTION = 2 - - local self = Animation.CurveTimeline.new(frameCount) - self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) -- time, mix, bendDirection, ... - self.ikConstraintIndex = -1 - - function self:setFrame (frameIndex, time, mix, bendDirection) - frameIndex = frameIndex * ENTRIES - self.frames[frameIndex] = time - self.frames[frameIndex + MIX] = mix - self.frames[frameIndex + BEND_DIRECTION] = bendDirection - end - - function self:apply (skeleton, lastTime, time, firedEvents, alpha) - local frames = self.frames - if time < frames[0] then return end -- Time is before first frame. - - local constraint = skeleton.ikConstraints[self.ikConstraintIndex] - - if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. - constraint.mix = constraint.mix + (frames[zlen(frames) + PREV_MIX] - constraint.mix) * alpha - constraint.bendDirection = frames[zlen(frames) + PREV_BEND_DIRECTION] - return - end - - -- Interpolate between the previous frame and the current frame. - local frame = binarySearch(frames, time, ENTRIES) - local mix = frames[frame + PREV_MIX] - local frameTime = frames[frame] - local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, - 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) - - constraint.mix = constraint.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha - constraint.bendDirection = math.floor(frames[frame + PREV_BEND_DIRECTION]) - end - - return self -end - -Animation.TransformConstraintTimeline = {} -Animation.TransformConstraintTimeline.ENTRIES = 5 -function Animation.TransformConstraintTimeline.new (frameCount) - local ENTRIES = Animation.TransformConstraintTimeline.ENTRIES - local PREV_TIME = -5 - local PREV_ROTATE = -4 - local PREV_TRANSLATE = -3 - local PREV_SCALE = -2 - local PREV_SHEAR = -1 - local ROTATE = 1 - local TRANSLATE = 2 - local SCALE = 3 - local SHEAR = 4 - - local self = Animation.CurveTimeline.new(frameCount) - self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) - self.transformConstraintIndex = -1 - - function self:setFrame (frameIndex, time, rotateMix, translateMix, scaleMix, shearMix) - frameIndex = frameIndex * ENTRIES - self.frames[frameIndex] = time - self.frames[frameIndex + ROTATE] = rotateMix - self.frames[frameIndex + TRANSLATE] = translateMix - self.frames[frameIndex + SCALE] = scaleMix - self.frames[frameIndex + SHEAR] = shearMix - end - - function self:apply (skeleton, lastTime, time, firedEvents, alpha) - local frames = self.frames - if time < frames[0] then return end -- Time is before first frame. - - local constraint = skeleton.transformConstraints[self.transformConstraintIndex] - - if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. - local i = zlen(frames) - constraint.rotateMix = constraintMix.rotateMix + (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha - constraint.translateMix = constraintMix.translateMix + (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha - constraint.scaleMix = constraintMix.scaleMix + (frames[i + PREV_SCALE] - constraint.scaleMix) * alpha - constraint.shearMix = constraintMix.shearMix + (frames[i + PREV_SHEAR] - constraint.shearMix) * alpha - return - end - - -- Interpolate between the last frame and the current frame. - local frame = binarySearch(frames, time, ENTRIES) - local frameTime = frames[frame] - local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) - - local rotate = frames[frame + PREV_ROTATE] - local translate = frames[frame + PREV_TRANSLATE] - local scale = frames[frame + PREV_SCALE] - local shear = frames[frame + PREV_SHEAR] - constraint.rotateMix = constraint.rotateMix + (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha - constraint.translateMix = constraint.translateMix + (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix) * alpha - constraint.scaleMix = constraint.scaleMix + (scale + (frames[frame + SCALE] - scale) * percent - constraint.scaleMix) * alpha - constraint.shearMix = constraint.shearMix + (shear + (frames[frame + SHEAR] - shear) * percent - constraint.shearMix) * alpha - end - - return self -end - -Animation.PathConstraintPositionTimeline = {} -Animation.PathConstraintPositionTimeline.ENTRIES = 2 -function Animation.PathConstraintPositionTimeline.new (frameCount) - local ENTRIES = Animation.PathConstraintPositionTimeline.ENTRIES - local PREV_TIME = -2 - local PREV_VALUE = -1 - local VALUE = 1 - - local self = Animation.CurveTimeline.new(frameCount) - self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) - self.pathConstraintIndex = -1 - - function self:setFrame (frameIndex, time, value) - frameIndex = frameIndex * ENTRIES - self.frames[frameIndex] = time - self.frames[frameIndex + VALUE] = value - end - - function self:apply (skeleton, lastTime, time, firedEvents, alpha) - local frames = self.frames - if (time < frames[0]) then return end -- Time is before first frame. - - local constraint = skeleton.pathConstraints[self.pathConstraintIndex] - - if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. - local i = zlen(frames) - constraint.position = constraint.position + (frames[i + PREV_VALUE] - constraint.position) * alpha - return - end - - -- Interpolate between the previous frame and the current frame. - local frame = binarySearch(frames, time, ENTRIES) - local position = frames[frame + PREV_VALUE] - local frameTime = frames[frame] - local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) - - constraint.position = constraint.position + (position + (frames[frame + VALUE] - position) * percent - constraint.position) * alpha - end - - return self -end - -Animation.PathConstraintSpacingTimeline = {} -Animation.PathConstraintSpacingTimeline.ENTRIES = 2 -function Animation.PathConstraintSpacingTimeline.new (frameCount) - local ENTRIES = Animation.PathConstraintSpacingTimeline.ENTRIES - local PREV_TIME = -2 - local PREV_VALUE = -1 - local VALUE = 1 - - local self = Animation.CurveTimeline.new(frameCount) - self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) - self.pathConstraintIndex = -1 - - function self:setFrame (frameIndex, time, value) - frameIndex = frameIndex * ENTRIES - self.frames[frameIndex] = time - self.frames[frameIndex + VALUE] = value - end - - function self:apply (skeleton, lastTime, time, firedEvents, alpha) - local frames = self.frames - if (time < frames[0]) then return end -- Time is before first frame. - - local constraint = skeleton.pathConstraints[self.pathConstraintIndex] - - if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. - local i = zlen(frames) - constraint.spacing = constraint.spacing + (frames[i + PREV_VALUE] - constraint.spacing) * alpha - return - end - - -- Interpolate between the previous frame and the current frame. - local frame = binarySearch(frames, time, ENTRIES) - local spacing = frames[frame + PREV_VALUE] - local frameTime = frames[frame] - local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) - - constraint.spacing = constraint.spacing + (spacing + (frames[frame + VALUE] - spacing) * percent - constraint.spacing) * alpha - end - - return self -end - -Animation.PathConstraintMixTimeline = {} -Animation.PathConstraintMixTimeline.ENTRIES = 3 -function Animation.PathConstraintMixTimeline.new (frameCount) - local ENTRIES = Animation.PathConstraintMixTimeline.ENTRIES - local PREV_TIME = -3 - local PREV_ROTATE = -2 - local PREV_TRANSLATE = -1 - local ROTATE = 1 - local TRANSLATE = 2 - - local self = Animation.CurveTimeline.new(frameCount) - self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) - self.pathConstraintIndex = -1 - - function self:setFrame (frameIndex, time, rotateMix, translateMix) - frameIndex = frameIndex * ENTRIES - self.frames[frameIndex] = time - self.frames[frameIndex + ROTATE] = rotateMix - self.frames[frameIndex + TRANSLATE] = translateMix - end - - function self:apply (skeleton, lastTime, time, firedEvents, alpha) - local frames = self.frames - if (time < frames[0]) then return end -- Time is before first frame. - - local constraint = skeleton.pathConstraints[self.pathConstraintIndex] - - if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. - local i = zlen(frames) - constraint.rotateMix = constraint.rotateMix + (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha - constraint.translateMix = constraint.translateMix + (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha - return - end - - -- Interpolate between the previous frame and the current frame. - local frame = binarySearch(frames, time, ENTRIES) - local rotate = frames[frame + PREV_ROTATE] - local translate = frames[frame + PREV_TRANSLATE] - local frameTime = frames[frame] - local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) - - constraint.rotateMix = constraint.rotateMix + (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha - constraint.translateMix = constraint.translateMix + (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix) * alpha - end - - return self -end +-- FIXME +-- All the indexing in this file is zero based. We use zlen() +-- instead of the # operator. Initialization of number arrays +-- is performed via utils.newNumberArrayZero. This needs +-- to be rewritten using one-based indexing for better performance + +local utils = require "spine-lua.utils" +local AttachmentType = require "spine-lua.attachments.AttachmentType" + +local function zlen(array) + return #array + 1 +end + +local Animation = {} +function Animation.new (name, timelines, duration) + if not timelines then error("timelines cannot be nil", 2) end + + local self = { + name = name, + timelines = timelines, + duration = duration + } + + function self:apply (skeleton, lastTime, time, loop, events) + if not skeleton then error("skeleton cannot be nil.", 2) end + + if loop and duration > 0 then + time = time % self.duration + if lastTime > 0 then lastTime = lastTime % self.duration end + end + + for i,timeline in ipairs(self.timelines) do + timeline:apply(skeleton, lastTime, time, events, 1) + end + end + + function self:mix (skeleton, lastTime, time, loop, events, alpha) + if not skeleton then error("skeleton cannot be nil.", 2) end + + if loop and duration > 0 then + time = time % self.duration + if lastTime > 0 then lastTime = lastTime % self.duration end + end + + for i,timeline in ipairs(self.timelines) do + timeline:apply(skeleton, lastTime, time, events, alpha) + end + end + + return self +end + +local function binarySearch (values, target, step) + local low = 0 + local high = math.floor(zlen(values) / step - 2) + if high == 0 then return step end + local current = math.floor(high / 2) + while true do + if values[(current + 1) * step] <= target then + low = current + 1 + else + high = current + end + if low == high then return (low + 1) * step end + current = math.floor((low + high) / 2) + end +end + +local function binarySearch1 (values, target) + local low = 0 + local high = math.floor(zlen(values) - 2) + if high == 0 then return 1 end + local current = math.floor(high / 2) + while true do + if values[current + 1] <= target then + low = current + 1 + else + high = current + end + if low == high then return low + 1 end + current = math.floor((low + high) / 2) + end +end + +local function linearSearch (values, target, step) + local i = 0 + local last = zlen(values) - step + while i <= last do + if (values[i] > target) then return i end + i = i + step + end + return -1 +end + +Animation.CurveTimeline = {} +function Animation.CurveTimeline.new (frameCount) + local LINEAR = 0 + local STEPPED = 1 + local BEZIER = 2 + local BEZIER_SIZE = 10 * 2 - 1 + + local self = { + curves = utils.newNumberArrayZero((frameCount - 1) * BEZIER_SIZE) -- type, x, y, ... + } + + function self:getFrameCount () + return math.floor(zlen(self.curves) / BEZIER_SIZE) + 1 + end + + function self:setStepped (frameIndex) + self.curves[frameIndex * BEZIER_SIZE] = STEPPED + end + + function self:getCurveType (frameIndex) + local index = frameIndex * BEZIER_SIZE + if index == zlen(self.curves) then return LINEAR end + local type = self.curves[index] + if type == LINEAR then return LINEAR end + if type == STEPPED then return STEPPED end + return BEZIER + end + + function self:setCurve (frameIndex, cx1, cy1, cx2, cy2) + local tmpx = (-cx1 * 2 + cx2) * 0.03 + local tmpy = (-cy1 * 2 + cy2) * 0.03 + local dddfx = ((cx1 - cx2) * 3 + 1) * 0.006 + local dddfy = ((cy1 - cy2) * 3 + 1) * 0.006 + local ddfx = tmpx * 2 + dddfx + local ddfy = tmpy * 2 + dddfy + local dfx = cx1 * 0.3 + tmpx + dddfx * 0.16666667 + local dfy = cy1 * 0.3 + tmpy + dddfy * 0.16666667 + + local i = frameIndex * BEZIER_SIZE + local curves = self.curves + curves[i] = BEZIER + i = i + 1 + + local x = dfx + local y = dfy + local n = i + BEZIER_SIZE - 1 + while i < n do + curves[i] = x + curves[i + 1] = y + dfx = dfx + ddfx + dfy = dfy + ddfy + ddfx = ddfx + dddfx + ddfy = ddfy + dddfy + x = x + dfx + y = y + dfy + i = i + 2 + end + end + + function self:getCurvePercent (frameIndex, percent) + percent = utils.clamp(percent, 0, 1) + local curves = self.curves + local i = frameIndex * BEZIER_SIZE + local type = curves[i] + if type == LINEAR then return percent end + if type == STEPPED then return 0 end + i = i + 1 + local x + local n = i + BEZIER_SIZE - 1 + local start = i + while i < n do + x = curves[i] + if x >= percent then + local prevX, prevY + if i == start then + prevX = 0 + prevY = 0 + else + prevX = curves[i - 2] + prevY = curves[i - 1] + end + return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX) + end + i = i + 2 + end + local y = curves[i - 1] + return y + (1 - y) * (percent - x) / (1 - x) -- Last point is 1,1. + end + + return self +end + +Animation.RotateTimeline = {} +Animation.RotateTimeline.ENTRIES = 2 +function Animation.RotateTimeline.new (frameCount) + local ENTRIES = Animation.RotateTimeline.ENTRIES + local PREV_TIME = -2 + local PREV_ROTATION = -1 + local ROTATION = 1 + + local self = Animation.CurveTimeline.new(frameCount) + self.boneIndex = -1 + self.frames = utils.newNumberArrayZero(frameCount * 2) + + function self:setFrame (frameIndex, time, degrees) + frameIndex = frameIndex * 2 + self.frames[frameIndex] = time + self.frames[frameIndex + ROTATION] = degrees + end + + function self:apply (skeleton, lastTime, time, firedEvents, alpha) + local frames = self.frames + if time < frames[0] then return end -- Time is before first frame. + + local bone = skeleton.bones[self.boneIndex] + + if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. + local amount = bone.data.rotation + frames[zlen(frames) + PREV_ROTATION] - bone.rotation + while amount > 180 do + amount = amount - 360 + end + while amount < -180 do + amount = amount + 360 + end + bone.rotation = bone.rotation + amount * alpha + return + end + + -- Interpolate between the last frame and the current frame. + local frame = binarySearch(frames, time, ENTRIES) + local prevRotation = frames[frame + PREV_ROTATION] + local frameTime = frames[frame] + local percent = self:getCurvePercent((math.floor(frame / 2)) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) + + local amount = frames[frame + ROTATION] - prevRotation + while amount > 180 do + amount = amount - 360 + end + while amount < -180 do + amount = amount + 360 + end + amount = bone.data.rotation + (prevRotation + amount * percent) - bone.rotation + while amount > 180 do + amount = amount - 360 + end + while amount < -180 do + amount = amount + 360 + end + bone.rotation = bone.rotation + amount * alpha + end + + return self +end + +Animation.TranslateTimeline = {} +Animation.TranslateTimeline.ENTRIES = 3 +function Animation.TranslateTimeline.new (frameCount) + local ENTRIES = Animation.TranslateTimeline.ENTRIES + local PREV_TIME = -3 + local PREV_X = -2 + local PREV_Y = -1 + local X = 1 + local Y = 2 + + local self = Animation.CurveTimeline.new(frameCount) + self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) + self.boneIndex = -1 + + function self:setFrame (frameIndex, time, x, y) + frameIndex = frameIndex * ENTRIES + self.frames[frameIndex] = time + self.frames[frameIndex + X] = x + self.frames[frameIndex + Y] = y + end + + function self:apply (skeleton, lastTime, time, firedEvents, alpha) + local frames = self.frames + if time < frames[0] then return end -- Time is before first frame. + + local bone = skeleton.bones[self.boneIndex] + + if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. + bone.x = bone.x + (bone.data.x + frames[zlen(frames) + PREV_X] - bone.x) * alpha + bone.y = bone.y + (bone.data.y + frames[zlen(frames) + PREV_Y] - bone.y) * alpha + return + end + + -- Interpolate between the last frame and the current frame. + local frame = binarySearch(frames, time, ENTRIES) + local prevX = frames[frame + PREV_X] + local prevY = frames[frame + PREV_Y] + local frameTime = frames[frame] + local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) + + bone.x = bone.x + (bone.data.x + prevX + (frames[frame + X] - prevX) * percent - bone.x) * alpha + bone.y = bone.y + (bone.data.y + prevY + (frames[frame + Y] - prevY) * percent - bone.y) * alpha + end + + return self +end + +Animation.ScaleTimeline = {} +Animation.ScaleTimeline.ENTRIES = Animation.TranslateTimeline.ENTRIES +function Animation.ScaleTimeline.new (frameCount) + local ENTRIES = Animation.ScaleTimeline.ENTRIES + local PREV_TIME = -3 + local PREV_X = -2 + local PREV_Y = -1 + local X = 1 + local Y = 2 + + local self = Animation.TranslateTimeline.new(frameCount) + + function self:apply (skeleton, lastTime, time, firedEvents, alpha) + local frames = self.frames + if time < frames[0] then return end -- Time is before first frame. + + local bone = skeleton.bones[self.boneIndex] + + if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. + bone.scaleX = bone.scaleX + (bone.data.scaleX * frames[zlen(frames) + PREV_X] - bone.scaleX) * alpha + bone.scaleY = bone.scaleY + (bone.data.scaleY * frames[zlen(frames) + PREV_Y] - bone.scaleY) * alpha + return + end + + -- Interpolate between the last frame and the current frame. + local frame = binarySearch(frames, time, ENTRIES) + local prevX = frames[frame + PREV_X] + local prevY = frames[frame + PREV_Y] + local frameTime = frames[frame] + local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, + 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) + + bone.scaleX = bone.scaleX + (bone.data.scaleX * (prevX + (frames[frame + X] - prevX) * percent) - bone.scaleX) * alpha + bone.scaleY = bone.scaleY + (bone.data.scaleY * (prevY + (frames[frame + Y] - prevY) * percent) - bone.scaleY) * alpha + end + + return self +end + +Animation.ShearTimeline = {} +Animation.ShearTimeline.ENTRIES = Animation.TranslateTimeline.ENTRIES +function Animation.ShearTimeline.new (frameCount) + local ENTRIES = Animation.ShearTimeline.ENTRIES + local PREV_TIME = -3 + local PREV_X = -2 + local PREV_Y = -1 + local X = 1 + local Y = 2 + + local self = Animation.TranslateTimeline.new(frameCount) + + function self:apply (skeleton, lastTime, time, firedEvents, alpha) + local frames = self.frames + if time < frames[0] then return end -- Time is before first frame. + + local bone = skeleton.bones[self.boneIndex] + + if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. + bone.shearX = bone.shearX + (bone.data.shearX * frames[zlen(frames) + PREV_X] - bone.shearX) * alpha + bone.shearY = bone.shearY + (bone.data.shearY * frames[zlen(frames) + PREV_Y] - bone.shearY) * alpha + return + end + + -- Interpolate between the last frame and the current frame. + local frame = binarySearch(frames, time, ENTRIES) + local prevX = frames[frame + PREV_X] + local prevY = frames[frame + PREV_Y] + local frameTime = frames[frame] + local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, + 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) + + bone.shearX = bone.shearX + (bone.data.shearX + (prevX + (frames[frame + X] - prevX) * percent) - bone.shearX) * alpha + bone.shearY = bone.shearY + (bone.data.shearY + (prevY + (frames[frame + Y] - prevY) * percent) - bone.shearY) * alpha + end + + return self +end + +Animation.ColorTimeline = {} +Animation.ColorTimeline.ENTRIES = 5 +function Animation.ColorTimeline.new (frameCount) + local ENTRIES = Animation.ColorTimeline.ENTRIES + local PREV_TIME = -5 + local PREV_R = -4 + local PREV_G = -3 + local PREV_B = -2 + local PREV_A = -1 + local R = 1 + local G = 2 + local B = 3 + local A = 4 + + local self = Animation.CurveTimeline.new(frameCount) + self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) + self.slotIndex = -1 + + function self:setFrame (frameIndex, time, r, g, b, a) + frameIndex = frameIndex * ENTRIES + self.frames[frameIndex] = time + self.frames[frameIndex + R] = r + self.frames[frameIndex + G] = g + self.frames[frameIndex + B] = b + self.frames[frameIndex + A] = a + end + + function self:apply (skeleton, lastTime, time, firedEvents, alpha) + local frames = self.frames + if time < frames[0] then return end -- Time is before first frame. + + local r, g, b, a + if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. + local i = zlen(frames) + r = frames[i + PREV_R] + g = frames[i + PREV_G] + b = frames[i + PREV_B] + a = frames[i + PREV_A] + else + -- Interpolate between the last frame and the current frame. + local frame = binarySearch(frames, time, ENTRIES) + r = frames[frame + PREV_R] + g = frames[frame + PREV_G] + b = frames[frame + PREV_B] + a = frames[frame + PREV_A] + local frameTime = frames[frame] + local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, + 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) + + r = r + (frames[frame + R] - r) * percent + g = g + (frames[frame + G] - g) * percent + b = b + (frames[frame + B] - b) * percent + a = a + (frames[frame + A] - a) * percent + end + local color = skeleton.slots[self.slotIndex].color + if alpha < 1 then + color:add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha) + else + color:set(r, g, b, a) + end + end + + return self +end + +Animation.AttachmentTimeline = {} +function Animation.AttachmentTimeline.new (frameCount) + local self = { + frames = utils.newNumberArrayZero(frameCount), -- time, ... + attachmentNames = {}, + slotName = nil + } + + function self:getFrameCount () + return zlen(self.frames) + end + + function self:setFrame (frameIndex, time, attachmentName) + self.frames[frameIndex] = time + self.attachmentNames[frameIndex] = attachmentName + end + + function self:apply (skeleton, lastTime, time, firedEvents, alpha) + local frames = self.frames + if time < frames[0] then return end + + local frameIndex = 0 + if time >= frames[zlen(frames) - 1] then + frameIndex = zlen(frames) - 1 + else + frameIndex = binarySearch(frames, time, 1) - 1 + end + + local attachmentName = self.attachmentNames[frameIndex] + local slot = skeleton.slotsByName[self.slotName] + if attachmentName then + if not slot.attachment then + slot:setAttachment(skeleton:getAttachment(self.slotName, attachmentName)) + elseif slot.attachment.name ~= attachmentName then + slot:setAttachment(skeleton:getAttachment(self.slotName, attachmentName)) + end + else + slot:setAttachment(nil) + end + end + + return self +end + +Animation.EventTimeline = {} +function Animation.EventTimeline.new (frameCount) + local self = { + frames = utils.newNumberArrayZero(frameCount), + events = {} + } + + function self:getFrameCount () + return zlen(self.frames) + end + + function self:setFrame (frameIndex, event) + self.frames[frameIndex] = event.time + self.events[frameIndex] = event + end + + -- Fires events for frames > lastTime and <= time. + function self:apply (skeleton, lastTime, time, firedEvents, alpha) + if not firedEvents then return end + + local frames = self.frames + local frameCount = zlen(frames) + + if lastTime > time then -- Fire events after last time for looped animations. + self:apply(skeleton, lastTime, 999999, firedEvents, alpha) + lastTime = -1 + elseif lastTime >= frames[frameCount - 1] then -- Last time is after last frame. + return + end + if time < frames[0] then return end -- Time is before first frame. + + local frame + if lastTime < frames[0] then + frame = 0 + else + frame = binarySearch1(frames, lastTime) + local frame = frames[frame] + while frame > 0 do -- Fire multiple events with the same frame. + if frames[frame - 1] ~= frame then break end + frame = frame - 1 + end + end + local events = self.events + while frame < frameCount and time >= frames[frame] do + table.insert(firedEvents, events[frame]) + frame = frame + 1 + end + end + + return self +end + +Animation.DrawOrderTimeline = {} +function Animation.DrawOrderTimeline.new (frameCount) + local self = { + frames = utils.newNumberArrayZero(frameCount), + drawOrders = {} + } + + function self:getFrameCount () + return zlen(self.frames) + end + + function self:setFrame (frameIndex, time, drawOrder) + self.frames[frameIndex] = time + self.drawOrders[frameIndex] = drawOrder + end + + function self:apply (skeleton, lastTime, time, firedEvents, alpha) + local frames = self.frames + if time < frames[0] then return end -- Time is before first frame. + + local frame + if time >= frames[zlen(frames) - 1] then -- Time is after last frame. + frame = zlen(frames) - 1 + else + frame = binarySearch1(frames, time) - 1 + end + + local drawOrder = skeleton.drawOrder + local slots = skeleton.slots + local drawOrderToSetupIndex = self.drawOrders[frame] + if not drawOrderToSetupIndex then + for i,slot in ipairs(slots) do + drawOrder[i] = slots[i] + end + else + for i,setupIndex in ipairs(drawOrderToSetupIndex) do + drawOrder[i] = skeleton.slots[setupIndex] + end + end + end + + return self +end + +Animation.DeformTimeline = {} +function Animation.DeformTimeline.new (frameCount) + + local self = Animation.CurveTimeline.new(frameCount) + self.frames = utils.newNumberArrayZero(frameCount) + self.frameVertices = utils.newNumberArrayZero(frameCount) + self.slotIndex = -1 + self.attachment = nil + + function self:setFrame (frameIndex, time, vertices) + self.frames[frameIndex] = time + self.frameVertices[frameIndex] = vertices + end + + function self:apply (skeleton, lastTime, time, firedEvents, alpha) + local slot = skeleton.slots[self.slotIndex] + local slotAttachment = slot.attachment + if not slotAttachment then return end + if not (slotAttachment.type == AttachmentType.mesh or slotAttachment.type == AttachmentType.linkedmesh or slotAttachment.type == AttachmentType.path) then return end + if not slotAttachment:applyDeform(self.attachment) then return end + + local frames = self.frames + if time < frames[0] then return end -- Time is before first frame. + + local frameVertices = self.frameVertices + local vertexCount = #(frameVertices[0]) + + local verticesArray = slot.attachmentVertices + if (#verticesArray ~= vertexCount) then alpha = 1 end -- Don't mix from uninitialized slot vertices. + local vertices = utils.setArraySize(verticesArray, vertexCount) + + if time >= frames[zlen(frames) - 1] then + local lastVertices = frameVertices[zlen(frames) - 1] + if alpha < 1 then + local i = 1 + while i <= vertexCount do + vertices[i] = vertices[i] + (lastVertices[i] - vertices[i]) * alpha + i = i + 1 + end + else + local i = 1 + while i <= vertexCount do + vertices[i] = lastVertices[i] + i = i + 1 + end + end + return; + end + + -- Interpolate between the previous frame and the current frame. + local frame = binarySearch(frames, time, 1) + local prevVertices = frameVertices[frame - 1] + local nextVertices = frameVertices[frame] + local frameTime = frames[frame] + local percent = self:getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime)) + + if alpha < 1 then + local i = 1 + while i <= vertexCount do + local prev = prevVertices[i] + vertices[i] = vertices[i] + (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha + i = i + 1 + end + else + local i = 1 + while i <= vertexCount do + local prev = prevVertices[i] + vertices[i] = prev + (nextVertices[i] - prev) * percent + i = i + 1 + end + end + end + + return self +end + +Animation.IkConstraintTimeline = {} +Animation.IkConstraintTimeline.ENTRIES = 3 +function Animation.IkConstraintTimeline.new (frameCount) + local ENTRIES = Animation.IkConstraintTimeline.ENTRIES + local PREV_TIME = -3 + local PREV_MIX = -2 + local PREV_BEND_DIRECTION = -1 + local MIX = 1 + local BEND_DIRECTION = 2 + + local self = Animation.CurveTimeline.new(frameCount) + self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) -- time, mix, bendDirection, ... + self.ikConstraintIndex = -1 + + function self:setFrame (frameIndex, time, mix, bendDirection) + frameIndex = frameIndex * ENTRIES + self.frames[frameIndex] = time + self.frames[frameIndex + MIX] = mix + self.frames[frameIndex + BEND_DIRECTION] = bendDirection + end + + function self:apply (skeleton, lastTime, time, firedEvents, alpha) + local frames = self.frames + if time < frames[0] then return end -- Time is before first frame. + + local constraint = skeleton.ikConstraints[self.ikConstraintIndex] + + if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. + constraint.mix = constraint.mix + (frames[zlen(frames) + PREV_MIX] - constraint.mix) * alpha + constraint.bendDirection = frames[zlen(frames) + PREV_BEND_DIRECTION] + return + end + + -- Interpolate between the previous frame and the current frame. + local frame = binarySearch(frames, time, ENTRIES) + local mix = frames[frame + PREV_MIX] + local frameTime = frames[frame] + local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, + 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) + + constraint.mix = constraint.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha + constraint.bendDirection = math.floor(frames[frame + PREV_BEND_DIRECTION]) + end + + return self +end + +Animation.TransformConstraintTimeline = {} +Animation.TransformConstraintTimeline.ENTRIES = 5 +function Animation.TransformConstraintTimeline.new (frameCount) + local ENTRIES = Animation.TransformConstraintTimeline.ENTRIES + local PREV_TIME = -5 + local PREV_ROTATE = -4 + local PREV_TRANSLATE = -3 + local PREV_SCALE = -2 + local PREV_SHEAR = -1 + local ROTATE = 1 + local TRANSLATE = 2 + local SCALE = 3 + local SHEAR = 4 + + local self = Animation.CurveTimeline.new(frameCount) + self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) + self.transformConstraintIndex = -1 + + function self:setFrame (frameIndex, time, rotateMix, translateMix, scaleMix, shearMix) + frameIndex = frameIndex * ENTRIES + self.frames[frameIndex] = time + self.frames[frameIndex + ROTATE] = rotateMix + self.frames[frameIndex + TRANSLATE] = translateMix + self.frames[frameIndex + SCALE] = scaleMix + self.frames[frameIndex + SHEAR] = shearMix + end + + function self:apply (skeleton, lastTime, time, firedEvents, alpha) + local frames = self.frames + if time < frames[0] then return end -- Time is before first frame. + + local constraint = skeleton.transformConstraints[self.transformConstraintIndex] + + if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. + local i = zlen(frames) + constraint.rotateMix = constraintMix.rotateMix + (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha + constraint.translateMix = constraintMix.translateMix + (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha + constraint.scaleMix = constraintMix.scaleMix + (frames[i + PREV_SCALE] - constraint.scaleMix) * alpha + constraint.shearMix = constraintMix.shearMix + (frames[i + PREV_SHEAR] - constraint.shearMix) * alpha + return + end + + -- Interpolate between the last frame and the current frame. + local frame = binarySearch(frames, time, ENTRIES) + local frameTime = frames[frame] + local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) + + local rotate = frames[frame + PREV_ROTATE] + local translate = frames[frame + PREV_TRANSLATE] + local scale = frames[frame + PREV_SCALE] + local shear = frames[frame + PREV_SHEAR] + constraint.rotateMix = constraint.rotateMix + (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha + constraint.translateMix = constraint.translateMix + (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix) * alpha + constraint.scaleMix = constraint.scaleMix + (scale + (frames[frame + SCALE] - scale) * percent - constraint.scaleMix) * alpha + constraint.shearMix = constraint.shearMix + (shear + (frames[frame + SHEAR] - shear) * percent - constraint.shearMix) * alpha + end + + return self +end + +Animation.PathConstraintPositionTimeline = {} +Animation.PathConstraintPositionTimeline.ENTRIES = 2 +function Animation.PathConstraintPositionTimeline.new (frameCount) + local ENTRIES = Animation.PathConstraintPositionTimeline.ENTRIES + local PREV_TIME = -2 + local PREV_VALUE = -1 + local VALUE = 1 + + local self = Animation.CurveTimeline.new(frameCount) + self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) + self.pathConstraintIndex = -1 + + function self:setFrame (frameIndex, time, value) + frameIndex = frameIndex * ENTRIES + self.frames[frameIndex] = time + self.frames[frameIndex + VALUE] = value + end + + function self:apply (skeleton, lastTime, time, firedEvents, alpha) + local frames = self.frames + if (time < frames[0]) then return end -- Time is before first frame. + + local constraint = skeleton.pathConstraints[self.pathConstraintIndex] + + if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. + local i = zlen(frames) + constraint.position = constraint.position + (frames[i + PREV_VALUE] - constraint.position) * alpha + return + end + + -- Interpolate between the previous frame and the current frame. + local frame = binarySearch(frames, time, ENTRIES) + local position = frames[frame + PREV_VALUE] + local frameTime = frames[frame] + local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) + + constraint.position = constraint.position + (position + (frames[frame + VALUE] - position) * percent - constraint.position) * alpha + end + + return self +end + +Animation.PathConstraintSpacingTimeline = {} +Animation.PathConstraintSpacingTimeline.ENTRIES = 2 +function Animation.PathConstraintSpacingTimeline.new (frameCount) + local ENTRIES = Animation.PathConstraintSpacingTimeline.ENTRIES + local PREV_TIME = -2 + local PREV_VALUE = -1 + local VALUE = 1 + + local self = Animation.CurveTimeline.new(frameCount) + self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) + self.pathConstraintIndex = -1 + + function self:setFrame (frameIndex, time, value) + frameIndex = frameIndex * ENTRIES + self.frames[frameIndex] = time + self.frames[frameIndex + VALUE] = value + end + + function self:apply (skeleton, lastTime, time, firedEvents, alpha) + local frames = self.frames + if (time < frames[0]) then return end -- Time is before first frame. + + local constraint = skeleton.pathConstraints[self.pathConstraintIndex] + + if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. + local i = zlen(frames) + constraint.spacing = constraint.spacing + (frames[i + PREV_VALUE] - constraint.spacing) * alpha + return + end + + -- Interpolate between the previous frame and the current frame. + local frame = binarySearch(frames, time, ENTRIES) + local spacing = frames[frame + PREV_VALUE] + local frameTime = frames[frame] + local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) + + constraint.spacing = constraint.spacing + (spacing + (frames[frame + VALUE] - spacing) * percent - constraint.spacing) * alpha + end + + return self +end + +Animation.PathConstraintMixTimeline = {} +Animation.PathConstraintMixTimeline.ENTRIES = 3 +function Animation.PathConstraintMixTimeline.new (frameCount) + local ENTRIES = Animation.PathConstraintMixTimeline.ENTRIES + local PREV_TIME = -3 + local PREV_ROTATE = -2 + local PREV_TRANSLATE = -1 + local ROTATE = 1 + local TRANSLATE = 2 + + local self = Animation.CurveTimeline.new(frameCount) + self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) + self.pathConstraintIndex = -1 + + function self:setFrame (frameIndex, time, rotateMix, translateMix) + frameIndex = frameIndex * ENTRIES + self.frames[frameIndex] = time + self.frames[frameIndex + ROTATE] = rotateMix + self.frames[frameIndex + TRANSLATE] = translateMix + end + + function self:apply (skeleton, lastTime, time, firedEvents, alpha) + local frames = self.frames + if (time < frames[0]) then return end -- Time is before first frame. + + local constraint = skeleton.pathConstraints[self.pathConstraintIndex] + + if time >= frames[zlen(frames) - ENTRIES] then -- Time is after last frame. + local i = zlen(frames) + constraint.rotateMix = constraint.rotateMix + (frames[i + PREV_ROTATE] - constraint.rotateMix) * alpha + constraint.translateMix = constraint.translateMix + (frames[i + PREV_TRANSLATE] - constraint.translateMix) * alpha + return + end + + -- Interpolate between the previous frame and the current frame. + local frame = binarySearch(frames, time, ENTRIES) + local rotate = frames[frame + PREV_ROTATE] + local translate = frames[frame + PREV_TRANSLATE] + local frameTime = frames[frame] + local percent = self:getCurvePercent(math.floor(frame / ENTRIES) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)) + + constraint.rotateMix = constraint.rotateMix + (rotate + (frames[frame + ROTATE] - rotate) * percent - constraint.rotateMix) * alpha + constraint.translateMix = constraint.translateMix + (translate + (frames[frame + TRANSLATE] - translate) * percent - constraint.translateMix) * alpha + end + + return self +end + return Animation diff --git a/spine-lua/AnimationState.lua b/spine-lua/AnimationState.lua index 06258ba03e..ebd87cbb8b 100644 --- a/spine-lua/AnimationState.lua +++ b/spine-lua/AnimationState.lua @@ -1,252 +1,251 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local AnimationState = {} - -function AnimationState.new (data) - if not data then error("data cannot be nil", 2) end - - local self = { - data = data, - tracks = {}, - trackCount = 0, - events = {}, - onStart = nil, onEnd = nil, onComplete = nil, onEvent = nil, - timeScale = 1 - } - - local function setCurrent (index, entry) - local current = self.tracks[index] - if current then - local previous = current.previous - current.previous = nil - - if current.onEnd then current.onEnd(index) end - if self.onEnd then self.onEnd(index) end - - entry.mixDuration = self.data:getMix(current.animation.name, entry.animation.name) - if entry.mixDuration > 0 then - entry.mixTime = 0 - -- If a mix is in progress, mix from the closest animation. - if previous and current.mixTime / current.mixDuration < 0.5 then - entry.previous = previous - else - entry.previous = current - end - end - end - - self.tracks[index] = entry - self.trackCount = math.max(self.trackCount, index + 1) - - if entry.onStart then entry.onStart(index) end - if self.onStart then self.onStart(index) end - end - - function self:update (delta) - delta = delta * self.timeScale - for i = 0, self.trackCount - 1 do - local current = self.tracks[i] - if current then - current.time = current.time + delta * current.timeScale - if current.previous then - local previousDelta = delta * current.previous.timeScale - current.previous.time = current.previous.time + previousDelta - current.mixTime = current.mixTime + previousDelta - end - - local next = current.next - if next then - next.time = current.lastTime - next.delay - if next.time >= 0 then setCurrent(i, next) end - else - -- End non-looping animation when it reaches its end time and there is no next entry. - if not current.loop and current.lastTime >= current.endTime then self:clearTrack(i) end - end - end - end - end - - function self:apply(skeleton) - for i = 0, self.trackCount - 1 do - local current = self.tracks[i] - if current then - local time = current.time - local lastTime = current.lastTime - local endTime = current.endTime - local loop = current.loop - if not loop and time > endTime then time = endTime end - - local previous = current.previous - if not previous then - if current.mix == 1 then - current.animation:apply(skeleton, current.lastTime, time, loop, self.events) - else - current.animation:mix(skeleton, current.lastTime, time, loop, self.events, current.mix) - end - else - local previousTime = previous.time - if not previous.loop and previousTime > previous.endTime then previousTime = previous.endTime end - previous.animation:apply(skeleton, previousTime, previousTime, previous.loop, nil) - - local alpha = current.mixTime / current.mixDuration * current.mix - if alpha >= 1 then - alpha = 1 - current.previous = nil - end - current.animation:mix(skeleton, current.lastTime, time, loop, self.events, alpha) - end - - local eventCount = #self.events - for ii = 1, eventCount, 1 do - local event = self.events[ii] - if current.onEvent then current.onEvent(i, event) end - if self.onEvent then self.onEvent(i, event) end - end - for ii = 1, eventCount, 1 do - table.remove(self.events) - end - - -- Check if completed the animation or a loop iteration. - local complete - if current.loop then - complete = lastTime % endTime > time % endTime - else - complete = lastTime < endTime and time >= endTime - end - if complete then - local count = math.floor(time / endTime) - if current.onComplete then current.onComplete(i, count) end - if self.onComplete then self.onComplete(i, count) end - end - - current.lastTime = current.time - end - end - end - - function self:clearTracks () - for i,current in pairs(self.tracks) do - self.clearTrack(i) - end - self.tracks = {} - self.trackCount = 0 - end - - function self:clearTrack (trackIndex) - local current = self.tracks[trackIndex] - if not current then return end - - if current.onEnd then current.onEnd(trackIndex) end - if self.onEnd then self.onEnd(trackIndex) end - - self.tracks[trackIndex] = nil - if trackIndex == self.trackCount - 1 then - self.trackCount = self.trackCount - 1 - end - end - - function self:setAnimationByName (trackIndex, animationName, loop) - local animation = self.data.skeletonData:findAnimation(animationName) - if not animation then error("Animation not found: " .. animationName) end - return self:setAnimation(trackIndex, animation, loop) - end - - -- Set the current animation. Any queued animations are cleared. - function self:setAnimation (trackIndex, animation, loop) - local entry = AnimationState.TrackEntry.new() - entry.animation = animation - entry.loop = loop - entry.endTime = animation.duration - setCurrent(trackIndex, entry) - return entry - end - - function self:addAnimationByName (trackIndex, animationName, loop, delay) - local animation = self.data.skeletonData:findAnimation(animationName) - if not animation then error("Animation not found: " .. animationName) end - return self:addAnimation(trackIndex, animation, loop, delay) - end - - -- Adds an animation to be played delay seconds after the current or last queued animation. - -- @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. - function self:addAnimation (trackIndex, animation, loop, delay) - local entry = AnimationState.TrackEntry.new() - entry.animation = animation - entry.loop = loop - entry.endTime = animation.duration - - local last = self.tracks[trackIndex] - if last then - while (last.next) do - last = last.next - end - last.next = entry - else - setCurrent(trackIndex, entry) - end - - delay = delay or 0 - if delay <= 0 then - if last then - delay = delay + last.endTime - self.data:getMix(last.animation.name, animation.name) - else - delay = 0 - end - end - entry.delay = delay - - return entry - end - - -- May return nil. - function self:getCurrent (trackIndex) - return self.tracks[trackIndex] - end - - return self -end - -AnimationState.TrackEntry = {} -function AnimationState.TrackEntry.new (data) - local self = { - next = nil, previous = nil, - animation = nil, - loop = false, - delay = 0, time = 0, lastTime = -1, endTime = 0, - timeScale = 1, - mixTime = 0, mixDuration = 0, mix = 1, - onStart = nil, onEnd = nil, onComplete = nil, onEvent = nil - } - return self -end +local AnimationState = {} + +function AnimationState.new (data) + if not data then error("data cannot be nil", 2) end + + local self = { + data = data, + tracks = {}, + trackCount = 0, + events = {}, + onStart = nil, onEnd = nil, onComplete = nil, onEvent = nil, + timeScale = 1 + } + + local function setCurrent (index, entry) + local current = self.tracks[index] + if current then + local previous = current.previous + current.previous = nil + + if current.onEnd then current.onEnd(index) end + if self.onEnd then self.onEnd(index) end + + entry.mixDuration = self.data:getMix(current.animation.name, entry.animation.name) + if entry.mixDuration > 0 then + entry.mixTime = 0 + -- If a mix is in progress, mix from the closest animation. + if previous and current.mixTime / current.mixDuration < 0.5 then + entry.previous = previous + else + entry.previous = current + end + end + end + + self.tracks[index] = entry + self.trackCount = math.max(self.trackCount, index + 1) + + if entry.onStart then entry.onStart(index) end + if self.onStart then self.onStart(index) end + end + + function self:update (delta) + delta = delta * self.timeScale + for i = 0, self.trackCount - 1 do + local current = self.tracks[i] + if current then + current.time = current.time + delta * current.timeScale + if current.previous then + local previousDelta = delta * current.previous.timeScale + current.previous.time = current.previous.time + previousDelta + current.mixTime = current.mixTime + previousDelta + end + + local next = current.next + if next then + next.time = current.lastTime - next.delay + if next.time >= 0 then setCurrent(i, next) end + else + -- End non-looping animation when it reaches its end time and there is no next entry. + if not current.loop and current.lastTime >= current.endTime then self:clearTrack(i) end + end + end + end + end + + function self:apply(skeleton) + for i = 0, self.trackCount - 1 do + local current = self.tracks[i] + if current then + local time = current.time + local lastTime = current.lastTime + local endTime = current.endTime + local loop = current.loop + if not loop and time > endTime then time = endTime end + + local previous = current.previous + if not previous then + if current.mix == 1 then + current.animation:apply(skeleton, current.lastTime, time, loop, self.events) + else + current.animation:mix(skeleton, current.lastTime, time, loop, self.events, current.mix) + end + else + local previousTime = previous.time + if not previous.loop and previousTime > previous.endTime then previousTime = previous.endTime end + previous.animation:apply(skeleton, previousTime, previousTime, previous.loop, nil) + + local alpha = current.mixTime / current.mixDuration * current.mix + if alpha >= 1 then + alpha = 1 + current.previous = nil + end + current.animation:mix(skeleton, current.lastTime, time, loop, self.events, alpha) + end + + local eventCount = #self.events + for ii = 1, eventCount, 1 do + local event = self.events[ii] + if current.onEvent then current.onEvent(i, event) end + if self.onEvent then self.onEvent(i, event) end + end + for ii = 1, eventCount, 1 do + table.remove(self.events) + end + + -- Check if completed the animation or a loop iteration. + local complete + if current.loop then + complete = lastTime % endTime > time % endTime + else + complete = lastTime < endTime and time >= endTime + end + if complete then + local count = math.floor(time / endTime) + if current.onComplete then current.onComplete(i, count) end + if self.onComplete then self.onComplete(i, count) end + end + + current.lastTime = current.time + end + end + end + + function self:clearTracks () + for i,current in pairs(self.tracks) do + self.clearTrack(i) + end + self.tracks = {} + self.trackCount = 0 + end + + function self:clearTrack (trackIndex) + local current = self.tracks[trackIndex] + if not current then return end + + if current.onEnd then current.onEnd(trackIndex) end + if self.onEnd then self.onEnd(trackIndex) end + + self.tracks[trackIndex] = nil + if trackIndex == self.trackCount - 1 then + self.trackCount = self.trackCount - 1 + end + end + + function self:setAnimationByName (trackIndex, animationName, loop) + local animation = self.data.skeletonData:findAnimation(animationName) + if not animation then error("Animation not found: " .. animationName) end + return self:setAnimation(trackIndex, animation, loop) + end + + -- Set the current animation. Any queued animations are cleared. + function self:setAnimation (trackIndex, animation, loop) + local entry = AnimationState.TrackEntry.new() + entry.animation = animation + entry.loop = loop + entry.endTime = animation.duration + setCurrent(trackIndex, entry) + return entry + end + + function self:addAnimationByName (trackIndex, animationName, loop, delay) + local animation = self.data.skeletonData:findAnimation(animationName) + if not animation then error("Animation not found: " .. animationName) end + return self:addAnimation(trackIndex, animation, loop, delay) + end + + -- Adds an animation to be played delay seconds after the current or last queued animation. + -- @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. + function self:addAnimation (trackIndex, animation, loop, delay) + local entry = AnimationState.TrackEntry.new() + entry.animation = animation + entry.loop = loop + entry.endTime = animation.duration + + local last = self.tracks[trackIndex] + if last then + while (last.next) do + last = last.next + end + last.next = entry + else + setCurrent(trackIndex, entry) + end + + delay = delay or 0 + if delay <= 0 then + if last then + delay = delay + last.endTime - self.data:getMix(last.animation.name, animation.name) + else + delay = 0 + end + end + entry.delay = delay + + return entry + end + + -- May return nil. + function self:getCurrent (trackIndex) + return self.tracks[trackIndex] + end + + return self +end + +AnimationState.TrackEntry = {} +function AnimationState.TrackEntry.new (data) + local self = { + next = nil, previous = nil, + animation = nil, + loop = false, + delay = 0, time = 0, lastTime = -1, endTime = 0, + timeScale = 1, + mixTime = 0, mixDuration = 0, mix = 1, + onStart = nil, onEnd = nil, onComplete = nil, onEvent = nil + } + return self +end + return AnimationState diff --git a/spine-lua/AnimationStateData.lua b/spine-lua/AnimationStateData.lua index c238e71039..b8142deb6d 100644 --- a/spine-lua/AnimationStateData.lua +++ b/spine-lua/AnimationStateData.lua @@ -1,60 +1,59 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local AnimationStateData = {} - -function AnimationStateData.new (skeletonData) - if not skeletonData then error("skeletonData cannot be nil", 2) end - - local self = { - skeletonData = skeletonData, - animationToMixTime = {}, - defaultMix = 0 - } - - function self:setMix (fromName, toName, duration) - if not self.animationToMixTime[fromName] then - self.animationToMixTime[fromName] = {} - end - self.animationToMixTime[fromName][toName] = duration - end - - function self:getMix (fromName, toName) - local first = self.animationToMixTime[fromName] - if not first then return self.defaultMix end - local duration = first[toName] - if not duration then return self.defaultMix end - return duration - end - return self -end +local AnimationStateData = {} + +function AnimationStateData.new (skeletonData) + if not skeletonData then error("skeletonData cannot be nil", 2) end + + local self = { + skeletonData = skeletonData, + animationToMixTime = {}, + defaultMix = 0 + } + + function self:setMix (fromName, toName, duration) + if not self.animationToMixTime[fromName] then + self.animationToMixTime[fromName] = {} + end + self.animationToMixTime[fromName][toName] = duration + end + + function self:getMix (fromName, toName) + local first = self.animationToMixTime[fromName] + if not first then return self.defaultMix end + local duration = first[toName] + if not duration then return self.defaultMix end + return duration + end + + return self +end return AnimationStateData diff --git a/spine-lua/Atlas.lua b/spine-lua/Atlas.lua index e0b728d8e6..0a6cfcaaa3 100644 --- a/spine-lua/Atlas.lua +++ b/spine-lua/Atlas.lua @@ -1,106 +1,105 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local Atlas = {} - -function Atlas.parse(atlasPath, atlasBase) - local function parseIntTuple4( l ) - local a,b,c,d = string.match( l , " ? ?%a+: ([+-]?%d+), ?([+-]?%d+), ?([+-]?%d+), ?([+-]?%d+)" ) - local a,b,c,d = tonumber( a ), tonumber( b ), tonumber( c ), tonumber( d ) - return a and b and c and d and {a, b, c ,d} - end - - local function parseIntTuple2( l ) - local a,b = string.match( l , " ? ?%a+: ([+-]?%d+), ?([+-]?%d+)" ) - local a,b = tonumber( a ), tonumber( b ) - return a and b and {a, b} - end - - if not atlasPath then - error("Error: " .. atlasPath .. ".atlas" .. " doesn't exist!") - return nil - end - - local atlasLines = spine.utils.readFile( atlasPath, atlasBase ) - if not atlasLines then - error("Error: " .. atlasPath .. ".atlas" .. " unable to read!") - return nil - end - - local pages = {} - - - local it = string.gmatch(atlasLines, "(.-)\r?\n") -- iterate over lines - for l in it do - if #l == 0 then - l = it() - if l then - local page = { name = l } - l = it() - page.size = parseIntTuple2( l ) - if page.size then - l = it() - end - page.format = string.match( l, "%a+: (.+)" ) - page.filter = {string.match( it(), "%a+: (.+),(.+)" )} - page.wrap = string.match( it(), "%a+: (.+)" ) - page.regions = {} - table.insert( pages, page ) - else - break - end - else - local region = {name = l} - - region.rotate = string.match( it(), "%a+: (.+)" ) == "true" - region.xy = parseIntTuple2( it() ) - region.size = parseIntTuple2( it() ) - l = it() - region.splits = parseIntTuple4(l) - if region.splits then - l = it() - region.pad = parseIntTuple4(l) - if region.pad then - l = it() - end - end - region.orig = parseIntTuple2( l ) - region.offset = parseIntTuple2( it() ) - region.index = tonumber( string.match( it() , "%a+: ([+-]?%d+)" ) ) - - table.insert( pages[#pages].regions, region ) - end - end - - return pages -end +local Atlas = {} + +function Atlas.parse(atlasPath, atlasBase) + local function parseIntTuple4( l ) + local a,b,c,d = string.match( l , " ? ?%a+: ([+-]?%d+), ?([+-]?%d+), ?([+-]?%d+), ?([+-]?%d+)" ) + local a,b,c,d = tonumber( a ), tonumber( b ), tonumber( c ), tonumber( d ) + return a and b and c and d and {a, b, c ,d} + end + + local function parseIntTuple2( l ) + local a,b = string.match( l , " ? ?%a+: ([+-]?%d+), ?([+-]?%d+)" ) + local a,b = tonumber( a ), tonumber( b ) + return a and b and {a, b} + end + + if not atlasPath then + error("Error: " .. atlasPath .. ".atlas" .. " doesn't exist!") + return nil + end + + local atlasLines = spine.utils.readFile( atlasPath, atlasBase ) + if not atlasLines then + error("Error: " .. atlasPath .. ".atlas" .. " unable to read!") + return nil + end + + local pages = {} + + + local it = string.gmatch(atlasLines, "(.-)\r?\n") -- iterate over lines + for l in it do + if #l == 0 then + l = it() + if l then + local page = { name = l } + l = it() + page.size = parseIntTuple2( l ) + if page.size then + l = it() + end + page.format = string.match( l, "%a+: (.+)" ) + page.filter = {string.match( it(), "%a+: (.+),(.+)" )} + page.wrap = string.match( it(), "%a+: (.+)" ) + page.regions = {} + table.insert( pages, page ) + else + break + end + else + local region = {name = l} + + region.rotate = string.match( it(), "%a+: (.+)" ) == "true" + region.xy = parseIntTuple2( it() ) + region.size = parseIntTuple2( it() ) + l = it() + region.splits = parseIntTuple4(l) + if region.splits then + l = it() + region.pad = parseIntTuple4(l) + if region.pad then + l = it() + end + end + region.orig = parseIntTuple2( l ) + region.offset = parseIntTuple2( it() ) + region.index = tonumber( string.match( it() , "%a+: ([+-]?%d+)" ) ) + + table.insert( pages[#pages].regions, region ) + end + end + + return pages +end + return Atlas diff --git a/spine-lua/AttachmentLoader.lua b/spine-lua/AttachmentLoader.lua index 2ffa2e8ca1..7eefd5e228 100644 --- a/spine-lua/AttachmentLoader.lua +++ b/spine-lua/AttachmentLoader.lua @@ -1,64 +1,63 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local AttachmentType = require "spine-lua.attachments.AttachmentType" -local RegionAttachment = require "spine-lua.attachments.RegionAttachment" -local BoundingBoxAttachment = require "spine-lua.attachments.BoundingBoxAttachment" -local MeshAttachment = require "spine-lua.attachments.MeshAttachment" -local PathAttachment = require "spine-lua.attachments.PathAttachment" - -local AttachmentLoader = {} -function AttachmentLoader.new () - local self = {} - - function self:newRegionAttachment (skin, name, path) - return RegionAttachment.new(name) - end - - function self:newMeshAttachment (skin, name, path) - return MeshAttachment.new(name) - end - - function self:newSkinningMeshAttachment (skin, name, path) - return SkinningMeshAttachment.new(name) - end - - function self:newBoundingBoxAttachment (skin, name) - return BoundingBoxAttachment.new(name) - end - - function self:newPathAttachment(skin, name) - return PathAttachment.new(name) - end - return self -end +local AttachmentType = require "spine-lua.attachments.AttachmentType" +local RegionAttachment = require "spine-lua.attachments.RegionAttachment" +local BoundingBoxAttachment = require "spine-lua.attachments.BoundingBoxAttachment" +local MeshAttachment = require "spine-lua.attachments.MeshAttachment" +local PathAttachment = require "spine-lua.attachments.PathAttachment" + +local AttachmentLoader = {} +function AttachmentLoader.new () + local self = {} + + function self:newRegionAttachment (skin, name, path) + return RegionAttachment.new(name) + end + + function self:newMeshAttachment (skin, name, path) + return MeshAttachment.new(name) + end + + function self:newSkinningMeshAttachment (skin, name, path) + return SkinningMeshAttachment.new(name) + end + + function self:newBoundingBoxAttachment (skin, name) + return BoundingBoxAttachment.new(name) + end + + function self:newPathAttachment(skin, name) + return PathAttachment.new(name) + end + + return self +end return AttachmentLoader diff --git a/spine-lua/AttachmentType.lua b/spine-lua/AttachmentType.lua index 494e65ac49..649d6fad35 100644 --- a/spine-lua/AttachmentType.lua +++ b/spine-lua/AttachmentType.lua @@ -1,38 +1,37 @@ -------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- -local AttachmentType = { - region = 0, - boundingbox = 1, - mesh = 2, - skinnedmesh = 3 -} +local AttachmentType = { + region = 0, + boundingbox = 1, + mesh = 2, + skinnedmesh = 3 +} return AttachmentType diff --git a/spine-lua/BlendMode.lua b/spine-lua/BlendMode.lua index ecf4dd8349..8d68c1ccd2 100644 --- a/spine-lua/BlendMode.lua +++ b/spine-lua/BlendMode.lua @@ -1,38 +1,37 @@ -------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- -local BlendMode = { - normal = 0, - additive = 1, - multiply = 2, - screen = 3 -} +local BlendMode = { + normal = 0, + additive = 1, + multiply = 2, + screen = 3 +} return BlendMode diff --git a/spine-lua/Bone.lua b/spine-lua/Bone.lua index 54023e5c2a..8461abf92d 100644 --- a/spine-lua/Bone.lua +++ b/spine-lua/Bone.lua @@ -1,345 +1,344 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local setmetatable = setmetatable -local math_rad = math.rad -local math_deg = math.deg -local math_sin = math.sin -local math_cos = math.cos -local math_atan2 = math.atan2 -local math_sqrt = math.sqrt - -function math.sign(x) - if x<0 then - return -1 - elseif x>0 then - return 1 - else - return 0 - end -end - -local math_sign = math.sign - -local Bone = {} -Bone.__index = Bone - -function Bone.new (data, skeleton, parent) - if not data then error("data cannot be nil", 2) end - if not skeleton then error("skeleton cannot be nil", 2) end - - local self = { - data = data, - skeleton = skeleton, - parent = parent, - children = { }, - x = 0, y = 0, rotation = 0, scaleX = 1, scaleY = 1, shearX = 0, shearY = 0, - appliedRotation = 0, - - a = 0, b = 0, worldX = 0, -- a b x - c = 0, d = 0, worldY = 0, -- c d y - worldSignX = 0, worldSignY = 0, - sorted = false - } - setmetatable(self, Bone) - - self:setToSetupPose() - return self -end - -function Bone:update () - self:updateWorldTransformWith(self.x, self.y, self.rotation, self.scaleX, self.scaleY, self.shearX, self.shearY) -end - -function Bone:updateWorldTransform () - self:updateWorldTransformWith(self.x, self.y, self.rotation, self.scaleX, self.scaleY, self.shearX, self.shearY) -end - -function Bone:updateWorldTransformWith (x, y, rotation, scaleX, scaleY, shearX, shearY) - self.appliedRotation = rotation - - local rotationY = rotation + 90 + shearY - local rotationRad = math_rad(rotation + shearX) - local rotationYRad = math_rad(rotationY) - local la = math_cos(rotationRad) * scaleX - local lb = math_cos(rotationYRad) * scaleY - local lc = math_sin(rotationRad) * scaleX - local ld = math_sin(rotationYRad) * scaleY - - local parent = self.parent - if parent == nil then - local skeleton = self.skeleton - if skeleton.flipX then - x = -x - la = -la - lb = -lb - end - if skeleton.flipY then - y = -y - lc = -lc - ld = -ld - end - self.a = la - self.b = lb - self.c = lc - self.d = ld - self.worldX = x - self.worldY = y - self.worldSignX = math_sign(scaleX) - self.worldSignY = math_sign(scaleY) - return - end - - local pa = parent.a - local pb = parent.b - local pc = parent.c - local pd = parent.d - self.worldX = pa * x + pb * y + parent.worldX - self.worldY = pc * x + pd * y + parent.worldY - self.worldSignX = parent.worldSignX * math_sign(scaleX) - self.worldSignY = parent.worldSignY * math_sign(scaleY) - - if self.data.inheritRotation and self.data.inheritScale then - self.a = pa * la + pb * lc - self.b = pa * lb + pb * ld - self.c = pc * la + pd * lc - self.d = pc * lb + pd * ld - else - if self.data.inheritRotation then - pa = 1 - pb = 0 - pc = 0 - pd = 1 - repeat - local appliedRotationRad = math_rad(parent.appliedRotation) - local cos = math_cos(appliedRotationRad) - local sin = math_sin(appliedRotationRad) - local temp = pa * cos + pb * sin - pb = pb * cos - pa * sin - pa = temp - temp = pc * cos + pd * sin - pd = pd * cos - pc * sin - pc = temp - - if not parent.data.inheritRotation then break end - parent = parent.parent - until parent == nil - self.a = pa * la + pb * lc - self.b = pa * lb + pb * ld - self.c = pc * la + pd * lc - self.d = pc * lb + pd * ld - elseif self.data.inheritScale then - pa = 1 - pb = 0 - pc = 0 - pd = 1 - repeat - local appliedRotationRad = math_rad(parent.appliedRotation) - local cos = math_cos(appliedRotationRad) - local sin = math_sin(appliedRotationRad) - local psx = parent.scaleX - local psy = parent.scaleY - local za = cos * psx - local zb = sin * psy - local zc = sin * psx - local zd = cos * psy - local temp = pa * za + pb * zc - pb = pb * zd - pa * zb - pa = temp - temp = pc * za + pd * zc - pd = pd * zd - pc * zb - pc = temp - - if psx >= 0 then sin = -sin end - temp = pa * cos + pb * sin - pb = pb * cos - pa * sin - pa = temp - temp = pc * cos + pd * sin - pd = pd * cos - pc * sin - pc = temp - - if not parent.data.inheritScale then break end - parent = parent.parent - until parent == nil - self.a = pa * la + pb * lc - self.b = pa * lb + pb * ld - self.c = pc * la + pd * lc - self.d = pc * lb + pd * ld - else - self.a = la - self.b = lb - self.c = lc - self.d = ld - end - if self.skeleton.flipX then - self.a = -self.a - self.b = -self.b - end - if self.skeleton.flipY then - self.c = -self.c - self.d = -self.d - end - end -end - -function Bone:setToSetupPose () - local data = self.data - self.x = data.x - self.y = data.y - self.rotation = data.rotation - self.scaleX = data.scaleX - self.scaleY = data.scaleY - self.shearX = data.shearX - self.shearY = data.shearY -end - -function Bone:getWorldRotationX () - return math_deg(math_atan2(self.c, self.a)) -end - -function Bone:getWorldRotationY () - return math_deg(math_atan2(self.d, self.b)) -end - -function Bone:getWorldScaleX () - return math_sqrt(self.a * self.a + self.b * self.b) * self.worldSignX -end - -function Bone:getWorldScaleY () - return math_sqrt(self.c * self.c + self.d * self.d) * self.worldSignY -end - -function Bone:worldToLocalRotationX () - local parent = self.parent - if parent == nil then return self.rotation end - local pa = parent.a - local pb = parent.b - local pc = parent.c - local pd = parent.d - local a = self.a - local c = self.c - return math_deg(math_atan2(pa * c - pc * a, pd * a - pb * c)) -end - -function Bone:worldToLocalRotationY () - local parent = self.parent - if parent == nil then return self.rotation end - local pa = parent.a - local pb = parent.b - local pc = parent.c - local pd = parent.d - local b = self.b - local d = self.d - return math_deg(math_atan2(pa * d - pc * b, pd * b - pb * d)) -end - -function Bone:rotateWorld (degrees) - local a = self.a - local b = self.b - local c = self.c - local d = self.d - local degreesRad = math_rad(degrees) - local cos = math_cos(degreesRad) - local sin = math_sin(degreesRad) - self.a = cos * a - sin * c - self.b = cos * b - sin * d - self.c = sin * a + cos * c - self.d = sin * b + cos * d -end - -function updateLocalTransform () - local parent = self.parent - if parent == nil then - self.x = self.worldX - self.y = self.worldY - self.rotation = math_deg(math_atan2(self.c, self.a)) - self.scaleX = math_sqrt(self.a * self.a + self.c * self.c) - self.scaleY = math_sqrt(self.b * self.b + self.d * self.d) - local det = self.a * self.d - self.b * self.c - self.shearX = 0 - self.shearY = math_deg(math_atan2(self.a * self.b + self.c * self.d, det)) - return - end - local pa = parent.a - local pb = parent.b - local pc = parent.c - local pd = parent.d - local pid = 1 / (pa * pd - pb * pc) - local dx = self.worldX - parent.worldX - local dy = self.worldY - parent.worldY - self.x = (dx * pd * pid - dy * pb * pid) - self.y = (dy * pa * pid - dx * pc * pid) - local ia = pid * pd - local id = pid * pa - local ib = pid * pb - local ic = pid * pc - local ra = ia * self.a - ib * self.c - local rb = ia * self.b - ib * self.d - local rc = id * self.c - ic * self.a - local rd = id * self.d - ic * self.b - self.shearX = 0 - self.scaleX = math_sqrt(ra * ra + rc * rc) - if self.scaleX > 0.0001 then - local det = ra * rd - rb * rc - self.scaleY = det / self.scaleX - self.shearY = math_deg(math_atan2(ra * rb + rc * rd, det)) - self.rotation = math_deg(math_atan2(rc, ra)) - else - self.scaleX = 0 - self.scaleY = math_sqrt(rb * rb + rd * rd) - self.shearY = 0 - self.rotation = 90 - math_deg(math_atan2(rd, rb)) - end - self.appliedRotation = self.rotation -end - -function Bone:worldToLocal (world) - local a = self.a - local b = self.b - local c = self.c - local d = self.d - local invDet = 1 / (a * d - b * c) - local x = world[1] - self.worldX - local y = world[2] - self.worldY - world[1] = (x * d * invDet - y * b * invDet) - world[2] = (y * a * invDet - x * c * invDet) - return world -end - -function Bone:localToWorld (localCoords) - local x = localCoords[1] - local y = localCoords[2] - localCoords[1] = x * self.a + y * self.b + self.worldX - localCoords[2] = x * self.c + y * self.d + self.worldY - return localCoords -end -return Bone \ No newline at end of file +local setmetatable = setmetatable +local math_rad = math.rad +local math_deg = math.deg +local math_sin = math.sin +local math_cos = math.cos +local math_atan2 = math.atan2 +local math_sqrt = math.sqrt + +function math.sign(x) + if x<0 then + return -1 + elseif x>0 then + return 1 + else + return 0 + end +end + +local math_sign = math.sign + +local Bone = {} +Bone.__index = Bone + +function Bone.new (data, skeleton, parent) + if not data then error("data cannot be nil", 2) end + if not skeleton then error("skeleton cannot be nil", 2) end + + local self = { + data = data, + skeleton = skeleton, + parent = parent, + children = { }, + x = 0, y = 0, rotation = 0, scaleX = 1, scaleY = 1, shearX = 0, shearY = 0, + appliedRotation = 0, + + a = 0, b = 0, worldX = 0, -- a b x + c = 0, d = 0, worldY = 0, -- c d y + worldSignX = 0, worldSignY = 0, + sorted = false + } + setmetatable(self, Bone) + + self:setToSetupPose() + return self +end + +function Bone:update () + self:updateWorldTransformWith(self.x, self.y, self.rotation, self.scaleX, self.scaleY, self.shearX, self.shearY) +end + +function Bone:updateWorldTransform () + self:updateWorldTransformWith(self.x, self.y, self.rotation, self.scaleX, self.scaleY, self.shearX, self.shearY) +end + +function Bone:updateWorldTransformWith (x, y, rotation, scaleX, scaleY, shearX, shearY) + self.appliedRotation = rotation + + local rotationY = rotation + 90 + shearY + local rotationRad = math_rad(rotation + shearX) + local rotationYRad = math_rad(rotationY) + local la = math_cos(rotationRad) * scaleX + local lb = math_cos(rotationYRad) * scaleY + local lc = math_sin(rotationRad) * scaleX + local ld = math_sin(rotationYRad) * scaleY + + local parent = self.parent + if parent == nil then + local skeleton = self.skeleton + if skeleton.flipX then + x = -x + la = -la + lb = -lb + end + if skeleton.flipY then + y = -y + lc = -lc + ld = -ld + end + self.a = la + self.b = lb + self.c = lc + self.d = ld + self.worldX = x + self.worldY = y + self.worldSignX = math_sign(scaleX) + self.worldSignY = math_sign(scaleY) + return + end + + local pa = parent.a + local pb = parent.b + local pc = parent.c + local pd = parent.d + self.worldX = pa * x + pb * y + parent.worldX + self.worldY = pc * x + pd * y + parent.worldY + self.worldSignX = parent.worldSignX * math_sign(scaleX) + self.worldSignY = parent.worldSignY * math_sign(scaleY) + + if self.data.inheritRotation and self.data.inheritScale then + self.a = pa * la + pb * lc + self.b = pa * lb + pb * ld + self.c = pc * la + pd * lc + self.d = pc * lb + pd * ld + else + if self.data.inheritRotation then + pa = 1 + pb = 0 + pc = 0 + pd = 1 + repeat + local appliedRotationRad = math_rad(parent.appliedRotation) + local cos = math_cos(appliedRotationRad) + local sin = math_sin(appliedRotationRad) + local temp = pa * cos + pb * sin + pb = pb * cos - pa * sin + pa = temp + temp = pc * cos + pd * sin + pd = pd * cos - pc * sin + pc = temp + + if not parent.data.inheritRotation then break end + parent = parent.parent + until parent == nil + self.a = pa * la + pb * lc + self.b = pa * lb + pb * ld + self.c = pc * la + pd * lc + self.d = pc * lb + pd * ld + elseif self.data.inheritScale then + pa = 1 + pb = 0 + pc = 0 + pd = 1 + repeat + local appliedRotationRad = math_rad(parent.appliedRotation) + local cos = math_cos(appliedRotationRad) + local sin = math_sin(appliedRotationRad) + local psx = parent.scaleX + local psy = parent.scaleY + local za = cos * psx + local zb = sin * psy + local zc = sin * psx + local zd = cos * psy + local temp = pa * za + pb * zc + pb = pb * zd - pa * zb + pa = temp + temp = pc * za + pd * zc + pd = pd * zd - pc * zb + pc = temp + + if psx >= 0 then sin = -sin end + temp = pa * cos + pb * sin + pb = pb * cos - pa * sin + pa = temp + temp = pc * cos + pd * sin + pd = pd * cos - pc * sin + pc = temp + + if not parent.data.inheritScale then break end + parent = parent.parent + until parent == nil + self.a = pa * la + pb * lc + self.b = pa * lb + pb * ld + self.c = pc * la + pd * lc + self.d = pc * lb + pd * ld + else + self.a = la + self.b = lb + self.c = lc + self.d = ld + end + if self.skeleton.flipX then + self.a = -self.a + self.b = -self.b + end + if self.skeleton.flipY then + self.c = -self.c + self.d = -self.d + end + end +end + +function Bone:setToSetupPose () + local data = self.data + self.x = data.x + self.y = data.y + self.rotation = data.rotation + self.scaleX = data.scaleX + self.scaleY = data.scaleY + self.shearX = data.shearX + self.shearY = data.shearY +end + +function Bone:getWorldRotationX () + return math_deg(math_atan2(self.c, self.a)) +end + +function Bone:getWorldRotationY () + return math_deg(math_atan2(self.d, self.b)) +end + +function Bone:getWorldScaleX () + return math_sqrt(self.a * self.a + self.b * self.b) * self.worldSignX +end + +function Bone:getWorldScaleY () + return math_sqrt(self.c * self.c + self.d * self.d) * self.worldSignY +end + +function Bone:worldToLocalRotationX () + local parent = self.parent + if parent == nil then return self.rotation end + local pa = parent.a + local pb = parent.b + local pc = parent.c + local pd = parent.d + local a = self.a + local c = self.c + return math_deg(math_atan2(pa * c - pc * a, pd * a - pb * c)) +end + +function Bone:worldToLocalRotationY () + local parent = self.parent + if parent == nil then return self.rotation end + local pa = parent.a + local pb = parent.b + local pc = parent.c + local pd = parent.d + local b = self.b + local d = self.d + return math_deg(math_atan2(pa * d - pc * b, pd * b - pb * d)) +end + +function Bone:rotateWorld (degrees) + local a = self.a + local b = self.b + local c = self.c + local d = self.d + local degreesRad = math_rad(degrees) + local cos = math_cos(degreesRad) + local sin = math_sin(degreesRad) + self.a = cos * a - sin * c + self.b = cos * b - sin * d + self.c = sin * a + cos * c + self.d = sin * b + cos * d +end + +function updateLocalTransform () + local parent = self.parent + if parent == nil then + self.x = self.worldX + self.y = self.worldY + self.rotation = math_deg(math_atan2(self.c, self.a)) + self.scaleX = math_sqrt(self.a * self.a + self.c * self.c) + self.scaleY = math_sqrt(self.b * self.b + self.d * self.d) + local det = self.a * self.d - self.b * self.c + self.shearX = 0 + self.shearY = math_deg(math_atan2(self.a * self.b + self.c * self.d, det)) + return + end + local pa = parent.a + local pb = parent.b + local pc = parent.c + local pd = parent.d + local pid = 1 / (pa * pd - pb * pc) + local dx = self.worldX - parent.worldX + local dy = self.worldY - parent.worldY + self.x = (dx * pd * pid - dy * pb * pid) + self.y = (dy * pa * pid - dx * pc * pid) + local ia = pid * pd + local id = pid * pa + local ib = pid * pb + local ic = pid * pc + local ra = ia * self.a - ib * self.c + local rb = ia * self.b - ib * self.d + local rc = id * self.c - ic * self.a + local rd = id * self.d - ic * self.b + self.shearX = 0 + self.scaleX = math_sqrt(ra * ra + rc * rc) + if self.scaleX > 0.0001 then + local det = ra * rd - rb * rc + self.scaleY = det / self.scaleX + self.shearY = math_deg(math_atan2(ra * rb + rc * rd, det)) + self.rotation = math_deg(math_atan2(rc, ra)) + else + self.scaleX = 0 + self.scaleY = math_sqrt(rb * rb + rd * rd) + self.shearY = 0 + self.rotation = 90 - math_deg(math_atan2(rd, rb)) + end + self.appliedRotation = self.rotation +end + +function Bone:worldToLocal (world) + local a = self.a + local b = self.b + local c = self.c + local d = self.d + local invDet = 1 / (a * d - b * c) + local x = world[1] - self.worldX + local y = world[2] - self.worldY + world[1] = (x * d * invDet - y * b * invDet) + world[2] = (y * a * invDet - x * c * invDet) + return world +end + +function Bone:localToWorld (localCoords) + local x = localCoords[1] + local y = localCoords[2] + localCoords[1] = x * self.a + y * self.b + self.worldX + localCoords[2] = x * self.c + y * self.d + self.worldY + return localCoords +end + +return Bone diff --git a/spine-lua/BoneData.lua b/spine-lua/BoneData.lua index f9f402d4d9..63cc808146 100644 --- a/spine-lua/BoneData.lua +++ b/spine-lua/BoneData.lua @@ -1,52 +1,51 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local BoneData = {} -function BoneData.new (index, name, parent) - if index < 0 then error("index must be >= 0", 2) end - if not name then error("name cannot be nil", 2) end - - local self = { - index = index, - name = name, - parent = parent, - length = 0, - x = 0, y = 0, - rotation = 0, - scaleX = 1, scaleY = 1, - shearX = 0, shearY = 0, - inheritRotation = true, - inheritScale = true - } - return self -end -return BoneData \ No newline at end of file +local BoneData = {} +function BoneData.new (index, name, parent) + if index < 0 then error("index must be >= 0", 2) end + if not name then error("name cannot be nil", 2) end + + local self = { + index = index, + name = name, + parent = parent, + length = 0, + x = 0, y = 0, + rotation = 0, + scaleX = 1, scaleY = 1, + shearX = 0, shearY = 0, + inheritRotation = true, + inheritScale = true + } + + return self +end +return BoneData diff --git a/spine-lua/BoundingBoxAttachment.lua b/spine-lua/BoundingBoxAttachment.lua index 5beee7bf38..0b736cd102 100644 --- a/spine-lua/BoundingBoxAttachment.lua +++ b/spine-lua/BoundingBoxAttachment.lua @@ -1,63 +1,62 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local AttachmentType = require "spine-lua.AttachmentType" - -local BoundingBoxAttachment = {} -function BoundingBoxAttachment.new (name) - if not name then error("name cannot be nil", 2) end - - local self = { - name = name, - type = AttachmentType.boundingbox, - vertices = {} - } - - function self:computeWorldVertices (x, y, bone, worldVertices) - x = x + bone.worldX - y = y + bone.worldY - local m00 = bone.m00 - local m01 = bone.m01 - local m10 = bone.m10 - local m11 = bone.m11 - local vertices = self.vertices - local count = #vertices - for i = 1, count, 2 do - local px = vertices[i] - local py = vertices[i + 1] - worldVertices[i] = px * m00 + py * m01 + x - worldVertices[i + 1] = px * m10 + py * m11 + y - end - end - return self -end +local AttachmentType = require "spine-lua.AttachmentType" + +local BoundingBoxAttachment = {} +function BoundingBoxAttachment.new (name) + if not name then error("name cannot be nil", 2) end + + local self = { + name = name, + type = AttachmentType.boundingbox, + vertices = {} + } + + function self:computeWorldVertices (x, y, bone, worldVertices) + x = x + bone.worldX + y = y + bone.worldY + local m00 = bone.m00 + local m01 = bone.m01 + local m10 = bone.m10 + local m11 = bone.m11 + local vertices = self.vertices + local count = #vertices + for i = 1, count, 2 do + local px = vertices[i] + local py = vertices[i + 1] + worldVertices[i] = px * m00 + py * m01 + x + worldVertices[i + 1] = px * m10 + py * m11 + y + end + end + + return self +end return BoundingBoxAttachment diff --git a/spine-lua/Color.lua b/spine-lua/Color.lua index 547b75d962..431f443278 100644 --- a/spine-lua/Color.lua +++ b/spine-lua/Color.lua @@ -1,84 +1,84 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- -local setmetatable = setmetatable -local utils = require "spine-lua.utils" - -local Color = {} -Color.__index = Color - -function Color.new () - local self = { - r = 0, g = 0, b = 0, a = 0 - } - setmetatable(self, Color) - - return self -end - -function Color.newWith (r, g, b, a) - local self = { - r = a, g = g, b = b, a = a - } - setmetatable(self, Color) - - return self -end - -function Color:set(r, g, b, a) - self.r = r - self.g = g - self.b = b - self.a = a -end - -function Color:setFrom(color) - self.r = color.r - self.g = color.g - self.b = color.b - self.a = color.a -end - -function Color:add(r, g, b, a) - self.r = self.r + r - self.g = self.g + g - self.b = self.b + b - self.a = self.a + a - self:clamp() -end - -function Color:clamp() - self.r = utils.clamp(self.r, 0, 1) - self.g = utils.clamp(self.g, 0, 1) - self.b = utils.clamp(self.b, 0, 1) - self.a = utils.clamp(self.a, 0, 1) -end -return Color \ No newline at end of file +local setmetatable = setmetatable +local utils = require "spine-lua.utils" + +local Color = {} +Color.__index = Color + +function Color.new () + local self = { + r = 0, g = 0, b = 0, a = 0 + } + setmetatable(self, Color) + + return self +end + +function Color.newWith (r, g, b, a) + local self = { + r = a, g = g, b = b, a = a + } + setmetatable(self, Color) + + return self +end + +function Color:set(r, g, b, a) + self.r = r + self.g = g + self.b = b + self.a = a +end + +function Color:setFrom(color) + self.r = color.r + self.g = color.g + self.b = color.b + self.a = color.a +end + +function Color:add(r, g, b, a) + self.r = self.r + r + self.g = self.g + g + self.b = self.b + b + self.a = self.a + a + self:clamp() +end + +function Color:clamp() + self.r = utils.clamp(self.r, 0, 1) + self.g = utils.clamp(self.g, 0, 1) + self.b = utils.clamp(self.b, 0, 1) + self.a = utils.clamp(self.a, 0, 1) +end + +return Color diff --git a/spine-lua/Event.lua b/spine-lua/Event.lua index cb701327e2..2d975ee61c 100644 --- a/spine-lua/Event.lua +++ b/spine-lua/Event.lua @@ -1,46 +1,45 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local Event = {} -function Event.new (time, data) - if not data then error("data cannot be nil", 2) end - - local self = { - data = data, - intValue = 0, - floatValue = 0, - stringValue = nil, - time = time - } - return self -end +local Event = {} +function Event.new (time, data) + if not data then error("data cannot be nil", 2) end + + local self = { + data = data, + intValue = 0, + floatValue = 0, + stringValue = nil, + time = time + } + + return self +end return Event diff --git a/spine-lua/EventData.lua b/spine-lua/EventData.lua index 7b707e3233..392bcb035e 100644 --- a/spine-lua/EventData.lua +++ b/spine-lua/EventData.lua @@ -1,45 +1,44 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local EventData = {} -function EventData.new (name) - if not name then error("name cannot be nil", 2) end - - local self = { - name = name, - intValue = 0, - floatValue = 0, - stringValue = nil - } - return self -end +local EventData = {} +function EventData.new (name) + if not name then error("name cannot be nil", 2) end + + local self = { + name = name, + intValue = 0, + floatValue = 0, + stringValue = nil + } + + return self +end return EventData diff --git a/spine-lua/IkConstraint.lua b/spine-lua/IkConstraint.lua index bd3899d7bc..9e1589447d 100644 --- a/spine-lua/IkConstraint.lua +++ b/spine-lua/IkConstraint.lua @@ -1,276 +1,275 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local setmetatable = setmetatable -local math_pi = math.pi -local math_atan2 = math.atan2 -local math_sqrt = math.sqrt -local math_acos = math.acos -local math_sin = math.sin -local math_cos = math.cos -local table_insert = table.insert -local math_deg = math.deg -local math_rad = math.rad -local math_abs = math.abs - -local IkConstraint = {} -IkConstraint.__index = IkConstraint - -function IkConstraint.new (data, skeleton) - if not data then error("data cannot be nil", 2) end - if not skeleton then error("skeleton cannot be nil", 2) end - - local self = { - data = data, - bones = {}, - target = nil, - mix = data.mix, - bendDirection = data.bendDirection, - level = 0 - } - setmetatable(self, IkConstraint) - - local self_bones = self.bones - for i,boneData in ipairs(data.bones) do - table_insert(self_bones, skeleton:findBone(boneData.name)) - end - self.target = skeleton:findBone(data.target.name) - - return self -end - -function IkConstraint:apply () - self:update() -end - -function IkConstraint:update () - local target = self.target - local bones = self.bones - local boneCount = #bones - if boneCount == 1 then - self:apply1(bones[1], target.worldX, target.worldY, self.mix) - elseif boneCount == 2 then - self:apply2(bones[1], bones[2], target.worldX, target.worldY, self.bendDirection, self.mix) - end -end - -function IkConstraint:apply1 (bone, targetX, targetY, alpha) - local pp = bone.parent - local id = 1 / (pp.a * pp.d - pp.b * pp.c) - local x = targetX - pp.worldX - local y = targetY - pp.worldY - local tx = (x * pp.d - y * pp.b) * id - bone.x - local ty = (y * pp.a - x * pp.c) * id - bone.y - local rotationIK = math_deg(math_atan2(ty, tx)) - bone.shearX - bone.rotation - if bone.scaleX < 0 then rotationIK = rotationIK + 180 end - if rotationIK > 180 then - rotationIK = rotationIK - 360 - elseif (rotationIK < -180) then - rotationIK = rotationIK + 360 - end - bone:updateWorldTransformWith(bone.x, bone.y, bone.rotation + rotationIK * alpha, bone.scaleX, bone.scaleY, bone.shearX, bone.shearY) -end - -function IkConstraint:apply2 (parent, child, targetX, targetY, bendDir, alpha) - if alpha == 0 then - child:updateWorldTransform() - return - end - local px = parent.x - local py = parent.y - local psx = parent.scaleX - local psy = parent.scaleY - local csx = child.scaleX - local os1 = 0 - local os2 = 0 - local s2 = 0 - if psx < 0 then - psx = -psx - os1 = 180 - s2 = -1 - else - os1 = 0 - s2 = 1 - end - if psy < 0 then - psy = -psy - s2 = -s2 - end - if csx < 0 then - csx = -csx - os2 = 180 - else - os2 = 0 - end - local cx = child.x - local cy = 0 - local cwx = 0 - local cwy = 0 - local a = parent.a - local b = parent.b - local c = parent.c - local d = parent.d - local u = math_abs(psx - psy) <= 0.0001 - if not u then - cy = 0 - cwx = a * cx + parent.worldX - cwy = c * cx + parent.worldY - else - cy = child.y - cwx = a * cx + b * cy + parent.worldX - cwy = c * cx + d * cy + parent.worldY - end - local pp = parent.parent - a = pp.a - b = pp.b - c = pp.c - d = pp.d - local id = 1 / (a * d - b * c) - local x = targetX - pp.worldX - local y = targetY - pp.worldY - local tx = (x * d - y * b) * id - px - local ty = (y * a - x * c) * id - py - x = cwx - pp.worldX - y = cwy - pp.worldY - local dx = (x * d - y * b) * id - px - local dy = (y * a - x * c) * id - py - local l1 = math_sqrt(dx * dx + dy * dy) - local l2 = child.data.length * csx - local a1 = 0 - local a2 = 0 - - if u then - l2 = l2 * psx - local cos = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2) - if cos < -1 then - cos = -1 - elseif cos > 1 then - cos = 1 - end - a2 = math_acos(cos) * bendDir - a = l1 + l2 * cos - b = l2 * math_sin(a2) - a1 = math_atan2(ty * a - tx * b, tx * a + ty * b) - else - local skip = false - a = psx * l2 - b = psy * l2 - local aa = a * a - local bb = b * b - local dd = tx * tx + ty * ty - local ta = math_atan2(ty, tx); - c = bb * l1 * l1 + aa * dd - aa * bb - local c1 = -2 * bb * l1 - local c2 = bb - aa - d = c1 * c1 - 4 * c2 * c - if d >= 0 then - local q = math_sqrt(d); - if (c1 < 0) then q = -q end - q = -(c1 + q) / 2 - local r0 = q / c2 - local r1 = c / q - local r = r1 - if math_abs(r0) < math_abs(r1) then r = r0 end - if r * r <= dd then - y = math_sqrt(dd - r * r) * bendDir - a1 = ta - math_atan2(y, r) - a2 = math_atan2(y / psy, (r - l1) / psx) - skip = true - end - end - if not skip then - local minAngle = 0 - local minDist = 9999999999 - local minX = 0 - local minY = 0 - local maxAngle = 0 - local maxDist = 0 - local maxX = 0 - local maxY = 0 - x = l1 + a - d = x * x - if d > maxDist then - maxAngle = 0 - maxDist = d - maxX = x - end - x = l1 - a - d = x * x - if d < minDist then - minAngle = math_pi - minDist = d - minX = x - end - local angle = math_acos(-a * l1 / (aa - bb)) - x = a * math_cos(angle) + l1 - y = b * math_sin(angle) - d = x * x + y * y - if d < minDist then - minAngle = angle - minDist = d - minX = x - minY = y - end - if d > maxDist then - maxAngle = angle - maxDist = d - maxX = x - maxY = y - end - if dd <= (minDist + maxDist) / 2 then - a1 = ta - math_atan2(minY * bendDir, minX) - a2 = minAngle * bendDir - else - a1 = ta - math_atan2(maxY * bendDir, maxX) - a2 = maxAngle * bendDir - end - end - end - local os = math_atan2(cy, cx) * s2 - local rotation = parent.rotation - a1 = math_deg(a1 - os) + os1 - rotation - if a1 > 180 then - a1 = a1 - 360 - elseif a1 < -180 then - a1 = a1 + 360 - end - parent:updateWorldTransformWith(px, py, rotation + a1 * alpha, parent.scaleX, parent.scaleY, 0, 0) - rotation = child.rotation - a2 = (math_deg(a2 + os) - child.shearX) * s2 + os2 - rotation - if a2 > 180 then - a2 = a2 - 360 - elseif a2 < -180 then - a2 = a2 + 360 - end - child:updateWorldTransformWith(cx, cy, rotation + a2 * alpha, child.scaleX, child.scaleY, child.shearX, child.shearY); -end -return IkConstraint \ No newline at end of file +local setmetatable = setmetatable +local math_pi = math.pi +local math_atan2 = math.atan2 +local math_sqrt = math.sqrt +local math_acos = math.acos +local math_sin = math.sin +local math_cos = math.cos +local table_insert = table.insert +local math_deg = math.deg +local math_rad = math.rad +local math_abs = math.abs + +local IkConstraint = {} +IkConstraint.__index = IkConstraint + +function IkConstraint.new (data, skeleton) + if not data then error("data cannot be nil", 2) end + if not skeleton then error("skeleton cannot be nil", 2) end + + local self = { + data = data, + bones = {}, + target = nil, + mix = data.mix, + bendDirection = data.bendDirection, + level = 0 + } + setmetatable(self, IkConstraint) + + local self_bones = self.bones + for i,boneData in ipairs(data.bones) do + table_insert(self_bones, skeleton:findBone(boneData.name)) + end + self.target = skeleton:findBone(data.target.name) + + return self +end + +function IkConstraint:apply () + self:update() +end + +function IkConstraint:update () + local target = self.target + local bones = self.bones + local boneCount = #bones + if boneCount == 1 then + self:apply1(bones[1], target.worldX, target.worldY, self.mix) + elseif boneCount == 2 then + self:apply2(bones[1], bones[2], target.worldX, target.worldY, self.bendDirection, self.mix) + end +end + +function IkConstraint:apply1 (bone, targetX, targetY, alpha) + local pp = bone.parent + local id = 1 / (pp.a * pp.d - pp.b * pp.c) + local x = targetX - pp.worldX + local y = targetY - pp.worldY + local tx = (x * pp.d - y * pp.b) * id - bone.x + local ty = (y * pp.a - x * pp.c) * id - bone.y + local rotationIK = math_deg(math_atan2(ty, tx)) - bone.shearX - bone.rotation + if bone.scaleX < 0 then rotationIK = rotationIK + 180 end + if rotationIK > 180 then + rotationIK = rotationIK - 360 + elseif (rotationIK < -180) then + rotationIK = rotationIK + 360 + end + bone:updateWorldTransformWith(bone.x, bone.y, bone.rotation + rotationIK * alpha, bone.scaleX, bone.scaleY, bone.shearX, bone.shearY) +end + +function IkConstraint:apply2 (parent, child, targetX, targetY, bendDir, alpha) + if alpha == 0 then + child:updateWorldTransform() + return + end + local px = parent.x + local py = parent.y + local psx = parent.scaleX + local psy = parent.scaleY + local csx = child.scaleX + local os1 = 0 + local os2 = 0 + local s2 = 0 + if psx < 0 then + psx = -psx + os1 = 180 + s2 = -1 + else + os1 = 0 + s2 = 1 + end + if psy < 0 then + psy = -psy + s2 = -s2 + end + if csx < 0 then + csx = -csx + os2 = 180 + else + os2 = 0 + end + local cx = child.x + local cy = 0 + local cwx = 0 + local cwy = 0 + local a = parent.a + local b = parent.b + local c = parent.c + local d = parent.d + local u = math_abs(psx - psy) <= 0.0001 + if not u then + cy = 0 + cwx = a * cx + parent.worldX + cwy = c * cx + parent.worldY + else + cy = child.y + cwx = a * cx + b * cy + parent.worldX + cwy = c * cx + d * cy + parent.worldY + end + local pp = parent.parent + a = pp.a + b = pp.b + c = pp.c + d = pp.d + local id = 1 / (a * d - b * c) + local x = targetX - pp.worldX + local y = targetY - pp.worldY + local tx = (x * d - y * b) * id - px + local ty = (y * a - x * c) * id - py + x = cwx - pp.worldX + y = cwy - pp.worldY + local dx = (x * d - y * b) * id - px + local dy = (y * a - x * c) * id - py + local l1 = math_sqrt(dx * dx + dy * dy) + local l2 = child.data.length * csx + local a1 = 0 + local a2 = 0 + + if u then + l2 = l2 * psx + local cos = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2) + if cos < -1 then + cos = -1 + elseif cos > 1 then + cos = 1 + end + a2 = math_acos(cos) * bendDir + a = l1 + l2 * cos + b = l2 * math_sin(a2) + a1 = math_atan2(ty * a - tx * b, tx * a + ty * b) + else + local skip = false + a = psx * l2 + b = psy * l2 + local aa = a * a + local bb = b * b + local dd = tx * tx + ty * ty + local ta = math_atan2(ty, tx); + c = bb * l1 * l1 + aa * dd - aa * bb + local c1 = -2 * bb * l1 + local c2 = bb - aa + d = c1 * c1 - 4 * c2 * c + if d >= 0 then + local q = math_sqrt(d); + if (c1 < 0) then q = -q end + q = -(c1 + q) / 2 + local r0 = q / c2 + local r1 = c / q + local r = r1 + if math_abs(r0) < math_abs(r1) then r = r0 end + if r * r <= dd then + y = math_sqrt(dd - r * r) * bendDir + a1 = ta - math_atan2(y, r) + a2 = math_atan2(y / psy, (r - l1) / psx) + skip = true + end + end + if not skip then + local minAngle = 0 + local minDist = 9999999999 + local minX = 0 + local minY = 0 + local maxAngle = 0 + local maxDist = 0 + local maxX = 0 + local maxY = 0 + x = l1 + a + d = x * x + if d > maxDist then + maxAngle = 0 + maxDist = d + maxX = x + end + x = l1 - a + d = x * x + if d < minDist then + minAngle = math_pi + minDist = d + minX = x + end + local angle = math_acos(-a * l1 / (aa - bb)) + x = a * math_cos(angle) + l1 + y = b * math_sin(angle) + d = x * x + y * y + if d < minDist then + minAngle = angle + minDist = d + minX = x + minY = y + end + if d > maxDist then + maxAngle = angle + maxDist = d + maxX = x + maxY = y + end + if dd <= (minDist + maxDist) / 2 then + a1 = ta - math_atan2(minY * bendDir, minX) + a2 = minAngle * bendDir + else + a1 = ta - math_atan2(maxY * bendDir, maxX) + a2 = maxAngle * bendDir + end + end + end + local os = math_atan2(cy, cx) * s2 + local rotation = parent.rotation + a1 = math_deg(a1 - os) + os1 - rotation + if a1 > 180 then + a1 = a1 - 360 + elseif a1 < -180 then + a1 = a1 + 360 + end + parent:updateWorldTransformWith(px, py, rotation + a1 * alpha, parent.scaleX, parent.scaleY, 0, 0) + rotation = child.rotation + a2 = (math_deg(a2 + os) - child.shearX) * s2 + os2 - rotation + if a2 > 180 then + a2 = a2 - 360 + elseif a2 < -180 then + a2 = a2 + 360 + end + child:updateWorldTransformWith(cx, cy, rotation + a2 * alpha, child.scaleX, child.scaleY, child.shearX, child.shearY); +end + +return IkConstraint diff --git a/spine-lua/IkConstraintData.lua b/spine-lua/IkConstraintData.lua index 1c4eb033ff..756b9367bc 100644 --- a/spine-lua/IkConstraintData.lua +++ b/spine-lua/IkConstraintData.lua @@ -1,46 +1,45 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local IkConstraintData = {} -function IkConstraintData.new (name) - if not name then error("name cannot be nil", 2) end - - local self = { - name = name, - bones = {}, - target = nil, - bendDirection = 1, - mix = 1 - } - return self -end +local IkConstraintData = {} +function IkConstraintData.new (name) + if not name then error("name cannot be nil", 2) end + + local self = { + name = name, + bones = {}, + target = nil, + bendDirection = 1, + mix = 1 + } + + return self +end return IkConstraintData diff --git a/spine-lua/MeshAttachment.lua b/spine-lua/MeshAttachment.lua index ef22e8246a..6e50fc7685 100644 --- a/spine-lua/MeshAttachment.lua +++ b/spine-lua/MeshAttachment.lua @@ -1,95 +1,94 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local AttachmentType = require "spine-lua.AttachmentType" - -local MeshAttachment = {} -function MeshAttachment.new (name) - if not name then error("name cannot be nil", 2) end - - local self = { - name = name, - type = AttachmentType.mesh, - vertices = nil, - uvs = nil, - regionUVs = nil, - triangles = nil, - hullLength = 0, - r = 1, g = 1, b = 1, a = 1, - path = nil, - rendererObject = nil, - regionU = 0, regionV = 0, regionU2 = 1, regionV2 = 1, regionRotate = false, - regionOffsetX = 0, regionOffsetY = 0, - regionWidth = 0, regionHeight = 0, - regionOriginalWidth = 0, regionOriginalHeight = 0, - edges = nil, - width = 0, height = 0 - } - - function self:updateUVs () - local width, height = self.regionU2 - self.regionU, self.regionV2 - self.regionV - local n = #self.regionUVs - if not self.uvs or #self.uvs ~= n then - self.uvs = {} - end - if self.regionRotate then - for i = 1, n, 2 do - self.uvs[i] = self.regionU + self.regionUVs[i + 1] * width - self.uvs[i + 1] = self.regionV + height - self.regionUVs[i] * height - end - else - for i = 1, n, 2 do - self.uvs[i] = self.regionU + self.regionUVs[i] * width - self.uvs[i + 1] = self.regionV + self.regionUVs[i + 1] * height - end - end - end - - function self:computeWorldVertices (x, y, slot, worldVertices) - local bone = slot.bone -x,y=slot.bone.skeleton.x,slot.bone.skeleton.y - x = x + bone.worldX - y = y + bone.worldY - local m00, m01, m10, m11 = bone.m00, bone.m01, bone.m10, bone.m11 - local vertices = self.vertices - local verticesCount = #vertices - if slot.attachmentVertices and #slot.attachmentVertices == verticesCount then vertices = slot.attachmentVertices end - for i = 1, verticesCount, 2 do - local vx = vertices[i] - local vy = vertices[i + 1] - worldVertices[i] = vx * m00 + vy * m01 + x - worldVertices[i + 1] = vx * m10 + vy * m11 + y - end - end - return self -end +local AttachmentType = require "spine-lua.AttachmentType" + +local MeshAttachment = {} +function MeshAttachment.new (name) + if not name then error("name cannot be nil", 2) end + + local self = { + name = name, + type = AttachmentType.mesh, + vertices = nil, + uvs = nil, + regionUVs = nil, + triangles = nil, + hullLength = 0, + r = 1, g = 1, b = 1, a = 1, + path = nil, + rendererObject = nil, + regionU = 0, regionV = 0, regionU2 = 1, regionV2 = 1, regionRotate = false, + regionOffsetX = 0, regionOffsetY = 0, + regionWidth = 0, regionHeight = 0, + regionOriginalWidth = 0, regionOriginalHeight = 0, + edges = nil, + width = 0, height = 0 + } + + function self:updateUVs () + local width, height = self.regionU2 - self.regionU, self.regionV2 - self.regionV + local n = #self.regionUVs + if not self.uvs or #self.uvs ~= n then + self.uvs = {} + end + if self.regionRotate then + for i = 1, n, 2 do + self.uvs[i] = self.regionU + self.regionUVs[i + 1] * width + self.uvs[i + 1] = self.regionV + height - self.regionUVs[i] * height + end + else + for i = 1, n, 2 do + self.uvs[i] = self.regionU + self.regionUVs[i] * width + self.uvs[i + 1] = self.regionV + self.regionUVs[i + 1] * height + end + end + end + + function self:computeWorldVertices (x, y, slot, worldVertices) + local bone = slot.bone +x,y=slot.bone.skeleton.x,slot.bone.skeleton.y + x = x + bone.worldX + y = y + bone.worldY + local m00, m01, m10, m11 = bone.m00, bone.m01, bone.m10, bone.m11 + local vertices = self.vertices + local verticesCount = #vertices + if slot.attachmentVertices and #slot.attachmentVertices == verticesCount then vertices = slot.attachmentVertices end + for i = 1, verticesCount, 2 do + local vx = vertices[i] + local vy = vertices[i + 1] + worldVertices[i] = vx * m00 + vy * m01 + x + worldVertices[i + 1] = vx * m10 + vy * m11 + y + end + end + + return self +end return MeshAttachment diff --git a/spine-lua/PathConstraint.lua b/spine-lua/PathConstraint.lua index ae90670ca0..8659fe6476 100644 --- a/spine-lua/PathConstraint.lua +++ b/spine-lua/PathConstraint.lua @@ -1,517 +1,516 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - --- FIXME the logic in this file uses 0-based indexing. Each array --- access adds 1 to the calculated index. We should switch the logic --- to 1-based indexing eventually. - -local setmetatable = setmetatable -local AttachmentType = require "spine-lua.attachments.AttachmentType" -local PathConstraintData = require "spine-lua.PathConstraintData" -local utils = require "spine-lua.utils" -local math_pi = math.pi -local math_pi2 = math.pi * 2 -local math_atan2 = math.atan2 -local math_sqrt = math.sqrt -local math_acos = math.acos -local math_sin = math.sin -local math_cos = math.cos -local table_insert = table.insert -local math_deg = math.deg -local math_rad = math.rad -local math_abs = math.abs -local math_max = math.max - -local PathConstraint = {} -PathConstraint.__index = PathConstraint - -PathConstraint.NONE = -1 -PathConstraint.BEFORE = -2 -PathConstraint.AFTER = -3 - -function PathConstraint.new (data, skeleton) - if not data then error("data cannot be nil", 2) end - if not skeleton then error("skeleton cannot be nil", 2) end - - local self = { - data = data, - bones = {}, - target = skeleton:findSlot(data.target.name), - position = data.position, - spacing = data.spacing, - rotateMix = data.rotateMix, - translateMix = data.translateMix, - spaces = {}, - positions = {}, - world = {}, - curves = {}, - lengths = {}, - segments = {} - } - setmetatable(self, PathConstraint) - - for i,boneData in ipairs(data.bones) do - table_insert(self.bones, skeleton:findBone(boneData.name)) - end - - return self -end - -function PathConstraint:apply () - self:update() -end - -function PathConstraint:update () - local attachment = self.target.attachment - if not (attachment.type == AttachmentType.path) then return end - - local rotateMix = self.rotateMix - local translateMix = self.translateMix - local translate = translateMix > 0 - local rotate = rotateMix > 0 - if not translate and not rotate then return end - - local data = self.data; - local spacingMode = data.spacingMode - local lengthSpacing = spacingMode == PathConstraintData.SpacingMode.length - local rotateMode = data.rotateMode - local tangents = rotateMode == PathConstraintData.RotateMode.tangent - local scale = rotateMode == PathConstraintData.RotateMode.chainscale - local bones = self.bones - local boneCount = #bones - local spacesCount = boneCount + 1 - if tangents then spacesCount = boneCount end - local spaces = utils.setArraySize(self.spaces, spacesCount) - local lengths = nil - local spacing = self.spacing - if scale or lengthSpacing then - if scale then lengths = utils.setArraySize(self.lengths, boneCount) end - local i = 0 - local n = spacesCount - 1 - while i < n do - local bone = bones[i + 1]; - local length = bone.data.length - local x = length * bone.a - local y = length * bone.c - length = math_sqrt(x * x + y * y) - if scale then lengths[i + 1] = length end - i = i + 1 - if lengthSpacing then spaces[i + 1] = math_max(0, length + spacing) else spaces[i + 1] = spacing end - end - else - local i = 1 - while i < spacesCount do - spaces[i + 1] = spacing - i = i + 1 - end - end - - local positions = self:computeWorldPositions(attachment, spacesCount, tangents, data.positionMode == PathConstraintData.PositionMode.percent, spacingMode == PathConstraintData.SpacingMode.percent) - local skeleton = self.target.bone.skeleton - local skeletonX = skeleton.x - local skeletonY = skeleton.y - local boneX = positions[1] - local boneY = positions[2] - local offsetRotation = data.offsetRotation - local tip = rotateMode == PathConstraintData.RotateMode.chain and offsetRotation == 0 - local i = 0 - local p = 3 - while i < boneCount do - local bone = bones[i + 1] - bone.worldX = bone.worldX + (boneX - skeletonX - bone.worldX) * translateMix - bone.worldY = bone.worldY + (boneY - skeletonY - bone.worldY) * translateMix - local x = positions[p + 1] - local y = positions[p + 2] - local dx = x - boneX - local dy = y - boneY - if scale then - local length = lengths[i + 1] - if length ~= 0 then - local s = (math_sqrt(dx * dx + dy * dy) / length - 1) * rotateMix + 1 - bone.a = bone.a * s - bone.c = bone.c * s - end - end - boneX = x - boneY = y - if rotate then - local a = bone.a - local b = bone.b - local c = bone.c - local d = bone.d - local r = 0 - local cos = 0 - local sin = 0 - if tangents then - r = positions[p - 1 + 1] - elseif spaces[i + 1 + 1] == 0 then - r = positions[p + 2 + 1] - else - r = math_atan2(dy, dx) - end - r = r - (math_atan2(c, a) - math_rad(offsetRotation)) - if tip then - cos = math_cos(r) - sin = math_sin(r) - local length = bone.data.length - boneX = boneX + (length * (cos * a - sin * c) - dx) * rotateMix; - boneY = boneY + (length * (sin * a + cos * c) - dy) * rotateMix; - end - if r > math_pi then - r = r - math_pi2 - elseif r < -math_pi then - r = r + math_pi2 - end - r = r * rotateMix - cos = math_cos(r) - sin = math.sin(r) - bone.a = cos * a - sin * c - bone.b = cos * b - sin * d - bone.c = sin * a + cos * c - bone.d = sin * b + cos * d - end - i = i + 1 - p = p + 3 - end -end - -function PathConstraint:computeWorldPositions (path, spacesCount, tangents, percentPosition, percentSpacing) - local target = self.target - local position = self.position - local spaces = self.spaces - local out = utils.setArraySize(self.positions, spacesCount * 3 + 2) - local world = nil - local closed = path.closed - local verticesLength = path.worldVerticesLength - local curveCount = verticesLength / 6 - local prevCurve = PathConstraint.NONE - - if not path.constantSpeed then - local lengths = path.lengths - if closed then curveCount = curveCount - 1 else curveCount = curveCount - 2 end - local pathLength = lengths[curveCount + 1]; - if percentPosition then position = position * pathLength end - if percentSpacing then - local i = 0 - while i < spacesCount do - spaces[i + 1] = spaces[i + 1] * pathLength - i = i + 1 - end - end - world = utils.setArraySize(self.world, 8); - local i = 0 - local o = 0 - local curve = 0 - while i < spacesCount do - local space = spaces[i + 1]; - position = position + space - local p = position - - local skip = false - if closed then - p = p % pathLength - if p < 0 then p = p + pathLength end - curve = 0 - elseif p < 0 then - if prevCurve ~= PathConstraint.BEFORE then - prevCurve = PathConstraint.BEFORE - path:computeWorldVerticesWith(target, 2, 4, world, 0) - end - self:addBeforePosition(p, world, 0, out, o) - skip = true - elseif p > pathLength then - if prevCurve ~= PathConstraint.AFTER then - prevCurve = PathConstraint.AFTER - path:computeWorldVerticesWith(target, verticesLength - 6, 4, world, 0) - end - self:addAfterPosition(p - pathLength, world, 0, out, o) - skip = true - end - - if not skip then - -- Determine curve containing position. - while true do - local length = lengths[curve + 1] - if p <= length then - if curve == 0 then - p = p / length - else - local prev = lengths[curve - 1 + 1] - p = (p - prev) / (length - prev) - end - break - end - curve = curve + 1 - end - if curve ~= prevCurve then - prevCurve = curve - if closed and curve == curveCount then - path:computeWorldVerticesWith(target, verticesLength - 4, 4, world, 0) - path:computeWorldVerticesWith(target, 0, 4, world, 4) - else - path:computeWorldVerticesWith(target, curve * 6 + 2, 8, world, 0) - end - end - self:addCurvePosition(p, world[1], world[2], world[3], world[4], world[5], world[6], world[7], world[8], out, o, tangents or (i > 0 and space == 0)) - end - - i = i + 1 - o = o + 3 - end - return out - end - - -- World vertices. - if closed then - verticesLength = verticesLength + 2 - world = utils.setArraySize(self.world, verticesLength) - path:computeWorldVerticesWith(target, 2, verticesLength - 4, world, 0) - path:computeWorldVerticesWith(target, 0, 2, world, verticesLength - 4) - world[verticesLength - 2 + 1] = world[0 + 1] - world[verticesLength - 1 + 1] = world[1 + 1] - else - curveCount = curveCount - 1 - verticesLength = verticesLength - 4; - world = utils.setArraySize(self.world, verticesLength) - path:computeWorldVerticesWith(target, 2, verticesLength, world, 0) - end - - -- Curve lengths. - local curves = utils.setArraySize(self.curves, curveCount) - local pathLength = 0; - local x1 = world[0 + 1] - local y1 = world[1 + 1] - local cx1 = 0 - local cy1 = 0 - local cx2 = 0 - local cy2 = 0 - local x2 = 0 - local y2 = 0 - local tmpx = 0 - local tmpy = 0 - local dddfx = 0 - local dddfy = 0 - local ddfx = 0 - local ddfy = 0 - local dfx = 0 - local dfy = 0 - i = 0 - local w = 2 - while i < curveCount do - cx1 = world[w + 1] - cy1 = world[w + 2] - cx2 = world[w + 3] - cy2 = world[w + 4] - x2 = world[w + 5] - y2 = world[w + 6] - tmpx = (x1 - cx1 * 2 + cx2) * 0.1875 - tmpy = (y1 - cy1 * 2 + cy2) * 0.1875 - dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375 - dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375 - ddfx = tmpx * 2 + dddfx - ddfy = tmpy * 2 + dddfy - dfx = (cx1 - x1) * 0.75 + tmpx + dddfx * 0.16666667 - dfy = (cy1 - y1) * 0.75 + tmpy + dddfy * 0.16666667 - pathLength = pathLength + math_sqrt(dfx * dfx + dfy * dfy) - dfx = dfx + ddfx - dfy = dfy + ddfy - ddfx = ddfx + dddfx - ddfy = ddfy + dddfy - pathLength = pathLength + math_sqrt(dfx * dfx + dfy * dfy) - dfx = dfx + ddfx - dfy = dfy + ddfy - pathLength = pathLength + math_sqrt(dfx * dfx + dfy * dfy) - dfx = dfx + ddfx + dddfx - dfy = dfy + ddfy + dddfy - pathLength = pathLength + math_sqrt(dfx * dfx + dfy * dfy) - curves[i + 1] = pathLength - x1 = x2 - y1 = y2 - i = i + 1 - w = w + 6 - end - if percentPosition then position = position * pathLength end - if percentSpacing then - local i = 0 - while i < spacesCount do - spaces[i + 1] = spaces[i + 1] * pathLength - i = i + 1 - end - end - - local segments = self.segments - local curveLength = 0 - local i = 0 - local o = 0 - local curve = 0 - local segment = 0 - while i < spacesCount do - local space = spaces[i + 1] - position = position + space - local p = position - - local skip = false - if closed then - p = p % pathLength - if p < 0 then p = p + pathLength end - curve = 0 - elseif p < 0 then - self:addBeforePosition(p, world, 0, out, o) - skip = true - elseif p > pathLength then - self:addAfterPosition(p - pathLength, world, verticesLength - 4, out, o) - skip = true - end - - if not skip then - -- Determine curve containing position. - while true do - local length = curves[curve + 1] - if p <= length then - if curve == 0 then - p = p / length - else - local prev = curves[curve - 1 + 1] - p = (p - prev) / (length - prev) - end - break - end - curve = curve + 1 - end - - -- Curve segment lengths. - if curve ~= prevCurve then - prevCurve = curve - local ii = curve * 6 - x1 = world[ii + 1] - y1 = world[ii + 2] - cx1 = world[ii + 3] - cy1 = world[ii + 4] - cx2 = world[ii + 5] - cy2 = world[ii + 6] - x2 = world[ii + 7] - y2 = world[ii + 8] - tmpx = (x1 - cx1 * 2 + cx2) * 0.03 - tmpy = (y1 - cy1 * 2 + cy2) * 0.03 - dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006 - dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006 - ddfx = tmpx * 2 + dddfx - ddfy = tmpy * 2 + dddfy - dfx = (cx1 - x1) * 0.3 + tmpx + dddfx * 0.16666667 - dfy = (cy1 - y1) * 0.3 + tmpy + dddfy * 0.16666667 - curveLength = math_sqrt(dfx * dfx + dfy * dfy) - segments[1] = curveLength - ii = 1 - while ii < 8 do - dfx = dfx + ddfx - dfy = dfy + ddfy - ddfx = ddfx + dddfx - ddfy = ddfy + dddfy - curveLength = curveLength + math_sqrt(dfx * dfx + dfy * dfy) - segments[ii + 1] = curveLength - ii = ii + 1 - end - dfx = dfx + ddfx - dfy = dfy + ddfy - curveLength = curveLength + math_sqrt(dfx * dfx + dfy * dfy) - segments[9] = curveLength - dfx = dfx + ddfx + dddfx - dfy = dfy + ddfy + dddfy - curveLength = curveLength + math_sqrt(dfx * dfx + dfy * dfy) - segments[10] = curveLength - segment = 0 - end - - -- Weight by segment length. - p = p * curveLength - while true do - local length = segments[segment + 1] - if p <= length then - if segment == 0 then - p = p / length - else - local prev = segments[segment - 1 + 1] - p = segment + (p - prev) / (length - prev) - end - break; - end - segment = segment + 1 - end - self:addCurvePosition(p * 0.1, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents or (i > 0 and space == 0)) - end - - i = i + 1 - o = o + 3 - end - return out -end - -function PathConstraint:addBeforePosition (p, temp, i, out, o) - local x1 = temp[i + 1] - local y1 = temp[i + 2] - local dx = temp[i + 3] - x1 - local dy = temp[i + 4] - y1 - local r = math_atan2(dy, dx) - out[o + 1] = x1 + p * math_cos(r) - out[o + 2] = y1 + p * math_sin(r) - out[o + 3] = r -end - -function PathConstraint:addAfterPosition(p, temp, i, out, o) - local x1 = temp[i + 3] - local y1 = temp[i + 4] - local dx = x1 - temp[i + 1] - local dy = y1 - temp[i + 2] - local r = math_atan2(dy, dx) - out[o + 1] = x1 + p * math_cos(r) - out[o + 2] = y1 + p * math_sin(r) - out[o + 3] = r -end - -function PathConstraint:addCurvePosition(p, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents) - if p == 0 then p = 0.0001 end - local tt = p * p - local ttt = tt * p - local u = 1 - p - local uu = u * u - local uuu = uu * u - local ut = u * p - local ut3 = ut * 3 - local uut3 = u * ut3 - local utt3 = ut3 * p - local x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt - local y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt - out[o + 1] = x - out[o + 2] = y - if tangents then out[o + 3] = math_atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)) end -end -return PathConstraint \ No newline at end of file +-- FIXME the logic in this file uses 0-based indexing. Each array +-- access adds 1 to the calculated index. We should switch the logic +-- to 1-based indexing eventually. + +local setmetatable = setmetatable +local AttachmentType = require "spine-lua.attachments.AttachmentType" +local PathConstraintData = require "spine-lua.PathConstraintData" +local utils = require "spine-lua.utils" +local math_pi = math.pi +local math_pi2 = math.pi * 2 +local math_atan2 = math.atan2 +local math_sqrt = math.sqrt +local math_acos = math.acos +local math_sin = math.sin +local math_cos = math.cos +local table_insert = table.insert +local math_deg = math.deg +local math_rad = math.rad +local math_abs = math.abs +local math_max = math.max + +local PathConstraint = {} +PathConstraint.__index = PathConstraint + +PathConstraint.NONE = -1 +PathConstraint.BEFORE = -2 +PathConstraint.AFTER = -3 + +function PathConstraint.new (data, skeleton) + if not data then error("data cannot be nil", 2) end + if not skeleton then error("skeleton cannot be nil", 2) end + + local self = { + data = data, + bones = {}, + target = skeleton:findSlot(data.target.name), + position = data.position, + spacing = data.spacing, + rotateMix = data.rotateMix, + translateMix = data.translateMix, + spaces = {}, + positions = {}, + world = {}, + curves = {}, + lengths = {}, + segments = {} + } + setmetatable(self, PathConstraint) + + for i,boneData in ipairs(data.bones) do + table_insert(self.bones, skeleton:findBone(boneData.name)) + end + + return self +end + +function PathConstraint:apply () + self:update() +end + +function PathConstraint:update () + local attachment = self.target.attachment + if not (attachment.type == AttachmentType.path) then return end + + local rotateMix = self.rotateMix + local translateMix = self.translateMix + local translate = translateMix > 0 + local rotate = rotateMix > 0 + if not translate and not rotate then return end + + local data = self.data; + local spacingMode = data.spacingMode + local lengthSpacing = spacingMode == PathConstraintData.SpacingMode.length + local rotateMode = data.rotateMode + local tangents = rotateMode == PathConstraintData.RotateMode.tangent + local scale = rotateMode == PathConstraintData.RotateMode.chainscale + local bones = self.bones + local boneCount = #bones + local spacesCount = boneCount + 1 + if tangents then spacesCount = boneCount end + local spaces = utils.setArraySize(self.spaces, spacesCount) + local lengths = nil + local spacing = self.spacing + if scale or lengthSpacing then + if scale then lengths = utils.setArraySize(self.lengths, boneCount) end + local i = 0 + local n = spacesCount - 1 + while i < n do + local bone = bones[i + 1]; + local length = bone.data.length + local x = length * bone.a + local y = length * bone.c + length = math_sqrt(x * x + y * y) + if scale then lengths[i + 1] = length end + i = i + 1 + if lengthSpacing then spaces[i + 1] = math_max(0, length + spacing) else spaces[i + 1] = spacing end + end + else + local i = 1 + while i < spacesCount do + spaces[i + 1] = spacing + i = i + 1 + end + end + + local positions = self:computeWorldPositions(attachment, spacesCount, tangents, data.positionMode == PathConstraintData.PositionMode.percent, spacingMode == PathConstraintData.SpacingMode.percent) + local skeleton = self.target.bone.skeleton + local skeletonX = skeleton.x + local skeletonY = skeleton.y + local boneX = positions[1] + local boneY = positions[2] + local offsetRotation = data.offsetRotation + local tip = rotateMode == PathConstraintData.RotateMode.chain and offsetRotation == 0 + local i = 0 + local p = 3 + while i < boneCount do + local bone = bones[i + 1] + bone.worldX = bone.worldX + (boneX - skeletonX - bone.worldX) * translateMix + bone.worldY = bone.worldY + (boneY - skeletonY - bone.worldY) * translateMix + local x = positions[p + 1] + local y = positions[p + 2] + local dx = x - boneX + local dy = y - boneY + if scale then + local length = lengths[i + 1] + if length ~= 0 then + local s = (math_sqrt(dx * dx + dy * dy) / length - 1) * rotateMix + 1 + bone.a = bone.a * s + bone.c = bone.c * s + end + end + boneX = x + boneY = y + if rotate then + local a = bone.a + local b = bone.b + local c = bone.c + local d = bone.d + local r = 0 + local cos = 0 + local sin = 0 + if tangents then + r = positions[p - 1 + 1] + elseif spaces[i + 1 + 1] == 0 then + r = positions[p + 2 + 1] + else + r = math_atan2(dy, dx) + end + r = r - (math_atan2(c, a) - math_rad(offsetRotation)) + if tip then + cos = math_cos(r) + sin = math_sin(r) + local length = bone.data.length + boneX = boneX + (length * (cos * a - sin * c) - dx) * rotateMix; + boneY = boneY + (length * (sin * a + cos * c) - dy) * rotateMix; + end + if r > math_pi then + r = r - math_pi2 + elseif r < -math_pi then + r = r + math_pi2 + end + r = r * rotateMix + cos = math_cos(r) + sin = math.sin(r) + bone.a = cos * a - sin * c + bone.b = cos * b - sin * d + bone.c = sin * a + cos * c + bone.d = sin * b + cos * d + end + i = i + 1 + p = p + 3 + end +end + +function PathConstraint:computeWorldPositions (path, spacesCount, tangents, percentPosition, percentSpacing) + local target = self.target + local position = self.position + local spaces = self.spaces + local out = utils.setArraySize(self.positions, spacesCount * 3 + 2) + local world = nil + local closed = path.closed + local verticesLength = path.worldVerticesLength + local curveCount = verticesLength / 6 + local prevCurve = PathConstraint.NONE + + if not path.constantSpeed then + local lengths = path.lengths + if closed then curveCount = curveCount - 1 else curveCount = curveCount - 2 end + local pathLength = lengths[curveCount + 1]; + if percentPosition then position = position * pathLength end + if percentSpacing then + local i = 0 + while i < spacesCount do + spaces[i + 1] = spaces[i + 1] * pathLength + i = i + 1 + end + end + world = utils.setArraySize(self.world, 8); + local i = 0 + local o = 0 + local curve = 0 + while i < spacesCount do + local space = spaces[i + 1]; + position = position + space + local p = position + + local skip = false + if closed then + p = p % pathLength + if p < 0 then p = p + pathLength end + curve = 0 + elseif p < 0 then + if prevCurve ~= PathConstraint.BEFORE then + prevCurve = PathConstraint.BEFORE + path:computeWorldVerticesWith(target, 2, 4, world, 0) + end + self:addBeforePosition(p, world, 0, out, o) + skip = true + elseif p > pathLength then + if prevCurve ~= PathConstraint.AFTER then + prevCurve = PathConstraint.AFTER + path:computeWorldVerticesWith(target, verticesLength - 6, 4, world, 0) + end + self:addAfterPosition(p - pathLength, world, 0, out, o) + skip = true + end + + if not skip then + -- Determine curve containing position. + while true do + local length = lengths[curve + 1] + if p <= length then + if curve == 0 then + p = p / length + else + local prev = lengths[curve - 1 + 1] + p = (p - prev) / (length - prev) + end + break + end + curve = curve + 1 + end + if curve ~= prevCurve then + prevCurve = curve + if closed and curve == curveCount then + path:computeWorldVerticesWith(target, verticesLength - 4, 4, world, 0) + path:computeWorldVerticesWith(target, 0, 4, world, 4) + else + path:computeWorldVerticesWith(target, curve * 6 + 2, 8, world, 0) + end + end + self:addCurvePosition(p, world[1], world[2], world[3], world[4], world[5], world[6], world[7], world[8], out, o, tangents or (i > 0 and space == 0)) + end + + i = i + 1 + o = o + 3 + end + return out + end + + -- World vertices. + if closed then + verticesLength = verticesLength + 2 + world = utils.setArraySize(self.world, verticesLength) + path:computeWorldVerticesWith(target, 2, verticesLength - 4, world, 0) + path:computeWorldVerticesWith(target, 0, 2, world, verticesLength - 4) + world[verticesLength - 2 + 1] = world[0 + 1] + world[verticesLength - 1 + 1] = world[1 + 1] + else + curveCount = curveCount - 1 + verticesLength = verticesLength - 4; + world = utils.setArraySize(self.world, verticesLength) + path:computeWorldVerticesWith(target, 2, verticesLength, world, 0) + end + + -- Curve lengths. + local curves = utils.setArraySize(self.curves, curveCount) + local pathLength = 0; + local x1 = world[0 + 1] + local y1 = world[1 + 1] + local cx1 = 0 + local cy1 = 0 + local cx2 = 0 + local cy2 = 0 + local x2 = 0 + local y2 = 0 + local tmpx = 0 + local tmpy = 0 + local dddfx = 0 + local dddfy = 0 + local ddfx = 0 + local ddfy = 0 + local dfx = 0 + local dfy = 0 + i = 0 + local w = 2 + while i < curveCount do + cx1 = world[w + 1] + cy1 = world[w + 2] + cx2 = world[w + 3] + cy2 = world[w + 4] + x2 = world[w + 5] + y2 = world[w + 6] + tmpx = (x1 - cx1 * 2 + cx2) * 0.1875 + tmpy = (y1 - cy1 * 2 + cy2) * 0.1875 + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375 + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375 + ddfx = tmpx * 2 + dddfx + ddfy = tmpy * 2 + dddfy + dfx = (cx1 - x1) * 0.75 + tmpx + dddfx * 0.16666667 + dfy = (cy1 - y1) * 0.75 + tmpy + dddfy * 0.16666667 + pathLength = pathLength + math_sqrt(dfx * dfx + dfy * dfy) + dfx = dfx + ddfx + dfy = dfy + ddfy + ddfx = ddfx + dddfx + ddfy = ddfy + dddfy + pathLength = pathLength + math_sqrt(dfx * dfx + dfy * dfy) + dfx = dfx + ddfx + dfy = dfy + ddfy + pathLength = pathLength + math_sqrt(dfx * dfx + dfy * dfy) + dfx = dfx + ddfx + dddfx + dfy = dfy + ddfy + dddfy + pathLength = pathLength + math_sqrt(dfx * dfx + dfy * dfy) + curves[i + 1] = pathLength + x1 = x2 + y1 = y2 + i = i + 1 + w = w + 6 + end + if percentPosition then position = position * pathLength end + if percentSpacing then + local i = 0 + while i < spacesCount do + spaces[i + 1] = spaces[i + 1] * pathLength + i = i + 1 + end + end + + local segments = self.segments + local curveLength = 0 + local i = 0 + local o = 0 + local curve = 0 + local segment = 0 + while i < spacesCount do + local space = spaces[i + 1] + position = position + space + local p = position + + local skip = false + if closed then + p = p % pathLength + if p < 0 then p = p + pathLength end + curve = 0 + elseif p < 0 then + self:addBeforePosition(p, world, 0, out, o) + skip = true + elseif p > pathLength then + self:addAfterPosition(p - pathLength, world, verticesLength - 4, out, o) + skip = true + end + + if not skip then + -- Determine curve containing position. + while true do + local length = curves[curve + 1] + if p <= length then + if curve == 0 then + p = p / length + else + local prev = curves[curve - 1 + 1] + p = (p - prev) / (length - prev) + end + break + end + curve = curve + 1 + end + + -- Curve segment lengths. + if curve ~= prevCurve then + prevCurve = curve + local ii = curve * 6 + x1 = world[ii + 1] + y1 = world[ii + 2] + cx1 = world[ii + 3] + cy1 = world[ii + 4] + cx2 = world[ii + 5] + cy2 = world[ii + 6] + x2 = world[ii + 7] + y2 = world[ii + 8] + tmpx = (x1 - cx1 * 2 + cx2) * 0.03 + tmpy = (y1 - cy1 * 2 + cy2) * 0.03 + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006 + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006 + ddfx = tmpx * 2 + dddfx + ddfy = tmpy * 2 + dddfy + dfx = (cx1 - x1) * 0.3 + tmpx + dddfx * 0.16666667 + dfy = (cy1 - y1) * 0.3 + tmpy + dddfy * 0.16666667 + curveLength = math_sqrt(dfx * dfx + dfy * dfy) + segments[1] = curveLength + ii = 1 + while ii < 8 do + dfx = dfx + ddfx + dfy = dfy + ddfy + ddfx = ddfx + dddfx + ddfy = ddfy + dddfy + curveLength = curveLength + math_sqrt(dfx * dfx + dfy * dfy) + segments[ii + 1] = curveLength + ii = ii + 1 + end + dfx = dfx + ddfx + dfy = dfy + ddfy + curveLength = curveLength + math_sqrt(dfx * dfx + dfy * dfy) + segments[9] = curveLength + dfx = dfx + ddfx + dddfx + dfy = dfy + ddfy + dddfy + curveLength = curveLength + math_sqrt(dfx * dfx + dfy * dfy) + segments[10] = curveLength + segment = 0 + end + + -- Weight by segment length. + p = p * curveLength + while true do + local length = segments[segment + 1] + if p <= length then + if segment == 0 then + p = p / length + else + local prev = segments[segment - 1 + 1] + p = segment + (p - prev) / (length - prev) + end + break; + end + segment = segment + 1 + end + self:addCurvePosition(p * 0.1, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents or (i > 0 and space == 0)) + end + + i = i + 1 + o = o + 3 + end + return out +end + +function PathConstraint:addBeforePosition (p, temp, i, out, o) + local x1 = temp[i + 1] + local y1 = temp[i + 2] + local dx = temp[i + 3] - x1 + local dy = temp[i + 4] - y1 + local r = math_atan2(dy, dx) + out[o + 1] = x1 + p * math_cos(r) + out[o + 2] = y1 + p * math_sin(r) + out[o + 3] = r +end + +function PathConstraint:addAfterPosition(p, temp, i, out, o) + local x1 = temp[i + 3] + local y1 = temp[i + 4] + local dx = x1 - temp[i + 1] + local dy = y1 - temp[i + 2] + local r = math_atan2(dy, dx) + out[o + 1] = x1 + p * math_cos(r) + out[o + 2] = y1 + p * math_sin(r) + out[o + 3] = r +end + +function PathConstraint:addCurvePosition(p, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents) + if p == 0 then p = 0.0001 end + local tt = p * p + local ttt = tt * p + local u = 1 - p + local uu = u * u + local uuu = uu * u + local ut = u * p + local ut3 = ut * 3 + local uut3 = u * ut3 + local utt3 = ut3 * p + local x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt + local y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt + out[o + 1] = x + out[o + 2] = y + if tangents then out[o + 3] = math_atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)) end +end + +return PathConstraint diff --git a/spine-lua/PathConstraintData.lua b/spine-lua/PathConstraintData.lua index 5fec1a360f..1a55c3fd7f 100644 --- a/spine-lua/PathConstraintData.lua +++ b/spine-lua/PathConstraintData.lua @@ -1,70 +1,69 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local PathConstraintData = {} -function PathConstraintData.new (name) - if not name then error("name cannot be nil", 2) end - - local self = { - name = name, - bones = {}, - target = nil, - positionMode = nil, - spacingMode = nil, - rotateMode = nil, - offsetRotation = 0, - position = 0, - spacing = 0, - rotateMix = 0, - translateMix = 0 - } - - return self -end - -PathConstraintData.PositionMode = { - fixed = 0, - percent = 1 -} - -PathConstraintData.SpacingMode = { - length = 0, - fixed = 1, - percent = 2 -} - -PathConstraintData.RotateMode = { - tangent = 0, - chain = 1, - chainscale = 2 -} +local PathConstraintData = {} +function PathConstraintData.new (name) + if not name then error("name cannot be nil", 2) end + + local self = { + name = name, + bones = {}, + target = nil, + positionMode = nil, + spacingMode = nil, + rotateMode = nil, + offsetRotation = 0, + position = 0, + spacing = 0, + rotateMix = 0, + translateMix = 0 + } + + return self +end + +PathConstraintData.PositionMode = { + fixed = 0, + percent = 1 +} + +PathConstraintData.SpacingMode = { + length = 0, + fixed = 1, + percent = 2 +} + +PathConstraintData.RotateMode = { + tangent = 0, + chain = 1, + chainscale = 2 +} + return PathConstraintData diff --git a/spine-lua/RegionAttachment.lua b/spine-lua/RegionAttachment.lua index 6540a9c4ce..7baaeba985 100644 --- a/spine-lua/RegionAttachment.lua +++ b/spine-lua/RegionAttachment.lua @@ -1,101 +1,100 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local AttachmentType = require "spine-lua.AttachmentType" - -local RegionAttachment = {} -function RegionAttachment.new (name) - if not name then error("name cannot be nil", 2) end - - local self = { - name = name, - type = AttachmentType.region, - x = 0, y = 0, - rotation = 0, - scaleX = 1, scaleY = 1, - width = 0, height = 0, - offset = {}, - uvs = {}, - r = 1, g = 1, b = 1, a = 1, - path = nil, - rendererObject = nil, - regionOffsetX = 0, regionOffsetY = 0, - regionWidth = 0, regionHeight = 0, - regionOriginalWidth = 0, regionOriginalHeight = 0 - } - - function self:updateOffset () - local regionScaleX = self.width / self.regionOriginalWidth * self.scaleX - local regionScaleY = self.height / self.regionOriginalHeight * self.scaleY - local localX = -self.width / 2 * self.scaleX + self.regionOffsetX * regionScaleX - local localY = -self.height / 2 * self.scaleY + self.regionOffsetY * regionScaleY - local localX2 = localX + self.regionWidth * regionScaleX - local localY2 = localY + self.regionHeight * regionScaleY - local radians = self.rotation * math.pi / 180 - local cos = math.cos(radians) - local sin = math.sin(radians) - local localXCos = localX * cos + self.x - local localXSin = localX * sin - local localYCos = localY * cos + self.y - local localYSin = localY * sin - local localX2Cos = localX2 * cos + self.x - local localX2Sin = localX2 * sin - local localY2Cos = localY2 * cos + self.y - local localY2Sin = localY2 * sin - local offset = self.offset - offset[0] = localXCos - localYSin -- X1 - offset[1] = localYCos + localXSin -- Y1 - offset[2] = localXCos - localY2Sin -- X2 - offset[3] = localY2Cos + localXSin -- Y2 - offset[4] = localX2Cos - localY2Sin -- X3 - offset[5] = localY2Cos + localX2Sin -- Y3 - offset[6] = localX2Cos - localYSin -- X4 - offset[7] = localYCos + localX2Sin -- Y4 - end - - function self:computeWorldVertices (x, y, bone, worldVertices) - x = x + bone.worldX - y = y + bone.worldY - local m00, m01, m10, m11 = bone.m00, bone.m01, bone.m10, bone.m11 - local offset = self.offset - vertices[0] = offset[0] * m00 + offset[1] * m01 + x - vertices[1] = offset[0] * m10 + offset[1] * m11 + y - vertices[2] = offset[2] * m00 + offset[3] * m01 + x - vertices[3] = offset[2] * m10 + offset[3] * m11 + y - vertices[4] = offset[4] * m00 + offset[5] * m01 + x - vertices[5] = offset[4] * m10 + offset[5] * m11 + y - vertices[6] = offset[6] * m00 + offset[7] * m01 + x - vertices[7] = offset[6] * m10 + offset[7] * m11 + y - end - return self -end +local AttachmentType = require "spine-lua.AttachmentType" + +local RegionAttachment = {} +function RegionAttachment.new (name) + if not name then error("name cannot be nil", 2) end + + local self = { + name = name, + type = AttachmentType.region, + x = 0, y = 0, + rotation = 0, + scaleX = 1, scaleY = 1, + width = 0, height = 0, + offset = {}, + uvs = {}, + r = 1, g = 1, b = 1, a = 1, + path = nil, + rendererObject = nil, + regionOffsetX = 0, regionOffsetY = 0, + regionWidth = 0, regionHeight = 0, + regionOriginalWidth = 0, regionOriginalHeight = 0 + } + + function self:updateOffset () + local regionScaleX = self.width / self.regionOriginalWidth * self.scaleX + local regionScaleY = self.height / self.regionOriginalHeight * self.scaleY + local localX = -self.width / 2 * self.scaleX + self.regionOffsetX * regionScaleX + local localY = -self.height / 2 * self.scaleY + self.regionOffsetY * regionScaleY + local localX2 = localX + self.regionWidth * regionScaleX + local localY2 = localY + self.regionHeight * regionScaleY + local radians = self.rotation * math.pi / 180 + local cos = math.cos(radians) + local sin = math.sin(radians) + local localXCos = localX * cos + self.x + local localXSin = localX * sin + local localYCos = localY * cos + self.y + local localYSin = localY * sin + local localX2Cos = localX2 * cos + self.x + local localX2Sin = localX2 * sin + local localY2Cos = localY2 * cos + self.y + local localY2Sin = localY2 * sin + local offset = self.offset + offset[0] = localXCos - localYSin -- X1 + offset[1] = localYCos + localXSin -- Y1 + offset[2] = localXCos - localY2Sin -- X2 + offset[3] = localY2Cos + localXSin -- Y2 + offset[4] = localX2Cos - localY2Sin -- X3 + offset[5] = localY2Cos + localX2Sin -- Y3 + offset[6] = localX2Cos - localYSin -- X4 + offset[7] = localYCos + localX2Sin -- Y4 + end + + function self:computeWorldVertices (x, y, bone, worldVertices) + x = x + bone.worldX + y = y + bone.worldY + local m00, m01, m10, m11 = bone.m00, bone.m01, bone.m10, bone.m11 + local offset = self.offset + vertices[0] = offset[0] * m00 + offset[1] * m01 + x + vertices[1] = offset[0] * m10 + offset[1] * m11 + y + vertices[2] = offset[2] * m00 + offset[3] * m01 + x + vertices[3] = offset[2] * m10 + offset[3] * m11 + y + vertices[4] = offset[4] * m00 + offset[5] * m01 + x + vertices[5] = offset[4] * m10 + offset[5] * m11 + y + vertices[6] = offset[6] * m00 + offset[7] * m01 + x + vertices[7] = offset[6] * m10 + offset[7] * m11 + y + end + + return self +end return RegionAttachment diff --git a/spine-lua/Skeleton.lua b/spine-lua/Skeleton.lua index 74d3595a77..18ac3e6eb1 100644 --- a/spine-lua/Skeleton.lua +++ b/spine-lua/Skeleton.lua @@ -1,477 +1,476 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local Bone = require "spine-lua.Bone" -local Slot = require "spine-lua.Slot" -local IkConstraint = require "spine-lua.IkConstraint" -local PathConstraint = require "spine-lua.PathConstraint" -local TransformConstraint = require "spine-lua.TransformConstraint" -local AttachmentLoader = require "spine-lua.AttachmentLoader" -local AttachmentType = require "spine-lua.attachments.AttachmentType" -local Color = require "spine-lua.Color" - -local setmetatable = setmetatable -local ipairs = ipairs -local table_insert = table.insert - -local Skeleton = {} -Skeleton.__index = Skeleton - -function Skeleton.new (data) - if not data then error("data cannot be nil", 2) end - - local self = { - data = data, - bones = {}, - slots = {}, - slotsByName = {}, - drawOrder = {}, - ikConstraints = {}, ikConstaintsSorted = {}, - transformConstraints = {}, - pathConstraints = {}, - _updateCache = {}, - skin = nil, - color = Color.newWith(1, 1, 1, 1), - time = 0, - flipX = false, flipY = false, - x = 0, y = 0 - } - setmetatable(self, Skeleton) - - for i,boneData in ipairs(data.bones) do - local bone = nil - if boneData.parent == nil then - bone = Bone.new(boneData, self, nil) - else - local parent = self.bones[boneData.parent.index] - bone = Bone.new(boneData, self, parent) - table_insert(parent.children, bone) - end - table_insert(self.bones, bone) - end - - for i,slotData in ipairs(data.slots) do - local bone = self.bones[slotData.boneData.index] - local slot = Slot.new(slotData, bone) - table_insert(self.slots, slot) - self.slotsByName[slot.data.name] = slot - table_insert(self.drawOrder, slot) - end - - for i,ikConstraintData in ipairs(data.ikConstraints) do - table_insert(self.ikConstraints, IkConstraint.new(ikConstraintData, self)) - end - - for i, transformConstraintData in ipairs(data.transformConstraints) do - table_insert(self.transformConstraints, TransformConstraint.new(transformConstraintData, self)) - end - - for i, pathConstraintData in ipairs(data.pathConstraints) do - table_insert(self.pathConstraints, PathConstraint.new(pathConstraintData, self)) - end - - self:updateCache() - - return self -end - - --- Caches information about bones and IK constraints. Must be called if bones or IK constraints are added or removed. -function Skeleton:updateCache () - local updateCache = {} - self._updateCache = updateCache - - local bones = self.bones - for i, bone in ipairs(bones) do - bone.sorted = false - end - - local ikConstraints = {} - self.ikConstraintsSorted = ikConstraints - for i, constraint in ipairs(self.ikConstraints) do - table_insert(ikConstraints, constraint) - end - - local level = 0 - for i, ik in ipairs(ikConstraints) do - local bone = ik.bones[1].parent - level = 0 - while bone do - bone = bone.parent - level = level + 1 - end - ik.level = level - end - - local i = 1 - local ikCount = #ikConstraints - while i < ikCount do - local ik = ikConstraints[i + 1] - local level = ik.level - local ii = i - 1 - while ii >= 0 do - local other = ikConstraints[ii + 1] - if other.level < level then break end - ikConstraints[ii + 1 + 1] = other - ii = ii - 1 - end - ikConstraints[ii + 1 + 1] = ik - i = i + 1 - end - - for i, constraint in ipairs(ikConstraints) do - local target = constraint.target - self:sortBone(target) - - local constrained = constraint.bones - local parent = constrained[1] - self:sortBone(parent) - - table_insert(updateCache, constraint) - - self:sortReset(parent.children) - constrained[#constrained].sorted = true - end - - -- path constraints - local pathConstraints = self.pathConstraints - for i,constraint in ipairs(pathConstraints) do - local slot = constraint.target - local slotIndex = slot.data.index - local slotBone = slot.bone - if self.skin then self:sortPathConstraintAttachment(self.skin, slotIndex, slotBone) end - if self.data.defaultSkin and self.data.defaultSkin ~= self.skin then self:sortPathConstraintAttachment(self.data.defaultSkin, slotIndex, slotBone) end - for i,skin in ipairs(self.data.skins) do - self:sortPathConstraintAttachment(skin, slotIndex, slotBone) - end - - local attachment = slot.attachment - if attachment.type == AttachmentType.path then self:sortPathConstraintAttachmentWith(attachment, slotBone) end - - local constrained = constraint.bones - for i,c in ipairs(constrained) do - self:sortBone(c) - end - - table_insert(updateCache, constraint) - - for i,c in ipairs(constrained) do - self:sortReset(c.children) - end - for i,c in ipairs(constrained) do - c.sorted = true - end - end - - -- transform constraints - local transformConstraints = self.transformConstraints - for i, constraint in ipairs(transformConstraints) do - self:sortBone(constraint.target) - - local constrained = constraint.bones - for i,c in ipairs(constrained) do - self:sortBone(c) - end - - table_insert(updateCache, constraint) - - for i,c in ipairs(constrained) do - self:sortReset(c.children) - end - for i,c in ipairs(constrained) do - c.sorted = true - end - end - - for i, bone in ipairs(self.bones) do - self:sortBone(bone) - end -end - -function Skeleton:sortPathConstraintAttachment(skin, slotIndex, slotBone) - local attachments = skin.attachments[slotIndex] - if not attachments then return end - for key,attachment in pairs(attachments) do - self:sortPathConstraintAttachmentWith(attachment, slotBone) - end -end - -function Skeleton:sortPathConstraintAttachmentWith(attachment, slotBone) - if attachment.type ~= AttachmentType.path then return end - local pathBones = attachment.bones - if not pathBones then - self:sortBone(slotBone) - else - local bones = self.bones - local i = 0 - local n = #pathBones - while i < n do - local boneCount = pathBones[i + 1] - i = i + 1 - local nn = i + boneCount - while i < nn do - self:sortBone(bones[pathBones[i + 1]]) - i = i + 1 - end - end - end -end - -function Skeleton:sortBone(bone) - if bone.sorted then return end - local parent = bone.parent - if parent then self:sortBone(parent) end - bone.sorted = true - table_insert(self._updateCache, bone) -end - -function Skeleton:sortReset(bones) - for i, bone in ipairs(bones) do - if bone.sorted then self:sortReset(bone.children) end - bone.sorted = false - end -end - --- Updates the world transform for each bone and applies IK constraints. -function Skeleton:updateWorldTransform () - local updateCache = self._updateCache - for i, updatable in ipairs(updateCache) do - updatable:update() - end -end - -function Skeleton:setToSetupPose () - self:setBonesToSetupPose() - self:setSlotsToSetupPose() -end - -function Skeleton:setBonesToSetupPose () - for i,bone in ipairs(self.bones) do - bone:setToSetupPose() - end - - for i,ikConstraint in ipairs(self.ikConstraints) do - ikConstraint.bendDirection = ikConstraint.data.bendDirection - ikConstraint.mix = ikConstraint.data.mix - end - - local transformConstraints = self.transformConstraints - for i, constraint in ipairs(transformConstraints) do - local data = constraint.data - constraint.rotateMix = data.rotateMix - constraint.translateMix = data.translateMix - constraint.scaleMix = data.scaleMix - constraint.shearMix = data.shearMix - end - - local pathConstraints = self.pathConstraints - for i, constraint in ipairs(pathConstraints) do - local data = constraint.data - constraint.position = data.position - constraint.spacing = data.spacing - constraint.rotateMix = data.rotateMix - constraint.translateMix = data.translateMix - end -end - -function Skeleton:setSlotsToSetupPose () - for i,slot in ipairs(self.slots) do - self.drawOrder[i] = slot - slot:setToSetupPose() - end -end - -function Skeleton:getRootBone () - return self.bones[1] -end - -function Skeleton:findBone (boneName) - if not boneName then error("boneName cannot be nil.", 2) end - for i,bone in ipairs(self.bones) do - if bone.data.name == boneName then return bone end - end - return nil -end - -function Skeleton:findBoneIndex(boneName) - if not boneName then error("boneName cannot be nil.", 2) end - for i,bone in ipairs(self.bones) do - if bone.data.name == boneName then return i end - end - return -1 -end - -function Skeleton:findSlot (slotName) - if not slotName then error("slotName cannot be nil.", 2) end - return self.slotsByName[slotName] -end - -function Skeleton:findSlotIndex(slotName) - if not slotName then error("slotName cannot be nil.", 2) end - for i, slot in ipairs(self.slots) do - if slot.data.name == slotName then return i end - end - return -1 -end - --- 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. -function Skeleton:setSkin (skinName) - local skin = self.data:findSkin(skinName) - if not skin then error("Skin not found: " .. skinName, 2) end - self:setSkinByReference(skin) -end - -function Skeleton:setSkinByReference(newSkin) - if newSkin then - if self.skin then - newSkin:attachAll(self, self.skin) - else - local slots = self.slots - for i, slot in ipairs(slots) do - local name = slot.data.attachmentName - if name then - local attachment = newSkin:getAttachment(i, name) - if attachment then - slot:setAttachment(attachment) - end - end - end - end - end - self.skin = newSkin -end - -function Skeleton:getAttachment (slotName, attachmentName) - return self:getAttachmentByIndex(self.data.slotNameIndices[slotName], attachmentName) -end - -function Skeleton:getAttachmentByIndex (slotIndex, attachmentName) - if self.skin then - local attachment = self.skin:getAttachment(slotIndex, attachmentName) - if attachment then return attachment end - end - if self.data.defaultSkin then - return self.data.defaultSkin:getAttachment(slotIndex, attachmentName) - end - return nil -end - -function Skeleton:setAttachment (slotName, attachmentName) - if not slotName then error("slotName cannot be nil.", 2) end - for i,slot in ipairs(self.slots) do - if slot.data.name == slotName then - local attachment = nil - if attachmentName then - attachment = self:getAttachmentByIndex(i, attachmentName) - if not attachment then error("Attachment not found: " .. attachmentName .. ", for slot: " .. slotName, 2) end - end - slot:setAttachment(attachment) - return - end - end - error("Slot not found: " .. slotName, 2) -end - -function Skeleton:findIkConstraint(constraintName) - if not constraintName then error("constraintName cannot be null.", 2) end - local ikConstaints = self.ikConstraints - for i, ikConstraint in ipairs(ikConstraints) do - if ikConstraint.data.name == constraintName then return ikConstraint end - end - return nil -end - -function Skeleton:findTransformConstraint(constraintName) - if not constraintName then error("constraintName cannot be null.", 2) end - local transformConstraints = self.transformConstraints - for i, transformConstraint in ipairs(transformConstraints) do - if transformConstraint.data.name == constraintName then return transformConstraint end - end - return nil -end - -function Skeleton:findPathConstraint(constraintName) - if not constraintName then error("constraintName cannot be null.", 2) end - local pathConstraints = self.pathConstraints - for i, pathConstraint in ipairs(pathConstraints) do - if pathConstraint.data.name == constraintName then return pathConstraint end - end - return nil -end - -function Skeleton:getBounds(offset, size) - if not offset then error("offset cannot be null.", 2) end - if not size then error("size cannot be null.", 2) end - local drawOrder = self.drawOrder; - local minX = 99999999 - local minY = 99999999 - local maxX = -99999999 - local maxY = -99999999 - for i, slot in ipairs(drawOrder) do - local vertices = nil - local attachment = slot.attachment - if attachment.type == AttachmentType.region or attachment.type == AttachmentType.mesh then - vertices = attachment:updateWorldVertices(slot, false); - end - if vertices then - local nn = #vertices - local ii = 1 - while ii <= nn do - local x = vertices[ii] - local y = vertices[ii + 1] - minX = math_min(minX, x) - minY = math_min(minY, y) - maxX = math_max(maxX, x) - maxY = math_max(maxY, y) - ii = ii + 8 - end - end - end - offset[1] = minX - offset[2] = minY - size[1] = maxX - minX - size[2] = maxY - minY -end - -function Skeleton:update (delta) - self.time = self.time + delta -end - -function Skeleton:setColor (r, g, b, a) - self.r = r - self.g = g - self.b = b - self.a = a -end -return Skeleton \ No newline at end of file +local Bone = require "spine-lua.Bone" +local Slot = require "spine-lua.Slot" +local IkConstraint = require "spine-lua.IkConstraint" +local PathConstraint = require "spine-lua.PathConstraint" +local TransformConstraint = require "spine-lua.TransformConstraint" +local AttachmentLoader = require "spine-lua.AttachmentLoader" +local AttachmentType = require "spine-lua.attachments.AttachmentType" +local Color = require "spine-lua.Color" + +local setmetatable = setmetatable +local ipairs = ipairs +local table_insert = table.insert + +local Skeleton = {} +Skeleton.__index = Skeleton + +function Skeleton.new (data) + if not data then error("data cannot be nil", 2) end + + local self = { + data = data, + bones = {}, + slots = {}, + slotsByName = {}, + drawOrder = {}, + ikConstraints = {}, ikConstaintsSorted = {}, + transformConstraints = {}, + pathConstraints = {}, + _updateCache = {}, + skin = nil, + color = Color.newWith(1, 1, 1, 1), + time = 0, + flipX = false, flipY = false, + x = 0, y = 0 + } + setmetatable(self, Skeleton) + + for i,boneData in ipairs(data.bones) do + local bone = nil + if boneData.parent == nil then + bone = Bone.new(boneData, self, nil) + else + local parent = self.bones[boneData.parent.index] + bone = Bone.new(boneData, self, parent) + table_insert(parent.children, bone) + end + table_insert(self.bones, bone) + end + + for i,slotData in ipairs(data.slots) do + local bone = self.bones[slotData.boneData.index] + local slot = Slot.new(slotData, bone) + table_insert(self.slots, slot) + self.slotsByName[slot.data.name] = slot + table_insert(self.drawOrder, slot) + end + + for i,ikConstraintData in ipairs(data.ikConstraints) do + table_insert(self.ikConstraints, IkConstraint.new(ikConstraintData, self)) + end + + for i, transformConstraintData in ipairs(data.transformConstraints) do + table_insert(self.transformConstraints, TransformConstraint.new(transformConstraintData, self)) + end + + for i, pathConstraintData in ipairs(data.pathConstraints) do + table_insert(self.pathConstraints, PathConstraint.new(pathConstraintData, self)) + end + + self:updateCache() + + return self +end + + +-- Caches information about bones and IK constraints. Must be called if bones or IK constraints are added or removed. +function Skeleton:updateCache () + local updateCache = {} + self._updateCache = updateCache + + local bones = self.bones + for i, bone in ipairs(bones) do + bone.sorted = false + end + + local ikConstraints = {} + self.ikConstraintsSorted = ikConstraints + for i, constraint in ipairs(self.ikConstraints) do + table_insert(ikConstraints, constraint) + end + + local level = 0 + for i, ik in ipairs(ikConstraints) do + local bone = ik.bones[1].parent + level = 0 + while bone do + bone = bone.parent + level = level + 1 + end + ik.level = level + end + + local i = 1 + local ikCount = #ikConstraints + while i < ikCount do + local ik = ikConstraints[i + 1] + local level = ik.level + local ii = i - 1 + while ii >= 0 do + local other = ikConstraints[ii + 1] + if other.level < level then break end + ikConstraints[ii + 1 + 1] = other + ii = ii - 1 + end + ikConstraints[ii + 1 + 1] = ik + i = i + 1 + end + + for i, constraint in ipairs(ikConstraints) do + local target = constraint.target + self:sortBone(target) + + local constrained = constraint.bones + local parent = constrained[1] + self:sortBone(parent) + + table_insert(updateCache, constraint) + + self:sortReset(parent.children) + constrained[#constrained].sorted = true + end + + -- path constraints + local pathConstraints = self.pathConstraints + for i,constraint in ipairs(pathConstraints) do + local slot = constraint.target + local slotIndex = slot.data.index + local slotBone = slot.bone + if self.skin then self:sortPathConstraintAttachment(self.skin, slotIndex, slotBone) end + if self.data.defaultSkin and self.data.defaultSkin ~= self.skin then self:sortPathConstraintAttachment(self.data.defaultSkin, slotIndex, slotBone) end + for i,skin in ipairs(self.data.skins) do + self:sortPathConstraintAttachment(skin, slotIndex, slotBone) + end + + local attachment = slot.attachment + if attachment.type == AttachmentType.path then self:sortPathConstraintAttachmentWith(attachment, slotBone) end + + local constrained = constraint.bones + for i,c in ipairs(constrained) do + self:sortBone(c) + end + + table_insert(updateCache, constraint) + + for i,c in ipairs(constrained) do + self:sortReset(c.children) + end + for i,c in ipairs(constrained) do + c.sorted = true + end + end + + -- transform constraints + local transformConstraints = self.transformConstraints + for i, constraint in ipairs(transformConstraints) do + self:sortBone(constraint.target) + + local constrained = constraint.bones + for i,c in ipairs(constrained) do + self:sortBone(c) + end + + table_insert(updateCache, constraint) + + for i,c in ipairs(constrained) do + self:sortReset(c.children) + end + for i,c in ipairs(constrained) do + c.sorted = true + end + end + + for i, bone in ipairs(self.bones) do + self:sortBone(bone) + end +end + +function Skeleton:sortPathConstraintAttachment(skin, slotIndex, slotBone) + local attachments = skin.attachments[slotIndex] + if not attachments then return end + for key,attachment in pairs(attachments) do + self:sortPathConstraintAttachmentWith(attachment, slotBone) + end +end + +function Skeleton:sortPathConstraintAttachmentWith(attachment, slotBone) + if attachment.type ~= AttachmentType.path then return end + local pathBones = attachment.bones + if not pathBones then + self:sortBone(slotBone) + else + local bones = self.bones + local i = 0 + local n = #pathBones + while i < n do + local boneCount = pathBones[i + 1] + i = i + 1 + local nn = i + boneCount + while i < nn do + self:sortBone(bones[pathBones[i + 1]]) + i = i + 1 + end + end + end +end + +function Skeleton:sortBone(bone) + if bone.sorted then return end + local parent = bone.parent + if parent then self:sortBone(parent) end + bone.sorted = true + table_insert(self._updateCache, bone) +end + +function Skeleton:sortReset(bones) + for i, bone in ipairs(bones) do + if bone.sorted then self:sortReset(bone.children) end + bone.sorted = false + end +end + +-- Updates the world transform for each bone and applies IK constraints. +function Skeleton:updateWorldTransform () + local updateCache = self._updateCache + for i, updatable in ipairs(updateCache) do + updatable:update() + end +end + +function Skeleton:setToSetupPose () + self:setBonesToSetupPose() + self:setSlotsToSetupPose() +end + +function Skeleton:setBonesToSetupPose () + for i,bone in ipairs(self.bones) do + bone:setToSetupPose() + end + + for i,ikConstraint in ipairs(self.ikConstraints) do + ikConstraint.bendDirection = ikConstraint.data.bendDirection + ikConstraint.mix = ikConstraint.data.mix + end + + local transformConstraints = self.transformConstraints + for i, constraint in ipairs(transformConstraints) do + local data = constraint.data + constraint.rotateMix = data.rotateMix + constraint.translateMix = data.translateMix + constraint.scaleMix = data.scaleMix + constraint.shearMix = data.shearMix + end + + local pathConstraints = self.pathConstraints + for i, constraint in ipairs(pathConstraints) do + local data = constraint.data + constraint.position = data.position + constraint.spacing = data.spacing + constraint.rotateMix = data.rotateMix + constraint.translateMix = data.translateMix + end +end + +function Skeleton:setSlotsToSetupPose () + for i,slot in ipairs(self.slots) do + self.drawOrder[i] = slot + slot:setToSetupPose() + end +end + +function Skeleton:getRootBone () + return self.bones[1] +end + +function Skeleton:findBone (boneName) + if not boneName then error("boneName cannot be nil.", 2) end + for i,bone in ipairs(self.bones) do + if bone.data.name == boneName then return bone end + end + return nil +end + +function Skeleton:findBoneIndex(boneName) + if not boneName then error("boneName cannot be nil.", 2) end + for i,bone in ipairs(self.bones) do + if bone.data.name == boneName then return i end + end + return -1 +end + +function Skeleton:findSlot (slotName) + if not slotName then error("slotName cannot be nil.", 2) end + return self.slotsByName[slotName] +end + +function Skeleton:findSlotIndex(slotName) + if not slotName then error("slotName cannot be nil.", 2) end + for i, slot in ipairs(self.slots) do + if slot.data.name == slotName then return i end + end + return -1 +end + +-- 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. +function Skeleton:setSkin (skinName) + local skin = self.data:findSkin(skinName) + if not skin then error("Skin not found: " .. skinName, 2) end + self:setSkinByReference(skin) +end + +function Skeleton:setSkinByReference(newSkin) + if newSkin then + if self.skin then + newSkin:attachAll(self, self.skin) + else + local slots = self.slots + for i, slot in ipairs(slots) do + local name = slot.data.attachmentName + if name then + local attachment = newSkin:getAttachment(i, name) + if attachment then + slot:setAttachment(attachment) + end + end + end + end + end + self.skin = newSkin +end + +function Skeleton:getAttachment (slotName, attachmentName) + return self:getAttachmentByIndex(self.data.slotNameIndices[slotName], attachmentName) +end + +function Skeleton:getAttachmentByIndex (slotIndex, attachmentName) + if self.skin then + local attachment = self.skin:getAttachment(slotIndex, attachmentName) + if attachment then return attachment end + end + if self.data.defaultSkin then + return self.data.defaultSkin:getAttachment(slotIndex, attachmentName) + end + return nil +end + +function Skeleton:setAttachment (slotName, attachmentName) + if not slotName then error("slotName cannot be nil.", 2) end + for i,slot in ipairs(self.slots) do + if slot.data.name == slotName then + local attachment = nil + if attachmentName then + attachment = self:getAttachmentByIndex(i, attachmentName) + if not attachment then error("Attachment not found: " .. attachmentName .. ", for slot: " .. slotName, 2) end + end + slot:setAttachment(attachment) + return + end + end + error("Slot not found: " .. slotName, 2) +end + +function Skeleton:findIkConstraint(constraintName) + if not constraintName then error("constraintName cannot be null.", 2) end + local ikConstaints = self.ikConstraints + for i, ikConstraint in ipairs(ikConstraints) do + if ikConstraint.data.name == constraintName then return ikConstraint end + end + return nil +end + +function Skeleton:findTransformConstraint(constraintName) + if not constraintName then error("constraintName cannot be null.", 2) end + local transformConstraints = self.transformConstraints + for i, transformConstraint in ipairs(transformConstraints) do + if transformConstraint.data.name == constraintName then return transformConstraint end + end + return nil +end + +function Skeleton:findPathConstraint(constraintName) + if not constraintName then error("constraintName cannot be null.", 2) end + local pathConstraints = self.pathConstraints + for i, pathConstraint in ipairs(pathConstraints) do + if pathConstraint.data.name == constraintName then return pathConstraint end + end + return nil +end + +function Skeleton:getBounds(offset, size) + if not offset then error("offset cannot be null.", 2) end + if not size then error("size cannot be null.", 2) end + local drawOrder = self.drawOrder; + local minX = 99999999 + local minY = 99999999 + local maxX = -99999999 + local maxY = -99999999 + for i, slot in ipairs(drawOrder) do + local vertices = nil + local attachment = slot.attachment + if attachment.type == AttachmentType.region or attachment.type == AttachmentType.mesh then + vertices = attachment:updateWorldVertices(slot, false); + end + if vertices then + local nn = #vertices + local ii = 1 + while ii <= nn do + local x = vertices[ii] + local y = vertices[ii + 1] + minX = math_min(minX, x) + minY = math_min(minY, y) + maxX = math_max(maxX, x) + maxY = math_max(maxY, y) + ii = ii + 8 + end + end + end + offset[1] = minX + offset[2] = minY + size[1] = maxX - minX + size[2] = maxY - minY +end + +function Skeleton:update (delta) + self.time = self.time + delta +end + +function Skeleton:setColor (r, g, b, a) + self.r = r + self.g = g + self.b = b + self.a = a +end + +return Skeleton diff --git a/spine-lua/SkeletonBounds.lua b/spine-lua/SkeletonBounds.lua index 7f46905e9c..a95bb4bdd6 100644 --- a/spine-lua/SkeletonBounds.lua +++ b/spine-lua/SkeletonBounds.lua @@ -1,192 +1,191 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local AttachmentType = require "spine-lua.attachments.AttachmentType" -local utils = require "spine-lua.utils" - -local setmetatable = setmetatable -local math_min = math.min -local math_max = math.max -local ipairs = ipairs -local table_insert = table.insert - -local SkeletonBounds = {} -SkeletonBounds.__index = SkeletonBounds - -function SkeletonBounds.new () - local self = { - minX = 0, minY = 0, maxX = 0, maxY = 0, - polygons = {}, - boundingBoxes = {}, - } - setmetatable(self, SkeletonBounds) - - return self -end - -function SkeletonBounds:update (skeleton, updateAabb) - if skeleton == nil then error("skeleton cannot be null", 2) end - local boundingBoxes = {} - self.boundingBoxes = boundingBoxes - local polygons = {} - self.polygons = polygons - local slots = skeleton.slots - - for i,slot in ipairs(skeleton.slots) do - local attachment = slot.attachment - if attachment and attachment.type == AttachmentType.boundingbox then - local boundingBox = attachment - table_insert(boundingBoxes, boundingBox) - - local polygon = {} - table_insert(polygons, polygon) - - boundingBox:computeWorldVertices(slot, polygon) - end - end - - if updateAabb then self:aabbCompute() end -end - -function SkeletonBounds:aabbCompute () - local minX, minY, maxX, maxY = 9999999, 9999999, -9999999, -9999999 - local polygons = self.polygons - for i,vertices in ipairs(polygons) do - local count = #vertices - for ii = 1, count, 2 do - local x = vertices[ii] - local y = vertices[ii + 1] - minX = math_min(minX, x) - minY = math_min(minY, y) - maxX = math_max(maxX, x) - maxY = math_max(maxY, y) - end - end - self.minX = minX - self.minY = minY - self.maxX = maxX - self.maxY = maxY -end - -function SkeletonBounds:aabbContainsPoint (x, y) - return x >= self.minX and x <= self.maxX and y >= self.minY and y <= self.maxY -end - -function SkeletonBounds:aabbIntersectsSegment (x1, y1, x2, y2) - local minX, minY, maxX, maxY = self.minX, self.minY, self.maxX, self.maxY - if (x1 <= minX and x2 <= minX) or (y1 <= minY and y2 <= minY) or (x1 >= maxX and x2 >= maxX) or (y1 >= maxY and y2 >= maxY) then - return false - end - local m = (y2 - y1) / (x2 - x1) - local y = m * (minX - x1) + y1 - if y > minY and y < maxY then return true end - y = m * (maxX - x1) + y1 - if y > minY and y < maxY then return true end - local x = (minY - y1) / m + x1 - if x > minX and x < maxX then return true end - x = (maxY - y1) / m + x1 - if x > minX and x < maxX then return true end - return false -end - -function SkeletonBounds:aabbIntersectsSkeleton (bounds) - return self.minX < bounds.maxX and self.maxX > bounds.minX and self.minY < bounds.maxY and self.maxY > bounds.minY -end - -function SkeletonBounds:containsPoint (x, y) - for i,polygon in ipairs(self.polygons) do - if self:polygonContainsPoint(polygon, x, y) then return self.boundingBoxes[i] end - end - return nil -end - -function SkeletonBounds:intersectsSegment (x1, y1, x2, y2) - for i,polygon in ipairs(self.polygons) do - if self:polygonIntersectsSegment(polygon, x1, y1, x2, y2) then return self.boundingBoxes[i] end - end - return nil -end - -function SkeletonBounds:polygonContainsPoint (polygon, x, y) - local nn = #polygon - local prevIndex = nn - 1 - local inside = false - for ii = 1, nn, 2 do - local vertexY = polygon[ii + 1] - local prevY = polygon[prevIndex + 1] - if (vertexY < y and prevY >= y) or (prevY < y and vertexY >= y) then - local vertexX = polygon[ii] - if vertexX + (y - vertexY) / (prevY - vertexY) * (polygon[prevIndex] - vertexX) < x then inside = not inside end - end - prevIndex = ii - end - return inside -end - -function SkeletonBounds:polygonIntersectsSegment (polygon, x1, y1, x2, y2) - local nn = #polygon - local width12, height12 = x1 - x2, y1 - y2 - local det1 = x1 * y2 - y1 * x2 - local x3, y3 = polygon[nn - 2], polygon[nn - 1] - for ii = 1, nn, 2 do - local x4, y4 = polygon[ii], polygon[ii + 1] - local det2 = x3 * y4 - y3 * x4 - local width34, height34 = x3 - x4, y3 - y4 - local det3 = width12 * height34 - height12 * width34 - local x = (det1 * width34 - width12 * det2) / det3 - if ((x >= x3 and x <= x4) or (x >= x4 and x <= x3)) and ((x >= x1 and x <= x2) or (x >= x2 and x <= x1)) then - local y = (det1 * height34 - height12 * det2) / det3 - if ((y >= y3 and y <= y4) or (y >= y4 and y <= y3)) and ((y >= y1 and y <= y2) or (y >= y2 and y <= y1)) then return true end - end - x3 = x4 - y3 = y4 - end - return false -end - -function SkeletonBounds:getPolygon (attachment) - local index = spine.utils.indexOf(self.boundingBoxes, attachment) - if index == -1 then - return nil - else - return self.polygons[index] - end -end - -function SkeletonBounds:getWidth() - return self.maxX - self.minX -end - -function SkeletonBounds:getHeight() - return self.maxY - self.minY -end -return SkeletonBounds \ No newline at end of file +local AttachmentType = require "spine-lua.attachments.AttachmentType" +local utils = require "spine-lua.utils" + +local setmetatable = setmetatable +local math_min = math.min +local math_max = math.max +local ipairs = ipairs +local table_insert = table.insert + +local SkeletonBounds = {} +SkeletonBounds.__index = SkeletonBounds + +function SkeletonBounds.new () + local self = { + minX = 0, minY = 0, maxX = 0, maxY = 0, + polygons = {}, + boundingBoxes = {}, + } + setmetatable(self, SkeletonBounds) + + return self +end + +function SkeletonBounds:update (skeleton, updateAabb) + if skeleton == nil then error("skeleton cannot be null", 2) end + local boundingBoxes = {} + self.boundingBoxes = boundingBoxes + local polygons = {} + self.polygons = polygons + local slots = skeleton.slots + + for i,slot in ipairs(skeleton.slots) do + local attachment = slot.attachment + if attachment and attachment.type == AttachmentType.boundingbox then + local boundingBox = attachment + table_insert(boundingBoxes, boundingBox) + + local polygon = {} + table_insert(polygons, polygon) + + boundingBox:computeWorldVertices(slot, polygon) + end + end + + if updateAabb then self:aabbCompute() end +end + +function SkeletonBounds:aabbCompute () + local minX, minY, maxX, maxY = 9999999, 9999999, -9999999, -9999999 + local polygons = self.polygons + for i,vertices in ipairs(polygons) do + local count = #vertices + for ii = 1, count, 2 do + local x = vertices[ii] + local y = vertices[ii + 1] + minX = math_min(minX, x) + minY = math_min(minY, y) + maxX = math_max(maxX, x) + maxY = math_max(maxY, y) + end + end + self.minX = minX + self.minY = minY + self.maxX = maxX + self.maxY = maxY +end + +function SkeletonBounds:aabbContainsPoint (x, y) + return x >= self.minX and x <= self.maxX and y >= self.minY and y <= self.maxY +end + +function SkeletonBounds:aabbIntersectsSegment (x1, y1, x2, y2) + local minX, minY, maxX, maxY = self.minX, self.minY, self.maxX, self.maxY + if (x1 <= minX and x2 <= minX) or (y1 <= minY and y2 <= minY) or (x1 >= maxX and x2 >= maxX) or (y1 >= maxY and y2 >= maxY) then + return false + end + local m = (y2 - y1) / (x2 - x1) + local y = m * (minX - x1) + y1 + if y > minY and y < maxY then return true end + y = m * (maxX - x1) + y1 + if y > minY and y < maxY then return true end + local x = (minY - y1) / m + x1 + if x > minX and x < maxX then return true end + x = (maxY - y1) / m + x1 + if x > minX and x < maxX then return true end + return false +end + +function SkeletonBounds:aabbIntersectsSkeleton (bounds) + return self.minX < bounds.maxX and self.maxX > bounds.minX and self.minY < bounds.maxY and self.maxY > bounds.minY +end + +function SkeletonBounds:containsPoint (x, y) + for i,polygon in ipairs(self.polygons) do + if self:polygonContainsPoint(polygon, x, y) then return self.boundingBoxes[i] end + end + return nil +end + +function SkeletonBounds:intersectsSegment (x1, y1, x2, y2) + for i,polygon in ipairs(self.polygons) do + if self:polygonIntersectsSegment(polygon, x1, y1, x2, y2) then return self.boundingBoxes[i] end + end + return nil +end + +function SkeletonBounds:polygonContainsPoint (polygon, x, y) + local nn = #polygon + local prevIndex = nn - 1 + local inside = false + for ii = 1, nn, 2 do + local vertexY = polygon[ii + 1] + local prevY = polygon[prevIndex + 1] + if (vertexY < y and prevY >= y) or (prevY < y and vertexY >= y) then + local vertexX = polygon[ii] + if vertexX + (y - vertexY) / (prevY - vertexY) * (polygon[prevIndex] - vertexX) < x then inside = not inside end + end + prevIndex = ii + end + return inside +end + +function SkeletonBounds:polygonIntersectsSegment (polygon, x1, y1, x2, y2) + local nn = #polygon + local width12, height12 = x1 - x2, y1 - y2 + local det1 = x1 * y2 - y1 * x2 + local x3, y3 = polygon[nn - 2], polygon[nn - 1] + for ii = 1, nn, 2 do + local x4, y4 = polygon[ii], polygon[ii + 1] + local det2 = x3 * y4 - y3 * x4 + local width34, height34 = x3 - x4, y3 - y4 + local det3 = width12 * height34 - height12 * width34 + local x = (det1 * width34 - width12 * det2) / det3 + if ((x >= x3 and x <= x4) or (x >= x4 and x <= x3)) and ((x >= x1 and x <= x2) or (x >= x2 and x <= x1)) then + local y = (det1 * height34 - height12 * det2) / det3 + if ((y >= y3 and y <= y4) or (y >= y4 and y <= y3)) and ((y >= y1 and y <= y2) or (y >= y2 and y <= y1)) then return true end + end + x3 = x4 + y3 = y4 + end + return false +end + +function SkeletonBounds:getPolygon (attachment) + local index = spine.utils.indexOf(self.boundingBoxes, attachment) + if index == -1 then + return nil + else + return self.polygons[index] + end +end + +function SkeletonBounds:getWidth() + return self.maxX - self.minX +end + +function SkeletonBounds:getHeight() + return self.maxY - self.minY +end + +return SkeletonBounds diff --git a/spine-lua/SkeletonData.lua b/spine-lua/SkeletonData.lua index 8a50a82ff6..90d34a44b7 100644 --- a/spine-lua/SkeletonData.lua +++ b/spine-lua/SkeletonData.lua @@ -1,142 +1,142 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- -local setmetatable = setmetatable - -local SkeletonData = {} -SkeletonData.__index = SkeletonData - -function SkeletonData.new () - local self = { - name, - bones = {}, - slots = {}, - skins = {}, - defaultSkin = nil, - events = {}, - animations = {}, - ikConstraints = {}, - transformConstraints = {}, - pathConstraints = {}, - width, height, - version, hash, imagesPath, - slotNameIndices = {} - } - setmetatable(self, SkeletonData) - - return self -end - -function SkeletonData:findBone (boneName) - if not boneName then error("boneName cannot be nil.", 2) end - for i,bone in ipairs(self.bones) do - if bone.name == boneName then return bone end - end - return nil -end - -function SkeletonData:findBoneIndex (boneName) - if not boneName then error("boneName cannot be nil.", 2) end - for i,bone in ipairs(self.bones) do - if bone.name == boneName then return i end - end - return -1 -end - -function SkeletonData:findSlot (slotName) - if not slotName then error("slotName cannot be nil.", 2) end - for i,slot in ipairs(self.slots) do - if slot.name == slotName then return slot end - end - return nil -end - -function SkeletonData:findSlotIndex (slotName) - if not slotName then error("slotName cannot be nil.", 2) end - return self.slotNameIndices[slotName] or -1 -end - -function SkeletonData:findSkin (skinName) - if not skinName then error("skinName cannot be nil.", 2) end - for i,skin in ipairs(self.skins) do - if skin.name == skinName then return skin end - end - return nil -end - -function SkeletonData:findEvent (eventName) - if not eventName then error("eventName cannot be nil.", 2) end - for i,event in ipairs(self.events) do - if event.name == eventName then return event end - end - return nil -end - -function SkeletonData:findAnimation (animationName) - if not animationName then error("animationName cannot be nil.", 2) end - for i,animation in ipairs(self.animations) do - if animation.name == animationName then return animation end - end - return nil -end - -function SkeletonData:findIkConstraint (constraintName) - if not constraintName then error("constraintName cannot be nil.", 2) end - for i,constraint in ipairs(self.ikConstraints) do - if constraint.name == constraintName then return constraint end - end - return nil -end - -function SkeletonData:findTransformConstraint (constraintName) - if not constraintName then error("constraintName cannot be nil.", 2) end - for i,constraint in ipairs(self.transformConstraints) do - if constraint.name == constraintName then return constraint end - end - return nil -end - -function SkeletonData:findPathConstraint (constraintName) - if not constraintName then error("constraintName cannot be nil.", 2) end - for i,constraint in ipairs(self.pathConstraints) do - if constraint.name == constraintName then return constraint end - end - return nil -end - -function SkeletonData:findPathConstraintIndex (constraintName) - if not constraintName then error("constraintName cannot be nil.", 2) end - for i,constraint in ipairs(self.pathConstraints) do - if constraint.name == constraintName then return i end - end - return -1 -end -return SkeletonData \ No newline at end of file +local setmetatable = setmetatable + +local SkeletonData = {} +SkeletonData.__index = SkeletonData + +function SkeletonData.new () + local self = { + name, + bones = {}, + slots = {}, + skins = {}, + defaultSkin = nil, + events = {}, + animations = {}, + ikConstraints = {}, + transformConstraints = {}, + pathConstraints = {}, + width, height, + version, hash, imagesPath, + slotNameIndices = {} + } + setmetatable(self, SkeletonData) + + return self +end + +function SkeletonData:findBone (boneName) + if not boneName then error("boneName cannot be nil.", 2) end + for i,bone in ipairs(self.bones) do + if bone.name == boneName then return bone end + end + return nil +end + +function SkeletonData:findBoneIndex (boneName) + if not boneName then error("boneName cannot be nil.", 2) end + for i,bone in ipairs(self.bones) do + if bone.name == boneName then return i end + end + return -1 +end + +function SkeletonData:findSlot (slotName) + if not slotName then error("slotName cannot be nil.", 2) end + for i,slot in ipairs(self.slots) do + if slot.name == slotName then return slot end + end + return nil +end + +function SkeletonData:findSlotIndex (slotName) + if not slotName then error("slotName cannot be nil.", 2) end + return self.slotNameIndices[slotName] or -1 +end + +function SkeletonData:findSkin (skinName) + if not skinName then error("skinName cannot be nil.", 2) end + for i,skin in ipairs(self.skins) do + if skin.name == skinName then return skin end + end + return nil +end + +function SkeletonData:findEvent (eventName) + if not eventName then error("eventName cannot be nil.", 2) end + for i,event in ipairs(self.events) do + if event.name == eventName then return event end + end + return nil +end + +function SkeletonData:findAnimation (animationName) + if not animationName then error("animationName cannot be nil.", 2) end + for i,animation in ipairs(self.animations) do + if animation.name == animationName then return animation end + end + return nil +end + +function SkeletonData:findIkConstraint (constraintName) + if not constraintName then error("constraintName cannot be nil.", 2) end + for i,constraint in ipairs(self.ikConstraints) do + if constraint.name == constraintName then return constraint end + end + return nil +end + +function SkeletonData:findTransformConstraint (constraintName) + if not constraintName then error("constraintName cannot be nil.", 2) end + for i,constraint in ipairs(self.transformConstraints) do + if constraint.name == constraintName then return constraint end + end + return nil +end + +function SkeletonData:findPathConstraint (constraintName) + if not constraintName then error("constraintName cannot be nil.", 2) end + for i,constraint in ipairs(self.pathConstraints) do + if constraint.name == constraintName then return constraint end + end + return nil +end + +function SkeletonData:findPathConstraintIndex (constraintName) + if not constraintName then error("constraintName cannot be nil.", 2) end + for i,constraint in ipairs(self.pathConstraints) do + if constraint.name == constraintName then return i end + end + return -1 +end + +return SkeletonData diff --git a/spine-lua/SkeletonJson.lua b/spine-lua/SkeletonJson.lua index f1c66209a0..86cd924854 100644 --- a/spine-lua/SkeletonJson.lua +++ b/spine-lua/SkeletonJson.lua @@ -1,788 +1,787 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local table_insert = table.insert -local SkeletonData = require "spine-lua.SkeletonData" -local BoneData = require "spine-lua.BoneData" -local SlotData = require "spine-lua.SlotData" -local Skin = require "spine-lua.Skin" -local AttachmentLoader = require "spine-lua.AttachmentLoader" -local Animation = require "spine-lua.Animation" -local IkConstraintData = require "spine-lua.IkConstraintData" -local IkConstraint = require "spine-lua.IkConstraint" -local PathConstraintData = require "spine-lua.PathConstraintData" -local PathConstraint = require "spine-lua.PathConstraint" -local TransformConstraintData = require "spine-lua.TransformConstraintData" -local TransformConstraint = require "spine-lua.TransformConstraint" -local EventData = require "spine-lua.EventData" -local Event = require "spine-lua.Event" -local AttachmentType = require "spine-lua.attachments.AttachmentType" -local BlendMode = require "spine-lua.BlendMode" -local utils = require "spine-lua.utils" - -local SkeletonJson = {} -function SkeletonJson.new (attachmentLoader) - if not attachmentLoader then attachmentLoader = AttachmentLoader.new() end - - local self = { - attachmentLoader = attachmentLoader, - scale = 1, - linkedMeshes = {} - } - - function self:readSkeletonDataFile (fileName, base) - return self:readSkeletonData(spine.utils.readFile(fileName, base)) - end - - local readAttachment - local readAnimation - local readCurve - local getArray - - local getValue = function (map, name, default) - local value = map[name] - if value == nil then return default else return value end - end - - function self:readSkeletonData (jsonText) - local scale = self.scale - local skeletonData = SkeletonData.new(self.attachmentLoader) - local root = spine.utils.readJSON(jsonText) - if not root then error("Invalid JSON: " .. jsonText, 2) end - - -- Skeleton. - local skeletonMap = root["skeleton"] - if skeletonMap then - skeletonData.hash = skeletonMap["hash"] - skeletonData.version = skeletonMap["spine"] - skeletonData.width = skeletonMap["width"] - skeletonData.height = skeletonMap["height"] - skeletonData.imagesPath = skeletonMap["images"] - end - - -- Bones. - for i,boneMap in ipairs(root["bones"]) do - local boneName = boneMap["name"] - - local parent = nil - local parentName = boneMap["parent"] - if parentName then - parent = skeletonData:findBone(parentName) - if not parent then error("Parent bone not found: " .. parentName) end - end - local data = BoneData.new(i, boneName, parent) - data.length = getValue(boneMap, "length", 0) * scale; - data.x = getValue(boneMap, "x", 0) * scale; - data.y = getValue(boneMap, "y", 0) * scale; - data.rotation = getValue(boneMap, "rotation", 0); - data.scaleX = getValue(boneMap, "scaleX", 1); - data.scaleY = getValue(boneMap, "scaleY", 1); - data.shearX = getValue(boneMap, "shearX", 0); - data.shearY = getValue(boneMap, "shearY", 0); - data.inheritRotation = getValue(boneMap, "inheritRotation", true); - data.inheritScale = getValue(boneMap, "inheritScale", true); - - table_insert(skeletonData.bones, data) - end - - -- Slots. - if root["slots"] then - for i,slotMap in ipairs(root["slots"]) do - local index = i - local slotName = slotMap["name"] - local boneName = slotMap["bone"] - local boneData = skeletonData:findBone(boneName) - if not boneData then error("Slot bone not found: " .. boneName) end - local data = SlotData.new(i, slotName, boneData) - - local color = slotMap["color"] - if color then - data.color:set(tonumber(color:sub(1, 2), 16) / 255, - tonumber(color:sub(3, 4), 16) / 255, - tonumber(color:sub(5, 6), 16) / 255, - tonumber(color:sub(7, 8), 16) / 255) - end - - data.attachmentName = getValue(slotMap, "attachment", nil) - data.blendMode = BlendMode[getValue(slotMap, "blend", "normal")] - - table_insert(skeletonData.slots, data) - skeletonData.slotNameIndices[data.name] = #skeletonData.slots - end - end - - -- IK constraints. - if root["ik"] then - for i,constraintMap in ipairs(root["ik"]) do - local data = IkConstraintData.new(constraintMap["name"]) - - for i,boneName in ipairs(constraintMap["bones"]) do - local bone = skeletonData:findBone(boneName) - if not bone then error("IK bone not found: " .. boneName) end - table_insert(data.bones, bone) - end - - local targetName = constraintMap["target"] - data.target = skeletonData:findBone(targetName) - if not data.target then error("Target bone not found: " .. targetName) end - - if constraintMap["bendPositive"] == false then data.bendDirection = -1 else data.bendDirection = 1 end - data.mix = getValue(constraintMap, "mix", 1) - - table_insert(skeletonData.ikConstraints, data) - end - end - - -- Transform constraints - if root["transform"] then - for i,constraintMap in ipairs(root["transform"]) do - data = TransformConstraintData.new(constraintMap.name) - - for i,boneName in ipairs(constraintMap.bones) do - local bone = skeletonData:findBone(boneName) - if not bone then error("Transform constraint bone not found: " .. boneName, 2) end - table_insert(data.bones, bone) - end - - local targetName = constraintMap.target - data.target = skeletonData:findBone(targetName) - if not data.target then error("Transform constraint target bone not found: " .. boneName, 2) end - - data.offsetRotation = getValue(constraintMap, "rotation", 0); - data.offsetX = getValue(constraintMap, "x", 0) * scale; - data.offsetY = getValue(constraintMap, "y", 0) * scale; - data.offsetScaleX = getValue(constraintMap, "scaleX", 0); - data.offsetScaleY = getValue(constraintMap, "scaleY", 0); - data.offsetShearY = getValue(constraintMap, "shearY", 0); - - data.rotateMix = getValue(constraintMap, "rotateMix", 1); - data.translateMix = getValue(constraintMap, "translateMix", 1); - data.scaleMix = getValue(constraintMap, "scaleMix", 1); - data.shearMix = getValue(constraintMap, "shearMix", 1); - - table_insert(skeletonData.transformConstraints, data) - end - end - - -- Path constraints - if root["path"] then - for i,constraintMap in ipairs(root.path) do - local data = PathConstraintData.new(constraintMap.name); - - for i,boneName in ipairs(constraintMap.bones) do - local bone = skeletonData:findBone(boneName) - if not bone then error("Path constraint bone not found: " .. boneName, 2) end - table_insert(data.bones, bone) - end - - local targetName = constraintMap.target; - data.target = skeletonData:findSlot(targetName) - if data.target == nil then error("Path target slot not found: " .. targetName, 2) end - - data.positionMode = PathConstraintData.PositionMode[getValue(constraintMap, "positionMode", "percent"):lower()] - data.spacingMode = PathConstraintData.SpacingMode[getValue(constraintMap, "spacingMode", "length"):lower()] - data.rotateMode = PathConstraintData.RotateMode[getValue(constraintMap, "rotateMode", "tangent"):lower()] - data.offsetRotation = getValue(constraintMap, "rotation", 0); - data.position = getValue(constraintMap, "position", 0); - if data.positionMode == PathConstraintData.PositionMode.fixed then data.position = data.position * scale end - data.spacing = getValue(constraintMap, "spacing", 0); - if data.spacingMode == PathConstraintData.SpacingMode.length or data.spacingMode == PathConstraintData.SpacingMode.fixed then data.spacing = data.spacing * scale end - data.rotateMix = getValue(constraintMap, "rotateMix", 1); - data.translateMix = getValue(constraintMap, "translateMix", 1); - - table_insert(skeletonData.pathConstraints, data) - end - end - - -- Skins. - if root["skins"] then - for skinName,skinMap in pairs(root["skins"]) do - local skin = Skin.new(skinName) - for slotName,slotMap in pairs(skinMap) do - local slotIndex = skeletonData.slotNameIndices[slotName] - for attachmentName,attachmentMap in pairs(slotMap) do - local attachment = readAttachment(attachmentMap, skin, slotIndex, attachmentName) - if attachment then - skin:addAttachment(slotIndex, attachmentName, attachment) - end - end - end - table_insert(skeletonData.skins, skin) - if skin.name == "default" then skeletonData.defaultSkin = skin end - end - end - - -- Linked meshes - for i, linkedMesh in ipairs(self.linkedMeshes) do - local skin = skeletonData.defaultSkin - if linkedMesh.skin then skin = skeletonData.findSkin(linkedMesh.skin) end - if not skin then error("Skin not found: " .. linkedMesh.skin) end - local parent = skin:getAttachment(linkedMesh.slotIndex, linkedMesh.parent) - if not parent then error("Parent mesh not found: " + linkedMesh.parent) end - linkedMesh.mesh:setParentMesh(parent) - linkedMesh.mesh:updateUVs() - end - self.linkedMeshes = {} - - -- Events. - if root["events"] then - for eventName,eventMap in pairs(root["events"]) do - local data = EventData.new(eventName) - data.intValue = getValue(eventMap, "int", 0) - data.floatValue = getValue(eventMap, "float", 0) - data.stringValue = getValue(eventMap, "string", nil) - table_insert(skeletonData.events, data) - end - end - - -- Animations. - if root["animations"] then - for animationName,animationMap in pairs(root["animations"]) do - readAnimation(animationMap, animationName, skeletonData) - end - end - - return skeletonData - end - - readAttachment = function (map, skin, slotIndex, name) - local scale = self.scale - name = getValue(map, "name", name) - - local type = AttachmentType[getValue(map, "type", "region")] - local path = getValue(map, "path", name) - - if type == AttachmentType.region then - local region = attachmentLoader:newRegionAttachment(skin, name, path) - if not region then return nil end - region.path = path - region.x = getValue(map, "x", 0) * scale - region.y = getValue(map, "y", 0) * scale - region.scaleX = getValue(map, "scaleX", 1); - region.scaleY = getValue(map, "scaleY", 1); - region.rotation = getValue(map, "rotation", 0); - region.width = map.width * scale; - region.height = map.height * scale; - - local color = map["color"] - if color then - region.color:set(tonumber(color:sub(1, 2), 16) / 255, - tonumber(color:sub(3, 4), 16) / 255, - tonumber(color:sub(5, 6), 16) / 255, - tonumber(color:sub(7, 8), 16) / 255) - end - - region:updateOffset() - return region - - elseif type == AttachmentType.boundingbox then - local box = attachmentLoader:newBoundingBoxAttachment(skin, name) - if not box then return nil end - readVertices(map, box, map.vertexCount * 2) - local color = map.color - if color then - box.color:set(tonumber(color:sub(1, 2), 16) / 255, - tonumber(color:sub(3, 4), 16) / 255, - tonumber(color:sub(5, 6), 16) / 255, - tonumber(color:sub(7, 8), 16) / 255) - end - return box - - elseif type == AttachmentType.mesh or type == AttachmentType.linkedmesh then - local mesh = attachmentLoader:newMeshAttachment(skin, name, path) - if not mesh then return null end - mesh.path = path - - local color = map.color - if color then - mesh.color:set(tonumber(color:sub(1, 2), 16) / 255, - tonumber(color:sub(3, 4), 16) / 255, - tonumber(color:sub(5, 6), 16) / 255, - tonumber(color:sub(7, 8), 16) / 255) - end - - local parent = map.parent - if parent then - mesh.inheritDeform = getValue(map, "deform", true) - table_insert(self.linkedMeshes, { - mesh = mesh, - skin = getValue(map, skin, nil), - slotIndex = slotIndex, - parent = parent - }) - return mesh - end - - local uvs = getArray(map, "uvs", 1) - readVertices(map, mesh, #uvs) - mesh.triangles = getArray(map, "triangles", 1) - -- adjust triangle indices by 1, vertices are one-indexed - for i,v in ipairs(mesh.triangles) do - mesh.triangles[i] = v + 1 - end - mesh.regionUVs = uvs - mesh:updateUVs() - - mesh.hullLength = getValue(map, "hull", 0) * 2 - return mesh - - elseif type == AttachmentType.path then - local path = self.attachmentLoader:newPathAttachment(skin, name) - if not path then return nil end - path.closed = getValue(map, "closed", false) - path.constantSpeed = getValue(map, "constantSpeed", true) - - local vertexCount = map.vertexCount - readVertices(map, path, vertexCount * 2) - - local lengths = utils.newNumberArray(vertexCount / 3, 0) - for i,v in ipairs(map.lengths) do - lengths[i] = v * scale - end - path.lengths = lengths - - local color = map.color - if color then - path.color:set(tonumber(color:sub(1, 2), 16) / 255, - tonumber(color:sub(3, 4), 16) / 255, - tonumber(color:sub(5, 6), 16) / 255, - tonumber(color:sub(7, 8), 16) / 255) - end - return path; - end - - error("Unknown attachment type: " .. type .. " (" .. name .. ")") - end - - readVertices = function (map, attachment, verticesLength) - local scale = self.scale - attachment.worldVerticesLength = verticesLength - local vertices = getArray(map, "vertices", 1) - if verticesLength == #vertices then - if scale ~= 1 then - local i = 0 - local n = #vertices - while i < n do - vertices[i + 1] = vertices[i + 1] * scale - i = i + 1 - end - end - attachment.vertices = vertices - return - end - - local weights = {} - local bones = {} - local i = 0 - local n = #vertices - while i < n do - local boneCount = vertices[i + 1] - i = i + 1 - table_insert(bones, boneCount) - local nn = i + boneCount * 4 - while i < nn do - table_insert(bones, vertices[i + 1] + 1) -- +1 because bones are one-indexed - table_insert(weights, vertices[i + 2] * scale) - table_insert(weights, vertices[i + 3] * scale) - table_insert(weights, vertices[i + 4]) - i = i + 4 - end - end - attachment.bones = bones - attachment.vertices = weights - end - - readAnimation = function (map, name, skeletonData) - local timelines = {} - local duration = 0 - local scale = self.scale - - -- Slot timelines - local slotsMap = map["slots"] - if slotsMap then - for slotName,timelineMap in pairs(slotsMap) do - local slotIndex = skeletonData.slotNameIndices[slotName] - - for timelineName,values in pairs(timelineMap) do - if timelineName == "color" then - local timeline = Animation.ColorTimeline.new(#values) - timeline.slotIndex = slotIndex - - local frameIndex = 0 - for i,valueMap in ipairs(values) do - local color = valueMap["color"] - timeline:setFrame( - frameIndex, valueMap["time"], - tonumber(color:sub(1, 2), 16) / 255, - tonumber(color:sub(3, 4), 16) / 255, - tonumber(color:sub(5, 6), 16) / 255, - tonumber(color:sub(7, 8), 16) / 255 - ) - readCurve(valueMap, timeline, frameIndex) - frameIndex = frameIndex + 1 - end - table_insert(timelines, timeline) - duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.ColorTimeline.ENTRIES]) - - elseif timelineName == "attachment" then - local timeline = Animation.AttachmentTimeline.new(#values) - timeline.slotName = slotName - - local frameIndex = 0 - for i,valueMap in ipairs(values) do - local attachmentName = valueMap["name"] - timeline:setFrame(frameIndex, valueMap["time"], attachmentName) - frameIndex = frameIndex + 1 - end - table_insert(timelines, timeline) - duration = math.max(duration, timeline.frames[timeline:getFrameCount() - 1]) - - else - error("Invalid frame type for a slot: " .. timelineName .. " (" .. slotName .. ")") - end - end - end - end - - -- Bone timelines - local bonesMap = map["bones"] - if bonesMap then - for boneName,timelineMap in pairs(bonesMap) do - local boneIndex = skeletonData:findBoneIndex(boneName) - if boneIndex == -1 then error("Bone not found: " .. boneName) end - - for timelineName,values in pairs(timelineMap) do - if timelineName == "rotate" then - local timeline = Animation.RotateTimeline.new(#values) - timeline.boneIndex = boneIndex - - local frameIndex = 0 - for i,valueMap in ipairs(values) do - timeline:setFrame(frameIndex, valueMap["time"], valueMap["angle"]) - readCurve(valueMap, timeline, frameIndex) - frameIndex = frameIndex + 1 - end - table_insert(timelines, timeline) - duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.RotateTimeline.ENTRIES]) - - elseif timelineName == "translate" or timelineName == "scale" or timelineName == "shear" then - local timeline - local timelineScale = 1 - if timelineName == "scale" then - timeline = Animation.ScaleTimeline.new(#values) - elseif timelineName == "shear" then - timeline = Animation.ShearTimeline.new(#values) - else - timeline = Animation.TranslateTimeline.new(#values) - timelineScale = self.scale - end - timeline.boneIndex = boneIndex - - local frameIndex = 0 - for i,valueMap in ipairs(values) do - local x = (valueMap["x"] or 0) * timelineScale - local y = (valueMap["y"] or 0) * timelineScale - timeline:setFrame(frameIndex, valueMap["time"], x, y) - readCurve(valueMap, timeline, frameIndex) - frameIndex = frameIndex + 1 - end - table_insert(timelines, timeline) - duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.TranslateTimeline.ENTRIES]) - else - error("Invalid timeline type for a bone: " .. timelineName .. " (" .. boneName .. ")") - end - end - end - end - - -- IK timelines. - local ik = map["ik"] - if ik then - for ikConstraintName,values in pairs(ik) do - local ikConstraint = skeletonData:findIkConstraint(ikConstraintName) - local timeline = Animation.IkConstraintTimeline.new(#values) - for i,other in pairs(skeletonData.ikConstraints) do - if other == ikConstraint then - timeline.ikConstraintIndex = i - break - end - end - local frameIndex = 0 - for i,valueMap in ipairs(values) do - local mix = 1 - if valueMap["mix"] ~= nil then mix = valueMap["mix"] end - local bendPositive = 1 - if valueMap["bendPositive"] == false then bendPositive = -1 end - timeline:setFrame(frameIndex, valueMap["time"], mix, bendPositive) - readCurve(valueMap, timeline, frameIndex) - frameIndex = frameIndex + 1 - end - table_insert(timelines, timeline) - duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.IkConstraintTimeline.ENTRIES]) - end - end - - -- Transform constraint timelines. - local transform = map["transform"] - if transform then - for constraintName, values in pairs(transform) do - local constraint = skeletonData:findTransformConstraint(constraintName) - local timeline = Animation.TransformConstraintTimeline.new(#values) - for i,other in pairs(skeletonData.transformConstraints) do - if other == constraint then - timeline.transformConstraintIndex = i - break - end - end - local frameIndex = 0 - for i,valueMap in ipairs(values) do - timeline:setFrame(frameIndex, valueMap.time, getValue(valueMap, "rotateMix", 1), getValue(valueMap, "translateMix", 1), getValue(valueMap, "scaleMix", 1), getValue(valueMap, "shearMix", 1)) - readCurve(valueMap, timeline, frameIndex) - frameIndex = frameIndex + 1 - end - table_insert(timelines, timeline) - duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.TransformConstraintTimeline.ENTRIES]) - end - end - - -- Path constraint timelines. - if map.paths then - for constraintName,constraintMap in pairs(map.paths) do - local index = skeletonData:findPathConstraintIndex(constraintName) - if index == -1 then error("Path constraint not found: " .. constraintName, 2) end - local data = skeletonData.pathConstraints[index] - for timelineName, timelineMap in pairs(constraintMap) do - if timelineName == "position" or timelineName == "spacing" then - local timeline = nil - local timelineScale = 1 - if timelineName == "spacing" then - timeline = Animation.PathConstraintSpacingTimeline.new(#timelineMap) - if data.spacingMode == PathConstraintData.SpacingMode.length or data.spacingMode == PathConstraintData.SpacingMode.fixed then timelineScale = scale end - else - timeline = Animation.PathConstraintPositionTimeline.new(#timelineMap) - if data.positionMode == PathConstraintData.PositionMode.fixed then timelineScale = scale end - end - timeline.pathConstraintIndex = index - local frameIndex = 0 - for i,valueMap in ipairs(timelineMap) do - timeline:setFrame(frameIndex, valueMap.time, getValue(valueMap, timelineName, 0) * timelineScale) - readCurve(valueMap, timeline, frameIndex) - frameIndex = frameIndex + 1 - end - table_insert(timelines, timeline) - duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.PathConstraintPositionTimeline.ENTRIES]) - elseif timelineName == "mix" then - local timeline = Animation.PathConstraintMixTimeline.new(#timelineMap) - timeline.pathConstraintIndex = index - local frameIndex = 0 - for i,valueMap in ipairs(timelineMap) do - timeline:setFrame(frameIndex, valueMap.time, getValue(valueMap, "rotateMix", 1), getValue(valueMap, "translateMix", 1)) - readCurve(valueMap, timeline, frameIndex) - frameIndex = frameIndex + 1 - end - table_insert(timelines, timeline) - duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.PathConstraintMixTimeline.ENTRIES]) - end - end - end - end - - -- Deform timelines. - if map.deform then - for deformName, deformMap in pairs(map.deform) do - local skin = skeletonData:findSkin(deformName) - if not skin then error("Skin not found: " .. deformName, 2) end - for slotName,slotMap in pairs(deformMap) do - local slotIndex = skeletonData:findSlotIndex(slotName) - if slotIndex == -1 then error("Slot not found: " .. slotMap.name, 2) end - for timelineName,timelineMap in pairs(slotMap) do - local attachment = skin:getAttachment(slotIndex, timelineName) - if not attachment then error("Deform attachment not found: " .. timelineMap.name, 2) end - local weighted = attachment.bones ~= nil - local vertices = attachment.vertices; - local deformLength = #vertices - if weighted then deformLength = math.floor(#vertices / 3) * 2 end - - local timeline = Animation.DeformTimeline.new(#timelineMap) - timeline.slotIndex = slotIndex - timeline.attachment = attachment - - local frameIndex = 0 - for i,valueMap in ipairs(timelineMap) do - local deform = nil - local verticesValue = getValue(valueMap, "vertices", nil) - if verticesValue == nil then - deform = vertices - if weighted then deform = utils.newNumberArray(deformLength) end - else - deform = utils.newNumberArray(deformLength) - local start = getValue(valueMap, "offset", 0) + 1 - utils.arrayCopy(verticesValue, 1, deform, start, #verticesValue) - if scale ~= 1 then - local i = start - local n = i + #verticesValue - while i < n do - deform[i] = deform[i] * scale - i = i + 1 - end - end - if not weighted then - local i = 1 - local n = i + deformLength - while i < n do - deform[i] = deform[i] + vertices[i] - i = i + 1 - end - end - end - - timeline:setFrame(frameIndex, valueMap.time, deform) - readCurve(valueMap, timeline, frameIndex) - frameIndex = frameIndex + 1 - end - table_insert(timelines, timeline) - duration = math.max(duration, timeline.frames[timeline:getFrameCount() - 1]) - end - end - end - end - - -- Draworder timeline. - local drawOrderValues = map["drawOrder"] - if not drawOrderValues then drawOrderValues = map["draworder"] end - if drawOrderValues then - local timeline = Animation.DrawOrderTimeline.new(#drawOrderValues) - local slotCount = #skeletonData.slots - local frameIndex = 0 - for i,drawOrderMap in ipairs(drawOrderValues) do - local drawOrder = nil - local offsets = drawOrderMap["offsets"] - if offsets then - drawOrder = {} - local unchanged = {} - local originalIndex = 1 - local unchangedIndex = 1 - for ii,offsetMap in ipairs(offsets) do - local slotIndex = skeletonData:findSlotIndex(offsetMap["slot"]) - if slotIndex == -1 then error("Slot not found: " .. offsetMap["slot"]) end - -- Collect unchanged items. - while originalIndex ~= slotIndex do - unchanged[unchangedIndex] = originalIndex - unchangedIndex = unchangedIndex + 1 - originalIndex = originalIndex + 1 - end - -- Set changed items. - drawOrder[originalIndex + offsetMap["offset"]] = originalIndex - originalIndex = originalIndex + 1 - end - -- Collect remaining unchanged items. - while originalIndex <= slotCount do - unchanged[unchangedIndex] = originalIndex - unchangedIndex = unchangedIndex + 1 - originalIndex = originalIndex + 1 - end - -- Fill in unchanged items. - for ii = slotCount, 1, -1 do - if not drawOrder[ii] then - unchangedIndex = unchangedIndex - 1 - drawOrder[ii] = unchanged[unchangedIndex] - end - end - end - timeline:setFrame(frameIndex, drawOrderMap["time"], drawOrder) - frameIndex = frameIndex + 1 - end - table_insert(timelines, timeline) - duration = math.max(duration, timeline.frames[timeline:getFrameCount() - 1]) - end - - -- Event timeline. - local events = map["events"] - if events then - local timeline = Animation.EventTimeline.new(#events) - local frameIndex = 0 - for i,eventMap in ipairs(events) do - local eventData = skeletonData:findEvent(eventMap["name"]) - if not eventData then error("Event not found: " .. eventMap["name"]) end - local event = Event.new(eventMap["time"], eventData) - if eventMap["int"] ~= nil then - event.intValue = eventMap["int"] - else - event.intValue = eventData.intValue - end - if eventMap["float"] ~= nil then - event.floatValue = eventMap["float"] - else - event.floatValue = eventData.floatValue - end - if eventMap["string"] ~= nil then - event.stringValue = eventMap["string"] - else - event.stringValue = eventData.stringValue - end - timeline:setFrame(frameIndex, event) - frameIndex = frameIndex + 1 - end - table_insert(timelines, timeline) - duration = math.max(duration, timeline.frames[timeline:getFrameCount() - 1]) - end - - table_insert(skeletonData.animations, Animation.new(name, timelines, duration)) - end - - readCurve = function (map, timeline, frameIndex) - local curve = map["curve"] - if not curve then return end - if curve == "stepped" then - timeline:setStepped(frameIndex) - elseif #curve > 0 then - timeline:setCurve(frameIndex, curve[1], curve[2], curve[3], curve[4]) - end - end - - getArray = function (map, name, scale) - local list = map[name] - local values = {} - if scale == 1 then - for i = 1, #list do - values[i] = list[i] - end - else - for i = 1, #list do - values[i] = list[i] * scale - end - end - return values - end - return self -end +local table_insert = table.insert +local SkeletonData = require "spine-lua.SkeletonData" +local BoneData = require "spine-lua.BoneData" +local SlotData = require "spine-lua.SlotData" +local Skin = require "spine-lua.Skin" +local AttachmentLoader = require "spine-lua.AttachmentLoader" +local Animation = require "spine-lua.Animation" +local IkConstraintData = require "spine-lua.IkConstraintData" +local IkConstraint = require "spine-lua.IkConstraint" +local PathConstraintData = require "spine-lua.PathConstraintData" +local PathConstraint = require "spine-lua.PathConstraint" +local TransformConstraintData = require "spine-lua.TransformConstraintData" +local TransformConstraint = require "spine-lua.TransformConstraint" +local EventData = require "spine-lua.EventData" +local Event = require "spine-lua.Event" +local AttachmentType = require "spine-lua.attachments.AttachmentType" +local BlendMode = require "spine-lua.BlendMode" +local utils = require "spine-lua.utils" + +local SkeletonJson = {} +function SkeletonJson.new (attachmentLoader) + if not attachmentLoader then attachmentLoader = AttachmentLoader.new() end + + local self = { + attachmentLoader = attachmentLoader, + scale = 1, + linkedMeshes = {} + } + + function self:readSkeletonDataFile (fileName, base) + return self:readSkeletonData(spine.utils.readFile(fileName, base)) + end + + local readAttachment + local readAnimation + local readCurve + local getArray + + local getValue = function (map, name, default) + local value = map[name] + if value == nil then return default else return value end + end + + function self:readSkeletonData (jsonText) + local scale = self.scale + local skeletonData = SkeletonData.new(self.attachmentLoader) + local root = spine.utils.readJSON(jsonText) + if not root then error("Invalid JSON: " .. jsonText, 2) end + + -- Skeleton. + local skeletonMap = root["skeleton"] + if skeletonMap then + skeletonData.hash = skeletonMap["hash"] + skeletonData.version = skeletonMap["spine"] + skeletonData.width = skeletonMap["width"] + skeletonData.height = skeletonMap["height"] + skeletonData.imagesPath = skeletonMap["images"] + end + + -- Bones. + for i,boneMap in ipairs(root["bones"]) do + local boneName = boneMap["name"] + + local parent = nil + local parentName = boneMap["parent"] + if parentName then + parent = skeletonData:findBone(parentName) + if not parent then error("Parent bone not found: " .. parentName) end + end + local data = BoneData.new(i, boneName, parent) + data.length = getValue(boneMap, "length", 0) * scale; + data.x = getValue(boneMap, "x", 0) * scale; + data.y = getValue(boneMap, "y", 0) * scale; + data.rotation = getValue(boneMap, "rotation", 0); + data.scaleX = getValue(boneMap, "scaleX", 1); + data.scaleY = getValue(boneMap, "scaleY", 1); + data.shearX = getValue(boneMap, "shearX", 0); + data.shearY = getValue(boneMap, "shearY", 0); + data.inheritRotation = getValue(boneMap, "inheritRotation", true); + data.inheritScale = getValue(boneMap, "inheritScale", true); + + table_insert(skeletonData.bones, data) + end + + -- Slots. + if root["slots"] then + for i,slotMap in ipairs(root["slots"]) do + local index = i + local slotName = slotMap["name"] + local boneName = slotMap["bone"] + local boneData = skeletonData:findBone(boneName) + if not boneData then error("Slot bone not found: " .. boneName) end + local data = SlotData.new(i, slotName, boneData) + + local color = slotMap["color"] + if color then + data.color:set(tonumber(color:sub(1, 2), 16) / 255, + tonumber(color:sub(3, 4), 16) / 255, + tonumber(color:sub(5, 6), 16) / 255, + tonumber(color:sub(7, 8), 16) / 255) + end + + data.attachmentName = getValue(slotMap, "attachment", nil) + data.blendMode = BlendMode[getValue(slotMap, "blend", "normal")] + + table_insert(skeletonData.slots, data) + skeletonData.slotNameIndices[data.name] = #skeletonData.slots + end + end + + -- IK constraints. + if root["ik"] then + for i,constraintMap in ipairs(root["ik"]) do + local data = IkConstraintData.new(constraintMap["name"]) + + for i,boneName in ipairs(constraintMap["bones"]) do + local bone = skeletonData:findBone(boneName) + if not bone then error("IK bone not found: " .. boneName) end + table_insert(data.bones, bone) + end + + local targetName = constraintMap["target"] + data.target = skeletonData:findBone(targetName) + if not data.target then error("Target bone not found: " .. targetName) end + + if constraintMap["bendPositive"] == false then data.bendDirection = -1 else data.bendDirection = 1 end + data.mix = getValue(constraintMap, "mix", 1) + + table_insert(skeletonData.ikConstraints, data) + end + end + + -- Transform constraints + if root["transform"] then + for i,constraintMap in ipairs(root["transform"]) do + data = TransformConstraintData.new(constraintMap.name) + + for i,boneName in ipairs(constraintMap.bones) do + local bone = skeletonData:findBone(boneName) + if not bone then error("Transform constraint bone not found: " .. boneName, 2) end + table_insert(data.bones, bone) + end + + local targetName = constraintMap.target + data.target = skeletonData:findBone(targetName) + if not data.target then error("Transform constraint target bone not found: " .. boneName, 2) end + + data.offsetRotation = getValue(constraintMap, "rotation", 0); + data.offsetX = getValue(constraintMap, "x", 0) * scale; + data.offsetY = getValue(constraintMap, "y", 0) * scale; + data.offsetScaleX = getValue(constraintMap, "scaleX", 0); + data.offsetScaleY = getValue(constraintMap, "scaleY", 0); + data.offsetShearY = getValue(constraintMap, "shearY", 0); + + data.rotateMix = getValue(constraintMap, "rotateMix", 1); + data.translateMix = getValue(constraintMap, "translateMix", 1); + data.scaleMix = getValue(constraintMap, "scaleMix", 1); + data.shearMix = getValue(constraintMap, "shearMix", 1); + + table_insert(skeletonData.transformConstraints, data) + end + end + + -- Path constraints + if root["path"] then + for i,constraintMap in ipairs(root.path) do + local data = PathConstraintData.new(constraintMap.name); + + for i,boneName in ipairs(constraintMap.bones) do + local bone = skeletonData:findBone(boneName) + if not bone then error("Path constraint bone not found: " .. boneName, 2) end + table_insert(data.bones, bone) + end + + local targetName = constraintMap.target; + data.target = skeletonData:findSlot(targetName) + if data.target == nil then error("Path target slot not found: " .. targetName, 2) end + + data.positionMode = PathConstraintData.PositionMode[getValue(constraintMap, "positionMode", "percent"):lower()] + data.spacingMode = PathConstraintData.SpacingMode[getValue(constraintMap, "spacingMode", "length"):lower()] + data.rotateMode = PathConstraintData.RotateMode[getValue(constraintMap, "rotateMode", "tangent"):lower()] + data.offsetRotation = getValue(constraintMap, "rotation", 0); + data.position = getValue(constraintMap, "position", 0); + if data.positionMode == PathConstraintData.PositionMode.fixed then data.position = data.position * scale end + data.spacing = getValue(constraintMap, "spacing", 0); + if data.spacingMode == PathConstraintData.SpacingMode.length or data.spacingMode == PathConstraintData.SpacingMode.fixed then data.spacing = data.spacing * scale end + data.rotateMix = getValue(constraintMap, "rotateMix", 1); + data.translateMix = getValue(constraintMap, "translateMix", 1); + + table_insert(skeletonData.pathConstraints, data) + end + end + + -- Skins. + if root["skins"] then + for skinName,skinMap in pairs(root["skins"]) do + local skin = Skin.new(skinName) + for slotName,slotMap in pairs(skinMap) do + local slotIndex = skeletonData.slotNameIndices[slotName] + for attachmentName,attachmentMap in pairs(slotMap) do + local attachment = readAttachment(attachmentMap, skin, slotIndex, attachmentName) + if attachment then + skin:addAttachment(slotIndex, attachmentName, attachment) + end + end + end + table_insert(skeletonData.skins, skin) + if skin.name == "default" then skeletonData.defaultSkin = skin end + end + end + + -- Linked meshes + for i, linkedMesh in ipairs(self.linkedMeshes) do + local skin = skeletonData.defaultSkin + if linkedMesh.skin then skin = skeletonData.findSkin(linkedMesh.skin) end + if not skin then error("Skin not found: " .. linkedMesh.skin) end + local parent = skin:getAttachment(linkedMesh.slotIndex, linkedMesh.parent) + if not parent then error("Parent mesh not found: " + linkedMesh.parent) end + linkedMesh.mesh:setParentMesh(parent) + linkedMesh.mesh:updateUVs() + end + self.linkedMeshes = {} + + -- Events. + if root["events"] then + for eventName,eventMap in pairs(root["events"]) do + local data = EventData.new(eventName) + data.intValue = getValue(eventMap, "int", 0) + data.floatValue = getValue(eventMap, "float", 0) + data.stringValue = getValue(eventMap, "string", nil) + table_insert(skeletonData.events, data) + end + end + + -- Animations. + if root["animations"] then + for animationName,animationMap in pairs(root["animations"]) do + readAnimation(animationMap, animationName, skeletonData) + end + end + + return skeletonData + end + + readAttachment = function (map, skin, slotIndex, name) + local scale = self.scale + name = getValue(map, "name", name) + + local type = AttachmentType[getValue(map, "type", "region")] + local path = getValue(map, "path", name) + + if type == AttachmentType.region then + local region = attachmentLoader:newRegionAttachment(skin, name, path) + if not region then return nil end + region.path = path + region.x = getValue(map, "x", 0) * scale + region.y = getValue(map, "y", 0) * scale + region.scaleX = getValue(map, "scaleX", 1); + region.scaleY = getValue(map, "scaleY", 1); + region.rotation = getValue(map, "rotation", 0); + region.width = map.width * scale; + region.height = map.height * scale; + + local color = map["color"] + if color then + region.color:set(tonumber(color:sub(1, 2), 16) / 255, + tonumber(color:sub(3, 4), 16) / 255, + tonumber(color:sub(5, 6), 16) / 255, + tonumber(color:sub(7, 8), 16) / 255) + end + + region:updateOffset() + return region + + elseif type == AttachmentType.boundingbox then + local box = attachmentLoader:newBoundingBoxAttachment(skin, name) + if not box then return nil end + readVertices(map, box, map.vertexCount * 2) + local color = map.color + if color then + box.color:set(tonumber(color:sub(1, 2), 16) / 255, + tonumber(color:sub(3, 4), 16) / 255, + tonumber(color:sub(5, 6), 16) / 255, + tonumber(color:sub(7, 8), 16) / 255) + end + return box + + elseif type == AttachmentType.mesh or type == AttachmentType.linkedmesh then + local mesh = attachmentLoader:newMeshAttachment(skin, name, path) + if not mesh then return null end + mesh.path = path + + local color = map.color + if color then + mesh.color:set(tonumber(color:sub(1, 2), 16) / 255, + tonumber(color:sub(3, 4), 16) / 255, + tonumber(color:sub(5, 6), 16) / 255, + tonumber(color:sub(7, 8), 16) / 255) + end + + local parent = map.parent + if parent then + mesh.inheritDeform = getValue(map, "deform", true) + table_insert(self.linkedMeshes, { + mesh = mesh, + skin = getValue(map, skin, nil), + slotIndex = slotIndex, + parent = parent + }) + return mesh + end + + local uvs = getArray(map, "uvs", 1) + readVertices(map, mesh, #uvs) + mesh.triangles = getArray(map, "triangles", 1) + -- adjust triangle indices by 1, vertices are one-indexed + for i,v in ipairs(mesh.triangles) do + mesh.triangles[i] = v + 1 + end + mesh.regionUVs = uvs + mesh:updateUVs() + + mesh.hullLength = getValue(map, "hull", 0) * 2 + return mesh + + elseif type == AttachmentType.path then + local path = self.attachmentLoader:newPathAttachment(skin, name) + if not path then return nil end + path.closed = getValue(map, "closed", false) + path.constantSpeed = getValue(map, "constantSpeed", true) + + local vertexCount = map.vertexCount + readVertices(map, path, vertexCount * 2) + + local lengths = utils.newNumberArray(vertexCount / 3, 0) + for i,v in ipairs(map.lengths) do + lengths[i] = v * scale + end + path.lengths = lengths + + local color = map.color + if color then + path.color:set(tonumber(color:sub(1, 2), 16) / 255, + tonumber(color:sub(3, 4), 16) / 255, + tonumber(color:sub(5, 6), 16) / 255, + tonumber(color:sub(7, 8), 16) / 255) + end + return path; + end + + error("Unknown attachment type: " .. type .. " (" .. name .. ")") + end + + readVertices = function (map, attachment, verticesLength) + local scale = self.scale + attachment.worldVerticesLength = verticesLength + local vertices = getArray(map, "vertices", 1) + if verticesLength == #vertices then + if scale ~= 1 then + local i = 0 + local n = #vertices + while i < n do + vertices[i + 1] = vertices[i + 1] * scale + i = i + 1 + end + end + attachment.vertices = vertices + return + end + + local weights = {} + local bones = {} + local i = 0 + local n = #vertices + while i < n do + local boneCount = vertices[i + 1] + i = i + 1 + table_insert(bones, boneCount) + local nn = i + boneCount * 4 + while i < nn do + table_insert(bones, vertices[i + 1] + 1) -- +1 because bones are one-indexed + table_insert(weights, vertices[i + 2] * scale) + table_insert(weights, vertices[i + 3] * scale) + table_insert(weights, vertices[i + 4]) + i = i + 4 + end + end + attachment.bones = bones + attachment.vertices = weights + end + + readAnimation = function (map, name, skeletonData) + local timelines = {} + local duration = 0 + local scale = self.scale + + -- Slot timelines + local slotsMap = map["slots"] + if slotsMap then + for slotName,timelineMap in pairs(slotsMap) do + local slotIndex = skeletonData.slotNameIndices[slotName] + + for timelineName,values in pairs(timelineMap) do + if timelineName == "color" then + local timeline = Animation.ColorTimeline.new(#values) + timeline.slotIndex = slotIndex + + local frameIndex = 0 + for i,valueMap in ipairs(values) do + local color = valueMap["color"] + timeline:setFrame( + frameIndex, valueMap["time"], + tonumber(color:sub(1, 2), 16) / 255, + tonumber(color:sub(3, 4), 16) / 255, + tonumber(color:sub(5, 6), 16) / 255, + tonumber(color:sub(7, 8), 16) / 255 + ) + readCurve(valueMap, timeline, frameIndex) + frameIndex = frameIndex + 1 + end + table_insert(timelines, timeline) + duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.ColorTimeline.ENTRIES]) + + elseif timelineName == "attachment" then + local timeline = Animation.AttachmentTimeline.new(#values) + timeline.slotName = slotName + + local frameIndex = 0 + for i,valueMap in ipairs(values) do + local attachmentName = valueMap["name"] + timeline:setFrame(frameIndex, valueMap["time"], attachmentName) + frameIndex = frameIndex + 1 + end + table_insert(timelines, timeline) + duration = math.max(duration, timeline.frames[timeline:getFrameCount() - 1]) + + else + error("Invalid frame type for a slot: " .. timelineName .. " (" .. slotName .. ")") + end + end + end + end + + -- Bone timelines + local bonesMap = map["bones"] + if bonesMap then + for boneName,timelineMap in pairs(bonesMap) do + local boneIndex = skeletonData:findBoneIndex(boneName) + if boneIndex == -1 then error("Bone not found: " .. boneName) end + + for timelineName,values in pairs(timelineMap) do + if timelineName == "rotate" then + local timeline = Animation.RotateTimeline.new(#values) + timeline.boneIndex = boneIndex + + local frameIndex = 0 + for i,valueMap in ipairs(values) do + timeline:setFrame(frameIndex, valueMap["time"], valueMap["angle"]) + readCurve(valueMap, timeline, frameIndex) + frameIndex = frameIndex + 1 + end + table_insert(timelines, timeline) + duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.RotateTimeline.ENTRIES]) + + elseif timelineName == "translate" or timelineName == "scale" or timelineName == "shear" then + local timeline + local timelineScale = 1 + if timelineName == "scale" then + timeline = Animation.ScaleTimeline.new(#values) + elseif timelineName == "shear" then + timeline = Animation.ShearTimeline.new(#values) + else + timeline = Animation.TranslateTimeline.new(#values) + timelineScale = self.scale + end + timeline.boneIndex = boneIndex + + local frameIndex = 0 + for i,valueMap in ipairs(values) do + local x = (valueMap["x"] or 0) * timelineScale + local y = (valueMap["y"] or 0) * timelineScale + timeline:setFrame(frameIndex, valueMap["time"], x, y) + readCurve(valueMap, timeline, frameIndex) + frameIndex = frameIndex + 1 + end + table_insert(timelines, timeline) + duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.TranslateTimeline.ENTRIES]) + else + error("Invalid timeline type for a bone: " .. timelineName .. " (" .. boneName .. ")") + end + end + end + end + + -- IK timelines. + local ik = map["ik"] + if ik then + for ikConstraintName,values in pairs(ik) do + local ikConstraint = skeletonData:findIkConstraint(ikConstraintName) + local timeline = Animation.IkConstraintTimeline.new(#values) + for i,other in pairs(skeletonData.ikConstraints) do + if other == ikConstraint then + timeline.ikConstraintIndex = i + break + end + end + local frameIndex = 0 + for i,valueMap in ipairs(values) do + local mix = 1 + if valueMap["mix"] ~= nil then mix = valueMap["mix"] end + local bendPositive = 1 + if valueMap["bendPositive"] == false then bendPositive = -1 end + timeline:setFrame(frameIndex, valueMap["time"], mix, bendPositive) + readCurve(valueMap, timeline, frameIndex) + frameIndex = frameIndex + 1 + end + table_insert(timelines, timeline) + duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.IkConstraintTimeline.ENTRIES]) + end + end + + -- Transform constraint timelines. + local transform = map["transform"] + if transform then + for constraintName, values in pairs(transform) do + local constraint = skeletonData:findTransformConstraint(constraintName) + local timeline = Animation.TransformConstraintTimeline.new(#values) + for i,other in pairs(skeletonData.transformConstraints) do + if other == constraint then + timeline.transformConstraintIndex = i + break + end + end + local frameIndex = 0 + for i,valueMap in ipairs(values) do + timeline:setFrame(frameIndex, valueMap.time, getValue(valueMap, "rotateMix", 1), getValue(valueMap, "translateMix", 1), getValue(valueMap, "scaleMix", 1), getValue(valueMap, "shearMix", 1)) + readCurve(valueMap, timeline, frameIndex) + frameIndex = frameIndex + 1 + end + table_insert(timelines, timeline) + duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.TransformConstraintTimeline.ENTRIES]) + end + end + + -- Path constraint timelines. + if map.paths then + for constraintName,constraintMap in pairs(map.paths) do + local index = skeletonData:findPathConstraintIndex(constraintName) + if index == -1 then error("Path constraint not found: " .. constraintName, 2) end + local data = skeletonData.pathConstraints[index] + for timelineName, timelineMap in pairs(constraintMap) do + if timelineName == "position" or timelineName == "spacing" then + local timeline = nil + local timelineScale = 1 + if timelineName == "spacing" then + timeline = Animation.PathConstraintSpacingTimeline.new(#timelineMap) + if data.spacingMode == PathConstraintData.SpacingMode.length or data.spacingMode == PathConstraintData.SpacingMode.fixed then timelineScale = scale end + else + timeline = Animation.PathConstraintPositionTimeline.new(#timelineMap) + if data.positionMode == PathConstraintData.PositionMode.fixed then timelineScale = scale end + end + timeline.pathConstraintIndex = index + local frameIndex = 0 + for i,valueMap in ipairs(timelineMap) do + timeline:setFrame(frameIndex, valueMap.time, getValue(valueMap, timelineName, 0) * timelineScale) + readCurve(valueMap, timeline, frameIndex) + frameIndex = frameIndex + 1 + end + table_insert(timelines, timeline) + duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.PathConstraintPositionTimeline.ENTRIES]) + elseif timelineName == "mix" then + local timeline = Animation.PathConstraintMixTimeline.new(#timelineMap) + timeline.pathConstraintIndex = index + local frameIndex = 0 + for i,valueMap in ipairs(timelineMap) do + timeline:setFrame(frameIndex, valueMap.time, getValue(valueMap, "rotateMix", 1), getValue(valueMap, "translateMix", 1)) + readCurve(valueMap, timeline, frameIndex) + frameIndex = frameIndex + 1 + end + table_insert(timelines, timeline) + duration = math.max(duration, timeline.frames[(timeline:getFrameCount() - 1) * Animation.PathConstraintMixTimeline.ENTRIES]) + end + end + end + end + + -- Deform timelines. + if map.deform then + for deformName, deformMap in pairs(map.deform) do + local skin = skeletonData:findSkin(deformName) + if not skin then error("Skin not found: " .. deformName, 2) end + for slotName,slotMap in pairs(deformMap) do + local slotIndex = skeletonData:findSlotIndex(slotName) + if slotIndex == -1 then error("Slot not found: " .. slotMap.name, 2) end + for timelineName,timelineMap in pairs(slotMap) do + local attachment = skin:getAttachment(slotIndex, timelineName) + if not attachment then error("Deform attachment not found: " .. timelineMap.name, 2) end + local weighted = attachment.bones ~= nil + local vertices = attachment.vertices; + local deformLength = #vertices + if weighted then deformLength = math.floor(#vertices / 3) * 2 end + + local timeline = Animation.DeformTimeline.new(#timelineMap) + timeline.slotIndex = slotIndex + timeline.attachment = attachment + + local frameIndex = 0 + for i,valueMap in ipairs(timelineMap) do + local deform = nil + local verticesValue = getValue(valueMap, "vertices", nil) + if verticesValue == nil then + deform = vertices + if weighted then deform = utils.newNumberArray(deformLength) end + else + deform = utils.newNumberArray(deformLength) + local start = getValue(valueMap, "offset", 0) + 1 + utils.arrayCopy(verticesValue, 1, deform, start, #verticesValue) + if scale ~= 1 then + local i = start + local n = i + #verticesValue + while i < n do + deform[i] = deform[i] * scale + i = i + 1 + end + end + if not weighted then + local i = 1 + local n = i + deformLength + while i < n do + deform[i] = deform[i] + vertices[i] + i = i + 1 + end + end + end + + timeline:setFrame(frameIndex, valueMap.time, deform) + readCurve(valueMap, timeline, frameIndex) + frameIndex = frameIndex + 1 + end + table_insert(timelines, timeline) + duration = math.max(duration, timeline.frames[timeline:getFrameCount() - 1]) + end + end + end + end + + -- Draworder timeline. + local drawOrderValues = map["drawOrder"] + if not drawOrderValues then drawOrderValues = map["draworder"] end + if drawOrderValues then + local timeline = Animation.DrawOrderTimeline.new(#drawOrderValues) + local slotCount = #skeletonData.slots + local frameIndex = 0 + for i,drawOrderMap in ipairs(drawOrderValues) do + local drawOrder = nil + local offsets = drawOrderMap["offsets"] + if offsets then + drawOrder = {} + local unchanged = {} + local originalIndex = 1 + local unchangedIndex = 1 + for ii,offsetMap in ipairs(offsets) do + local slotIndex = skeletonData:findSlotIndex(offsetMap["slot"]) + if slotIndex == -1 then error("Slot not found: " .. offsetMap["slot"]) end + -- Collect unchanged items. + while originalIndex ~= slotIndex do + unchanged[unchangedIndex] = originalIndex + unchangedIndex = unchangedIndex + 1 + originalIndex = originalIndex + 1 + end + -- Set changed items. + drawOrder[originalIndex + offsetMap["offset"]] = originalIndex + originalIndex = originalIndex + 1 + end + -- Collect remaining unchanged items. + while originalIndex <= slotCount do + unchanged[unchangedIndex] = originalIndex + unchangedIndex = unchangedIndex + 1 + originalIndex = originalIndex + 1 + end + -- Fill in unchanged items. + for ii = slotCount, 1, -1 do + if not drawOrder[ii] then + unchangedIndex = unchangedIndex - 1 + drawOrder[ii] = unchanged[unchangedIndex] + end + end + end + timeline:setFrame(frameIndex, drawOrderMap["time"], drawOrder) + frameIndex = frameIndex + 1 + end + table_insert(timelines, timeline) + duration = math.max(duration, timeline.frames[timeline:getFrameCount() - 1]) + end + + -- Event timeline. + local events = map["events"] + if events then + local timeline = Animation.EventTimeline.new(#events) + local frameIndex = 0 + for i,eventMap in ipairs(events) do + local eventData = skeletonData:findEvent(eventMap["name"]) + if not eventData then error("Event not found: " .. eventMap["name"]) end + local event = Event.new(eventMap["time"], eventData) + if eventMap["int"] ~= nil then + event.intValue = eventMap["int"] + else + event.intValue = eventData.intValue + end + if eventMap["float"] ~= nil then + event.floatValue = eventMap["float"] + else + event.floatValue = eventData.floatValue + end + if eventMap["string"] ~= nil then + event.stringValue = eventMap["string"] + else + event.stringValue = eventData.stringValue + end + timeline:setFrame(frameIndex, event) + frameIndex = frameIndex + 1 + end + table_insert(timelines, timeline) + duration = math.max(duration, timeline.frames[timeline:getFrameCount() - 1]) + end + + table_insert(skeletonData.animations, Animation.new(name, timelines, duration)) + end + + readCurve = function (map, timeline, frameIndex) + local curve = map["curve"] + if not curve then return end + if curve == "stepped" then + timeline:setStepped(frameIndex) + elseif #curve > 0 then + timeline:setCurve(frameIndex, curve[1], curve[2], curve[3], curve[4]) + end + end + + getArray = function (map, name, scale) + local list = map[name] + local values = {} + if scale == 1 then + for i = 1, #list do + values[i] = list[i] + end + else + for i = 1, #list do + values[i] = list[i] * scale + end + end + return values + end + + return self +end return SkeletonJson diff --git a/spine-lua/Skin.lua b/spine-lua/Skin.lua index e8386167b2..e34d8c40ec 100644 --- a/spine-lua/Skin.lua +++ b/spine-lua/Skin.lua @@ -1,99 +1,98 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local setmetatable = setmetatable -local table_insert = table.insert - -local Skin = {} -Skin.__index = Skin - -function Skin.new (name) - if not name then error("name cannot be nil", 2) end - - local self = { - name = name, - attachments = {} - } - setmetatable(self, Skin) - - return self -end - -function Skin:addAttachment (slotIndex, name, attachment) - if not name then error("name cannot be nil.", 2) end - if not self.attachments[slotIndex] then self.attachments[slotIndex] = {} end - self.attachments[slotIndex][name] = attachment -end - -function Skin:getAttachment (slotIndex, name) - if not name then error("name cannot be nil.", 2) end - local dictionary = self.attachments[slotIndex] - if dictionary then - return dictionary[name] - else - return nil - end -end - -function Skin:attachAll(skeleton, oldSkin) - local slotIndex = 0 - for i, slot in ipairs(skeleton.slots) do - local slotAttachment = slot.attachment - if slotAttachment and slotIndex <= #oldSkin.attachments then - local dictionary = oldSkin.attachments[slotIndex] - for key, value in dictionary do - local skinAttachment = value - if slotAttachment == skinAttachment then - local attachment = getAttachment(slotIndex, key) - if attachment then slot.attachment = attachment end - break - end - end - end - slotIndex = slotIndex + 1 - end -end - -function Skin:findNamesForSlot (slotIndex) - local names = {} - for k,v in self.attachments do - if v[1] == slotIndex then table_insert(names, v[2]) end - end -end - -function Skin:findAttachmentsForSlot (slotIndex) - local attachments = {} - for k,v in self.attachments do - if v[1] == slotIndex then table_insert(attachments, v[3]) end - end -end -return Skin \ No newline at end of file +local setmetatable = setmetatable +local table_insert = table.insert + +local Skin = {} +Skin.__index = Skin + +function Skin.new (name) + if not name then error("name cannot be nil", 2) end + + local self = { + name = name, + attachments = {} + } + setmetatable(self, Skin) + + return self +end + +function Skin:addAttachment (slotIndex, name, attachment) + if not name then error("name cannot be nil.", 2) end + if not self.attachments[slotIndex] then self.attachments[slotIndex] = {} end + self.attachments[slotIndex][name] = attachment +end + +function Skin:getAttachment (slotIndex, name) + if not name then error("name cannot be nil.", 2) end + local dictionary = self.attachments[slotIndex] + if dictionary then + return dictionary[name] + else + return nil + end +end + +function Skin:attachAll(skeleton, oldSkin) + local slotIndex = 0 + for i, slot in ipairs(skeleton.slots) do + local slotAttachment = slot.attachment + if slotAttachment and slotIndex <= #oldSkin.attachments then + local dictionary = oldSkin.attachments[slotIndex] + for key, value in dictionary do + local skinAttachment = value + if slotAttachment == skinAttachment then + local attachment = getAttachment(slotIndex, key) + if attachment then slot.attachment = attachment end + break + end + end + end + slotIndex = slotIndex + 1 + end +end + +function Skin:findNamesForSlot (slotIndex) + local names = {} + for k,v in self.attachments do + if v[1] == slotIndex then table_insert(names, v[2]) end + end +end + +function Skin:findAttachmentsForSlot (slotIndex) + local attachments = {} + for k,v in self.attachments do + if v[1] == slotIndex then table_insert(attachments, v[3]) end + end +end + +return Skin diff --git a/spine-lua/SkinnedMeshAttachment.lua b/spine-lua/SkinnedMeshAttachment.lua index ec9d6b3f77..d7115b6474 100644 --- a/spine-lua/SkinnedMeshAttachment.lua +++ b/spine-lua/SkinnedMeshAttachment.lua @@ -1,132 +1,131 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local AttachmentType = require "spine-lua.AttachmentType" - -local SkinnedMeshAttachment = {} -function SkinnedMeshAttachment.new (name) - if not name then error("name cannot be nil", 2) end - - local self = { - name = name, - type = AttachmentType.skinnedmesh, - bones = nil, - weights = nil, - uvs = nil, - regionUVs = nil, - triangles = nil, - hullLength = 0, - r = 1, g = 1, b = 1, a = 1, - path = nil, - rendererObject = nil, - regionU = 0, regionV = 0, regionU2 = 1, regionV2 = 1, regionRotate = false, - regionOffsetX = 0, regionOffsetY = 0, - regionWidth = 0, regionHeight = 0, - regionOriginalWidth = 0, regionOriginalHeight = 0, - edges = nil, - width = 0, height = 0 - } - - function self:updateUVs () - local width, height = self.regionU2 - self.regionU, self.regionV2 - self.regionV - local n = #self.regionUVs - if not self.uvs or #self.uvs ~= n then - self.uvs = {} - end - if self.regionRotate then - for i = 1, n, 2 do - self.uvs[i] = self.regionU + self.regionUVs[i + 1] * width - self.uvs[i + 1] = self.regionV + height - self.regionUVs[i] * height - end - else - for i = 1, n, 2 do - self.uvs[i] = self.regionU + self.regionUVs[i] * width - self.uvs[i + 1] = self.regionV + self.regionUVs[i + 1] * height - end - end - end - - function self:computeWorldVertices (x, y, slot, worldVertices) - local skeletonBones = slot.bone.skeleton.bones -x,y=slot.bone.skeleton.x,slot.bone.skeleton.y - local weights = self.weights - local bones = self.bones - local w, v, b, f = 1, 1, 1, 1 - local n = #bones - local wx, wy, bone, vx, vy, weight - if slot.attachmentVerticesCount == 0 then - while v <= n do - wx = 0 - wy = 0 - local nn = bones[v] + v - v = v + 1 - while v <= nn do - bone = skeletonBones[bones[v] + 1] - vx = weights[b] - vy = weights[b + 1] - weight = weights[b + 2] - wx = wx + (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight - wy = wy + (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight - v = v + 1 - b = b + 3 - end - worldVertices[w] = wx + x - worldVertices[w + 1] = wy + y - w = w + 2 - end - else - local ffd = slot.attachmentVertices - while v <= n do - wx = 0 - wy = 0 - local nn = bones[v] + v - v = v + 1 - while v <= nn do - bone = skeletonBones[bones[v] + 1] - vx = weights[b] + ffd[f] - vy = weights[b + 1] + ffd[f + 1] - weight = weights[b + 2] - wx = wx + (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight - wy = wy + (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight - v = v + 1 - b = b + 3 - f = f + 2 - end - worldVertices[w] = wx + x - worldVertices[w + 1] = wy + y - w = w + 2 - end - end - end - return self -end +local AttachmentType = require "spine-lua.AttachmentType" + +local SkinnedMeshAttachment = {} +function SkinnedMeshAttachment.new (name) + if not name then error("name cannot be nil", 2) end + + local self = { + name = name, + type = AttachmentType.skinnedmesh, + bones = nil, + weights = nil, + uvs = nil, + regionUVs = nil, + triangles = nil, + hullLength = 0, + r = 1, g = 1, b = 1, a = 1, + path = nil, + rendererObject = nil, + regionU = 0, regionV = 0, regionU2 = 1, regionV2 = 1, regionRotate = false, + regionOffsetX = 0, regionOffsetY = 0, + regionWidth = 0, regionHeight = 0, + regionOriginalWidth = 0, regionOriginalHeight = 0, + edges = nil, + width = 0, height = 0 + } + + function self:updateUVs () + local width, height = self.regionU2 - self.regionU, self.regionV2 - self.regionV + local n = #self.regionUVs + if not self.uvs or #self.uvs ~= n then + self.uvs = {} + end + if self.regionRotate then + for i = 1, n, 2 do + self.uvs[i] = self.regionU + self.regionUVs[i + 1] * width + self.uvs[i + 1] = self.regionV + height - self.regionUVs[i] * height + end + else + for i = 1, n, 2 do + self.uvs[i] = self.regionU + self.regionUVs[i] * width + self.uvs[i + 1] = self.regionV + self.regionUVs[i + 1] * height + end + end + end + + function self:computeWorldVertices (x, y, slot, worldVertices) + local skeletonBones = slot.bone.skeleton.bones +x,y=slot.bone.skeleton.x,slot.bone.skeleton.y + local weights = self.weights + local bones = self.bones + local w, v, b, f = 1, 1, 1, 1 + local n = #bones + local wx, wy, bone, vx, vy, weight + if slot.attachmentVerticesCount == 0 then + while v <= n do + wx = 0 + wy = 0 + local nn = bones[v] + v + v = v + 1 + while v <= nn do + bone = skeletonBones[bones[v] + 1] + vx = weights[b] + vy = weights[b + 1] + weight = weights[b + 2] + wx = wx + (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight + wy = wy + (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight + v = v + 1 + b = b + 3 + end + worldVertices[w] = wx + x + worldVertices[w + 1] = wy + y + w = w + 2 + end + else + local ffd = slot.attachmentVertices + while v <= n do + wx = 0 + wy = 0 + local nn = bones[v] + v + v = v + 1 + while v <= nn do + bone = skeletonBones[bones[v] + 1] + vx = weights[b] + ffd[f] + vy = weights[b + 1] + ffd[f + 1] + weight = weights[b + 2] + wx = wx + (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight + wy = wy + (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight + v = v + 1 + b = b + 3 + f = f + 2 + end + worldVertices[w] = wx + x + worldVertices[w + 1] = wy + y + w = w + 2 + end + end + end + + return self +end return SkinnedMeshAttachment diff --git a/spine-lua/Slot.lua b/spine-lua/Slot.lua index f1e0027e13..671c7cff82 100644 --- a/spine-lua/Slot.lua +++ b/spine-lua/Slot.lua @@ -1,85 +1,85 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- -local setmetatable = setmetatable - -local Color = require "spine-lua.Color" - -local Slot = {} -Slot.__index = Slot - -function Slot.new (data, bone) - if not data then error("slotData cannot be nil", 2) end - if not bone then error("bone cannot be nil", 2) end - - local self = { - data = data, - bone = bone, - color = Color.newWith(1, 1, 1, 1), - attachment = nil, - attachmentTime = 0, - attachmentVertices = {}, - attachmentVerticesCount = 0 - } - setmetatable(self, Slot) - - self:setToSetupPose() - - return self -end - -function Slot:setAttachment (attachment) - if self.attachment == attachment then return end - self.attachment = attachment - self.attachmentTime = self.bone.skeleton.time - self.attachmentVerticesCount = 0 -end - -function Slot:setAttachmentTime (time) - self.attachmentTime = self.bone.skeleton.time - time -end - -function Slot:getAttachmentTime () - return self.bone.skeleton.time - self.attachmentTime -end - -function Slot:setToSetupPose () - local data = self.data - - self.color:setFrom(data.color) - - local attachment = nil - if data.attachmentName then - attachment = self.bone.skeleton:getAttachmentByIndex(data.index, data.attachmentName) - end - self:setAttachment(attachment) -end -return Slot \ No newline at end of file +local setmetatable = setmetatable + +local Color = require "spine-lua.Color" + +local Slot = {} +Slot.__index = Slot + +function Slot.new (data, bone) + if not data then error("slotData cannot be nil", 2) end + if not bone then error("bone cannot be nil", 2) end + + local self = { + data = data, + bone = bone, + color = Color.newWith(1, 1, 1, 1), + attachment = nil, + attachmentTime = 0, + attachmentVertices = {}, + attachmentVerticesCount = 0 + } + setmetatable(self, Slot) + + self:setToSetupPose() + + return self +end + +function Slot:setAttachment (attachment) + if self.attachment == attachment then return end + self.attachment = attachment + self.attachmentTime = self.bone.skeleton.time + self.attachmentVerticesCount = 0 +end + +function Slot:setAttachmentTime (time) + self.attachmentTime = self.bone.skeleton.time - time +end + +function Slot:getAttachmentTime () + return self.bone.skeleton.time - self.attachmentTime +end + +function Slot:setToSetupPose () + local data = self.data + + self.color:setFrom(data.color) + + local attachment = nil + if data.attachmentName then + attachment = self.bone.skeleton:getAttachmentByIndex(data.index, data.attachmentName) + end + self:setAttachment(attachment) +end + +return Slot diff --git a/spine-lua/SlotData.lua b/spine-lua/SlotData.lua index 7c41131fa7..d98056cc50 100644 --- a/spine-lua/SlotData.lua +++ b/spine-lua/SlotData.lua @@ -1,58 +1,57 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local BlendMode = require "spine-lua.BlendMode" -local Color = require "spine-lua.Color" - -local setmetatable = setmetatable - -local SlotData = {} -SlotData.__index = SlotData - -function SlotData.new (index, name, boneData) - if index < 0 then error("index must be >= 0", 2) end - if not name then error("name cannot be nil", 2) end - if not boneData then error("boneData cannot be nil", 2) end - - local self = { - index = index, - name = name, - boneData = boneData, - color = Color.newWith(1, 1, 1, 1), - attachmentName = nil, - blendMode = BlendMode.normal - } - setmetatable(self, SlotData) - - return self -end +local BlendMode = require "spine-lua.BlendMode" +local Color = require "spine-lua.Color" + +local setmetatable = setmetatable + +local SlotData = {} +SlotData.__index = SlotData + +function SlotData.new (index, name, boneData) + if index < 0 then error("index must be >= 0", 2) end + if not name then error("name cannot be nil", 2) end + if not boneData then error("boneData cannot be nil", 2) end + + local self = { + index = index, + name = name, + boneData = boneData, + color = Color.newWith(1, 1, 1, 1), + attachmentName = nil, + blendMode = BlendMode.normal + } + setmetatable(self, SlotData) + + return self +end + return SlotData diff --git a/spine-lua/TextureAtlas.lua b/spine-lua/TextureAtlas.lua index 77c0adb673..9192fe129b 100644 --- a/spine-lua/TextureAtlas.lua +++ b/spine-lua/TextureAtlas.lua @@ -1,244 +1,244 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- -local setmetatable = setmetatable -local table_insert = table.insert -local math_abs = math.abs - -local TextureAtlasRegion = require "spine-lua.TextureAtlasRegion" -local TextureWrap = require "spine-lua.TextureWrap" -local TextureFilter = require "spine-lua.TextureFilter" - -local TextureAtlasPage = {} -TextureAtlasPage.__index = TextureAtlasPage - -function TextureAtlasPage.new () - local self = { - name = nil, - minFilter = nil, - magFilter = nil, - uWrap = nil, - vWrap = nil, - texture = nil, - width = 0, - height = 0 - } - setmetatable(self, TextureAtlasPage) - return self -end - - -local TextureAtlas = {} -TextureAtlas.__index = TextureAtlas - -function TextureAtlas.new (atlasContent, imageLoader) - local self = { - pages = {}, - regions = {} - } - setmetatable(self, TextureAtlas) - - self:parse(atlasContent, imageLoader) - - return self -end - -function TextureAtlas:parse (atlasContent, imageLoader) - if not atlasContent then error("atlasContent cannot be nil.", 2) end - if not imageLoader then error("imageLoader cannot be nil.", 2) end - - local lines = {} - local index = 0 - local numLines = 0 - for line in atlasContent:gmatch("[^\r\n]+") do - lines[numLines] = line - numLines = numLines + 1 - end - - local readLine = function () - if index >= numLines then return nil end - local line = lines[index] - index = index + 1 - return line - end - - local readValue = function () - local line = readLine() - local idx = line:find(":") - if not idx then error("Invalid line: " .. line, 2) end - return line:sub(idx + 1):match'^%s*(.*%S)' or '' - end - - local readTuple = function () - local line = readLine() - local idx = line:find(":") - if not idx then error("Invalid line: " .. line, 2) end - local i = 1 - local lastMatch = idx + 1 - local tuple = {} - while i <= 3 do - local comma = line:find(",", lastMatch) - if not comma then break end - tuple[i] = line:sub(lastMatch, comma - 1):match'^%s*(.*%S)' or '' - lastMatch = comma + 1 - i = i + 1 - end - tuple[i] = line:sub(lastMatch):match'^%s*(.*%S)' or '' - return tuple - end - - local parseInt = function (str) - return tonumber(str) - end - - local filterFromString = function (str) - str = str:lower() - if str == "nearest" then return TextureFilter.Nearest - elseif str == "linear" then return TextureFilter.Linear - elseif str == "mipmap" then return TextureFilter.MipMap - elseif str == "mipmapnearestnearest" then return TextureFilter.MipMapNearestNearest - elseif str == "mipmaplinearnearest" then return TextureFilter.MipMapLinearNearest - elseif str == "mipmapnearestlinear" then return TextureFilter.MipMapNearestLinear - elseif str == "mipmaplinearlinear" then return TextureFilter.MipMapLinearLinear - else error("Unknown texture wrap: " .. str, 2) - end - end - - local page = nil - while true do - local line = readLine() - if not line then break end - line = line:match'^%s*(.*%S)' or '' - if line:len() == 0 then - page = nil - elseif not page then - page = TextureAtlasPage.new() - page.name = line - - local tuple = readTuple() - if #tuple == 2 then - page.width = parseInt(tuple[1]) - page.height = parseInt(tuple[2]) - tuple = readTuple() - else - -- We only support atlases that have the page width/height - -- encoded in them. That way we don't rely on any special - -- wrapper objects for images to get the page size from - error("Atlas must specify page width/height. Please export to the latest atlas format", 2) - end - - tuple = readTuple() - page.minFilter = filterFromString(tuple[1]) - page.magFilter = filterFromString(tuple[2]) - - local direction = readValue() - page.uWrap = TextureWrap.ClampToEdge - page.vWrap = TextureWrap.ClampToEdge - if direction == "x" then - page.uWrap = TextureWrap.Repeat - elseif direction == "y" then - page.vWrap = TextureWrap.Repeat - elseif direction == "xy" then - page.uWrap = TextureWrap.Repeat - page.vWrap = TextureWrap.Repeat - end - - page.texture = imageLoader(line) - -- FIXME page.texture:setFilters(page.minFilter, page.magFilter) - -- FIXME page.texture:setWraps(page.uWrap, page.vWrap) - table_insert(self.pages, page) - else - local region = TextureAtlasRegion.new() - region.name = line - region.page = page - - if readValue() == "true" then region.rotate = true end - - local tuple = readTuple() - local x = parseInt(tuple[1]) - local y = parseInt(tuple[2]) - - tuple = readTuple() - local width = parseInt(tuple[1]) - local height = parseInt(tuple[2]) - - region.u = x / page.width - region.v = y / page.height - if region.rotate then - region.u2 = (x + height) / page.width - region.v2 = (y + width) / page.height - else - region.u2 = (x + width) / page.width - region.v2 = (y + height) / page.height - end - - region.x = x - region.y = y - region.width = math_abs(width) - region.height = math_abs(height) - - -- Read and skip optional splits - tuple = readTuple() - if #tuple == 4 then - tuple = readTuple() - if #tuple == 4 then - readTuple() - end - end - - region.originalWidth = parseInt(tuple[1]) - region.originalHeight = parseInt(tuple[2]) - - tuple = readTuple() - region.offsetX = parseInt(tuple[1]) - region.offsetY = parseInt(tuple[2]) - - region.index = parseInt(readValue()) - region.texture = page.texture - table_insert(self.regions, region) - end - end -end - -function TextureAtlas:findRegion(name) - for i, region in ipairs(self.regions) do - if region.name == name then return region end - end - return nil -end - -function TextureAtlas:dispose() - for i, page in ipairs(self.pairs) do - -- FIXME implement disposing of pages - -- love2d doesn't support manual disposing - end -end +local setmetatable = setmetatable +local table_insert = table.insert +local math_abs = math.abs + +local TextureAtlasRegion = require "spine-lua.TextureAtlasRegion" +local TextureWrap = require "spine-lua.TextureWrap" +local TextureFilter = require "spine-lua.TextureFilter" + +local TextureAtlasPage = {} +TextureAtlasPage.__index = TextureAtlasPage + +function TextureAtlasPage.new () + local self = { + name = nil, + minFilter = nil, + magFilter = nil, + uWrap = nil, + vWrap = nil, + texture = nil, + width = 0, + height = 0 + } + setmetatable(self, TextureAtlasPage) + return self +end + + +local TextureAtlas = {} +TextureAtlas.__index = TextureAtlas + +function TextureAtlas.new (atlasContent, imageLoader) + local self = { + pages = {}, + regions = {} + } + setmetatable(self, TextureAtlas) + + self:parse(atlasContent, imageLoader) + + return self +end + +function TextureAtlas:parse (atlasContent, imageLoader) + if not atlasContent then error("atlasContent cannot be nil.", 2) end + if not imageLoader then error("imageLoader cannot be nil.", 2) end + + local lines = {} + local index = 0 + local numLines = 0 + for line in atlasContent:gmatch("[^\r\n]+") do + lines[numLines] = line + numLines = numLines + 1 + end + + local readLine = function () + if index >= numLines then return nil end + local line = lines[index] + index = index + 1 + return line + end + + local readValue = function () + local line = readLine() + local idx = line:find(":") + if not idx then error("Invalid line: " .. line, 2) end + return line:sub(idx + 1):match'^%s*(.*%S)' or '' + end + + local readTuple = function () + local line = readLine() + local idx = line:find(":") + if not idx then error("Invalid line: " .. line, 2) end + local i = 1 + local lastMatch = idx + 1 + local tuple = {} + while i <= 3 do + local comma = line:find(",", lastMatch) + if not comma then break end + tuple[i] = line:sub(lastMatch, comma - 1):match'^%s*(.*%S)' or '' + lastMatch = comma + 1 + i = i + 1 + end + tuple[i] = line:sub(lastMatch):match'^%s*(.*%S)' or '' + return tuple + end + + local parseInt = function (str) + return tonumber(str) + end + + local filterFromString = function (str) + str = str:lower() + if str == "nearest" then return TextureFilter.Nearest + elseif str == "linear" then return TextureFilter.Linear + elseif str == "mipmap" then return TextureFilter.MipMap + elseif str == "mipmapnearestnearest" then return TextureFilter.MipMapNearestNearest + elseif str == "mipmaplinearnearest" then return TextureFilter.MipMapLinearNearest + elseif str == "mipmapnearestlinear" then return TextureFilter.MipMapNearestLinear + elseif str == "mipmaplinearlinear" then return TextureFilter.MipMapLinearLinear + else error("Unknown texture wrap: " .. str, 2) + end + end + + local page = nil + while true do + local line = readLine() + if not line then break end + line = line:match'^%s*(.*%S)' or '' + if line:len() == 0 then + page = nil + elseif not page then + page = TextureAtlasPage.new() + page.name = line + + local tuple = readTuple() + if #tuple == 2 then + page.width = parseInt(tuple[1]) + page.height = parseInt(tuple[2]) + tuple = readTuple() + else + -- We only support atlases that have the page width/height + -- encoded in them. That way we don't rely on any special + -- wrapper objects for images to get the page size from + error("Atlas must specify page width/height. Please export to the latest atlas format", 2) + end + + tuple = readTuple() + page.minFilter = filterFromString(tuple[1]) + page.magFilter = filterFromString(tuple[2]) + + local direction = readValue() + page.uWrap = TextureWrap.ClampToEdge + page.vWrap = TextureWrap.ClampToEdge + if direction == "x" then + page.uWrap = TextureWrap.Repeat + elseif direction == "y" then + page.vWrap = TextureWrap.Repeat + elseif direction == "xy" then + page.uWrap = TextureWrap.Repeat + page.vWrap = TextureWrap.Repeat + end + + page.texture = imageLoader(line) + -- FIXME page.texture:setFilters(page.minFilter, page.magFilter) + -- FIXME page.texture:setWraps(page.uWrap, page.vWrap) + table_insert(self.pages, page) + else + local region = TextureAtlasRegion.new() + region.name = line + region.page = page + + if readValue() == "true" then region.rotate = true end + + local tuple = readTuple() + local x = parseInt(tuple[1]) + local y = parseInt(tuple[2]) + + tuple = readTuple() + local width = parseInt(tuple[1]) + local height = parseInt(tuple[2]) + + region.u = x / page.width + region.v = y / page.height + if region.rotate then + region.u2 = (x + height) / page.width + region.v2 = (y + width) / page.height + else + region.u2 = (x + width) / page.width + region.v2 = (y + height) / page.height + end + + region.x = x + region.y = y + region.width = math_abs(width) + region.height = math_abs(height) + + -- Read and skip optional splits + tuple = readTuple() + if #tuple == 4 then + tuple = readTuple() + if #tuple == 4 then + readTuple() + end + end + + region.originalWidth = parseInt(tuple[1]) + region.originalHeight = parseInt(tuple[2]) + + tuple = readTuple() + region.offsetX = parseInt(tuple[1]) + region.offsetY = parseInt(tuple[2]) + + region.index = parseInt(readValue()) + region.texture = page.texture + table_insert(self.regions, region) + end + end +end + +function TextureAtlas:findRegion(name) + for i, region in ipairs(self.regions) do + if region.name == name then return region end + end + return nil +end + +function TextureAtlas:dispose() + for i, page in ipairs(self.pairs) do + -- FIXME implement disposing of pages + -- love2d doesn't support manual disposing + end +end + return TextureAtlas diff --git a/spine-lua/TextureAtlasAttachmentLoader.lua b/spine-lua/TextureAtlasAttachmentLoader.lua index c1100f0b1e..c6ee7ebeb8 100644 --- a/spine-lua/TextureAtlasAttachmentLoader.lua +++ b/spine-lua/TextureAtlasAttachmentLoader.lua @@ -1,82 +1,82 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- -local setmetatable = setmetatable - -local AttachmentType = require "spine-lua.attachments.AttachmentType" -local RegionAttachment = require "spine-lua.attachments.RegionAttachment" -local BoundingBoxAttachment = require "spine-lua.attachments.BoundingBoxAttachment" -local MeshAttachment = require "spine-lua.attachments.MeshAttachment" -local PathAttachment = require "spine-lua.attachments.PathAttachment" -local TextureAtlas = require "spine-lua.TextureAtlas" - -local TextureAtlasAttachmentLoader = {} -TextureAtlasAttachmentLoader.__index = TextureAtlasAttachmentLoader - -function TextureAtlasAttachmentLoader.new (atlas) - local self = { - atlas = atlas - } - setmetatable(self, TextureAtlasAttachmentLoader) - return self -end - -function TextureAtlasAttachmentLoader:newRegionAttachment (skin, name, path) - local region = self.atlas:findRegion(path) - if not region then error("Region not found in atlas: " .. path .. " (region attachment: " .. name .. ")") end - region.renderObject = region - local attachment = RegionAttachment.new(name) - attachment:setRegion(region) - attachment.region = region - return attachment -end - -function TextureAtlasAttachmentLoader:newMeshAttachment (skin, name, path) - local region = self.atlas:findRegion(path) - if not region then error("Region not found in atlas: " .. path .. " (mesh attachment: " .. name .. ")") end - region.renderObject = region - local attachment = MeshAttachment.new(name) - attachment.region = region - return attachment -end - -function TextureAtlasAttachmentLoader:newSkinningMeshAttachment (skin, name, path) - return SkinningMeshAttachment.new(name) -end - -function TextureAtlasAttachmentLoader:newBoundingBoxAttachment (skin, name) - return BoundingBoxAttachment.new(name) -end - -function TextureAtlasAttachmentLoader:newPathAttachment(skin, name) - return PathAttachment.new(name) -end +local setmetatable = setmetatable + +local AttachmentType = require "spine-lua.attachments.AttachmentType" +local RegionAttachment = require "spine-lua.attachments.RegionAttachment" +local BoundingBoxAttachment = require "spine-lua.attachments.BoundingBoxAttachment" +local MeshAttachment = require "spine-lua.attachments.MeshAttachment" +local PathAttachment = require "spine-lua.attachments.PathAttachment" +local TextureAtlas = require "spine-lua.TextureAtlas" + +local TextureAtlasAttachmentLoader = {} +TextureAtlasAttachmentLoader.__index = TextureAtlasAttachmentLoader + +function TextureAtlasAttachmentLoader.new (atlas) + local self = { + atlas = atlas + } + setmetatable(self, TextureAtlasAttachmentLoader) + return self +end + +function TextureAtlasAttachmentLoader:newRegionAttachment (skin, name, path) + local region = self.atlas:findRegion(path) + if not region then error("Region not found in atlas: " .. path .. " (region attachment: " .. name .. ")") end + region.renderObject = region + local attachment = RegionAttachment.new(name) + attachment:setRegion(region) + attachment.region = region + return attachment +end + +function TextureAtlasAttachmentLoader:newMeshAttachment (skin, name, path) + local region = self.atlas:findRegion(path) + if not region then error("Region not found in atlas: " .. path .. " (mesh attachment: " .. name .. ")") end + region.renderObject = region + local attachment = MeshAttachment.new(name) + attachment.region = region + return attachment +end + +function TextureAtlasAttachmentLoader:newSkinningMeshAttachment (skin, name, path) + return SkinningMeshAttachment.new(name) +end + +function TextureAtlasAttachmentLoader:newBoundingBoxAttachment (skin, name) + return BoundingBoxAttachment.new(name) +end + +function TextureAtlasAttachmentLoader:newPathAttachment(skin, name) + return PathAttachment.new(name) +end + return TextureAtlasAttachmentLoader diff --git a/spine-lua/TextureAtlasRegion.lua b/spine-lua/TextureAtlasRegion.lua index 86b65497e2..945fffb716 100644 --- a/spine-lua/TextureAtlasRegion.lua +++ b/spine-lua/TextureAtlasRegion.lua @@ -1,53 +1,53 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- -local setmetatable = setmetatable - -local TextureRegion = require "spine-lua.TextureRegion" - -local TextureAtlasRegion = {} -TextureAtlasRegion.__index = TextureAtlasRegion -setmetatable(TextureAtlasRegion, { __index = TextureRegion }) - -function TextureAtlasRegion.new () - local self = TextureRegion.new() - self.page = nil - self.name = nil - self.x = 0 - self.y = 0 - self.index = 0 - self.rotate = false - self.texture = nil - setmetatable(self, TextureAtlasRegion) - - return self -end +local setmetatable = setmetatable + +local TextureRegion = require "spine-lua.TextureRegion" + +local TextureAtlasRegion = {} +TextureAtlasRegion.__index = TextureAtlasRegion +setmetatable(TextureAtlasRegion, { __index = TextureRegion }) + +function TextureAtlasRegion.new () + local self = TextureRegion.new() + self.page = nil + self.name = nil + self.x = 0 + self.y = 0 + self.index = 0 + self.rotate = false + self.texture = nil + setmetatable(self, TextureAtlasRegion) + + return self +end + return TextureAtlasRegion diff --git a/spine-lua/TextureFilter.lua b/spine-lua/TextureFilter.lua index 2f9687555d..d6b6a82394 100644 --- a/spine-lua/TextureFilter.lua +++ b/spine-lua/TextureFilter.lua @@ -1,41 +1,40 @@ -------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- -local TextureFilter = { - Nearest = 0, - Linear = 1, - MipMap = 2, - MipMapNearestNearest = 3, - MipMapLinearNearest = 4, - MipMapNearestLinear = 5, - MipMapLinearLinear = 6 -} +local TextureFilter = { + Nearest = 0, + Linear = 1, + MipMap = 2, + MipMapNearestNearest = 3, + MipMapLinearNearest = 4, + MipMapNearestLinear = 5, + MipMapLinearLinear = 6 +} return TextureFilter diff --git a/spine-lua/TextureRegion.lua b/spine-lua/TextureRegion.lua index 421197da97..4c67a7fc30 100644 --- a/spine-lua/TextureRegion.lua +++ b/spine-lua/TextureRegion.lua @@ -1,52 +1,52 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- -local setmetatable = setmetatable - -local TextureRegion = {} -TextureRegion.__index = TextureRegion - -function TextureRegion.new () - - local self = { - renderObject = nil, - u = 0, v = 0, - u2 = 0, v2 = 0, - width = 0, height = 0, - rotate = false, - offsetX = 0, offsetY = 0, - originalWidth = 0, originalHeight = 0 - } - setmetatable(self, TextureRegion) - - return self -end +local setmetatable = setmetatable + +local TextureRegion = {} +TextureRegion.__index = TextureRegion + +function TextureRegion.new () + + local self = { + renderObject = nil, + u = 0, v = 0, + u2 = 0, v2 = 0, + width = 0, height = 0, + rotate = false, + offsetX = 0, offsetY = 0, + originalWidth = 0, originalHeight = 0 + } + setmetatable(self, TextureRegion) + + return self +end + return TextureRegion diff --git a/spine-lua/TextureWrap.lua b/spine-lua/TextureWrap.lua index 49a2550379..ceaa4e4d4a 100644 --- a/spine-lua/TextureWrap.lua +++ b/spine-lua/TextureWrap.lua @@ -1,36 +1,35 @@ -------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- -local TextureWrap = { - ClampToEdge = 0, - Repeat = 1 -} +local TextureWrap = { + ClampToEdge = 0, + Repeat = 1 +} return TextureWrap diff --git a/spine-lua/TransformConstraint.lua b/spine-lua/TransformConstraint.lua index b306ee18ef..f538753c35 100644 --- a/spine-lua/TransformConstraint.lua +++ b/spine-lua/TransformConstraint.lua @@ -1,151 +1,150 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local setmetatable = setmetatable -local math_pi = math.pi -local math_pi2 = math.pi * 2 -local math_atan2 = math.atan2 -local math_sqrt = math.sqrt -local math_acos = math.acos -local math_sin = math.sin -local math_cos = math.cos -local table_insert = table.insert -local math_deg = math.deg -local math_rad = math.rad -local math_abs = math.abs - -local TransformConstraint = {} -TransformConstraint.__index = TransformConstraint - -function TransformConstraint.new (data, skeleton) - if not data then error("data cannot be nil", 2) end - if not skeleton then error("skeleton cannot be nil", 2) end - - local self = { - data = data, - bones = {}, - target = nil, - rotateMix = data.rotateMix, translateMix = data.translateMix, scaleMix = data.scaleMix, shearMix = data.shearMix, - temp = { 0, 0 } - } - setmetatable(self, TransformConstraint) - - for i,bone in ipairs(data.bones) do - table_insert(self.bones, skeleton:findBone(bone.name)) - end - self.target = skeleton:findBone(data.target.name) - - return self -end - -function TransformConstraint:apply () - self:update() -end - -function TransformConstraint:update () - local rotateMix = self.rotateMix - local translateMix = self.translateMix - local scaleMix = self.scaleMix - local shearMix = self.shearMix - local target = self.target - local ta = target.a - local tb = target.b - local tc = target.c - local td = target.d - local bones = self.bones - for i, bone in ipairs(bones) do - if rotateMix > 0 then - local a = bone.a - local b = bone.b - local c = bone.c - local d = bone.d - local r = math_atan2(tc, ta) - math_atan2(c, a) + math_rad(self.data.offsetRotation); - if r > math_pi then - r = r - math_pi2 - elseif r < -math_pi then - r = r + math_pi2 - end - r = r * rotateMix - local cos = math_cos(r) - local sin = math_sin(r) - bone.a = cos * a - sin * c - bone.b = cos * b - sin * d - bone.c = sin * a + cos * c - bone.d = sin * b + cos * d - end - - if translateMix > 0 then - local temp = self.temp - temp[1] = self.data.offsetX - temp[2] = self.data.offsetY - target:localToWorld(temp) - bone.worldX = bone.worldX + (temp[1] - bone.worldX) * translateMix - bone.worldY = bone.worldY + (temp[2] - bone.worldY) * translateMix - end - - if scaleMix > 0 then - local bs = math_sqrt(bone.a * bone.a + bone.c * bone.c) - local ts = math_sqrt(ta * ta + tc * tc) - local s = 0 - if bs > 0.00001 then - s = (bs + (ts - bs + self.data.offsetScaleX) * scaleMix) / bs - end - bone.a = bone.a * s - bone.c = bone.c * s - bs = math_sqrt(bone.b * bone.b + bone.d * bone.d) - ts = math_sqrt(tb * tb + td * td) - s = 0 - if bs > 0.00001 then - s = (bs + (ts - bs + self.data.offsetScaleY) * scaleMix) / bs - end - bone.b = bone.b * s - bone.d = bone.d * s - end - - if shearMix > 0 then - local b = bone.b - local d = bone.d - local by = math_atan2(d, b) - local r = math_atan2(td, tb) - math_atan2(tc, ta) - (by - math_atan2(bone.c, bone.a)) - if r > math_pi then - r = r - math_pi2 - elseif r < -math_pi then - r = r + math_pi2 - end - r = by + (r + math_rad(self.data.offsetShearY)) * shearMix - local s = math_sqrt(b * b + d * d) - bone.b = math_cos(r) * s - bone.d = math_sin(r) * s - end - end -end -return TransformConstraint \ No newline at end of file +local setmetatable = setmetatable +local math_pi = math.pi +local math_pi2 = math.pi * 2 +local math_atan2 = math.atan2 +local math_sqrt = math.sqrt +local math_acos = math.acos +local math_sin = math.sin +local math_cos = math.cos +local table_insert = table.insert +local math_deg = math.deg +local math_rad = math.rad +local math_abs = math.abs + +local TransformConstraint = {} +TransformConstraint.__index = TransformConstraint + +function TransformConstraint.new (data, skeleton) + if not data then error("data cannot be nil", 2) end + if not skeleton then error("skeleton cannot be nil", 2) end + + local self = { + data = data, + bones = {}, + target = nil, + rotateMix = data.rotateMix, translateMix = data.translateMix, scaleMix = data.scaleMix, shearMix = data.shearMix, + temp = { 0, 0 } + } + setmetatable(self, TransformConstraint) + + for i,bone in ipairs(data.bones) do + table_insert(self.bones, skeleton:findBone(bone.name)) + end + self.target = skeleton:findBone(data.target.name) + + return self +end + +function TransformConstraint:apply () + self:update() +end + +function TransformConstraint:update () + local rotateMix = self.rotateMix + local translateMix = self.translateMix + local scaleMix = self.scaleMix + local shearMix = self.shearMix + local target = self.target + local ta = target.a + local tb = target.b + local tc = target.c + local td = target.d + local bones = self.bones + for i, bone in ipairs(bones) do + if rotateMix > 0 then + local a = bone.a + local b = bone.b + local c = bone.c + local d = bone.d + local r = math_atan2(tc, ta) - math_atan2(c, a) + math_rad(self.data.offsetRotation); + if r > math_pi then + r = r - math_pi2 + elseif r < -math_pi then + r = r + math_pi2 + end + r = r * rotateMix + local cos = math_cos(r) + local sin = math_sin(r) + bone.a = cos * a - sin * c + bone.b = cos * b - sin * d + bone.c = sin * a + cos * c + bone.d = sin * b + cos * d + end + + if translateMix > 0 then + local temp = self.temp + temp[1] = self.data.offsetX + temp[2] = self.data.offsetY + target:localToWorld(temp) + bone.worldX = bone.worldX + (temp[1] - bone.worldX) * translateMix + bone.worldY = bone.worldY + (temp[2] - bone.worldY) * translateMix + end + + if scaleMix > 0 then + local bs = math_sqrt(bone.a * bone.a + bone.c * bone.c) + local ts = math_sqrt(ta * ta + tc * tc) + local s = 0 + if bs > 0.00001 then + s = (bs + (ts - bs + self.data.offsetScaleX) * scaleMix) / bs + end + bone.a = bone.a * s + bone.c = bone.c * s + bs = math_sqrt(bone.b * bone.b + bone.d * bone.d) + ts = math_sqrt(tb * tb + td * td) + s = 0 + if bs > 0.00001 then + s = (bs + (ts - bs + self.data.offsetScaleY) * scaleMix) / bs + end + bone.b = bone.b * s + bone.d = bone.d * s + end + + if shearMix > 0 then + local b = bone.b + local d = bone.d + local by = math_atan2(d, b) + local r = math_atan2(td, tb) - math_atan2(tc, ta) - (by - math_atan2(bone.c, bone.a)) + if r > math_pi then + r = r - math_pi2 + elseif r < -math_pi then + r = r + math_pi2 + end + r = by + (r + math_rad(self.data.offsetShearY)) * shearMix + local s = math_sqrt(b * b + d * d) + bone.b = math_cos(r) * s + bone.d = math_sin(r) * s + end + end +end + +return TransformConstraint diff --git a/spine-lua/TransformConstraintData.lua b/spine-lua/TransformConstraintData.lua index 0aa8ddd6b4..30cc920d4b 100644 --- a/spine-lua/TransformConstraintData.lua +++ b/spine-lua/TransformConstraintData.lua @@ -1,47 +1,46 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local TransformConstraintData = {} -function TransformConstraintData.new (name) - if not name then error("name cannot be nil", 2) end - - local self = { - name = name, - bones = {}, - target = nil, - rotateMix = 0, translateMix = 0, scaleMix = 0, shearMix = 0, - offsetRotation = 0, offsetX = 0, offsetY = 0, offsetScaleX = 0, offsetScaleY = 0, offsetShearY = 0 - } - - return self -end +local TransformConstraintData = {} +function TransformConstraintData.new (name) + if not name then error("name cannot be nil", 2) end + + local self = { + name = name, + bones = {}, + target = nil, + rotateMix = 0, translateMix = 0, scaleMix = 0, shearMix = 0, + offsetRotation = 0, offsetX = 0, offsetY = 0, offsetScaleX = 0, offsetScaleY = 0, offsetShearY = 0 + } + + return self +end + return TransformConstraintData diff --git a/spine-lua/attachments/Attachment.lua b/spine-lua/attachments/Attachment.lua index 5acbd785b4..1bd1c425de 100644 --- a/spine-lua/attachments/Attachment.lua +++ b/spine-lua/attachments/Attachment.lua @@ -1,51 +1,50 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local setmetatable = setmetatable - -local AttachmentType = require "spine-lua.attachments.AttachmentType" - -local Attachment = {} -Attachment.__index = Attachment - -function Attachment.new (name, attachmentType) - if not name then error("name cannot be nil.", 2) end - if not attachmentType then error("attachmentType cannot be nil.", 2) end - - local self = { - name = name, - type = attachmentType - } - setmetatable(self, Attachment) - return self -end -return Attachment \ No newline at end of file +local setmetatable = setmetatable + +local AttachmentType = require "spine-lua.attachments.AttachmentType" + +local Attachment = {} +Attachment.__index = Attachment + +function Attachment.new (name, attachmentType) + if not name then error("name cannot be nil.", 2) end + if not attachmentType then error("attachmentType cannot be nil.", 2) end + + local self = { + name = name, + type = attachmentType + } + setmetatable(self, Attachment) + return self +end + +return Attachment diff --git a/spine-lua/attachments/AttachmentType.lua b/spine-lua/attachments/AttachmentType.lua index 0f6ef0dca6..d4254cc0fe 100644 --- a/spine-lua/attachments/AttachmentType.lua +++ b/spine-lua/attachments/AttachmentType.lua @@ -1,39 +1,38 @@ -------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- -local AttachmentType = { - region = 0, - boundingbox = 1, - mesh = 2, - linkedmesh = 3, - path = 4 -} +local AttachmentType = { + region = 0, + boundingbox = 1, + mesh = 2, + linkedmesh = 3, + path = 4 +} return AttachmentType diff --git a/spine-lua/attachments/BoundingBoxAttachment.lua b/spine-lua/attachments/BoundingBoxAttachment.lua index cb483607b0..ac262099d6 100644 --- a/spine-lua/attachments/BoundingBoxAttachment.lua +++ b/spine-lua/attachments/BoundingBoxAttachment.lua @@ -1,48 +1,47 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local AttachmentType = require "spine-lua.attachments.AttachmentType" -local VertexAttachment = require "spine-lua.attachments.VertexAttachment" -local Color = require "spine-lua.Color" - -local BoundingBoxAttachment = {} -BoundingBoxAttachment.__index = BoundingBoxAttachment -setmetatable(BoundingBoxAttachment, { __index = VertexAttachment }) - -function BoundingBoxAttachment.new (name) - if not name then error("name cannot be nil", 2) end - local self = VertexAttachment.new(name, AttachmentType.boundingbox) - self.color = Color.newWith(1, 1, 1, 1) - setmetatable(self, BoundingBoxAttachment) - return self -end -return BoundingBoxAttachment \ No newline at end of file +local AttachmentType = require "spine-lua.attachments.AttachmentType" +local VertexAttachment = require "spine-lua.attachments.VertexAttachment" +local Color = require "spine-lua.Color" + +local BoundingBoxAttachment = {} +BoundingBoxAttachment.__index = BoundingBoxAttachment +setmetatable(BoundingBoxAttachment, { __index = VertexAttachment }) + +function BoundingBoxAttachment.new (name) + if not name then error("name cannot be nil", 2) end + + local self = VertexAttachment.new(name, AttachmentType.boundingbox) + self.color = Color.newWith(1, 1, 1, 1) + setmetatable(self, BoundingBoxAttachment) + return self +end +return BoundingBoxAttachment diff --git a/spine-lua/attachments/MeshAttachment.lua b/spine-lua/attachments/MeshAttachment.lua index c66823d571..a0373a91ca 100644 --- a/spine-lua/attachments/MeshAttachment.lua +++ b/spine-lua/attachments/MeshAttachment.lua @@ -1,233 +1,232 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local setmetatable = setmetatable -local AttachmentType = require "spine-lua.attachments.AttachmentType" -local VertexAttachment = require "spine-lua.attachments.VertexAttachment" -local utils = require "spine-lua.utils" -local Color = require "spine-lua.Color" - -local MeshAttachment = {} -MeshAttachment.__index = MeshAttachment -setmetatable(MeshAttachment, { __index = VertexAttachment }) - -function MeshAttachment.new (name) - if not name then error("name cannot be nil", 2) end - - local self = VertexAttachment.new(name, AttachmentType.mesh) - self.region = nil - self.path = nil - self.regionUVs = nil - self.worldVertices = nil - self.triangles = nil - self.color = Color.newWith(1, 1, 1, 1) - self.hullLength = 0 - self.parentMesh = nil - self.inheritDeform = false - self.tempColor = Color.newWith(1, 1, 1, 1) - setmetatable(self, MeshAttachment) - return self -end - -function MeshAttachment:updateUVs () - local regionUVs = self.regionUVs - local verticesLength = #regionUVs - local worldVerticesLength = (verticesLength / 2) * 8 - if not self.worldVertices or #self.worldVertices ~= worldVerticesLength then - self.worldVertices = utils.newNumberArray(worldVerticesLength) - end - - local u = 0 - local v = 0 - local width = 0 - local height = 0 - if not self.region then - u = 0 - v = 0 - width = 1 - height = 1 - else - u = self.region.u; - v = self.region.v; - width = self.region.u2 - u; - height = self.region.v2 - v; - end - if self.region and self.region.rotate then - local i = 0 - local w = 2 - while i < verticesLength do - self.worldVertices[w + 1] = u + regionUVs[i + 2] * width; - self.worldVertices[w + 2] = v + height - regionUVs[i + 1] * height; - i = i + 2 - w = w + 8 - end - else - local i = 0 - local w = 2 - while i < verticesLength do - self.worldVertices[w + 1] = u + regionUVs[i + 1] * width; - self.worldVertices[w + 2] = v + regionUVs[i + 2] * height; - i = i + 2 - w = w + 8 - end - end -end - -function MeshAttachment:updateWorldVertices(slot, premultipliedAlpha) - local skeleton = slot.bone.skeleton - local skeletonColor = skeleton.color - local slotColor = slot.color - local meshColor = self.color - - local alpha = skeletonColor.a * slotColor.a * meshColor.a - local multiplier = 1 - if premultipliedAlpha then multiplier = alpha end - local color = self.tempColor - color:set(skeletonColor.r * slotColor.r * meshColor.r * multiplier, - skeletonColor.g * slotColor.g * meshColor.g * multiplier, - skeletonColor.b * slotColor.b * meshColor.b * multiplier, - alpha) - - local x = skeleton.x - local y = skeleton.y - local deformArray = slot.attachmentVertices - local vertices = self.vertices - local worldVertices = self.worldVertices - local bones = self.bones - if not bones then - local verticesLength = #vertices - if #deformArray > 0 then vertices = deformArray end - local bone = slot.bone; - x = x + bone.worldX - y = y + bone.worldY - local a = bone.a - local b = bone.b - local c = bone.c - local d = bone.d - local v = 0 - local w = 0 - while v < verticesLength do - local vx = vertices[v + 1] - local vy = vertices[v + 2] - worldVertices[w + 1] = vx * a + vy * b + x - worldVertices[w + 2] = vx * c + vy * d + y - worldVertices[w + 5] = color.r - worldVertices[w + 6] = color.g - worldVertices[w + 7] = color.b - worldVertices[w + 8] = color.a - v = v + 2 - w = w + 8 - end - return worldVertices - end - - local skeletonBones = skeleton.bones - if #deformArray == 0 then - local w = 0 - local v = 0 - local b = 0 - local n = #bones - while v < n do - local wx = x - local wy = y - local nn = bones[v + 1]; - v = v + 1 - nn = nn + v - while v < nn do - local bone = skeletonBones[bones[v + 1]]; - local vx = vertices[b + 1] - local vy = vertices[b + 2] - local weight = vertices[b + 3] - wx = wx + (vx * bone.a + vy * bone.b + bone.worldX) * weight - wy = wy + (vx * bone.c + vy * bone.d + bone.worldY) * weight - v = v + 1 - b = b + 3 - end - worldVertices[w + 1] = wx - worldVertices[w + 2] = wy - worldVertices[w + 5] = color.r - worldVertices[w + 6] = color.g - worldVertices[w + 7] = color.b - worldVertices[w + 8] = color.a - w = w + 8 - end - else - local deform = deformArray; - local w = 0 - local v = 0 - local b = 0 - local f = 0 - local n = #bones - while v < n do - local wx = x - local wy = y - local nn = bones[v + 1] - v = v + 1 - nn = nn + v - while v < nn do - local bone = skeletonBones[bones[v + 1]]; - local vx = vertices[b + 1] + deform[f + 1] - local vy = vertices[b + 2] + deform[f + 2] - local weight = vertices[b + 3] - wx = wx + (vx * bone.a + vy * bone.b + bone.worldX) * weight - wy = wy + (vx * bone.c + vy * bone.d + bone.worldY) * weight - b = b + 3 - f = f + 2 - v = v + 1 - end - worldVertices[w + 1] = wx; - worldVertices[w + 2] = wy; - worldVertices[w + 5] = color.r; - worldVertices[w + 6] = color.g; - worldVertices[w + 7] = color.b; - worldVertices[w + 8] = color.a; - w = w + 8 - end - end - return worldVertices; -end - -function MeshAttachment:applyDeform (sourceAttachment) - return self == sourceAttachment or (self.inheritDeform and self.parentMesh == sourceAttachment) -end - -function MeshAttachment:setParentMesh (parentMesh) - self.parentMesh = parentMesh - if parentMesh then - self.bones = parentMesh.bones - self.vertices = parentMesh.vertices - self.regionUVs = parentMesh.regionUVs - self.triangles = parentMesh.triangles - self.hullLength = parentMesh.hullLength - end -end -return MeshAttachment \ No newline at end of file +local setmetatable = setmetatable +local AttachmentType = require "spine-lua.attachments.AttachmentType" +local VertexAttachment = require "spine-lua.attachments.VertexAttachment" +local utils = require "spine-lua.utils" +local Color = require "spine-lua.Color" + +local MeshAttachment = {} +MeshAttachment.__index = MeshAttachment +setmetatable(MeshAttachment, { __index = VertexAttachment }) + +function MeshAttachment.new (name) + if not name then error("name cannot be nil", 2) end + + local self = VertexAttachment.new(name, AttachmentType.mesh) + self.region = nil + self.path = nil + self.regionUVs = nil + self.worldVertices = nil + self.triangles = nil + self.color = Color.newWith(1, 1, 1, 1) + self.hullLength = 0 + self.parentMesh = nil + self.inheritDeform = false + self.tempColor = Color.newWith(1, 1, 1, 1) + setmetatable(self, MeshAttachment) + return self +end + +function MeshAttachment:updateUVs () + local regionUVs = self.regionUVs + local verticesLength = #regionUVs + local worldVerticesLength = (verticesLength / 2) * 8 + if not self.worldVertices or #self.worldVertices ~= worldVerticesLength then + self.worldVertices = utils.newNumberArray(worldVerticesLength) + end + + local u = 0 + local v = 0 + local width = 0 + local height = 0 + if not self.region then + u = 0 + v = 0 + width = 1 + height = 1 + else + u = self.region.u; + v = self.region.v; + width = self.region.u2 - u; + height = self.region.v2 - v; + end + if self.region and self.region.rotate then + local i = 0 + local w = 2 + while i < verticesLength do + self.worldVertices[w + 1] = u + regionUVs[i + 2] * width; + self.worldVertices[w + 2] = v + height - regionUVs[i + 1] * height; + i = i + 2 + w = w + 8 + end + else + local i = 0 + local w = 2 + while i < verticesLength do + self.worldVertices[w + 1] = u + regionUVs[i + 1] * width; + self.worldVertices[w + 2] = v + regionUVs[i + 2] * height; + i = i + 2 + w = w + 8 + end + end +end + +function MeshAttachment:updateWorldVertices(slot, premultipliedAlpha) + local skeleton = slot.bone.skeleton + local skeletonColor = skeleton.color + local slotColor = slot.color + local meshColor = self.color + + local alpha = skeletonColor.a * slotColor.a * meshColor.a + local multiplier = 1 + if premultipliedAlpha then multiplier = alpha end + local color = self.tempColor + color:set(skeletonColor.r * slotColor.r * meshColor.r * multiplier, + skeletonColor.g * slotColor.g * meshColor.g * multiplier, + skeletonColor.b * slotColor.b * meshColor.b * multiplier, + alpha) + + local x = skeleton.x + local y = skeleton.y + local deformArray = slot.attachmentVertices + local vertices = self.vertices + local worldVertices = self.worldVertices + local bones = self.bones + if not bones then + local verticesLength = #vertices + if #deformArray > 0 then vertices = deformArray end + local bone = slot.bone; + x = x + bone.worldX + y = y + bone.worldY + local a = bone.a + local b = bone.b + local c = bone.c + local d = bone.d + local v = 0 + local w = 0 + while v < verticesLength do + local vx = vertices[v + 1] + local vy = vertices[v + 2] + worldVertices[w + 1] = vx * a + vy * b + x + worldVertices[w + 2] = vx * c + vy * d + y + worldVertices[w + 5] = color.r + worldVertices[w + 6] = color.g + worldVertices[w + 7] = color.b + worldVertices[w + 8] = color.a + v = v + 2 + w = w + 8 + end + return worldVertices + end + + local skeletonBones = skeleton.bones + if #deformArray == 0 then + local w = 0 + local v = 0 + local b = 0 + local n = #bones + while v < n do + local wx = x + local wy = y + local nn = bones[v + 1]; + v = v + 1 + nn = nn + v + while v < nn do + local bone = skeletonBones[bones[v + 1]]; + local vx = vertices[b + 1] + local vy = vertices[b + 2] + local weight = vertices[b + 3] + wx = wx + (vx * bone.a + vy * bone.b + bone.worldX) * weight + wy = wy + (vx * bone.c + vy * bone.d + bone.worldY) * weight + v = v + 1 + b = b + 3 + end + worldVertices[w + 1] = wx + worldVertices[w + 2] = wy + worldVertices[w + 5] = color.r + worldVertices[w + 6] = color.g + worldVertices[w + 7] = color.b + worldVertices[w + 8] = color.a + w = w + 8 + end + else + local deform = deformArray; + local w = 0 + local v = 0 + local b = 0 + local f = 0 + local n = #bones + while v < n do + local wx = x + local wy = y + local nn = bones[v + 1] + v = v + 1 + nn = nn + v + while v < nn do + local bone = skeletonBones[bones[v + 1]]; + local vx = vertices[b + 1] + deform[f + 1] + local vy = vertices[b + 2] + deform[f + 2] + local weight = vertices[b + 3] + wx = wx + (vx * bone.a + vy * bone.b + bone.worldX) * weight + wy = wy + (vx * bone.c + vy * bone.d + bone.worldY) * weight + b = b + 3 + f = f + 2 + v = v + 1 + end + worldVertices[w + 1] = wx; + worldVertices[w + 2] = wy; + worldVertices[w + 5] = color.r; + worldVertices[w + 6] = color.g; + worldVertices[w + 7] = color.b; + worldVertices[w + 8] = color.a; + w = w + 8 + end + end + return worldVertices; +end + +function MeshAttachment:applyDeform (sourceAttachment) + return self == sourceAttachment or (self.inheritDeform and self.parentMesh == sourceAttachment) +end + +function MeshAttachment:setParentMesh (parentMesh) + self.parentMesh = parentMesh + if parentMesh then + self.bones = parentMesh.bones + self.vertices = parentMesh.vertices + self.regionUVs = parentMesh.regionUVs + self.triangles = parentMesh.triangles + self.hullLength = parentMesh.hullLength + end +end + +return MeshAttachment diff --git a/spine-lua/attachments/PathAttachment.lua b/spine-lua/attachments/PathAttachment.lua index 9f2d92dd31..28b3fc3403 100644 --- a/spine-lua/attachments/PathAttachment.lua +++ b/spine-lua/attachments/PathAttachment.lua @@ -1,49 +1,48 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local AttachmentType = require "spine-lua.attachments.AttachmentType" -local VertexAttachment = require "spine-lua.attachments.VertexAttachment" -local Color = require "spine-lua.Color" - -local PathAttachment = {} -PathAttachment.__index = PathAttachment -setmetatable(PathAttachment, { __index = VertexAttachment }) - -function PathAttachment.new (name) - if not name then error("name cannot be nil", 2) end - local self = VertexAttachment.new(name, AttachmentType.path) - self.lengths = nil - self.color = Color.newWith(1, 1, 1, 1) - setmetatable(self, PathAttachment) - return self -end -return PathAttachment \ No newline at end of file +local AttachmentType = require "spine-lua.attachments.AttachmentType" +local VertexAttachment = require "spine-lua.attachments.VertexAttachment" +local Color = require "spine-lua.Color" + +local PathAttachment = {} +PathAttachment.__index = PathAttachment +setmetatable(PathAttachment, { __index = VertexAttachment }) + +function PathAttachment.new (name) + if not name then error("name cannot be nil", 2) end + + local self = VertexAttachment.new(name, AttachmentType.path) + self.lengths = nil + self.color = Color.newWith(1, 1, 1, 1) + setmetatable(self, PathAttachment) + return self +end +return PathAttachment diff --git a/spine-lua/attachments/RegionAttachment.lua b/spine-lua/attachments/RegionAttachment.lua index dd90c25ae8..2d57529a50 100644 --- a/spine-lua/attachments/RegionAttachment.lua +++ b/spine-lua/attachments/RegionAttachment.lua @@ -1,231 +1,230 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES LOSS OF USE, DATA, OR PROFITS --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local setmetatable = setmetatable -local math_pi = math.pi -local math_sin = math.sin -local math_cos = math.cos - -local AttachmentType = require "spine-lua.attachments.AttachmentType" -local Attachment = require "spine-lua.attachments.Attachment" -local Color = require "spine-lua.Color" -local Utils = require "spine-lua.utils" - -local OX1 = 1 -local OY1 = 2 -local OX2 = 3 -local OY2 = 4 -local OX3 = 5 -local OY3 = 6 -local OX4 = 7 -local OY4 = 8 - -local X1 = 1 -local Y1 = 2 -local U1 = 3 -local V1 = 4 -local C1R = 5 -local C1G = 6 -local C1B = 7 -local C1A = 8 - -local X2 = 9 -local Y2 = 10 -local U2 = 11 -local V2 = 12 -local C2R = 13 -local C2G = 14 -local C2B = 15 -local C2A = 16 - -local X3 = 17 -local Y3 = 18 -local U3 = 19 -local V3 = 20 -local C3R = 21 -local C3G = 22 -local C3B = 23 -local C3A = 24 - -local X4 = 25 -local Y4 = 26 -local U4 = 27 -local V4 = 28 -local C4R = 29 -local C4G = 30 -local C4B = 31 -local C4A = 32 - -local RegionAttachment = {} -RegionAttachment.__index = RegionAttachment -setmetatable(RegionAttachment, { __index = Attachment }) - -function RegionAttachment.new (name) - if not name then error("name cannot be nil", 2) end - - local self = Attachment.new(name, AttachmentType.region) - self.x = 0 - self.y = 0 - self.scaleX = 1 - self.scaleY = 1 - self.rotation = 0 - self.width = 0 - self.height = 0 - self.color = Color.newWith(1, 1, 1, 1) - self.path = nil - self.rendererObject = nil - self.region = nil - self.offset = Utils.newNumberArray(8) - self.vertices = Utils.newNumberArray(8 * 4) - self.tempColor = Color.newWith(1, 1, 1, 1) - setmetatable(self, RegionAttachment) - - return self -end - -function RegionAttachment:setRegion (region) - local vertices = self.vertices - if region.rotate then - vertices[U2] = region.u - vertices[V2] = region.v2 - vertices[U3] = region.u - vertices[V3] = region.v - vertices[U4] = region.u2 - vertices[V4] = region.v - vertices[U1] = region.u2 - vertices[V1] = region.v2 - else - vertices[U1] = region.u - vertices[V1] = region.v2 - vertices[U2] = region.u - vertices[V2] = region.v - vertices[U3] = region.u2 - vertices[V3] = region.v - vertices[U4] = region.u2 - vertices[V4] = region.v2 - end -end - -function RegionAttachment:updateOffset () - local regionScaleX = self.width / self.region.originalWidth * self.scaleX - local regionScaleY = self.height / self.region.originalHeight * self.scaleY - local localX = -self.width / 2 * self.scaleX + self.region.offsetX * regionScaleX - local localY = -self.height / 2 * self.scaleY + self.region.offsetY * regionScaleY - local localX2 = localX + self.region.width * regionScaleX - local localY2 = localY + self.region.height * regionScaleY - local radians = self.rotation * math_pi / 180 - local cos = math_cos(radians) - local sin = math_sin(radians) - local localXCos = localX * cos + self.x - local localXSin = localX * sin - local localYCos = localY * cos + self.y - local localYSin = localY * sin - local localX2Cos = localX2 * cos + self.x - local localX2Sin = localX2 * sin - local localY2Cos = localY2 * cos + self.y - local localY2Sin = localY2 * sin - local offset = self.offset - offset[OX1] = localXCos - localYSin - offset[OY1] = localYCos + localXSin - offset[OX2] = localXCos - localY2Sin - offset[OY2] = localY2Cos + localXSin - offset[OX3] = localX2Cos - localY2Sin - offset[OY3] = localY2Cos + localX2Sin - offset[OX4] = localX2Cos - localYSin - offset[OY4] = localYCos + localX2Sin -end - -function RegionAttachment:updateWorldVertices (slot, premultipliedAlpha) - local skeleton = slot.bone.skeleton - local skeletonColor = skeleton.color - local slotColor = slot.color - local regionColor = self.color - local alpha = skeletonColor.a * slotColor.a * regionColor.a - local multiplier = alpha - if premultipliedAlpha then multiplier = 1 end - local color = self.tempColor - color:set(skeletonColor.r * slotColor.r * regionColor.r * multiplier, - skeletonColor.g * slotColor.g * regionColor.g * multiplier, - skeletonColor.b * slotColor.b * regionColor.b * multiplier, - alpha) - - local vertices = self.vertices - local offset = self.offset - local bone = slot.bone - local x = skeleton.x + bone.worldX - local y = skeleton.y + bone.worldY - local a = bone.a - local b = bone.b - local c = bone.c - local d = bone.d - local offsetX = 0 - local offsetY = 0 - - offsetX = offset[OX1] - offsetY = offset[OY1] - vertices[X1] = offsetX * a + offsetY * b + x -- br - vertices[Y1] = offsetX * c + offsetY * d + y - vertices[C1R] = color.r - vertices[C1G] = color.g - vertices[C1B] = color.b - vertices[C1A] = color.a - - offsetX = offset[OX2] - offsetY = offset[OY2] - vertices[X2] = offsetX * a + offsetY * b + x -- bl - vertices[Y2] = offsetX * c + offsetY * d + y - vertices[C2R] = color.r - vertices[C2G] = color.g - vertices[C2B] = color.b - vertices[C2A] = color.a - - offsetX = offset[OX3] - offsetY = offset[OY3] - vertices[X3] = offsetX * a + offsetY * b + x -- ul - vertices[Y3] = offsetX * c + offsetY * d + y - vertices[C3R] = color.r - vertices[C3G] = color.g - vertices[C3B] = color.b - vertices[C3A] = color.a - - offsetX = offset[OX4] - offsetY = offset[OY4] - vertices[X4] = offsetX * a + offsetY * b + x -- ur - vertices[Y4] = offsetX * c + offsetY * d + y - vertices[C4R] = color.r - vertices[C4G] = color.g - vertices[C4B] = color.b - vertices[C4A] = color.a - - return vertices -end -return RegionAttachment \ No newline at end of file +local setmetatable = setmetatable +local math_pi = math.pi +local math_sin = math.sin +local math_cos = math.cos + +local AttachmentType = require "spine-lua.attachments.AttachmentType" +local Attachment = require "spine-lua.attachments.Attachment" +local Color = require "spine-lua.Color" +local Utils = require "spine-lua.utils" + +local OX1 = 1 +local OY1 = 2 +local OX2 = 3 +local OY2 = 4 +local OX3 = 5 +local OY3 = 6 +local OX4 = 7 +local OY4 = 8 + +local X1 = 1 +local Y1 = 2 +local U1 = 3 +local V1 = 4 +local C1R = 5 +local C1G = 6 +local C1B = 7 +local C1A = 8 + +local X2 = 9 +local Y2 = 10 +local U2 = 11 +local V2 = 12 +local C2R = 13 +local C2G = 14 +local C2B = 15 +local C2A = 16 + +local X3 = 17 +local Y3 = 18 +local U3 = 19 +local V3 = 20 +local C3R = 21 +local C3G = 22 +local C3B = 23 +local C3A = 24 + +local X4 = 25 +local Y4 = 26 +local U4 = 27 +local V4 = 28 +local C4R = 29 +local C4G = 30 +local C4B = 31 +local C4A = 32 + +local RegionAttachment = {} +RegionAttachment.__index = RegionAttachment +setmetatable(RegionAttachment, { __index = Attachment }) + +function RegionAttachment.new (name) + if not name then error("name cannot be nil", 2) end + + local self = Attachment.new(name, AttachmentType.region) + self.x = 0 + self.y = 0 + self.scaleX = 1 + self.scaleY = 1 + self.rotation = 0 + self.width = 0 + self.height = 0 + self.color = Color.newWith(1, 1, 1, 1) + self.path = nil + self.rendererObject = nil + self.region = nil + self.offset = Utils.newNumberArray(8) + self.vertices = Utils.newNumberArray(8 * 4) + self.tempColor = Color.newWith(1, 1, 1, 1) + setmetatable(self, RegionAttachment) + + return self +end + +function RegionAttachment:setRegion (region) + local vertices = self.vertices + if region.rotate then + vertices[U2] = region.u + vertices[V2] = region.v2 + vertices[U3] = region.u + vertices[V3] = region.v + vertices[U4] = region.u2 + vertices[V4] = region.v + vertices[U1] = region.u2 + vertices[V1] = region.v2 + else + vertices[U1] = region.u + vertices[V1] = region.v2 + vertices[U2] = region.u + vertices[V2] = region.v + vertices[U3] = region.u2 + vertices[V3] = region.v + vertices[U4] = region.u2 + vertices[V4] = region.v2 + end +end + +function RegionAttachment:updateOffset () + local regionScaleX = self.width / self.region.originalWidth * self.scaleX + local regionScaleY = self.height / self.region.originalHeight * self.scaleY + local localX = -self.width / 2 * self.scaleX + self.region.offsetX * regionScaleX + local localY = -self.height / 2 * self.scaleY + self.region.offsetY * regionScaleY + local localX2 = localX + self.region.width * regionScaleX + local localY2 = localY + self.region.height * regionScaleY + local radians = self.rotation * math_pi / 180 + local cos = math_cos(radians) + local sin = math_sin(radians) + local localXCos = localX * cos + self.x + local localXSin = localX * sin + local localYCos = localY * cos + self.y + local localYSin = localY * sin + local localX2Cos = localX2 * cos + self.x + local localX2Sin = localX2 * sin + local localY2Cos = localY2 * cos + self.y + local localY2Sin = localY2 * sin + local offset = self.offset + offset[OX1] = localXCos - localYSin + offset[OY1] = localYCos + localXSin + offset[OX2] = localXCos - localY2Sin + offset[OY2] = localY2Cos + localXSin + offset[OX3] = localX2Cos - localY2Sin + offset[OY3] = localY2Cos + localX2Sin + offset[OX4] = localX2Cos - localYSin + offset[OY4] = localYCos + localX2Sin +end + +function RegionAttachment:updateWorldVertices (slot, premultipliedAlpha) + local skeleton = slot.bone.skeleton + local skeletonColor = skeleton.color + local slotColor = slot.color + local regionColor = self.color + local alpha = skeletonColor.a * slotColor.a * regionColor.a + local multiplier = alpha + if premultipliedAlpha then multiplier = 1 end + local color = self.tempColor + color:set(skeletonColor.r * slotColor.r * regionColor.r * multiplier, + skeletonColor.g * slotColor.g * regionColor.g * multiplier, + skeletonColor.b * slotColor.b * regionColor.b * multiplier, + alpha) + + local vertices = self.vertices + local offset = self.offset + local bone = slot.bone + local x = skeleton.x + bone.worldX + local y = skeleton.y + bone.worldY + local a = bone.a + local b = bone.b + local c = bone.c + local d = bone.d + local offsetX = 0 + local offsetY = 0 + + offsetX = offset[OX1] + offsetY = offset[OY1] + vertices[X1] = offsetX * a + offsetY * b + x -- br + vertices[Y1] = offsetX * c + offsetY * d + y + vertices[C1R] = color.r + vertices[C1G] = color.g + vertices[C1B] = color.b + vertices[C1A] = color.a + + offsetX = offset[OX2] + offsetY = offset[OY2] + vertices[X2] = offsetX * a + offsetY * b + x -- bl + vertices[Y2] = offsetX * c + offsetY * d + y + vertices[C2R] = color.r + vertices[C2G] = color.g + vertices[C2B] = color.b + vertices[C2A] = color.a + + offsetX = offset[OX3] + offsetY = offset[OY3] + vertices[X3] = offsetX * a + offsetY * b + x -- ul + vertices[Y3] = offsetX * c + offsetY * d + y + vertices[C3R] = color.r + vertices[C3G] = color.g + vertices[C3B] = color.b + vertices[C3A] = color.a + + offsetX = offset[OX4] + offsetY = offset[OY4] + vertices[X4] = offsetX * a + offsetY * b + x -- ur + vertices[Y4] = offsetX * c + offsetY * d + y + vertices[C4R] = color.r + vertices[C4G] = color.g + vertices[C4B] = color.b + vertices[C4A] = color.a + + return vertices +end + +return RegionAttachment diff --git a/spine-lua/attachments/VertexAttachment.lua b/spine-lua/attachments/VertexAttachment.lua index 20882a6c71..54c69efac2 100644 --- a/spine-lua/attachments/VertexAttachment.lua +++ b/spine-lua/attachments/VertexAttachment.lua @@ -1,154 +1,153 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES LOSS OF USE, DATA, OR PROFITS --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - --- FIXME the logic in this file uses 0-based indexing. Each array --- access adds 1 to the calculated index. We should switch the logic --- to 1-based indexing eventually. - -local setmetatable = setmetatable - -local AttachmentType = require "spine-lua.attachments.AttachmentType" -local Attachment = require "spine-lua.attachments.Attachment" - -local VertexAttachment = {} -VertexAttachment.__index = VertexAttachment -setmetatable(VertexAttachment, { __index = Attachment }) - -function VertexAttachment.new (name, attachmentType) - local self = Attachment.new(name, attachmentType) - self.bones = nil - self.vertices = nil - self.worldVerticesLength = 0 - setmetatable(self, VertexAttachment) - return self -end - -function VertexAttachment:computeWorldVertices (slot, worldVertices) - self:computeWorldVerticesWith(slot, 0, self.worldVerticesLength, worldVertices, 0) -end - -function VertexAttachment:computeWorldVerticesWith (slot, start, count, worldVertices, offset) - count = count + offset - local skeleton = slot.bone.skeleton - local x = skeleton.x - local y = skeleton.y - local deformArray = slot.attachmentVertices - local vertices = self.vertices - local bones = self.bones - if not bones then - if #deformArray > 0 then vertices = deformArray end - local bone = slot.bone - x = x + bone.worldX - y = y + bone.worldY - local a = bone.a - local b = bone.b - local c = bone.c - local d = bone.d - local v = start - local w = offset - while w < count do - local vx = vertices[v + 1] - local vy = vertices[v + 2] - worldVertices[w + 1] = vx * a + vy * b + x - worldVertices[w + 2] = vx * c + vy * d + y - v = v + 2 - w = w + 2 - end - return - end - local v = 0 - local skip = 0 - local i = 0 - while i < start do - local n = bones[v + 1] - v = v + n + 1 - skip = skip + n - i = i + 2 - end - local skeletonBones = skeleton.bones - if #deformArray == 0 then - local w = offset - local b = skip * 3 - while w < count do - local wx = x - local wy = y - local n = bones[v + 1] - v = v + 1 - n = n + v - while v < n do - local bone = skeletonBones[bones[v + 1]] - local vx = vertices[b + 1] - local vy = vertices[b + 2] - local weight = vertices[b + 3] - wx = wx + (vx * bone.a + vy * bone.b + bone.worldX) * weight - wy = wy + (vx * bone.c + vy * bone.d + bone.worldY) * weight - v = v + 1 - b = b + 3 - end - worldVertices[w + 1] = wx - worldVertices[w + 2] = wy - w = w + 2 - end - else - local deform = deformArray - local w = offset - local b = skip * 3 - local f = skip * 2 - while w < count do - local wx = x - local wy = y - local n = bones[v + 1] - v = v + 1 - n = n + v - - while v < n do - local bone = skeletonBones[bones[v + 1]] - local vx = vertices[b + 1] + deform[f + 1] - local vy = vertices[b + 2] + deform[f + 2] - local weight = vertices[b + 3] - wx = wx + (vx * bone.a + vy * bone.b + bone.worldX) * weight - wy = wy + (vx * bone.c + vy * bone.d + bone.worldY) * weight - v = v + 1 - b = b + 3 - f = f + 2 - end - worldVertices[w + 1] = wx - worldVertices[w + 2] = wy - w = w + 2 - end - end -end - -function VertexAttachment:applyDeform (sourceAttachment) - return self == sourceAttachment -end -return VertexAttachment \ No newline at end of file +-- FIXME the logic in this file uses 0-based indexing. Each array +-- access adds 1 to the calculated index. We should switch the logic +-- to 1-based indexing eventually. + +local setmetatable = setmetatable + +local AttachmentType = require "spine-lua.attachments.AttachmentType" +local Attachment = require "spine-lua.attachments.Attachment" + +local VertexAttachment = {} +VertexAttachment.__index = VertexAttachment +setmetatable(VertexAttachment, { __index = Attachment }) + +function VertexAttachment.new (name, attachmentType) + local self = Attachment.new(name, attachmentType) + self.bones = nil + self.vertices = nil + self.worldVerticesLength = 0 + setmetatable(self, VertexAttachment) + return self +end + +function VertexAttachment:computeWorldVertices (slot, worldVertices) + self:computeWorldVerticesWith(slot, 0, self.worldVerticesLength, worldVertices, 0) +end + +function VertexAttachment:computeWorldVerticesWith (slot, start, count, worldVertices, offset) + count = count + offset + local skeleton = slot.bone.skeleton + local x = skeleton.x + local y = skeleton.y + local deformArray = slot.attachmentVertices + local vertices = self.vertices + local bones = self.bones + if not bones then + if #deformArray > 0 then vertices = deformArray end + local bone = slot.bone + x = x + bone.worldX + y = y + bone.worldY + local a = bone.a + local b = bone.b + local c = bone.c + local d = bone.d + local v = start + local w = offset + while w < count do + local vx = vertices[v + 1] + local vy = vertices[v + 2] + worldVertices[w + 1] = vx * a + vy * b + x + worldVertices[w + 2] = vx * c + vy * d + y + v = v + 2 + w = w + 2 + end + return + end + local v = 0 + local skip = 0 + local i = 0 + while i < start do + local n = bones[v + 1] + v = v + n + 1 + skip = skip + n + i = i + 2 + end + local skeletonBones = skeleton.bones + if #deformArray == 0 then + local w = offset + local b = skip * 3 + while w < count do + local wx = x + local wy = y + local n = bones[v + 1] + v = v + 1 + n = n + v + while v < n do + local bone = skeletonBones[bones[v + 1]] + local vx = vertices[b + 1] + local vy = vertices[b + 2] + local weight = vertices[b + 3] + wx = wx + (vx * bone.a + vy * bone.b + bone.worldX) * weight + wy = wy + (vx * bone.c + vy * bone.d + bone.worldY) * weight + v = v + 1 + b = b + 3 + end + worldVertices[w + 1] = wx + worldVertices[w + 2] = wy + w = w + 2 + end + else + local deform = deformArray + local w = offset + local b = skip * 3 + local f = skip * 2 + while w < count do + local wx = x + local wy = y + local n = bones[v + 1] + v = v + 1 + n = n + v + + while v < n do + local bone = skeletonBones[bones[v + 1]] + local vx = vertices[b + 1] + deform[f + 1] + local vy = vertices[b + 2] + deform[f + 2] + local weight = vertices[b + 3] + wx = wx + (vx * bone.a + vy * bone.b + bone.worldX) * weight + wy = wy + (vx * bone.c + vy * bone.d + bone.worldY) * weight + v = v + 1 + b = b + 3 + f = f + 2 + end + worldVertices[w + 1] = wx + worldVertices[w + 2] = wy + w = w + 2 + end + end +end + +function VertexAttachment:applyDeform (sourceAttachment) + return self == sourceAttachment +end + +return VertexAttachment diff --git a/spine-lua/utils.lua b/spine-lua/utils.lua index 9070a4c6c5..e73dbb8250 100644 --- a/spine-lua/utils.lua +++ b/spine-lua/utils.lua @@ -1,130 +1,129 @@ +------------------------------------------------------------------------------- +-- Spine Runtimes Software License v2.5 +-- +-- Copyright (c) 2013-2016, Esoteric Software +-- All rights reserved. +-- +-- You are granted a perpetual, non-exclusive, non-sublicensable, and +-- non-transferable license to use, install, execute, and perform the Spine +-- Runtimes software and derivative works solely for personal or internal +-- use. Without the written permission of Esoteric Software (see Section 2 of +-- the Spine Software License Agreement), you may not (a) modify, translate, +-- adapt, or develop new applications using the Spine Runtimes or otherwise +-- create derivative works or improvements of the Spine Runtimes or (b) remove, +-- delete, alter, or obscure any trademarks or any copyright, trademark, patent, +-- or other intellectual property or proprietary rights notices on or in the +-- Software, including any copy thereof. Redistributions in binary or source +-- form must include this license and terms. +-- +-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR +-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF +-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +-- IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------- --- Spine Runtimes Software License --- Version 2.3 --- --- Copyright (c) 2013-2015, Esoteric Software --- All rights reserved. --- --- You are granted a perpetual, non-exclusive, non-sublicensable and --- non-transferable license to use, install, execute and perform the Spine --- Runtimes Software (the "Software") and derivative works solely for personal --- or internal use. Without the written permission of Esoteric Software (see --- Section 2 of the Spine Software License Agreement), you may not (a) modify, --- translate, adapt or otherwise create derivative works, improvements of the --- Software or develop new applications using the Software or (b) remove, --- delete, alter or obscure any trademarks or any copyright, trademark, patent --- or other intellectual property or proprietary rights notices on or in the --- Software, including any copy thereof. Redistributions in binary or source --- form must include this license and terms. --- --- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR --- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF --- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO --- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, --- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; --- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, --- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR --- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF --- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- - -local utils = {} - -function tablePrint (tt, indent, done) - done = done or {} - for key, value in pairs(tt) do - local spaces = string.rep (" ", indent) - if type(value) == "table" and not done [value] then - done [value] = true - print(spaces .. "{") - utils.print(value, indent + 2, done) - print(spaces .. "}") - else - io.write(spaces .. tostring(key) .. " = ") - utils.print(value, indent + 2, done) - end - end -end - -function utils.print (value, indent, done) - indent = indent or 0 - if "nil" == type(value) then - print(tostring(nil)) - elseif "table" == type(value) then - local spaces = string.rep (" ", indent) - print(spaces .. "{") - tablePrint(value, indent + 2) - print(spaces .. "}") - elseif "string" == type(value) then - print("\"" .. value .. "\"") - else - print(tostring(value)) - end -end - -function utils.indexOf (haystack, needle) - for i,value in ipairs(haystack) do - if value == needle then return i end - end - return nil -end - -function utils.copy (from, to) - if not to then to = {} end - for k,v in pairs(from) do - to[k] = v - end - return to -end - -function utils.newNumberArray (size) - local a = {} - local i = 1 - while i <= size do - a[i] = 0 - i = i + 1 - end - return a -end - -function utils.newNumberArrayZero (size) - local a = {} - local i = 0 - while i < size do - a[i] = 0 - i = i + 1 - end - return a -end - -function utils.setArraySize (array, size) - if #array == size then return array end - if #array < size then - local i = #array + 1 - while i <= size do - array[i] = 0 - i = i + 1 - end - else - array[size + 1] = nil -- dirty trick to appease # without realloc - end - return array -end - -function utils.arrayCopy (src, srcOffset, dst, dstOffset, size) - local n = srcOffset + size - while srcOffset < n do - dst[dstOffset] = src[srcOffset] - dstOffset = dstOffset + 1 - srcOffset = srcOffset + 1 - end -end - -function utils.clamp (value, min, max) - if value < min then return min end - if value > max then return max end - return value -end +local utils = {} + +function tablePrint (tt, indent, done) + done = done or {} + for key, value in pairs(tt) do + local spaces = string.rep (" ", indent) + if type(value) == "table" and not done [value] then + done [value] = true + print(spaces .. "{") + utils.print(value, indent + 2, done) + print(spaces .. "}") + else + io.write(spaces .. tostring(key) .. " = ") + utils.print(value, indent + 2, done) + end + end +end + +function utils.print (value, indent, done) + indent = indent or 0 + if "nil" == type(value) then + print(tostring(nil)) + elseif "table" == type(value) then + local spaces = string.rep (" ", indent) + print(spaces .. "{") + tablePrint(value, indent + 2) + print(spaces .. "}") + elseif "string" == type(value) then + print("\"" .. value .. "\"") + else + print(tostring(value)) + end +end + +function utils.indexOf (haystack, needle) + for i,value in ipairs(haystack) do + if value == needle then return i end + end + return nil +end + +function utils.copy (from, to) + if not to then to = {} end + for k,v in pairs(from) do + to[k] = v + end + return to +end + +function utils.newNumberArray (size) + local a = {} + local i = 1 + while i <= size do + a[i] = 0 + i = i + 1 + end + return a +end + +function utils.newNumberArrayZero (size) + local a = {} + local i = 0 + while i < size do + a[i] = 0 + i = i + 1 + end + return a +end + +function utils.setArraySize (array, size) + if #array == size then return array end + if #array < size then + local i = #array + 1 + while i <= size do + array[i] = 0 + i = i + 1 + end + else + array[size + 1] = nil -- dirty trick to appease # without realloc + end + return array +end + +function utils.arrayCopy (src, srcOffset, dst, dstOffset, size) + local n = srcOffset + size + while srcOffset < n do + dst[dstOffset] = src[srcOffset] + dstOffset = dstOffset + 1 + srcOffset = srcOffset + 1 + end +end + +function utils.clamp (value, min, max) + if value < min then return min end + if value > max then return max end + return value +end + return utils diff --git a/spine-sfml/example/main.cpp b/spine-sfml/example/main.cpp index f1ed121798..f5c3577488 100644 --- a/spine-sfml/example/main.cpp +++ b/spine-sfml/example/main.cpp @@ -1,359 +1,358 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include -#include -#include -#include -#include - -using namespace std; -using namespace spine; -#include -#include - -void callback (AnimationState* state, int trackIndex, EventType type, Event* event, int loopCount) { - TrackEntry* entry = AnimationState_getCurrent(state, trackIndex); - const char* animationName = (entry && entry->animation) ? entry->animation->name : 0; - - switch (type) { - case ANIMATION_START: - printf("%d start: %s\n", trackIndex, animationName); - break; - case ANIMATION_END: - printf("%d end: %s\n", trackIndex, animationName); - break; - case ANIMATION_COMPLETE: - printf("%d complete: %s, %d\n", trackIndex, animationName, loopCount); - break; - case ANIMATION_EVENT: - printf("%d event: %s, %s: %d, %f, %s\n", trackIndex, animationName, event->data->name, event->intValue, event->floatValue, - event->stringValue); - break; - } - fflush(stdout); -} - -SkeletonData* readSkeletonJsonData (const char* filename, Atlas* atlas, float scale) { - SkeletonJson* json = SkeletonJson_create(atlas); - json->scale = scale; - SkeletonData* skeletonData = SkeletonJson_readSkeletonDataFile(json, filename); - if (!skeletonData) { - printf("%s\n", json->error); - exit(0); - } - SkeletonJson_dispose(json); - return skeletonData; -} - -SkeletonData* readSkeletonBinaryData (const char* filename, Atlas* atlas, float scale) { - SkeletonBinary* binary = SkeletonBinary_create(atlas); - binary->scale = scale; - SkeletonData *skeletonData = SkeletonBinary_readSkeletonDataFile(binary, filename); - if (!skeletonData) { - printf("%s\n", binary->error); - exit(0); - } - SkeletonBinary_dispose(binary); - return skeletonData; -} - -void testcase (void func(SkeletonData* skeletonData, Atlas* atlas), - const char* jsonName, const char* binaryName, const char* atlasName, - float scale) { - Atlas* atlas = Atlas_createFromFile(atlasName, 0); - - SkeletonData* skeletonData = readSkeletonJsonData(jsonName, atlas, scale); - func(skeletonData, atlas); - SkeletonData_dispose(skeletonData); - - skeletonData = readSkeletonBinaryData(binaryName, atlas, scale); - func(skeletonData, atlas); - SkeletonData_dispose(skeletonData); - - Atlas_dispose(atlas); -} - -void spineboy (SkeletonData* skeletonData, Atlas* atlas) { - SkeletonBounds* bounds = SkeletonBounds_create(); - - // Configure mixing. - AnimationStateData* stateData = AnimationStateData_create(skeletonData); - AnimationStateData_setMixByName(stateData, "walk", "jump", 0.2f); - AnimationStateData_setMixByName(stateData, "jump", "run", 0.2f); - - SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData, stateData); - drawable->timeScale = 1; - - Skeleton* skeleton = drawable->skeleton; - skeleton->flipX = false; - skeleton->flipY = false; - Skeleton_setToSetupPose(skeleton); - - skeleton->x = 320; - skeleton->y = 460; - Skeleton_updateWorldTransform(skeleton); - - Slot* headSlot = Skeleton_findSlot(skeleton, "head"); - - drawable->state->listener = callback; - AnimationState_setAnimationByName(drawable->state, 0, "test", true); - AnimationState_addAnimationByName(drawable->state, 0, "walk", true, 0); - AnimationState_addAnimationByName(drawable->state, 0, "jump", false, 3); - AnimationState_addAnimationByName(drawable->state, 0, "run", true, 0); - - sf::RenderWindow window(sf::VideoMode(640, 480), "Spine SFML - spineboy"); - window.setFramerateLimit(60); - sf::Event event; - sf::Clock deltaClock; - while (window.isOpen()) { - while (window.pollEvent(event)) - if (event.type == sf::Event::Closed) window.close(); - - float delta = deltaClock.getElapsedTime().asSeconds(); - deltaClock.restart(); - - SkeletonBounds_update(bounds, skeleton, true); - sf::Vector2i position = sf::Mouse::getPosition(window); - if (SkeletonBounds_containsPoint(bounds, position.x, position.y)) { - headSlot->g = 0; - headSlot->b = 0; - } else { - headSlot->g = 1; - headSlot->b = 1; - } - - drawable->update(delta); - - window.clear(); - window.draw(*drawable); - window.display(); - } - - SkeletonBounds_dispose(bounds); -} - -void goblins (SkeletonData* skeletonData, Atlas* atlas) { - SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData); - drawable->timeScale = 1; - - Skeleton* skeleton = drawable->skeleton; - skeleton->flipX = false; - skeleton->flipY = false; - Skeleton_setSkinByName(skeleton, "goblin"); - Skeleton_setSlotsToSetupPose(skeleton); - //Skeleton_setAttachment(skeleton, "left hand item", "dagger"); - - skeleton->x = 320; - skeleton->y = 590; - Skeleton_updateWorldTransform(skeleton); - - AnimationState_setAnimationByName(drawable->state, 0, "walk", true); - - sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - goblins"); - window.setFramerateLimit(60); - sf::Event event; - sf::Clock deltaClock; - while (window.isOpen()) { - while (window.pollEvent(event)) - if (event.type == sf::Event::Closed) window.close(); - - float delta = deltaClock.getElapsedTime().asSeconds(); - deltaClock.restart(); - - drawable->update(delta); - - window.clear(); - window.draw(*drawable); - window.display(); - } -} - -void raptor (SkeletonData* skeletonData, Atlas* atlas) { - SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData); - drawable->timeScale = 1; - - Skeleton* skeleton = drawable->skeleton; - skeleton->x = 320; - skeleton->y = 590; - Skeleton_updateWorldTransform(skeleton); - - AnimationState_setAnimationByName(drawable->state, 0, "walk", true); - AnimationState_addAnimationByName(drawable->state, 1, "gungrab", false, 2); - - sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - raptor"); - window.setFramerateLimit(60); - sf::Event event; - sf::Clock deltaClock; - while (window.isOpen()) { - while (window.pollEvent(event)) - if (event.type == sf::Event::Closed) window.close(); - - float delta = deltaClock.getElapsedTime().asSeconds(); - deltaClock.restart(); - - drawable->update(delta); - - window.clear(); - window.draw(*drawable); - window.display(); - } -} - -void tank (SkeletonData* skeletonData, Atlas* atlas) { - SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData); - drawable->timeScale = 1; - - Skeleton* skeleton = drawable->skeleton; - skeleton->x = 500; - skeleton->y = 590; - Skeleton_updateWorldTransform(skeleton); - - AnimationState_setAnimationByName(drawable->state, 0, "drive", true); - - sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - tank"); - window.setFramerateLimit(60); - sf::Event event; - sf::Clock deltaClock; - - while (window.isOpen()) { - while (window.pollEvent(event)) - if (event.type == sf::Event::Closed) window.close(); - - float delta = deltaClock.getElapsedTime().asSeconds(); - deltaClock.restart(); - drawable->update(delta); - window.clear(); - window.draw(*drawable); - window.display(); - } -} - -void vine (SkeletonData* skeletonData, Atlas* atlas) { - SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData); - drawable->timeScale = 1; - - Skeleton* skeleton = drawable->skeleton; - skeleton->x = 320; - skeleton->y = 590; - Skeleton_updateWorldTransform(skeleton); - - AnimationState_setAnimationByName(drawable->state, 0, "animation", true); - - sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - vine"); - window.setFramerateLimit(60); - sf::Event event; - sf::Clock deltaClock; - while (window.isOpen()) { - while (window.pollEvent(event)) - if (event.type == sf::Event::Closed) window.close(); - - float delta = deltaClock.getElapsedTime().asSeconds(); - deltaClock.restart(); - - drawable->update(delta); - - window.clear(); - window.draw(*drawable); - window.display(); - } -} - -void stretchyman (SkeletonData* skeletonData, Atlas* atlas) { - SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData); - drawable->timeScale = 1; - - Skeleton* skeleton = drawable->skeleton; - skeleton->flipX = false; - skeleton->flipY = false; - - skeleton->x = 320; - skeleton->y = 590; - Skeleton_updateWorldTransform(skeleton); - - AnimationState_setAnimationByName(drawable->state, 0, "sneak", true); - - sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - Streatchyman"); - window.setFramerateLimit(60); - sf::Event event; - sf::Clock deltaClock; - while (window.isOpen()) { - while (window.pollEvent(event)) - if (event.type == sf::Event::Closed) window.close(); - - float delta = deltaClock.getElapsedTime().asSeconds(); - deltaClock.restart(); - - drawable->update(delta); - - window.clear(); - window.draw(*drawable); - window.display(); - } -} - -/** - * Used for debugging purposes during runtime development - */ -void test (SkeletonData* skeletonData, Atlas* atlas) { - spSkeleton* skeleton = Skeleton_create(skeletonData); - spAnimationStateData* animData = spAnimationStateData_create(skeletonData); - spAnimationState* animState = spAnimationState_create(animData); - spAnimationState_setAnimationByName(animState, 0, "drive", true); - - - float d = 3; - for (int i = 0; i < 1; i++) { - spSkeleton_update(skeleton, d); - spAnimationState_update(animState, d); - spAnimationState_apply(animState, skeleton); - spSkeleton_updateWorldTransform(skeleton); - for (int ii = 0; ii < skeleton->bonesCount; ii++) { - spBone* bone = skeleton->bones[ii]; - printf("%s %f %f %f %f %f %f\n", bone->data->name, bone->a, bone->b, bone->c, bone->d, bone->worldX, bone->worldY); - } - printf("========================================\n"); - d += 0.1f; - } - - Skeleton_dispose(skeleton); -} - -int main () { - testcase(test, "data/tank.json", "data/tank.skel", "data/tank.atlas", 1.0f); - testcase(vine, "data/vine.json", "data/vine.skel", "data/vine.atlas", 0.5f); - testcase(tank, "data/tank.json", "data/tank.skel", "data/tank.atlas", 0.2f); - testcase(raptor, "data/raptor.json", "data/raptor.skel", "data/raptor.atlas", 0.5f); - testcase(spineboy, "data/spineboy.json", "data/spineboy.skel", "data/spineboy.atlas", 0.6f); - testcase(goblins, "data/goblins-mesh.json", "data/goblins-mesh.skel", "data/goblins.atlas", 1.4f); - testcase(stretchyman, "data/stretchyman.json", "data/stretchyman.skel", "data/stretchyman.atlas", 1.4f); - return 0; +#include +#include +#include +#include +#include + +using namespace std; +using namespace spine; +#include +#include + +void callback (AnimationState* state, int trackIndex, EventType type, Event* event, int loopCount) { + TrackEntry* entry = AnimationState_getCurrent(state, trackIndex); + const char* animationName = (entry && entry->animation) ? entry->animation->name : 0; + + switch (type) { + case ANIMATION_START: + printf("%d start: %s\n", trackIndex, animationName); + break; + case ANIMATION_END: + printf("%d end: %s\n", trackIndex, animationName); + break; + case ANIMATION_COMPLETE: + printf("%d complete: %s, %d\n", trackIndex, animationName, loopCount); + break; + case ANIMATION_EVENT: + printf("%d event: %s, %s: %d, %f, %s\n", trackIndex, animationName, event->data->name, event->intValue, event->floatValue, + event->stringValue); + break; + } + fflush(stdout); +} + +SkeletonData* readSkeletonJsonData (const char* filename, Atlas* atlas, float scale) { + SkeletonJson* json = SkeletonJson_create(atlas); + json->scale = scale; + SkeletonData* skeletonData = SkeletonJson_readSkeletonDataFile(json, filename); + if (!skeletonData) { + printf("%s\n", json->error); + exit(0); + } + SkeletonJson_dispose(json); + return skeletonData; +} + +SkeletonData* readSkeletonBinaryData (const char* filename, Atlas* atlas, float scale) { + SkeletonBinary* binary = SkeletonBinary_create(atlas); + binary->scale = scale; + SkeletonData *skeletonData = SkeletonBinary_readSkeletonDataFile(binary, filename); + if (!skeletonData) { + printf("%s\n", binary->error); + exit(0); + } + SkeletonBinary_dispose(binary); + return skeletonData; +} + +void testcase (void func(SkeletonData* skeletonData, Atlas* atlas), + const char* jsonName, const char* binaryName, const char* atlasName, + float scale) { + Atlas* atlas = Atlas_createFromFile(atlasName, 0); + + SkeletonData* skeletonData = readSkeletonJsonData(jsonName, atlas, scale); + func(skeletonData, atlas); + SkeletonData_dispose(skeletonData); + + skeletonData = readSkeletonBinaryData(binaryName, atlas, scale); + func(skeletonData, atlas); + SkeletonData_dispose(skeletonData); + + Atlas_dispose(atlas); +} + +void spineboy (SkeletonData* skeletonData, Atlas* atlas) { + SkeletonBounds* bounds = SkeletonBounds_create(); + + // Configure mixing. + AnimationStateData* stateData = AnimationStateData_create(skeletonData); + AnimationStateData_setMixByName(stateData, "walk", "jump", 0.2f); + AnimationStateData_setMixByName(stateData, "jump", "run", 0.2f); + + SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData, stateData); + drawable->timeScale = 1; + + Skeleton* skeleton = drawable->skeleton; + skeleton->flipX = false; + skeleton->flipY = false; + Skeleton_setToSetupPose(skeleton); + + skeleton->x = 320; + skeleton->y = 460; + Skeleton_updateWorldTransform(skeleton); + + Slot* headSlot = Skeleton_findSlot(skeleton, "head"); + + drawable->state->listener = callback; + AnimationState_setAnimationByName(drawable->state, 0, "test", true); + AnimationState_addAnimationByName(drawable->state, 0, "walk", true, 0); + AnimationState_addAnimationByName(drawable->state, 0, "jump", false, 3); + AnimationState_addAnimationByName(drawable->state, 0, "run", true, 0); + + sf::RenderWindow window(sf::VideoMode(640, 480), "Spine SFML - spineboy"); + window.setFramerateLimit(60); + sf::Event event; + sf::Clock deltaClock; + while (window.isOpen()) { + while (window.pollEvent(event)) + if (event.type == sf::Event::Closed) window.close(); + + float delta = deltaClock.getElapsedTime().asSeconds(); + deltaClock.restart(); + + SkeletonBounds_update(bounds, skeleton, true); + sf::Vector2i position = sf::Mouse::getPosition(window); + if (SkeletonBounds_containsPoint(bounds, position.x, position.y)) { + headSlot->g = 0; + headSlot->b = 0; + } else { + headSlot->g = 1; + headSlot->b = 1; + } + + drawable->update(delta); + + window.clear(); + window.draw(*drawable); + window.display(); + } + + SkeletonBounds_dispose(bounds); +} + +void goblins (SkeletonData* skeletonData, Atlas* atlas) { + SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData); + drawable->timeScale = 1; + + Skeleton* skeleton = drawable->skeleton; + skeleton->flipX = false; + skeleton->flipY = false; + Skeleton_setSkinByName(skeleton, "goblin"); + Skeleton_setSlotsToSetupPose(skeleton); + //Skeleton_setAttachment(skeleton, "left hand item", "dagger"); + + skeleton->x = 320; + skeleton->y = 590; + Skeleton_updateWorldTransform(skeleton); + + AnimationState_setAnimationByName(drawable->state, 0, "walk", true); + + sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - goblins"); + window.setFramerateLimit(60); + sf::Event event; + sf::Clock deltaClock; + while (window.isOpen()) { + while (window.pollEvent(event)) + if (event.type == sf::Event::Closed) window.close(); + + float delta = deltaClock.getElapsedTime().asSeconds(); + deltaClock.restart(); + + drawable->update(delta); + + window.clear(); + window.draw(*drawable); + window.display(); + } +} + +void raptor (SkeletonData* skeletonData, Atlas* atlas) { + SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData); + drawable->timeScale = 1; + + Skeleton* skeleton = drawable->skeleton; + skeleton->x = 320; + skeleton->y = 590; + Skeleton_updateWorldTransform(skeleton); + + AnimationState_setAnimationByName(drawable->state, 0, "walk", true); + AnimationState_addAnimationByName(drawable->state, 1, "gungrab", false, 2); + + sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - raptor"); + window.setFramerateLimit(60); + sf::Event event; + sf::Clock deltaClock; + while (window.isOpen()) { + while (window.pollEvent(event)) + if (event.type == sf::Event::Closed) window.close(); + + float delta = deltaClock.getElapsedTime().asSeconds(); + deltaClock.restart(); + + drawable->update(delta); + + window.clear(); + window.draw(*drawable); + window.display(); + } +} + +void tank (SkeletonData* skeletonData, Atlas* atlas) { + SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData); + drawable->timeScale = 1; + + Skeleton* skeleton = drawable->skeleton; + skeleton->x = 500; + skeleton->y = 590; + Skeleton_updateWorldTransform(skeleton); + + AnimationState_setAnimationByName(drawable->state, 0, "drive", true); + + sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - tank"); + window.setFramerateLimit(60); + sf::Event event; + sf::Clock deltaClock; + + while (window.isOpen()) { + while (window.pollEvent(event)) + if (event.type == sf::Event::Closed) window.close(); + + float delta = deltaClock.getElapsedTime().asSeconds(); + deltaClock.restart(); + drawable->update(delta); + window.clear(); + window.draw(*drawable); + window.display(); + } +} + +void vine (SkeletonData* skeletonData, Atlas* atlas) { + SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData); + drawable->timeScale = 1; + + Skeleton* skeleton = drawable->skeleton; + skeleton->x = 320; + skeleton->y = 590; + Skeleton_updateWorldTransform(skeleton); + + AnimationState_setAnimationByName(drawable->state, 0, "animation", true); + + sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - vine"); + window.setFramerateLimit(60); + sf::Event event; + sf::Clock deltaClock; + while (window.isOpen()) { + while (window.pollEvent(event)) + if (event.type == sf::Event::Closed) window.close(); + + float delta = deltaClock.getElapsedTime().asSeconds(); + deltaClock.restart(); + + drawable->update(delta); + + window.clear(); + window.draw(*drawable); + window.display(); + } +} + +void stretchyman (SkeletonData* skeletonData, Atlas* atlas) { + SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData); + drawable->timeScale = 1; + + Skeleton* skeleton = drawable->skeleton; + skeleton->flipX = false; + skeleton->flipY = false; + + skeleton->x = 320; + skeleton->y = 590; + Skeleton_updateWorldTransform(skeleton); + + AnimationState_setAnimationByName(drawable->state, 0, "sneak", true); + + sf::RenderWindow window(sf::VideoMode(640, 640), "Spine SFML - Streatchyman"); + window.setFramerateLimit(60); + sf::Event event; + sf::Clock deltaClock; + while (window.isOpen()) { + while (window.pollEvent(event)) + if (event.type == sf::Event::Closed) window.close(); + + float delta = deltaClock.getElapsedTime().asSeconds(); + deltaClock.restart(); + + drawable->update(delta); + + window.clear(); + window.draw(*drawable); + window.display(); + } +} + +/** + * Used for debugging purposes during runtime development + */ +void test (SkeletonData* skeletonData, Atlas* atlas) { + spSkeleton* skeleton = Skeleton_create(skeletonData); + spAnimationStateData* animData = spAnimationStateData_create(skeletonData); + spAnimationState* animState = spAnimationState_create(animData); + spAnimationState_setAnimationByName(animState, 0, "drive", true); + + + float d = 3; + for (int i = 0; i < 1; i++) { + spSkeleton_update(skeleton, d); + spAnimationState_update(animState, d); + spAnimationState_apply(animState, skeleton); + spSkeleton_updateWorldTransform(skeleton); + for (int ii = 0; ii < skeleton->bonesCount; ii++) { + spBone* bone = skeleton->bones[ii]; + printf("%s %f %f %f %f %f %f\n", bone->data->name, bone->a, bone->b, bone->c, bone->d, bone->worldX, bone->worldY); + } + printf("========================================\n"); + d += 0.1f; + } + + Skeleton_dispose(skeleton); +} + +int main () { + testcase(test, "data/tank.json", "data/tank.skel", "data/tank.atlas", 1.0f); + testcase(vine, "data/vine.json", "data/vine.skel", "data/vine.atlas", 0.5f); + testcase(tank, "data/tank.json", "data/tank.skel", "data/tank.atlas", 0.2f); + testcase(raptor, "data/raptor.json", "data/raptor.skel", "data/raptor.atlas", 0.5f); + testcase(spineboy, "data/spineboy.json", "data/spineboy.skel", "data/spineboy.atlas", 0.6f); + testcase(goblins, "data/goblins-mesh.json", "data/goblins-mesh.skel", "data/goblins.atlas", 1.4f); + testcase(stretchyman, "data/stretchyman.json", "data/stretchyman.skel", "data/stretchyman.atlas", 1.4f); + return 0; } diff --git a/spine-sfml/src/spine/spine-sfml.cpp b/spine-sfml/src/spine/spine-sfml.cpp index 1390461ae3..717ef6fb25 100644 --- a/spine-sfml/src/spine/spine-sfml.cpp +++ b/spine-sfml/src/spine/spine-sfml.cpp @@ -1,212 +1,211 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include - -#ifndef SPINE_MESH_VERTEX_COUNT_MAX -#define SPINE_MESH_VERTEX_COUNT_MAX 1000 -#endif - -using namespace sf; - -void _AtlasPage_createTexture (AtlasPage* self, const char* path){ - Texture* texture = new Texture(); - if (!texture->loadFromFile(path)) return; - - if (self->magFilter == SP_ATLAS_LINEAR) texture->setSmooth(true); - if (self->uWrap == SP_ATLAS_REPEAT && self->vWrap == SP_ATLAS_REPEAT) texture->setRepeated(true); - - self->rendererObject = texture; - Vector2u size = texture->getSize(); - self->width = size.x; - self->height = size.y; -} - -void _AtlasPage_disposeTexture (AtlasPage* self){ - delete (Texture*)self->rendererObject; -} - -char* _Util_readFile (const char* path, int* length){ - return _readFile(path, length); -} - -/**/ - -namespace spine { - -SkeletonDrawable::SkeletonDrawable (SkeletonData* skeletonData, AnimationStateData* stateData) : - timeScale(1), - vertexArray(new VertexArray(Triangles, skeletonData->bonesCount * 4)), - worldVertices(0) { - Bone_setYDown(true); - worldVertices = MALLOC(float, SPINE_MESH_VERTEX_COUNT_MAX); - skeleton = Skeleton_create(skeletonData); - - ownsAnimationStateData = stateData == 0; - if (ownsAnimationStateData) stateData = AnimationStateData_create(skeletonData); - - state = AnimationState_create(stateData); -} - -SkeletonDrawable::~SkeletonDrawable () { - delete vertexArray; - FREE(worldVertices); - if (ownsAnimationStateData) AnimationStateData_dispose(state->data); - AnimationState_dispose(state); - Skeleton_dispose(skeleton); -} - -void SkeletonDrawable::update (float deltaTime) { - Skeleton_update(skeleton, deltaTime); - AnimationState_update(state, deltaTime * timeScale); - AnimationState_apply(state, skeleton); - Skeleton_updateWorldTransform(skeleton); -} - -void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const { - vertexArray->clear(); - - sf::Vertex vertices[4]; - sf::Vertex vertex; - for (int i = 0; i < skeleton->slotsCount; ++i) { - Slot* slot = skeleton->drawOrder[i]; - Attachment* attachment = slot->attachment; - if (!attachment) continue; - - sf::BlendMode blend; - switch (slot->data->blendMode) { - case BLEND_MODE_ADDITIVE: - blend = BlendAdd; - break; - case BLEND_MODE_MULTIPLY: - blend = BlendMultiply; - break; - case BLEND_MODE_SCREEN: // Unsupported, fall through. - default: - blend = BlendAlpha; - } - if (states.blendMode != blend) { - target.draw(*vertexArray, states); - vertexArray->clear(); - states.blendMode = blend; - } - - Texture* texture = 0; - if (attachment->type == ATTACHMENT_REGION) { - RegionAttachment* regionAttachment = (RegionAttachment*)attachment; - texture = (Texture*)((AtlasRegion*)regionAttachment->rendererObject)->page->rendererObject; - RegionAttachment_computeWorldVertices(regionAttachment, slot->bone, worldVertices); - - Uint8 r = static_cast(skeleton->r * slot->r * 255); - Uint8 g = static_cast(skeleton->g * slot->g * 255); - Uint8 b = static_cast(skeleton->b * slot->b * 255); - Uint8 a = static_cast(skeleton->a * slot->a * 255); - - Vector2u size = texture->getSize(); - vertices[0].color.r = r; - vertices[0].color.g = g; - vertices[0].color.b = b; - vertices[0].color.a = a; - vertices[0].position.x = worldVertices[VERTEX_X1]; - vertices[0].position.y = worldVertices[VERTEX_Y1]; - vertices[0].texCoords.x = regionAttachment->uvs[VERTEX_X1] * size.x; - vertices[0].texCoords.y = regionAttachment->uvs[VERTEX_Y1] * size.y; - - vertices[1].color.r = r; - vertices[1].color.g = g; - vertices[1].color.b = b; - vertices[1].color.a = a; - vertices[1].position.x = worldVertices[VERTEX_X2]; - vertices[1].position.y = worldVertices[VERTEX_Y2]; - vertices[1].texCoords.x = regionAttachment->uvs[VERTEX_X2] * size.x; - vertices[1].texCoords.y = regionAttachment->uvs[VERTEX_Y2] * size.y; - - vertices[2].color.r = r; - vertices[2].color.g = g; - vertices[2].color.b = b; - vertices[2].color.a = a; - vertices[2].position.x = worldVertices[VERTEX_X3]; - vertices[2].position.y = worldVertices[VERTEX_Y3]; - vertices[2].texCoords.x = regionAttachment->uvs[VERTEX_X3] * size.x; - vertices[2].texCoords.y = regionAttachment->uvs[VERTEX_Y3] * size.y; - - vertices[3].color.r = r; - vertices[3].color.g = g; - vertices[3].color.b = b; - vertices[3].color.a = a; - vertices[3].position.x = worldVertices[VERTEX_X4]; - vertices[3].position.y = worldVertices[VERTEX_Y4]; - vertices[3].texCoords.x = regionAttachment->uvs[VERTEX_X4] * size.x; - vertices[3].texCoords.y = regionAttachment->uvs[VERTEX_Y4] * size.y; - - vertexArray->append(vertices[0]); - vertexArray->append(vertices[1]); - vertexArray->append(vertices[2]); - vertexArray->append(vertices[0]); - vertexArray->append(vertices[2]); - vertexArray->append(vertices[3]); - - } else if (attachment->type == ATTACHMENT_MESH) { - MeshAttachment* mesh = (MeshAttachment*)attachment; - if (mesh->super.worldVerticesLength > SPINE_MESH_VERTEX_COUNT_MAX) continue; - texture = (Texture*)((AtlasRegion*)mesh->rendererObject)->page->rendererObject; - MeshAttachment_computeWorldVertices(mesh, slot, worldVertices); - - Uint8 r = static_cast(skeleton->r * slot->r * 255); - Uint8 g = static_cast(skeleton->g * slot->g * 255); - Uint8 b = static_cast(skeleton->b * slot->b * 255); - Uint8 a = static_cast(skeleton->a * slot->a * 255); - vertex.color.r = r; - vertex.color.g = g; - vertex.color.b = b; - vertex.color.a = a; - - Vector2u size = texture->getSize(); - for (int i = 0; i < mesh->trianglesCount; ++i) { - int index = mesh->triangles[i] << 1; - vertex.position.x = worldVertices[index]; - vertex.position.y = worldVertices[index + 1]; - vertex.texCoords.x = mesh->uvs[index] * size.x; - vertex.texCoords.y = mesh->uvs[index + 1] * size.y; - vertexArray->append(vertex); - } - - } - - if (texture) { - // SMFL doesn't handle batching for us, so we'll just force a single texture per skeleton. - states.texture = texture; - } - } - target.draw(*vertexArray, states); -} - +#include + +#ifndef SPINE_MESH_VERTEX_COUNT_MAX +#define SPINE_MESH_VERTEX_COUNT_MAX 1000 +#endif + +using namespace sf; + +void _AtlasPage_createTexture (AtlasPage* self, const char* path){ + Texture* texture = new Texture(); + if (!texture->loadFromFile(path)) return; + + if (self->magFilter == SP_ATLAS_LINEAR) texture->setSmooth(true); + if (self->uWrap == SP_ATLAS_REPEAT && self->vWrap == SP_ATLAS_REPEAT) texture->setRepeated(true); + + self->rendererObject = texture; + Vector2u size = texture->getSize(); + self->width = size.x; + self->height = size.y; +} + +void _AtlasPage_disposeTexture (AtlasPage* self){ + delete (Texture*)self->rendererObject; +} + +char* _Util_readFile (const char* path, int* length){ + return _readFile(path, length); +} + +/**/ + +namespace spine { + +SkeletonDrawable::SkeletonDrawable (SkeletonData* skeletonData, AnimationStateData* stateData) : + timeScale(1), + vertexArray(new VertexArray(Triangles, skeletonData->bonesCount * 4)), + worldVertices(0) { + Bone_setYDown(true); + worldVertices = MALLOC(float, SPINE_MESH_VERTEX_COUNT_MAX); + skeleton = Skeleton_create(skeletonData); + + ownsAnimationStateData = stateData == 0; + if (ownsAnimationStateData) stateData = AnimationStateData_create(skeletonData); + + state = AnimationState_create(stateData); +} + +SkeletonDrawable::~SkeletonDrawable () { + delete vertexArray; + FREE(worldVertices); + if (ownsAnimationStateData) AnimationStateData_dispose(state->data); + AnimationState_dispose(state); + Skeleton_dispose(skeleton); +} + +void SkeletonDrawable::update (float deltaTime) { + Skeleton_update(skeleton, deltaTime); + AnimationState_update(state, deltaTime * timeScale); + AnimationState_apply(state, skeleton); + Skeleton_updateWorldTransform(skeleton); +} + +void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const { + vertexArray->clear(); + + sf::Vertex vertices[4]; + sf::Vertex vertex; + for (int i = 0; i < skeleton->slotsCount; ++i) { + Slot* slot = skeleton->drawOrder[i]; + Attachment* attachment = slot->attachment; + if (!attachment) continue; + + sf::BlendMode blend; + switch (slot->data->blendMode) { + case BLEND_MODE_ADDITIVE: + blend = BlendAdd; + break; + case BLEND_MODE_MULTIPLY: + blend = BlendMultiply; + break; + case BLEND_MODE_SCREEN: // Unsupported, fall through. + default: + blend = BlendAlpha; + } + if (states.blendMode != blend) { + target.draw(*vertexArray, states); + vertexArray->clear(); + states.blendMode = blend; + } + + Texture* texture = 0; + if (attachment->type == ATTACHMENT_REGION) { + RegionAttachment* regionAttachment = (RegionAttachment*)attachment; + texture = (Texture*)((AtlasRegion*)regionAttachment->rendererObject)->page->rendererObject; + RegionAttachment_computeWorldVertices(regionAttachment, slot->bone, worldVertices); + + Uint8 r = static_cast(skeleton->r * slot->r * 255); + Uint8 g = static_cast(skeleton->g * slot->g * 255); + Uint8 b = static_cast(skeleton->b * slot->b * 255); + Uint8 a = static_cast(skeleton->a * slot->a * 255); + + Vector2u size = texture->getSize(); + vertices[0].color.r = r; + vertices[0].color.g = g; + vertices[0].color.b = b; + vertices[0].color.a = a; + vertices[0].position.x = worldVertices[VERTEX_X1]; + vertices[0].position.y = worldVertices[VERTEX_Y1]; + vertices[0].texCoords.x = regionAttachment->uvs[VERTEX_X1] * size.x; + vertices[0].texCoords.y = regionAttachment->uvs[VERTEX_Y1] * size.y; + + vertices[1].color.r = r; + vertices[1].color.g = g; + vertices[1].color.b = b; + vertices[1].color.a = a; + vertices[1].position.x = worldVertices[VERTEX_X2]; + vertices[1].position.y = worldVertices[VERTEX_Y2]; + vertices[1].texCoords.x = regionAttachment->uvs[VERTEX_X2] * size.x; + vertices[1].texCoords.y = regionAttachment->uvs[VERTEX_Y2] * size.y; + + vertices[2].color.r = r; + vertices[2].color.g = g; + vertices[2].color.b = b; + vertices[2].color.a = a; + vertices[2].position.x = worldVertices[VERTEX_X3]; + vertices[2].position.y = worldVertices[VERTEX_Y3]; + vertices[2].texCoords.x = regionAttachment->uvs[VERTEX_X3] * size.x; + vertices[2].texCoords.y = regionAttachment->uvs[VERTEX_Y3] * size.y; + + vertices[3].color.r = r; + vertices[3].color.g = g; + vertices[3].color.b = b; + vertices[3].color.a = a; + vertices[3].position.x = worldVertices[VERTEX_X4]; + vertices[3].position.y = worldVertices[VERTEX_Y4]; + vertices[3].texCoords.x = regionAttachment->uvs[VERTEX_X4] * size.x; + vertices[3].texCoords.y = regionAttachment->uvs[VERTEX_Y4] * size.y; + + vertexArray->append(vertices[0]); + vertexArray->append(vertices[1]); + vertexArray->append(vertices[2]); + vertexArray->append(vertices[0]); + vertexArray->append(vertices[2]); + vertexArray->append(vertices[3]); + + } else if (attachment->type == ATTACHMENT_MESH) { + MeshAttachment* mesh = (MeshAttachment*)attachment; + if (mesh->super.worldVerticesLength > SPINE_MESH_VERTEX_COUNT_MAX) continue; + texture = (Texture*)((AtlasRegion*)mesh->rendererObject)->page->rendererObject; + MeshAttachment_computeWorldVertices(mesh, slot, worldVertices); + + Uint8 r = static_cast(skeleton->r * slot->r * 255); + Uint8 g = static_cast(skeleton->g * slot->g * 255); + Uint8 b = static_cast(skeleton->b * slot->b * 255); + Uint8 a = static_cast(skeleton->a * slot->a * 255); + vertex.color.r = r; + vertex.color.g = g; + vertex.color.b = b; + vertex.color.a = a; + + Vector2u size = texture->getSize(); + for (int i = 0; i < mesh->trianglesCount; ++i) { + int index = mesh->triangles[i] << 1; + vertex.position.x = worldVertices[index]; + vertex.position.y = worldVertices[index + 1]; + vertex.texCoords.x = mesh->uvs[index] * size.x; + vertex.texCoords.y = mesh->uvs[index + 1] * size.y; + vertexArray->append(vertex); + } + + } + + if (texture) { + // SMFL doesn't handle batching for us, so we'll just force a single texture per skeleton. + states.texture = texture; + } + } + target.draw(*vertexArray, states); +} + } /* namespace spine */ diff --git a/spine-sfml/src/spine/spine-sfml.h b/spine-sfml/src/spine/spine-sfml.h index 77385ab209..52de7acd65 100644 --- a/spine-sfml/src/spine/spine-sfml.h +++ b/spine-sfml/src/spine/spine-sfml.h @@ -1,65 +1,64 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef SPINE_SFML_H_ -#define SPINE_SFML_H_ - -#define SPINE_SHORT_NAMES -#include -#include -#include -#include -#include -#include -#include - -namespace spine { - -class SkeletonDrawable: public sf::Drawable { -public: - Skeleton* skeleton; - AnimationState* state; - float timeScale; - sf::VertexArray* vertexArray; - - SkeletonDrawable (SkeletonData* skeleton, AnimationStateData* stateData = 0); - ~SkeletonDrawable (); - - void update (float deltaTime); - - virtual void draw (sf::RenderTarget& target, sf::RenderStates states) const; -private: - bool ownsAnimationStateData; - float* worldVertices; -}; - -} /* namespace spine */ +#ifndef SPINE_SFML_H_ +#define SPINE_SFML_H_ + +#define SPINE_SHORT_NAMES +#include +#include +#include +#include +#include +#include +#include + +namespace spine { + +class SkeletonDrawable: public sf::Drawable { +public: + Skeleton* skeleton; + AnimationState* state; + float timeScale; + sf::VertexArray* vertexArray; + + SkeletonDrawable (SkeletonData* skeleton, AnimationStateData* stateData = 0); + ~SkeletonDrawable (); + + void update (float deltaTime); + + virtual void draw (sf::RenderTarget& target, sf::RenderStates states) const; +private: + bool ownsAnimationStateData; + float* worldVertices; +}; + +} /* namespace spine */ #endif /* SPINE_SFML_H_ */ diff --git a/spine-starling/spine-starling-example/src/spine/examples/GoblinsExample.as b/spine-starling/spine-starling-example/src/spine/examples/GoblinsExample.as index 991d609b66..50d8661848 100644 --- a/spine-starling/spine-starling-example/src/spine/examples/GoblinsExample.as +++ b/spine-starling/spine-starling-example/src/spine/examples/GoblinsExample.as @@ -1,105 +1,104 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.examples { -import spine.*; -import spine.atlas.Atlas; -import spine.attachments.AtlasAttachmentLoader; -import spine.attachments.AttachmentLoader; -import spine.starling.SkeletonAnimation; -import spine.starling.StarlingAtlasAttachmentLoader; -import spine.starling.StarlingTextureLoader; - -import starling.core.Starling; -import starling.display.Sprite; -import starling.events.Touch; -import starling.events.TouchEvent; -import starling.events.TouchPhase; -import starling.textures.Texture; -import starling.textures.TextureAtlas; - -public class GoblinsExample extends Sprite { - [Embed(source = "/goblins-mesh.json", mimeType = "application/octet-stream")] - static public const GoblinsJson:Class; - - [Embed(source = "/goblins.atlas", mimeType = "application/octet-stream")] - static public const GoblinsAtlas:Class; - - [Embed(source = "/goblins.png")] - static public const GoblinsAtlasTexture:Class; - - [Embed(source = "/goblins-mesh-starling.xml", mimeType = "application/octet-stream")] - static public const GoblinsStarlingAtlas:Class; - - [Embed(source = "/goblins-mesh-starling.png")] - static public const GoblinsStarlingAtlasTexture:Class; - - private var skeleton:SkeletonAnimation; - - public function GoblinsExample () { - var useStarlingAtlas:Boolean = false; - - var attachmentLoader:AttachmentLoader; - if (useStarlingAtlas) { - var texture:Texture = Texture.fromBitmap(new GoblinsStarlingAtlasTexture()); - var xml:XML = XML(new GoblinsStarlingAtlas()); - var starlingAtlas:TextureAtlas = new TextureAtlas(texture, xml); - attachmentLoader = new StarlingAtlasAttachmentLoader(starlingAtlas); - } else { - var spineAtlas:Atlas = new Atlas(new GoblinsAtlas(), new StarlingTextureLoader(new GoblinsAtlasTexture())); - attachmentLoader = new AtlasAttachmentLoader(spineAtlas); - } - - var json:SkeletonJson = new SkeletonJson(attachmentLoader); - var skeletonData:SkeletonData = json.readSkeletonData(new GoblinsJson()); - - skeleton = new SkeletonAnimation(skeletonData); - skeleton.x = 320; - skeleton.y = 420; - skeleton.skeleton.skinName = "goblin"; - skeleton.skeleton.setSlotsToSetupPose(); - skeleton.state.setAnimationByName(0, "walk", true); - - addChild(skeleton); - Starling.juggler.add(skeleton); - - addEventListener(TouchEvent.TOUCH, onClick); - } - - private function onClick (event:TouchEvent) : void { - var touch:Touch = event.getTouch(this); - if (touch && touch.phase == TouchPhase.BEGAN) { - skeleton.skeleton.skinName = skeleton.skeleton.skin.name == "goblin" ? "goblingirl" : "goblin"; - skeleton.skeleton.setSlotsToSetupPose(); - } - } -} +package spine.examples { +import spine.*; +import spine.atlas.Atlas; +import spine.attachments.AtlasAttachmentLoader; +import spine.attachments.AttachmentLoader; +import spine.starling.SkeletonAnimation; +import spine.starling.StarlingAtlasAttachmentLoader; +import spine.starling.StarlingTextureLoader; + +import starling.core.Starling; +import starling.display.Sprite; +import starling.events.Touch; +import starling.events.TouchEvent; +import starling.events.TouchPhase; +import starling.textures.Texture; +import starling.textures.TextureAtlas; + +public class GoblinsExample extends Sprite { + [Embed(source = "/goblins-mesh.json", mimeType = "application/octet-stream")] + static public const GoblinsJson:Class; + + [Embed(source = "/goblins.atlas", mimeType = "application/octet-stream")] + static public const GoblinsAtlas:Class; + + [Embed(source = "/goblins.png")] + static public const GoblinsAtlasTexture:Class; + + [Embed(source = "/goblins-mesh-starling.xml", mimeType = "application/octet-stream")] + static public const GoblinsStarlingAtlas:Class; + + [Embed(source = "/goblins-mesh-starling.png")] + static public const GoblinsStarlingAtlasTexture:Class; + + private var skeleton:SkeletonAnimation; + + public function GoblinsExample () { + var useStarlingAtlas:Boolean = false; + + var attachmentLoader:AttachmentLoader; + if (useStarlingAtlas) { + var texture:Texture = Texture.fromBitmap(new GoblinsStarlingAtlasTexture()); + var xml:XML = XML(new GoblinsStarlingAtlas()); + var starlingAtlas:TextureAtlas = new TextureAtlas(texture, xml); + attachmentLoader = new StarlingAtlasAttachmentLoader(starlingAtlas); + } else { + var spineAtlas:Atlas = new Atlas(new GoblinsAtlas(), new StarlingTextureLoader(new GoblinsAtlasTexture())); + attachmentLoader = new AtlasAttachmentLoader(spineAtlas); + } + + var json:SkeletonJson = new SkeletonJson(attachmentLoader); + var skeletonData:SkeletonData = json.readSkeletonData(new GoblinsJson()); + + skeleton = new SkeletonAnimation(skeletonData); + skeleton.x = 320; + skeleton.y = 420; + skeleton.skeleton.skinName = "goblin"; + skeleton.skeleton.setSlotsToSetupPose(); + skeleton.state.setAnimationByName(0, "walk", true); + + addChild(skeleton); + Starling.juggler.add(skeleton); + + addEventListener(TouchEvent.TOUCH, onClick); + } + + private function onClick (event:TouchEvent) : void { + var touch:Touch = event.getTouch(this); + if (touch && touch.phase == TouchPhase.BEGAN) { + skeleton.skeleton.skinName = skeleton.skeleton.skin.name == "goblin" ? "goblingirl" : "goblin"; + skeleton.skeleton.setSlotsToSetupPose(); + } + } +} } diff --git a/spine-starling/spine-starling-example/src/spine/examples/Main.as b/spine-starling/spine-starling-example/src/spine/examples/Main.as index d1c184a009..6d47aeef16 100644 --- a/spine-starling/spine-starling-example/src/spine/examples/Main.as +++ b/spine-starling/spine-starling-example/src/spine/examples/Main.as @@ -1,58 +1,57 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.examples { - -import flash.display.Sprite; - -import starling.core.Starling; - -[SWF(width = "800", height = "600", frameRate = "60", backgroundColor = "#dddddd")] -public class Main extends Sprite { - private var _starling:Starling; - - public function Main () { - var example:Class; - // example = SpineboyExample; - // example = GoblinsExample; - // example = RaptorExample; - example = TankExample; - // example = VineExample; - - _starling = new Starling(example, stage); - _starling.enableErrorChecking = true; - _starling.showStats = true; - _starling.skipUnchangedFrames = false; - _starling.start(); - } -} - +package spine.examples { + +import flash.display.Sprite; + +import starling.core.Starling; + +[SWF(width = "800", height = "600", frameRate = "60", backgroundColor = "#dddddd")] +public class Main extends Sprite { + private var _starling:Starling; + + public function Main () { + var example:Class; + // example = SpineboyExample; + // example = GoblinsExample; + // example = RaptorExample; + example = TankExample; + // example = VineExample; + + _starling = new Starling(example, stage); + _starling.enableErrorChecking = true; + _starling.showStats = true; + _starling.skipUnchangedFrames = false; + _starling.start(); + } +} + } diff --git a/spine-starling/spine-starling-example/src/spine/examples/RaptorExample.as b/spine-starling/spine-starling-example/src/spine/examples/RaptorExample.as index fb32890995..57b7896334 100644 --- a/spine-starling/spine-starling-example/src/spine/examples/RaptorExample.as +++ b/spine-starling/spine-starling-example/src/spine/examples/RaptorExample.as @@ -1,90 +1,89 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.examples { -import spine.atlas.Atlas; -import spine.*; -import spine.attachments.AtlasAttachmentLoader; -import spine.attachments.AttachmentLoader; -import spine.starling.SkeletonAnimation; -import spine.starling.StarlingTextureLoader; - -import starling.core.Starling; -import starling.display.Sprite; -import starling.events.Touch; -import starling.events.TouchEvent; -import starling.events.TouchPhase; - -public class RaptorExample extends Sprite { - [Embed(source = "/raptor.json", mimeType = "application/octet-stream")] - static public const RaptorJson:Class; - - [Embed(source = "/raptor.atlas", mimeType = "application/octet-stream")] - static public const RaptorAtlas:Class; - - [Embed(source = "/raptor.png")] - static public const RaptorAtlasTexture:Class; - - private var skeleton:SkeletonAnimation; - private var gunGrabbed:Boolean; - - public function RaptorExample () { - var attachmentLoader:AttachmentLoader; - var spineAtlas:Atlas = new Atlas(new RaptorAtlas(), new StarlingTextureLoader(new RaptorAtlasTexture())); - attachmentLoader = new AtlasAttachmentLoader(spineAtlas); - - var json:SkeletonJson = new SkeletonJson(attachmentLoader); - json.scale = 0.5; - var skeletonData:SkeletonData = json.readSkeletonData(new RaptorJson()); - - skeleton = new SkeletonAnimation(skeletonData); - skeleton.x = 400; - skeleton.y = 560; - skeleton.state.setAnimationByName(0, "walk", true); - - addChild(skeleton); - Starling.juggler.add(skeleton); - - addEventListener(TouchEvent.TOUCH, onClick); - } - - private function onClick (event:TouchEvent) : void { - var touch:Touch = event.getTouch(this); - if (touch && touch.phase == TouchPhase.BEGAN) { - if (gunGrabbed) - skeleton.skeleton.setToSetupPose(); - else - skeleton.state.setAnimationByName(1, "gungrab", false); - gunGrabbed = !gunGrabbed; - } - } -} +package spine.examples { +import spine.atlas.Atlas; +import spine.*; +import spine.attachments.AtlasAttachmentLoader; +import spine.attachments.AttachmentLoader; +import spine.starling.SkeletonAnimation; +import spine.starling.StarlingTextureLoader; + +import starling.core.Starling; +import starling.display.Sprite; +import starling.events.Touch; +import starling.events.TouchEvent; +import starling.events.TouchPhase; + +public class RaptorExample extends Sprite { + [Embed(source = "/raptor.json", mimeType = "application/octet-stream")] + static public const RaptorJson:Class; + + [Embed(source = "/raptor.atlas", mimeType = "application/octet-stream")] + static public const RaptorAtlas:Class; + + [Embed(source = "/raptor.png")] + static public const RaptorAtlasTexture:Class; + + private var skeleton:SkeletonAnimation; + private var gunGrabbed:Boolean; + + public function RaptorExample () { + var attachmentLoader:AttachmentLoader; + var spineAtlas:Atlas = new Atlas(new RaptorAtlas(), new StarlingTextureLoader(new RaptorAtlasTexture())); + attachmentLoader = new AtlasAttachmentLoader(spineAtlas); + + var json:SkeletonJson = new SkeletonJson(attachmentLoader); + json.scale = 0.5; + var skeletonData:SkeletonData = json.readSkeletonData(new RaptorJson()); + + skeleton = new SkeletonAnimation(skeletonData); + skeleton.x = 400; + skeleton.y = 560; + skeleton.state.setAnimationByName(0, "walk", true); + + addChild(skeleton); + Starling.juggler.add(skeleton); + + addEventListener(TouchEvent.TOUCH, onClick); + } + + private function onClick (event:TouchEvent) : void { + var touch:Touch = event.getTouch(this); + if (touch && touch.phase == TouchPhase.BEGAN) { + if (gunGrabbed) + skeleton.skeleton.setToSetupPose(); + else + skeleton.state.setAnimationByName(1, "gungrab", false); + gunGrabbed = !gunGrabbed; + } + } +} } diff --git a/spine-starling/spine-starling-example/src/spine/examples/SpineboyExample.as b/spine-starling/spine-starling-example/src/spine/examples/SpineboyExample.as index 46dc6a9cdb..fb57648a33 100644 --- a/spine-starling/spine-starling-example/src/spine/examples/SpineboyExample.as +++ b/spine-starling/spine-starling-example/src/spine/examples/SpineboyExample.as @@ -1,108 +1,107 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.examples { -import spine.animation.AnimationStateData; -import spine.*; -import spine.atlas.Atlas; -import spine.attachments.AtlasAttachmentLoader; -import spine.attachments.AttachmentLoader; -import spine.starling.SkeletonAnimation; -import spine.starling.StarlingTextureLoader; - -import starling.core.Starling; -import starling.display.Sprite; -import starling.events.Touch; -import starling.events.TouchEvent; -import starling.events.TouchPhase; - -public class SpineboyExample extends Sprite { - [Embed(source = "/spineboy.json", mimeType = "application/octet-stream")] - static public const SpineboyJson:Class; - - [Embed(source = "/spineboy.atlas", mimeType = "application/octet-stream")] - static public const SpineboyAtlas:Class; - - [Embed(source = "/spineboy.png")] - static public const SpineboyAtlasTexture:Class; - - private var skeleton:SkeletonAnimation; - - public function SpineboyExample () { - var spineAtlas:Atlas = new Atlas(new SpineboyAtlas(), new StarlingTextureLoader(new SpineboyAtlasTexture())); - var attachmentLoader:AttachmentLoader = new AtlasAttachmentLoader(spineAtlas); - var json:SkeletonJson = new SkeletonJson(attachmentLoader); - json.scale = 0.6; - var skeletonData:SkeletonData = json.readSkeletonData(new SpineboyJson()); - - var stateData:AnimationStateData = new AnimationStateData(skeletonData); - stateData.setMixByName("run", "jump", 0.2); - stateData.setMixByName("jump", "run", 0.4); - stateData.setMixByName("jump", "jump", 0.2); - - skeleton = new SkeletonAnimation(skeletonData, stateData); - skeleton.x = 400; - skeleton.y = 560; - - skeleton.state.onStart.add(function (trackIndex:int) : void { - trace(trackIndex + " start: " + skeleton.state.getCurrent(trackIndex)); - }); - skeleton.state.onEnd.add(function (trackIndex:int) : void { - trace(trackIndex + " end: " + skeleton.state.getCurrent(trackIndex)); - }); - skeleton.state.onComplete.add(function (trackIndex:int, count:int) : void { - trace(trackIndex + " complete: " + skeleton.state.getCurrent(trackIndex) + ", " + count); - }); - skeleton.state.onEvent.add(function (trackIndex:int, event:Event) : void { - trace(trackIndex + " event: " + skeleton.state.getCurrent(trackIndex) + ", " - + event.data.name + ": " + event.intValue + ", " + event.floatValue + ", " + event.stringValue); - }); - - skeleton.skeleton.setToSetupPose(); - skeleton.state.setAnimationByName(0, "run", true); - skeleton.state.addAnimationByName(0, "jump", false, 3); - skeleton.state.addAnimationByName(0, "run", true, 0); - - addChild(skeleton); - Starling.juggler.add(skeleton); - - addEventListener(TouchEvent.TOUCH, onClick); - } - - private function onClick (event:TouchEvent) : void { - var touch:Touch = event.getTouch(this); - if (touch && touch.phase == TouchPhase.BEGAN) { - skeleton.state.setAnimationByName(0, "jump", false); - skeleton.state.addAnimationByName(0, "run", true, 0); - } - } -} +package spine.examples { +import spine.animation.AnimationStateData; +import spine.*; +import spine.atlas.Atlas; +import spine.attachments.AtlasAttachmentLoader; +import spine.attachments.AttachmentLoader; +import spine.starling.SkeletonAnimation; +import spine.starling.StarlingTextureLoader; + +import starling.core.Starling; +import starling.display.Sprite; +import starling.events.Touch; +import starling.events.TouchEvent; +import starling.events.TouchPhase; + +public class SpineboyExample extends Sprite { + [Embed(source = "/spineboy.json", mimeType = "application/octet-stream")] + static public const SpineboyJson:Class; + + [Embed(source = "/spineboy.atlas", mimeType = "application/octet-stream")] + static public const SpineboyAtlas:Class; + + [Embed(source = "/spineboy.png")] + static public const SpineboyAtlasTexture:Class; + + private var skeleton:SkeletonAnimation; + + public function SpineboyExample () { + var spineAtlas:Atlas = new Atlas(new SpineboyAtlas(), new StarlingTextureLoader(new SpineboyAtlasTexture())); + var attachmentLoader:AttachmentLoader = new AtlasAttachmentLoader(spineAtlas); + var json:SkeletonJson = new SkeletonJson(attachmentLoader); + json.scale = 0.6; + var skeletonData:SkeletonData = json.readSkeletonData(new SpineboyJson()); + + var stateData:AnimationStateData = new AnimationStateData(skeletonData); + stateData.setMixByName("run", "jump", 0.2); + stateData.setMixByName("jump", "run", 0.4); + stateData.setMixByName("jump", "jump", 0.2); + + skeleton = new SkeletonAnimation(skeletonData, stateData); + skeleton.x = 400; + skeleton.y = 560; + + skeleton.state.onStart.add(function (trackIndex:int) : void { + trace(trackIndex + " start: " + skeleton.state.getCurrent(trackIndex)); + }); + skeleton.state.onEnd.add(function (trackIndex:int) : void { + trace(trackIndex + " end: " + skeleton.state.getCurrent(trackIndex)); + }); + skeleton.state.onComplete.add(function (trackIndex:int, count:int) : void { + trace(trackIndex + " complete: " + skeleton.state.getCurrent(trackIndex) + ", " + count); + }); + skeleton.state.onEvent.add(function (trackIndex:int, event:Event) : void { + trace(trackIndex + " event: " + skeleton.state.getCurrent(trackIndex) + ", " + + event.data.name + ": " + event.intValue + ", " + event.floatValue + ", " + event.stringValue); + }); + + skeleton.skeleton.setToSetupPose(); + skeleton.state.setAnimationByName(0, "run", true); + skeleton.state.addAnimationByName(0, "jump", false, 3); + skeleton.state.addAnimationByName(0, "run", true, 0); + + addChild(skeleton); + Starling.juggler.add(skeleton); + + addEventListener(TouchEvent.TOUCH, onClick); + } + + private function onClick (event:TouchEvent) : void { + var touch:Touch = event.getTouch(this); + if (touch && touch.phase == TouchPhase.BEGAN) { + skeleton.state.setAnimationByName(0, "jump", false); + skeleton.state.addAnimationByName(0, "run", true, 0); + } + } +} } diff --git a/spine-starling/spine-starling-example/src/spine/examples/TankExample.as b/spine-starling/spine-starling-example/src/spine/examples/TankExample.as index bc4108da87..46847c93ae 100644 --- a/spine-starling/spine-starling-example/src/spine/examples/TankExample.as +++ b/spine-starling/spine-starling-example/src/spine/examples/TankExample.as @@ -1,73 +1,72 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.examples { -import spine.atlas.Atlas; -import spine.*; -import spine.attachments.AtlasAttachmentLoader; -import spine.attachments.AttachmentLoader; -import spine.starling.SkeletonAnimation; -import spine.starling.StarlingTextureLoader; - -import starling.core.Starling; -import starling.display.Sprite; - -public class TankExample extends Sprite { - [Embed(source = "/tank.json", mimeType = "application/octet-stream")] - static public const TankJson:Class; - - [Embed(source = "/tank.atlas", mimeType = "application/octet-stream")] - static public const TankAtlas:Class; - - [Embed(source = "/tank.png")] - static public const TankAtlasTexture:Class; - - private var skeleton:SkeletonAnimation; - - public function TankExample () { - var attachmentLoader:AttachmentLoader; - var spineAtlas:Atlas = new Atlas(new TankAtlas(), new StarlingTextureLoader(new TankAtlasTexture())); - attachmentLoader = new AtlasAttachmentLoader(spineAtlas); - - var json:SkeletonJson = new SkeletonJson(attachmentLoader); - json.scale = 0.5; - var skeletonData:SkeletonData = json.readSkeletonData(new TankJson()); - - skeleton = new SkeletonAnimation(skeletonData); - skeleton.x = 400; - skeleton.y = 560; - skeleton.state.setAnimationByName(0, "drive", true); - - addChild(skeleton); - Starling.juggler.add(skeleton); - } -} +package spine.examples { +import spine.atlas.Atlas; +import spine.*; +import spine.attachments.AtlasAttachmentLoader; +import spine.attachments.AttachmentLoader; +import spine.starling.SkeletonAnimation; +import spine.starling.StarlingTextureLoader; + +import starling.core.Starling; +import starling.display.Sprite; + +public class TankExample extends Sprite { + [Embed(source = "/tank.json", mimeType = "application/octet-stream")] + static public const TankJson:Class; + + [Embed(source = "/tank.atlas", mimeType = "application/octet-stream")] + static public const TankAtlas:Class; + + [Embed(source = "/tank.png")] + static public const TankAtlasTexture:Class; + + private var skeleton:SkeletonAnimation; + + public function TankExample () { + var attachmentLoader:AttachmentLoader; + var spineAtlas:Atlas = new Atlas(new TankAtlas(), new StarlingTextureLoader(new TankAtlasTexture())); + attachmentLoader = new AtlasAttachmentLoader(spineAtlas); + + var json:SkeletonJson = new SkeletonJson(attachmentLoader); + json.scale = 0.5; + var skeletonData:SkeletonData = json.readSkeletonData(new TankJson()); + + skeleton = new SkeletonAnimation(skeletonData); + skeleton.x = 400; + skeleton.y = 560; + skeleton.state.setAnimationByName(0, "drive", true); + + addChild(skeleton); + Starling.juggler.add(skeleton); + } +} } diff --git a/spine-starling/spine-starling-example/src/spine/examples/VineExample.as b/spine-starling/spine-starling-example/src/spine/examples/VineExample.as index ff997d6ad7..f92972bfcb 100644 --- a/spine-starling/spine-starling-example/src/spine/examples/VineExample.as +++ b/spine-starling/spine-starling-example/src/spine/examples/VineExample.as @@ -1,73 +1,72 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.examples { -import spine.*; -import spine.atlas.Atlas; -import spine.attachments.AtlasAttachmentLoader; -import spine.attachments.AttachmentLoader; -import spine.starling.SkeletonAnimation; -import spine.starling.StarlingTextureLoader; - -import starling.core.Starling; -import starling.display.Sprite; - -public class VineExample extends Sprite { - [Embed(source = "/vine.json", mimeType = "application/octet-stream")] - static public const VineJson:Class; - - [Embed(source = "/vine.atlas", mimeType = "application/octet-stream")] - static public const VineAtlas:Class; - - [Embed(source = "/vine.png")] - static public const VineAtlasTexture:Class; - - private var skeleton:SkeletonAnimation; - - public function VineExample () { - var attachmentLoader:AttachmentLoader; - var spineAtlas:Atlas = new Atlas(new VineAtlas(), new StarlingTextureLoader(new VineAtlasTexture())); - attachmentLoader = new AtlasAttachmentLoader(spineAtlas); - - var json:SkeletonJson = new SkeletonJson(attachmentLoader); - json.scale = 0.5; - var skeletonData:SkeletonData = json.readSkeletonData(new VineJson()); - - skeleton = new SkeletonAnimation(skeletonData); - skeleton.x = 400; - skeleton.y = 560; - skeleton.state.setAnimationByName(0, "animation", true); - - addChild(skeleton); - Starling.juggler.add(skeleton); - } -} +package spine.examples { +import spine.*; +import spine.atlas.Atlas; +import spine.attachments.AtlasAttachmentLoader; +import spine.attachments.AttachmentLoader; +import spine.starling.SkeletonAnimation; +import spine.starling.StarlingTextureLoader; + +import starling.core.Starling; +import starling.display.Sprite; + +public class VineExample extends Sprite { + [Embed(source = "/vine.json", mimeType = "application/octet-stream")] + static public const VineJson:Class; + + [Embed(source = "/vine.atlas", mimeType = "application/octet-stream")] + static public const VineAtlas:Class; + + [Embed(source = "/vine.png")] + static public const VineAtlasTexture:Class; + + private var skeleton:SkeletonAnimation; + + public function VineExample () { + var attachmentLoader:AttachmentLoader; + var spineAtlas:Atlas = new Atlas(new VineAtlas(), new StarlingTextureLoader(new VineAtlasTexture())); + attachmentLoader = new AtlasAttachmentLoader(spineAtlas); + + var json:SkeletonJson = new SkeletonJson(attachmentLoader); + json.scale = 0.5; + var skeletonData:SkeletonData = json.readSkeletonData(new VineJson()); + + skeleton = new SkeletonAnimation(skeletonData); + skeleton.x = 400; + skeleton.y = 560; + skeleton.state.setAnimationByName(0, "animation", true); + + addChild(skeleton); + Starling.juggler.add(skeleton); + } +} } diff --git a/spine-starling/spine-starling/src/spine/starling/SkeletonAnimation.as b/spine-starling/spine-starling/src/spine/starling/SkeletonAnimation.as index 41e656809a..a8d89da394 100644 --- a/spine-starling/spine-starling/src/spine/starling/SkeletonAnimation.as +++ b/spine-starling/spine-starling/src/spine/starling/SkeletonAnimation.as @@ -1,58 +1,57 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.starling { -import spine.SkeletonData; -import spine.animation.AnimationState; -import spine.animation.AnimationStateData; - -import starling.animation.IAnimatable; - -public class SkeletonAnimation extends SkeletonSprite implements IAnimatable { - public var state:AnimationState; - public var timeScale:Number = 1; - - public function SkeletonAnimation (skeletonData:SkeletonData, stateData:AnimationStateData = null) { - super(skeletonData); - state = new AnimationState(stateData ? stateData : new AnimationStateData(skeletonData)); - } - - public function advanceTime (time:Number) : void { - time *= timeScale; - skeleton.update(time); - state.update(time); - state.apply(skeleton); - skeleton.updateWorldTransform(); - this.setRequiresRedraw(); - } -} - +package spine.starling { +import spine.SkeletonData; +import spine.animation.AnimationState; +import spine.animation.AnimationStateData; + +import starling.animation.IAnimatable; + +public class SkeletonAnimation extends SkeletonSprite implements IAnimatable { + public var state:AnimationState; + public var timeScale:Number = 1; + + public function SkeletonAnimation (skeletonData:SkeletonData, stateData:AnimationStateData = null) { + super(skeletonData); + state = new AnimationState(stateData ? stateData : new AnimationStateData(skeletonData)); + } + + public function advanceTime (time:Number) : void { + time *= timeScale; + skeleton.update(time); + state.update(time); + state.apply(skeleton); + skeleton.updateWorldTransform(); + this.setRequiresRedraw(); + } +} + } diff --git a/spine-starling/spine-starling/src/spine/starling/SkeletonMesh.as b/spine-starling/spine-starling/src/spine/starling/SkeletonMesh.as index 201c2693ac..91dc8f1736 100644 --- a/spine-starling/spine-starling/src/spine/starling/SkeletonMesh.as +++ b/spine-starling/spine-starling/src/spine/starling/SkeletonMesh.as @@ -1,55 +1,54 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.starling { -import starling.textures.Texture; -import starling.styles.MeshStyle; -import starling.rendering.IndexData; -import starling.rendering.VertexData; -import starling.display.Mesh; - -public class SkeletonMesh extends Mesh { - - public function SkeletonMesh(texture:Texture, vertexData:VertexData = null, indexData:IndexData = null, style:MeshStyle=null) { - super(vertexData == null? new VertexData(): vertexData, indexData == null? new IndexData(): indexData, style); - this.texture = texture; - } - - public function getVertexData(): VertexData { - return this.vertexData; - } - - public function getIndexData(): IndexData { - return this.indexData; - } +package spine.starling { +import starling.textures.Texture; +import starling.styles.MeshStyle; +import starling.rendering.IndexData; +import starling.rendering.VertexData; +import starling.display.Mesh; + +public class SkeletonMesh extends Mesh { + + public function SkeletonMesh(texture:Texture, vertexData:VertexData = null, indexData:IndexData = null, style:MeshStyle=null) { + super(vertexData == null? new VertexData(): vertexData, indexData == null? new IndexData(): indexData, style); + this.texture = texture; + } + + public function getVertexData(): VertexData { + return this.vertexData; + } + + public function getIndexData(): IndexData { + return this.indexData; + } +} + } - -} \ No newline at end of file diff --git a/spine-starling/spine-starling/src/spine/starling/SkeletonSprite.as b/spine-starling/spine-starling/src/spine/starling/SkeletonSprite.as index 72bd44e901..467bbdb251 100644 --- a/spine-starling/spine-starling/src/spine/starling/SkeletonSprite.as +++ b/spine-starling/spine-starling/src/spine/starling/SkeletonSprite.as @@ -1,258 +1,257 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.starling { -import spine.Bone; -import spine.Skeleton; -import spine.SkeletonData; -import spine.Slot; -import spine.atlas.AtlasRegion; -import spine.attachments.Attachment; -import spine.attachments.MeshAttachment; -import spine.attachments.RegionAttachment; - -import starling.display.BlendMode; -import starling.display.DisplayObject; -import starling.display.Image; -import starling.rendering.IndexData; -import starling.rendering.Painter; -import starling.rendering.VertexData; -import starling.utils.Color; -import starling.utils.MatrixUtil; - -import flash.geom.Matrix; -import flash.geom.Point; -import flash.geom.Rectangle; - -public class SkeletonSprite extends DisplayObject { - static private var _tempPoint:Point = new Point(); - static private var _tempMatrix:Matrix = new Matrix(); - static private var _tempVertices:Vector. = new Vector.(8); - static internal var blendModes:Vector. = new [ - BlendMode.NORMAL, BlendMode.ADD, BlendMode.MULTIPLY, BlendMode.SCREEN]; - - private var _skeleton:Skeleton; - public var batchable:Boolean = true; - private var _smoothing:String = "bilinear"; - - public function SkeletonSprite (skeletonData:SkeletonData) { - Bone.yDown = true; - _skeleton = new Skeleton(skeletonData); - _skeleton.updateWorldTransform(); - } - - override public function render (painter:Painter) : void { - alpha *= this.alpha * skeleton.a; - var originalBlendMode:String = painter.state.blendMode; - var r:Number = skeleton.r * 255; - var g:Number = skeleton.g * 255; - var b:Number = skeleton.b * 255; - var x:Number = skeleton.x; - var y:Number = skeleton.y; - var drawOrder:Vector. = skeleton.drawOrder; - var worldVertices:Vector. = _tempVertices; - var ii:int, iii:int; - var rgb:uint, a:Number; - var mesh:SkeletonMesh; - var verticesLength:int, verticesCount:int, indicesLength:int; - var indexData:IndexData, indices:Vector., vertexData:VertexData; - var uvs: Vector.; - - for (var i:int = 0, n:int = drawOrder.length; i < n; ++i) { - var slot:Slot = drawOrder[i]; - if (slot.attachment is RegionAttachment) { - var region:RegionAttachment = slot.attachment as RegionAttachment; - region.computeWorldVertices(x, y, slot.bone, worldVertices); - // FIXME pre-multiplied alpha? - a = slot.a * region.a; - rgb = Color.rgb( - r * slot.r * region.r, - g * slot.g * region.g, - b * slot.b * region.b); - - var image:Image = region.rendererObject as Image; - if (image == null) { - var origImage:Image = Image(AtlasRegion(region.rendererObject).rendererObject); - region.rendererObject = image = new Image(origImage.texture); - for (var j:int = 0; j < 4; j++) { - var p: Point = origImage.getTexCoords(j); - image.setTexCoords(j, p.x, p.y); - } - } - - image.setVertexPosition(0, worldVertices[2], worldVertices[3]); - image.setVertexColor(0, rgb); - image.setVertexAlpha(0, a); - - image.setVertexPosition(1, worldVertices[4], worldVertices[5]); - image.setVertexColor(1, rgb); - image.setVertexAlpha(1, a); - - image.setVertexPosition(2, worldVertices[0], worldVertices[1]); - image.setVertexColor(2, rgb); - image.setVertexAlpha(2, a); - - image.setVertexPosition(3, worldVertices[6], worldVertices[7]); - image.setVertexColor(3, rgb); - image.setVertexAlpha(3, a); - - image.setRequiresRedraw(); - painter.state.blendMode = blendModes[slot.data.blendMode.ordinal]; - // FIXME set smoothing/filter - painter.batchMesh(image); - } else if (slot.attachment is MeshAttachment) { - var meshAttachment:MeshAttachment = MeshAttachment(slot.attachment); - verticesLength = meshAttachment.worldVerticesLength; - verticesCount = verticesLength >> 1; - if (worldVertices.length < verticesLength) worldVertices.length = verticesLength; - meshAttachment.computeWorldVertices(slot, worldVertices); - mesh = meshAttachment.rendererObject as SkeletonMesh; - if (mesh == null) { - if (meshAttachment.rendererObject is Image) - meshAttachment.rendererObject = mesh = new SkeletonMesh(Image(meshAttachment.rendererObject).texture); - if (meshAttachment.rendererObject is AtlasRegion) - meshAttachment.rendererObject = mesh = new SkeletonMesh(Image(AtlasRegion(meshAttachment.rendererObject).rendererObject).texture); - } - - if (mesh.numIndices != meshAttachment.triangles.length) { - indexData = mesh.getIndexData(); - indices = meshAttachment.triangles; - indicesLength = meshAttachment.triangles.length; - for (ii = 0; ii < indicesLength; ii++) { - indexData.setIndex(ii, indices[ii]); - } - indexData.numIndices = indicesLength; - indexData.trim(); - } - - // FIXME pre-multiplied alpha? - a = slot.a * meshAttachment.a; - rgb = Color.rgb( - r * slot.r * meshAttachment.r, - g * slot.g * meshAttachment.g, - b * slot.b * meshAttachment.b); - - vertexData = mesh.getVertexData(); - uvs = meshAttachment.uvs; - vertexData.colorize("color", rgb, a); - for (ii = 0, iii = 0; ii < verticesCount; ii++, iii+=2) { - mesh.setVertexPosition(ii, worldVertices[iii], worldVertices[iii+1]); - mesh.setTexCoords(ii, uvs[iii], uvs[iii+1]); - } - vertexData.numVertices = verticesCount; - // FIXME set smoothing/filter - painter.batchMesh(mesh); - } - } - painter.state.blendMode = originalBlendMode; - } - - override public function hitTest (localPoint:Point) : DisplayObject { - // FIXME what to do here? -// if (forTouch && (!visible || !touchable)) -// return null; - - var minX:Number = Number.MAX_VALUE, minY:Number = Number.MAX_VALUE; - var maxX:Number = -Number.MAX_VALUE, maxY:Number = -Number.MAX_VALUE; - var slots:Vector. = skeleton.slots; - var worldVertices:Vector. = _tempVertices; - for (var i:int = 0, n:int = slots.length; i < n; ++i) { - var slot:Slot = slots[i]; - var attachment:Attachment = slot.attachment; - if (!attachment) continue; - var verticesLength:int; - if (attachment is RegionAttachment) { - var region:RegionAttachment = RegionAttachment(slot.attachment); - verticesLength = 8; - region.computeWorldVertices(0, 0, slot.bone, worldVertices); - } else if (attachment is MeshAttachment) { - var mesh:MeshAttachment = MeshAttachment(attachment); - verticesLength = mesh.worldVerticesLength; - if (worldVertices.length < verticesLength) worldVertices.length = verticesLength; - mesh.computeWorldVertices(slot, worldVertices); - } else - continue; - for (var ii:int = 0; ii < verticesLength; ii += 2) { - var x:Number = worldVertices[ii], y:Number = worldVertices[ii + 1]; - minX = minX < x ? minX : x; - minY = minY < y ? minY : y; - maxX = maxX > x ? maxX : x; - maxY = maxY > y ? maxY : y; - } - } - - var temp:Number; - if (maxX < minX) { - temp = maxX; - maxX = minX; - minX = temp; - } - if (maxY < minY) { - temp = maxY; - maxY = minY; - minY = temp; - } - - if (localPoint.x >= minX && localPoint.x < maxX && localPoint.y >= minY && localPoint.y < maxY) - return this; - - return null; - } - - override public function getBounds (targetSpace:DisplayObject, resultRect:Rectangle = null) : Rectangle { - if (!resultRect) - resultRect = new Rectangle(); - if (targetSpace == this) - resultRect.setTo(0, 0, 0, 0); - else if (targetSpace == parent) - resultRect.setTo(x, y, 0, 0); - else { - getTransformationMatrix(targetSpace, _tempMatrix); - MatrixUtil.transformCoords(_tempMatrix, 0, 0, _tempPoint); - resultRect.setTo(_tempPoint.x, _tempPoint.y, 0, 0); - } - return resultRect; - } - - public function get skeleton () : Skeleton { - return _skeleton; - } - - public function get smoothing () : String { - return _smoothing; - } - - public function set smoothing (smoothing:String) : void { - _smoothing = smoothing; - } -} - +package spine.starling { +import spine.Bone; +import spine.Skeleton; +import spine.SkeletonData; +import spine.Slot; +import spine.atlas.AtlasRegion; +import spine.attachments.Attachment; +import spine.attachments.MeshAttachment; +import spine.attachments.RegionAttachment; + +import starling.display.BlendMode; +import starling.display.DisplayObject; +import starling.display.Image; +import starling.rendering.IndexData; +import starling.rendering.Painter; +import starling.rendering.VertexData; +import starling.utils.Color; +import starling.utils.MatrixUtil; + +import flash.geom.Matrix; +import flash.geom.Point; +import flash.geom.Rectangle; + +public class SkeletonSprite extends DisplayObject { + static private var _tempPoint:Point = new Point(); + static private var _tempMatrix:Matrix = new Matrix(); + static private var _tempVertices:Vector. = new Vector.(8); + static internal var blendModes:Vector. = new [ + BlendMode.NORMAL, BlendMode.ADD, BlendMode.MULTIPLY, BlendMode.SCREEN]; + + private var _skeleton:Skeleton; + public var batchable:Boolean = true; + private var _smoothing:String = "bilinear"; + + public function SkeletonSprite (skeletonData:SkeletonData) { + Bone.yDown = true; + _skeleton = new Skeleton(skeletonData); + _skeleton.updateWorldTransform(); + } + + override public function render (painter:Painter) : void { + alpha *= this.alpha * skeleton.a; + var originalBlendMode:String = painter.state.blendMode; + var r:Number = skeleton.r * 255; + var g:Number = skeleton.g * 255; + var b:Number = skeleton.b * 255; + var x:Number = skeleton.x; + var y:Number = skeleton.y; + var drawOrder:Vector. = skeleton.drawOrder; + var worldVertices:Vector. = _tempVertices; + var ii:int, iii:int; + var rgb:uint, a:Number; + var mesh:SkeletonMesh; + var verticesLength:int, verticesCount:int, indicesLength:int; + var indexData:IndexData, indices:Vector., vertexData:VertexData; + var uvs: Vector.; + + for (var i:int = 0, n:int = drawOrder.length; i < n; ++i) { + var slot:Slot = drawOrder[i]; + if (slot.attachment is RegionAttachment) { + var region:RegionAttachment = slot.attachment as RegionAttachment; + region.computeWorldVertices(x, y, slot.bone, worldVertices); + // FIXME pre-multiplied alpha? + a = slot.a * region.a; + rgb = Color.rgb( + r * slot.r * region.r, + g * slot.g * region.g, + b * slot.b * region.b); + + var image:Image = region.rendererObject as Image; + if (image == null) { + var origImage:Image = Image(AtlasRegion(region.rendererObject).rendererObject); + region.rendererObject = image = new Image(origImage.texture); + for (var j:int = 0; j < 4; j++) { + var p: Point = origImage.getTexCoords(j); + image.setTexCoords(j, p.x, p.y); + } + } + + image.setVertexPosition(0, worldVertices[2], worldVertices[3]); + image.setVertexColor(0, rgb); + image.setVertexAlpha(0, a); + + image.setVertexPosition(1, worldVertices[4], worldVertices[5]); + image.setVertexColor(1, rgb); + image.setVertexAlpha(1, a); + + image.setVertexPosition(2, worldVertices[0], worldVertices[1]); + image.setVertexColor(2, rgb); + image.setVertexAlpha(2, a); + + image.setVertexPosition(3, worldVertices[6], worldVertices[7]); + image.setVertexColor(3, rgb); + image.setVertexAlpha(3, a); + + image.setRequiresRedraw(); + painter.state.blendMode = blendModes[slot.data.blendMode.ordinal]; + // FIXME set smoothing/filter + painter.batchMesh(image); + } else if (slot.attachment is MeshAttachment) { + var meshAttachment:MeshAttachment = MeshAttachment(slot.attachment); + verticesLength = meshAttachment.worldVerticesLength; + verticesCount = verticesLength >> 1; + if (worldVertices.length < verticesLength) worldVertices.length = verticesLength; + meshAttachment.computeWorldVertices(slot, worldVertices); + mesh = meshAttachment.rendererObject as SkeletonMesh; + if (mesh == null) { + if (meshAttachment.rendererObject is Image) + meshAttachment.rendererObject = mesh = new SkeletonMesh(Image(meshAttachment.rendererObject).texture); + if (meshAttachment.rendererObject is AtlasRegion) + meshAttachment.rendererObject = mesh = new SkeletonMesh(Image(AtlasRegion(meshAttachment.rendererObject).rendererObject).texture); + } + + if (mesh.numIndices != meshAttachment.triangles.length) { + indexData = mesh.getIndexData(); + indices = meshAttachment.triangles; + indicesLength = meshAttachment.triangles.length; + for (ii = 0; ii < indicesLength; ii++) { + indexData.setIndex(ii, indices[ii]); + } + indexData.numIndices = indicesLength; + indexData.trim(); + } + + // FIXME pre-multiplied alpha? + a = slot.a * meshAttachment.a; + rgb = Color.rgb( + r * slot.r * meshAttachment.r, + g * slot.g * meshAttachment.g, + b * slot.b * meshAttachment.b); + + vertexData = mesh.getVertexData(); + uvs = meshAttachment.uvs; + vertexData.colorize("color", rgb, a); + for (ii = 0, iii = 0; ii < verticesCount; ii++, iii+=2) { + mesh.setVertexPosition(ii, worldVertices[iii], worldVertices[iii+1]); + mesh.setTexCoords(ii, uvs[iii], uvs[iii+1]); + } + vertexData.numVertices = verticesCount; + // FIXME set smoothing/filter + painter.batchMesh(mesh); + } + } + painter.state.blendMode = originalBlendMode; + } + + override public function hitTest (localPoint:Point) : DisplayObject { + // FIXME what to do here? +// if (forTouch && (!visible || !touchable)) +// return null; + + var minX:Number = Number.MAX_VALUE, minY:Number = Number.MAX_VALUE; + var maxX:Number = -Number.MAX_VALUE, maxY:Number = -Number.MAX_VALUE; + var slots:Vector. = skeleton.slots; + var worldVertices:Vector. = _tempVertices; + for (var i:int = 0, n:int = slots.length; i < n; ++i) { + var slot:Slot = slots[i]; + var attachment:Attachment = slot.attachment; + if (!attachment) continue; + var verticesLength:int; + if (attachment is RegionAttachment) { + var region:RegionAttachment = RegionAttachment(slot.attachment); + verticesLength = 8; + region.computeWorldVertices(0, 0, slot.bone, worldVertices); + } else if (attachment is MeshAttachment) { + var mesh:MeshAttachment = MeshAttachment(attachment); + verticesLength = mesh.worldVerticesLength; + if (worldVertices.length < verticesLength) worldVertices.length = verticesLength; + mesh.computeWorldVertices(slot, worldVertices); + } else + continue; + for (var ii:int = 0; ii < verticesLength; ii += 2) { + var x:Number = worldVertices[ii], y:Number = worldVertices[ii + 1]; + minX = minX < x ? minX : x; + minY = minY < y ? minY : y; + maxX = maxX > x ? maxX : x; + maxY = maxY > y ? maxY : y; + } + } + + var temp:Number; + if (maxX < minX) { + temp = maxX; + maxX = minX; + minX = temp; + } + if (maxY < minY) { + temp = maxY; + maxY = minY; + minY = temp; + } + + if (localPoint.x >= minX && localPoint.x < maxX && localPoint.y >= minY && localPoint.y < maxY) + return this; + + return null; + } + + override public function getBounds (targetSpace:DisplayObject, resultRect:Rectangle = null) : Rectangle { + if (!resultRect) + resultRect = new Rectangle(); + if (targetSpace == this) + resultRect.setTo(0, 0, 0, 0); + else if (targetSpace == parent) + resultRect.setTo(x, y, 0, 0); + else { + getTransformationMatrix(targetSpace, _tempMatrix); + MatrixUtil.transformCoords(_tempMatrix, 0, 0, _tempPoint); + resultRect.setTo(_tempPoint.x, _tempPoint.y, 0, 0); + } + return resultRect; + } + + public function get skeleton () : Skeleton { + return _skeleton; + } + + public function get smoothing () : String { + return _smoothing; + } + + public function set smoothing (smoothing:String) : void { + _smoothing = smoothing; + } +} + } diff --git a/spine-starling/spine-starling/src/spine/starling/StarlingAtlasAttachmentLoader.as b/spine-starling/spine-starling/src/spine/starling/StarlingAtlasAttachmentLoader.as index ef5d95b416..e26fcb589e 100644 --- a/spine-starling/spine-starling/src/spine/starling/StarlingAtlasAttachmentLoader.as +++ b/spine-starling/spine-starling/src/spine/starling/StarlingAtlasAttachmentLoader.as @@ -1,129 +1,128 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.starling { -import spine.attachments.PathAttachment; -import starling.display.Image; -import spine.Bone; -import spine.Skin; -import spine.attachments.AttachmentLoader; -import spine.attachments.BoundingBoxAttachment; -import spine.attachments.MeshAttachment; -import spine.attachments.RegionAttachment; - -import starling.textures.SubTexture; -import starling.textures.Texture; -import starling.textures.TextureAtlas; - -import flash.geom.Rectangle; - -public class StarlingAtlasAttachmentLoader implements AttachmentLoader { - private var atlas:TextureAtlas; - - public function StarlingAtlasAttachmentLoader (atlas:TextureAtlas) { - this.atlas = atlas; - - Bone.yDown = true; - } - - public function newRegionAttachment (skin:Skin, name:String, path:String) : RegionAttachment { - var texture:Texture = atlas.getTexture(path); - if (texture == null) - throw new Error("Region not found in Starling atlas: " + path + " (region attachment: " + name + ")"); - var attachment:RegionAttachment = new RegionAttachment(name); - attachment.rendererObject = new Image(Texture.fromTexture(texture)); // Discard frame. - var frame:Rectangle = texture.frame; - attachment.regionOffsetX = frame ? -frame.x : 0; - attachment.regionOffsetY = frame ? -frame.y : 0; - attachment.regionWidth = texture.width; - attachment.regionHeight = texture.height; - attachment.regionOriginalWidth = frame ? frame.width : texture.width; - attachment.regionOriginalHeight = frame ? frame.height : texture.height; - var subTexture:SubTexture = texture as SubTexture; - if (subTexture) { - var root:Texture = subTexture.root; - var rectRegion:Rectangle = atlas.getRegion(path); - attachment["regionU"] = rectRegion.x / root.width; - attachment["regionV"] = rectRegion.y / root.height; - attachment["regionU2"] = (rectRegion.x + subTexture.width) / root.width; - attachment["regionV2"] = (rectRegion.y + subTexture.height) / root.height; - attachment.setUVs(attachment["regionU"], attachment["regionV"], attachment["regionU2"], attachment["regionV2"], - atlas.getRotation(path)); - } else { - attachment["regionU"] = 0; - attachment["regionV"] = 1; - attachment["regionU2"] = 1; - attachment["regionV2"] = 0; - } - return attachment; - } - - public function newMeshAttachment (skin:Skin, name:String, path:String) : MeshAttachment { - var texture:Texture = atlas.getTexture(path); - if (texture == null) - throw new Error("Region not found in Starling atlas: " + path + " (mesh attachment: " + name + ")"); - var attachment:MeshAttachment = new MeshAttachment(name); - attachment.rendererObject = new Image(Texture.fromTexture(texture)); // Discard frame. - var subTexture:SubTexture = texture as SubTexture; - if (subTexture) { - var root:Texture = subTexture.root; - var rectRegion:Rectangle = atlas.getRegion(path); - attachment.regionU = rectRegion.x / root.width; - attachment.regionV = rectRegion.y / root.height; - attachment.regionU2 = (rectRegion.x + subTexture.width) / root.width; - attachment.regionV2 = (rectRegion.y + subTexture.height) / root.height; - attachment.rendererObject = new Image(root); - } else { - attachment.regionU = 0; - attachment.regionV = 1; - attachment.regionU2 = 1; - attachment.regionV2 = 0; - } - var frame:Rectangle = texture.frame; - attachment.regionOffsetX = frame ? -frame.x : 0; - attachment.regionOffsetY = frame ? -frame.y : 0; - attachment.regionWidth = texture.width; - attachment.regionHeight = texture.height; - attachment.regionOriginalWidth = frame ? frame.width : texture.width; - attachment.regionOriginalHeight = frame ? frame.height : texture.height; - return attachment; - } - - public function newBoundingBoxAttachment (skin:Skin, name:String) : BoundingBoxAttachment { - return new BoundingBoxAttachment(name); - } - - public function newPathAttachment (skin:Skin, name:String) : PathAttachment { - return new PathAttachment(name); - } -} - +package spine.starling { +import spine.attachments.PathAttachment; +import starling.display.Image; +import spine.Bone; +import spine.Skin; +import spine.attachments.AttachmentLoader; +import spine.attachments.BoundingBoxAttachment; +import spine.attachments.MeshAttachment; +import spine.attachments.RegionAttachment; + +import starling.textures.SubTexture; +import starling.textures.Texture; +import starling.textures.TextureAtlas; + +import flash.geom.Rectangle; + +public class StarlingAtlasAttachmentLoader implements AttachmentLoader { + private var atlas:TextureAtlas; + + public function StarlingAtlasAttachmentLoader (atlas:TextureAtlas) { + this.atlas = atlas; + + Bone.yDown = true; + } + + public function newRegionAttachment (skin:Skin, name:String, path:String) : RegionAttachment { + var texture:Texture = atlas.getTexture(path); + if (texture == null) + throw new Error("Region not found in Starling atlas: " + path + " (region attachment: " + name + ")"); + var attachment:RegionAttachment = new RegionAttachment(name); + attachment.rendererObject = new Image(Texture.fromTexture(texture)); // Discard frame. + var frame:Rectangle = texture.frame; + attachment.regionOffsetX = frame ? -frame.x : 0; + attachment.regionOffsetY = frame ? -frame.y : 0; + attachment.regionWidth = texture.width; + attachment.regionHeight = texture.height; + attachment.regionOriginalWidth = frame ? frame.width : texture.width; + attachment.regionOriginalHeight = frame ? frame.height : texture.height; + var subTexture:SubTexture = texture as SubTexture; + if (subTexture) { + var root:Texture = subTexture.root; + var rectRegion:Rectangle = atlas.getRegion(path); + attachment["regionU"] = rectRegion.x / root.width; + attachment["regionV"] = rectRegion.y / root.height; + attachment["regionU2"] = (rectRegion.x + subTexture.width) / root.width; + attachment["regionV2"] = (rectRegion.y + subTexture.height) / root.height; + attachment.setUVs(attachment["regionU"], attachment["regionV"], attachment["regionU2"], attachment["regionV2"], + atlas.getRotation(path)); + } else { + attachment["regionU"] = 0; + attachment["regionV"] = 1; + attachment["regionU2"] = 1; + attachment["regionV2"] = 0; + } + return attachment; + } + + public function newMeshAttachment (skin:Skin, name:String, path:String) : MeshAttachment { + var texture:Texture = atlas.getTexture(path); + if (texture == null) + throw new Error("Region not found in Starling atlas: " + path + " (mesh attachment: " + name + ")"); + var attachment:MeshAttachment = new MeshAttachment(name); + attachment.rendererObject = new Image(Texture.fromTexture(texture)); // Discard frame. + var subTexture:SubTexture = texture as SubTexture; + if (subTexture) { + var root:Texture = subTexture.root; + var rectRegion:Rectangle = atlas.getRegion(path); + attachment.regionU = rectRegion.x / root.width; + attachment.regionV = rectRegion.y / root.height; + attachment.regionU2 = (rectRegion.x + subTexture.width) / root.width; + attachment.regionV2 = (rectRegion.y + subTexture.height) / root.height; + attachment.rendererObject = new Image(root); + } else { + attachment.regionU = 0; + attachment.regionV = 1; + attachment.regionU2 = 1; + attachment.regionV2 = 0; + } + var frame:Rectangle = texture.frame; + attachment.regionOffsetX = frame ? -frame.x : 0; + attachment.regionOffsetY = frame ? -frame.y : 0; + attachment.regionWidth = texture.width; + attachment.regionHeight = texture.height; + attachment.regionOriginalWidth = frame ? frame.width : texture.width; + attachment.regionOriginalHeight = frame ? frame.height : texture.height; + return attachment; + } + + public function newBoundingBoxAttachment (skin:Skin, name:String) : BoundingBoxAttachment { + return new BoundingBoxAttachment(name); + } + + public function newPathAttachment (skin:Skin, name:String) : PathAttachment { + return new PathAttachment(name); + } +} + } diff --git a/spine-starling/spine-starling/src/spine/starling/StarlingTextureLoader.as b/spine-starling/spine-starling/src/spine/starling/StarlingTextureLoader.as index 4dcc54e7be..df2c8c8b3f 100644 --- a/spine-starling/spine-starling/src/spine/starling/StarlingTextureLoader.as +++ b/spine-starling/spine-starling/src/spine/starling/StarlingTextureLoader.as @@ -1,102 +1,101 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -package spine.starling { - import starling.display.Image; -import spine.atlas.AtlasPage; -import spine.atlas.AtlasRegion; -import spine.atlas.TextureLoader; - -import starling.textures.Texture; - -import flash.display.Bitmap; -import flash.display.BitmapData; - -public class StarlingTextureLoader implements TextureLoader { - public var bitmapDatas:Object = {}; - public var singleBitmapData:BitmapData; - - /** @param bitmaps A Bitmap or BitmapData for an atlas that has only one page, or for a multi page atlas an object where the - * key is the image path and the value is the Bitmap or BitmapData. */ - public function StarlingTextureLoader (bitmaps:Object) { - if (bitmaps is BitmapData) { - singleBitmapData = BitmapData(bitmaps); - return; - } - if (bitmaps is Bitmap) { - singleBitmapData = Bitmap(bitmaps).bitmapData; - return; - } - - for (var path:* in bitmaps) { - var object:* = bitmaps[path]; - var bitmapData:BitmapData; - if (object is BitmapData) - bitmapData = BitmapData(object); - else if (object is Bitmap) - bitmapData = Bitmap(object).bitmapData; - else - throw new ArgumentError("Object for path \"" + path + "\" must be a Bitmap or BitmapData: " + object); - bitmapDatas[path] = bitmapData; - } - } - - public function loadPage (page:AtlasPage, path:String) : void { - var bitmapData:BitmapData = singleBitmapData || bitmapDatas[path]; - if (!bitmapData) - throw new ArgumentError("BitmapData not found with name: " + path); - page.rendererObject = Texture.fromBitmapData(bitmapData); - page.width = bitmapData.width; - page.height = bitmapData.height; - } - - public function loadRegion (region:AtlasRegion) : void { - var image:Image = new Image(Texture(region.page.rendererObject)); - if (region.rotate) { - image.setTexCoords(0, region.u, region.v2); - image.setTexCoords(1, region.u, region.v); - image.setTexCoords(2, region.u2, region.v2); - image.setTexCoords(3, region.u2, region.v); - } else { - image.setTexCoords(0, region.u, region.v); - image.setTexCoords(1, region.u2, region.v); - image.setTexCoords(2, region.u, region.v2); - image.setTexCoords(3, region.u2, region.v2); - } - region.rendererObject = image; - } - - public function unloadPage (page:AtlasPage) : void { - Texture(page.rendererObject).dispose(); - } -} - +package spine.starling { + import starling.display.Image; +import spine.atlas.AtlasPage; +import spine.atlas.AtlasRegion; +import spine.atlas.TextureLoader; + +import starling.textures.Texture; + +import flash.display.Bitmap; +import flash.display.BitmapData; + +public class StarlingTextureLoader implements TextureLoader { + public var bitmapDatas:Object = {}; + public var singleBitmapData:BitmapData; + + /** @param bitmaps A Bitmap or BitmapData for an atlas that has only one page, or for a multi page atlas an object where the + * key is the image path and the value is the Bitmap or BitmapData. */ + public function StarlingTextureLoader (bitmaps:Object) { + if (bitmaps is BitmapData) { + singleBitmapData = BitmapData(bitmaps); + return; + } + if (bitmaps is Bitmap) { + singleBitmapData = Bitmap(bitmaps).bitmapData; + return; + } + + for (var path:* in bitmaps) { + var object:* = bitmaps[path]; + var bitmapData:BitmapData; + if (object is BitmapData) + bitmapData = BitmapData(object); + else if (object is Bitmap) + bitmapData = Bitmap(object).bitmapData; + else + throw new ArgumentError("Object for path \"" + path + "\" must be a Bitmap or BitmapData: " + object); + bitmapDatas[path] = bitmapData; + } + } + + public function loadPage (page:AtlasPage, path:String) : void { + var bitmapData:BitmapData = singleBitmapData || bitmapDatas[path]; + if (!bitmapData) + throw new ArgumentError("BitmapData not found with name: " + path); + page.rendererObject = Texture.fromBitmapData(bitmapData); + page.width = bitmapData.width; + page.height = bitmapData.height; + } + + public function loadRegion (region:AtlasRegion) : void { + var image:Image = new Image(Texture(region.page.rendererObject)); + if (region.rotate) { + image.setTexCoords(0, region.u, region.v2); + image.setTexCoords(1, region.u, region.v); + image.setTexCoords(2, region.u2, region.v2); + image.setTexCoords(3, region.u2, region.v); + } else { + image.setTexCoords(0, region.u, region.v); + image.setTexCoords(1, region.u2, region.v); + image.setTexCoords(2, region.u, region.v2); + image.setTexCoords(3, region.u2, region.v2); + } + region.rendererObject = image; + } + + public function unloadPage (page:AtlasPage) : void { + Texture(page.rendererObject).dispose(); + } +} + } diff --git a/spine-ts/canvas/src/AssetManager.ts b/spine-ts/canvas/src/AssetManager.ts index 092a5d54b9..869388c19e 100644 --- a/spine-ts/canvas/src/AssetManager.ts +++ b/spine-ts/canvas/src/AssetManager.ts @@ -1,40 +1,39 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -/// - -module spine.canvas { - export class AssetManager extends spine.AssetManager { - constructor (pathPrefix: string = "") { - super((image: HTMLImageElement) => { return new spine.canvas.CanvasTexture(image); }, pathPrefix); - } - } -} \ No newline at end of file +/// + +module spine.canvas { + export class AssetManager extends spine.AssetManager { + constructor (pathPrefix: string = "") { + super((image: HTMLImageElement) => { return new spine.canvas.CanvasTexture(image); }, pathPrefix); + } + } +} diff --git a/spine-ts/canvas/src/CanvasTexture.ts b/spine-ts/canvas/src/CanvasTexture.ts index ebd646c389..a3a784ed3e 100644 --- a/spine-ts/canvas/src/CanvasTexture.ts +++ b/spine-ts/canvas/src/CanvasTexture.ts @@ -1,44 +1,43 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -/// - -module spine.canvas { - export class CanvasTexture extends Texture { - constructor (image: HTMLImageElement) { - super(image); - } - - setFilters (minFilter: TextureFilter, magFilter: TextureFilter) { } - setWraps (uWrap: TextureWrap, vWrap: TextureWrap) { } - dispose () { } - } -} \ No newline at end of file +/// + +module spine.canvas { + export class CanvasTexture extends Texture { + constructor (image: HTMLImageElement) { + super(image); + } + + setFilters (minFilter: TextureFilter, magFilter: TextureFilter) { } + setWraps (uWrap: TextureWrap, vWrap: TextureWrap) { } + dispose () { } + } +} diff --git a/spine-ts/canvas/src/SkeletonRenderer.ts b/spine-ts/canvas/src/SkeletonRenderer.ts index d960f69560..eab037f79a 100644 --- a/spine-ts/canvas/src/SkeletonRenderer.ts +++ b/spine-ts/canvas/src/SkeletonRenderer.ts @@ -1,201 +1,200 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.canvas { - export class SkeletonRenderer { - static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; - - private ctx: CanvasRenderingContext2D; - - public triangleRendering = false; - public debugRendering = false; - - constructor (context: CanvasRenderingContext2D) { - this.ctx = context; - } - - draw (skeleton: Skeleton) { - if (this.triangleRendering) this.drawTriangles(skeleton); - else this.drawImages(skeleton); - } - - private drawImages (skeleton: Skeleton) { - let ctx = this.ctx; - let drawOrder = skeleton.drawOrder; - - if (this.debugRendering) ctx.strokeStyle = "green"; - - for (let i = 0, n = drawOrder.length; i < n; i++) { - let slot = drawOrder[i]; - let attachment = slot.getAttachment(); - let region: TextureAtlasRegion = null; - let image: HTMLImageElement = null; - let vertices: ArrayLike = null; - if (attachment instanceof RegionAttachment) { - let regionAttachment = attachment; - vertices = regionAttachment.updateWorldVertices(slot, false); - region = regionAttachment.region; - image = ((region).texture).getImage(); - - } else continue; - - let att = attachment; - let bone = slot.bone; - let x = vertices[0]; - let y = vertices[1]; - let rotation = (bone.getWorldRotationX() - att.rotation) * Math.PI / 180; - let xx = vertices[24] - vertices[0]; - let xy = vertices[25] - vertices[1]; - let yx = vertices[8] - vertices[0]; - let yy = vertices[9] - vertices[1]; - let w = Math.sqrt(xx * xx + xy * xy), h = -Math.sqrt(yx * yx + yy * yy); - ctx.translate(x, y); - ctx.rotate(rotation); - if (region.rotate) { - ctx.rotate(Math.PI / 2); - ctx.drawImage(image, region.x, region.y, region.height, region.width, 0, 0, h, -w); - ctx.rotate(-Math.PI / 2); - } else { - ctx.drawImage(image, region.x, region.y, region.width, region.height, 0, 0, w, h); - } - if (this.debugRendering) ctx.strokeRect(0, 0, w, h); - ctx.rotate(-rotation); - ctx.translate(-x, -y); - } - } - - private drawTriangles (skeleton: Skeleton) { - let blendMode: BlendMode = null; - - let vertices: ArrayLike = null; - let triangles: Array = null; - let drawOrder = skeleton.drawOrder; - - for (let i = 0, n = drawOrder.length; i < n; i++) { - let slot = drawOrder[i]; - let attachment = slot.getAttachment(); - let texture: HTMLImageElement = null; - let region: TextureAtlasRegion = null; - if (attachment instanceof RegionAttachment) { - let regionAttachment = attachment; - vertices = regionAttachment.updateWorldVertices(slot, false); - triangles = SkeletonRenderer.QUAD_TRIANGLES; - region = regionAttachment.region; - texture = (region.texture).getImage(); - - } else if (attachment instanceof MeshAttachment) { - let mesh = attachment; - vertices = mesh.updateWorldVertices(slot, false); - triangles = mesh.triangles; - texture = (mesh.region.renderObject).texture.getImage(); - } else continue; - - if (texture != null) { - let slotBlendMode = slot.data.blendMode; - if (slotBlendMode != blendMode) { - blendMode = slotBlendMode; - } - - let ctx = this.ctx; - - for (var j = 0; j < triangles.length; j+=3) { - let t1 = triangles[j] * 8, t2 = triangles[j+1] * 8, t3 = triangles[j+2] * 8; - - let x0 = vertices[t1], y0 = vertices[t1 + 1], u0 = vertices[t1 + 6], v0 = vertices[t1 + 7]; - let x1 = vertices[t2], y1 = vertices[t2 + 1], u1 = vertices[t2 + 6], v1 = vertices[t2 + 7]; - let x2 = vertices[t3], y2 = vertices[t3 + 1], u2 = vertices[t3 + 6], v2 = vertices[t3 + 7]; - - this.drawTriangle(texture, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2); - - if (this.debugRendering) { - ctx.strokeStyle = "green"; - ctx.beginPath(); - ctx.moveTo(x0, y0); - ctx.lineTo(x1, y1); - ctx.lineTo(x2, y2); - ctx.lineTo(x0, y0); - ctx.stroke(); - } - } - } - } - } - - // Adapted from http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 - // Apache 2 licensed - private drawTriangle(img: HTMLImageElement, x0: number, y0: number, u0: number, v0: number, - x1: number, y1: number, u1: number, v1: number, - x2: number, y2: number, u2: number, v2: number) { - let ctx = this.ctx; - - u0 *= img.width; - v0 *= img.height; - u1 *= img.width; - v1 *= img.height; - u2 *= img.width; - v2 *= img.height; - - ctx.beginPath(); - ctx.moveTo(x0, y0); - ctx.lineTo(x1, y1); - ctx.lineTo(x2, y2); - ctx.closePath(); - - x1 -= x0; - y1 -= y0; - x2 -= x0; - y2 -= y0; - - u1 -= u0; - v1 -= v0; - u2 -= u0; - v2 -= v0; - - var det = 1 / (u1*v2 - u2*v1), - - // linear transformation - a = (v2*x1 - v1*x2) * det, - b = (v2*y1 - v1*y2) * det, - c = (u1*x2 - u2*x1) * det, - d = (u1*y2 - u2*y1) * det, - - // translation - e = x0 - a*u0 - c*v0, - f = y0 - b*u0 - d*v0; - - ctx.save(); - ctx.transform(a, b, c, d, e, f); - ctx.clip(); - ctx.drawImage(img, 0, 0); - ctx.restore(); - } - } -} \ No newline at end of file +module spine.canvas { + export class SkeletonRenderer { + static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; + + private ctx: CanvasRenderingContext2D; + + public triangleRendering = false; + public debugRendering = false; + + constructor (context: CanvasRenderingContext2D) { + this.ctx = context; + } + + draw (skeleton: Skeleton) { + if (this.triangleRendering) this.drawTriangles(skeleton); + else this.drawImages(skeleton); + } + + private drawImages (skeleton: Skeleton) { + let ctx = this.ctx; + let drawOrder = skeleton.drawOrder; + + if (this.debugRendering) ctx.strokeStyle = "green"; + + for (let i = 0, n = drawOrder.length; i < n; i++) { + let slot = drawOrder[i]; + let attachment = slot.getAttachment(); + let region: TextureAtlasRegion = null; + let image: HTMLImageElement = null; + let vertices: ArrayLike = null; + if (attachment instanceof RegionAttachment) { + let regionAttachment = attachment; + vertices = regionAttachment.updateWorldVertices(slot, false); + region = regionAttachment.region; + image = ((region).texture).getImage(); + + } else continue; + + let att = attachment; + let bone = slot.bone; + let x = vertices[0]; + let y = vertices[1]; + let rotation = (bone.getWorldRotationX() - att.rotation) * Math.PI / 180; + let xx = vertices[24] - vertices[0]; + let xy = vertices[25] - vertices[1]; + let yx = vertices[8] - vertices[0]; + let yy = vertices[9] - vertices[1]; + let w = Math.sqrt(xx * xx + xy * xy), h = -Math.sqrt(yx * yx + yy * yy); + ctx.translate(x, y); + ctx.rotate(rotation); + if (region.rotate) { + ctx.rotate(Math.PI / 2); + ctx.drawImage(image, region.x, region.y, region.height, region.width, 0, 0, h, -w); + ctx.rotate(-Math.PI / 2); + } else { + ctx.drawImage(image, region.x, region.y, region.width, region.height, 0, 0, w, h); + } + if (this.debugRendering) ctx.strokeRect(0, 0, w, h); + ctx.rotate(-rotation); + ctx.translate(-x, -y); + } + } + + private drawTriangles (skeleton: Skeleton) { + let blendMode: BlendMode = null; + + let vertices: ArrayLike = null; + let triangles: Array = null; + let drawOrder = skeleton.drawOrder; + + for (let i = 0, n = drawOrder.length; i < n; i++) { + let slot = drawOrder[i]; + let attachment = slot.getAttachment(); + let texture: HTMLImageElement = null; + let region: TextureAtlasRegion = null; + if (attachment instanceof RegionAttachment) { + let regionAttachment = attachment; + vertices = regionAttachment.updateWorldVertices(slot, false); + triangles = SkeletonRenderer.QUAD_TRIANGLES; + region = regionAttachment.region; + texture = (region.texture).getImage(); + + } else if (attachment instanceof MeshAttachment) { + let mesh = attachment; + vertices = mesh.updateWorldVertices(slot, false); + triangles = mesh.triangles; + texture = (mesh.region.renderObject).texture.getImage(); + } else continue; + + if (texture != null) { + let slotBlendMode = slot.data.blendMode; + if (slotBlendMode != blendMode) { + blendMode = slotBlendMode; + } + + let ctx = this.ctx; + + for (var j = 0; j < triangles.length; j+=3) { + let t1 = triangles[j] * 8, t2 = triangles[j+1] * 8, t3 = triangles[j+2] * 8; + + let x0 = vertices[t1], y0 = vertices[t1 + 1], u0 = vertices[t1 + 6], v0 = vertices[t1 + 7]; + let x1 = vertices[t2], y1 = vertices[t2 + 1], u1 = vertices[t2 + 6], v1 = vertices[t2 + 7]; + let x2 = vertices[t3], y2 = vertices[t3 + 1], u2 = vertices[t3 + 6], v2 = vertices[t3 + 7]; + + this.drawTriangle(texture, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2); + + if (this.debugRendering) { + ctx.strokeStyle = "green"; + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.lineTo(x0, y0); + ctx.stroke(); + } + } + } + } + } + + // Adapted from http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 + // Apache 2 licensed + private drawTriangle(img: HTMLImageElement, x0: number, y0: number, u0: number, v0: number, + x1: number, y1: number, u1: number, v1: number, + x2: number, y2: number, u2: number, v2: number) { + let ctx = this.ctx; + + u0 *= img.width; + v0 *= img.height; + u1 *= img.width; + v1 *= img.height; + u2 *= img.width; + v2 *= img.height; + + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.closePath(); + + x1 -= x0; + y1 -= y0; + x2 -= x0; + y2 -= y0; + + u1 -= u0; + v1 -= v0; + u2 -= u0; + v2 -= v0; + + var det = 1 / (u1*v2 - u2*v1), + + // linear transformation + a = (v2*x1 - v1*x2) * det, + b = (v2*y1 - v1*y2) * det, + c = (u1*x2 - u2*x1) * det, + d = (u1*y2 - u2*y1) * det, + + // translation + e = x0 - a*u0 - c*v0, + f = y0 - b*u0 - d*v0; + + ctx.save(); + ctx.transform(a, b, c, d, e, f); + ctx.clip(); + ctx.drawImage(img, 0, 0); + ctx.restore(); + } + } +} diff --git a/spine-ts/core/src/Animation.ts b/spine-ts/core/src/Animation.ts index 8d1c2bfcfd..c317c5569a 100644 --- a/spine-ts/core/src/Animation.ts +++ b/spine-ts/core/src/Animation.ts @@ -1,816 +1,815 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class Animation { - name: string; - timelines: Array; - duration: number; - - constructor (name: string, timelines: Array, duration: number) { - if (name == null) throw new Error("name cannot be null."); - if (timelines == null) throw new Error("timelines cannot be null."); - this.name = name; - this.timelines = timelines; - this.duration = duration; - } - - apply (skeleton: Skeleton, lastTime: number, time: number, loop: boolean, events: Array) { - if (skeleton == null) throw new Error("skeleton cannot be null."); - - if (loop && this.duration != 0) { - time %= this.duration; - if (lastTime > 0) lastTime %= this.duration; - } - - let timelines = this.timelines; - for (let i = 0, n = timelines.length; i < n; i++) - timelines[i].apply(skeleton, lastTime, time, events, 1); - } - - mix (skeleton: Skeleton, lastTime: number, time: number, loop: boolean, events: Array, alpha: number) { - if (skeleton == null) throw new Error("skeleton cannot be null."); - - if (loop && this.duration != 0) { - time %= this.duration; - if (lastTime > 0) lastTime %= this.duration; - } - - let timelines = this.timelines; - for (let i = 0, n = timelines.length; i < n; i++) - timelines[i].apply(skeleton, lastTime, time, events, alpha); - } - - static binarySearch (values: ArrayLike, target: number, step: number = 1) { - let low = 0; - let high = values.length / step - 2; - if (high == 0) return step; - let current = high >>> 1; - while (true) { - if (values[(current + 1) * step] <= target) - low = current + 1; - else - high = current; - if (low == high) return (low + 1) * step; - current = (low + high) >>> 1; - } - } - - static linearSearch (values: ArrayLike, target: number, step: number) { - for (let i = 0, last = values.length - step; i <= last; i += step) - if (values[i] > target) return i; - return -1; - } - } - - export interface Timeline { - apply (skeleton: Skeleton, lastTime: number, time: number, events: Array, alpha: number): void; - } - - export abstract class CurveTimeline implements Timeline { - static LINEAR = 0; static STEPPED = 1; static BEZIER = 2; - static BEZIER_SIZE = 10 * 2 - 1; - - private curves: ArrayLike; // type, x, y, ... - - constructor (frameCount: number) { - if (frameCount <= 0) throw new Error("frameCount must be > 0: " + frameCount); - this.curves = Utils.newFloatArray((frameCount - 1) * CurveTimeline.BEZIER_SIZE); - } - - getFrameCount () { - return this.curves.length / CurveTimeline.BEZIER_SIZE + 1; - } - - setLinear (frameIndex: number) { - this.curves[frameIndex * CurveTimeline.BEZIER_SIZE] = CurveTimeline.LINEAR; - } - - setStepped (frameIndex: number) { - this.curves[frameIndex * CurveTimeline.BEZIER_SIZE] = CurveTimeline.STEPPED; - } - - getCurveType (frameIndex: number): number { - let index = frameIndex * CurveTimeline.BEZIER_SIZE; - if (index == this.curves.length) return CurveTimeline.LINEAR; - let type = this.curves[index]; - if (type == CurveTimeline.LINEAR) return CurveTimeline.LINEAR; - if (type == CurveTimeline.STEPPED) return CurveTimeline.STEPPED; - return CurveTimeline.BEZIER; - } - - /** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. - * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of - * the difference between the keyframe's values. */ - setCurve (frameIndex: number, cx1: number, cy1: number, cx2: number, cy2: number) { - let tmpx = (-cx1 * 2 + cx2) * 0.03, tmpy = (-cy1 * 2 + cy2) * 0.03; - let dddfx = ((cx1 - cx2) * 3 + 1) * 0.006, dddfy = ((cy1 - cy2) * 3 + 1) * 0.006; - let ddfx = tmpx * 2 + dddfx, ddfy = tmpy * 2 + dddfy; - let dfx = cx1 * 0.3 + tmpx + dddfx * 0.16666667, dfy = cy1 * 0.3 + tmpy + dddfy * 0.16666667; - - let i = frameIndex * CurveTimeline.BEZIER_SIZE; - let curves = this.curves; - curves[i++] = CurveTimeline.BEZIER; - - let x = dfx, y = dfy; - for (let n = i + CurveTimeline.BEZIER_SIZE - 1; i < n; i += 2) { - curves[i] = x; - curves[i + 1] = y; - dfx += ddfx; - dfy += ddfy; - ddfx += dddfx; - ddfy += dddfy; - x += dfx; - y += dfy; - } - } - - getCurvePercent (frameIndex: number, percent: number) { - percent = MathUtils.clamp(percent, 0, 1); - let curves = this.curves; - let i = frameIndex * CurveTimeline.BEZIER_SIZE; - let type = curves[i]; - if (type == CurveTimeline.LINEAR) return percent; - if (type == CurveTimeline.STEPPED) return 0; - i++; - let x = 0; - for (let start = i, n = i + CurveTimeline.BEZIER_SIZE - 1; i < n; i += 2) { - x = curves[i]; - if (x >= percent) { - let prevX: number, prevY: number; - if (i == start) { - prevX = 0; - prevY = 0; - } else { - prevX = curves[i - 2]; - prevY = curves[i - 1]; - } - return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX); - } - } - let y = curves[i - 1]; - return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. - } - - abstract apply (skeleton: Skeleton, lastTime: number, time: number, events: Array, alpha: number): void; - } - - export class RotateTimeline extends CurveTimeline { - static ENTRIES = 2; - static PREV_TIME = -2; static PREV_ROTATION = -1; - static ROTATION = 1; - - boneIndex: number; - frames: ArrayLike; // time, degrees, ... - - constructor (frameCount: number) { - super(frameCount); - this.frames = Utils.newFloatArray(frameCount << 1); - } - - /** Sets the time and angle of the specified keyframe. */ - setFrame (frameIndex: number, time: number, degrees: number) { - frameIndex <<= 1; - this.frames[frameIndex] = time; - this.frames[frameIndex + RotateTimeline.ROTATION] = degrees; - } - - apply (skeleton: Skeleton, lastTime: number, time: number, events: Array, alpha: number) { - let frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - let bone = skeleton.bones[this.boneIndex]; - - if (time >= frames[frames.length - RotateTimeline.ENTRIES]) { // Time is after last frame. - let amount = bone.data.rotation + frames[frames.length + RotateTimeline.PREV_ROTATION] - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - let frame = Animation.binarySearch(frames, time, RotateTimeline.ENTRIES); - let prevRotation = frames[frame + RotateTimeline.PREV_ROTATION]; - let frameTime = frames[frame]; - let percent = this.getCurvePercent((frame >> 1) - 1, - 1 - (time - frameTime) / (frames[frame + RotateTimeline.PREV_TIME] - frameTime)); - - let amount = frames[frame + RotateTimeline.ROTATION] - prevRotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - amount = bone.data.rotation + (prevRotation + amount * percent) - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - } - } - - export class TranslateTimeline extends CurveTimeline { - static ENTRIES = 3; - static PREV_TIME = -3; static PREV_X = -2; static PREV_Y = -1; - static X = 1; static Y = 2; - - boneIndex: number; - frames: ArrayLike; // time, x, y, ... - - constructor (frameCount: number) { - super(frameCount); - this.frames = Utils.newFloatArray(frameCount * TranslateTimeline.ENTRIES); - } - - /** Sets the time and value of the specified keyframe. */ - setFrame (frameIndex: number, time: number, x: number, y: number) { - frameIndex *= TranslateTimeline.ENTRIES; - this.frames[frameIndex] = time; - this.frames[frameIndex + TranslateTimeline.X] = x; - this.frames[frameIndex + TranslateTimeline.Y] = y; - } - - apply (skeleton: Skeleton, lastTime: number, time: number, events: Array, alpha: number) { - let frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - let bone = skeleton.bones[this.boneIndex]; - - if (time >= frames[frames.length - TranslateTimeline.ENTRIES]) { // Time is after last frame. - bone.x += (bone.data.x + frames[frames.length + TranslateTimeline.PREV_X] - bone.x) * alpha; - bone.y += (bone.data.y + frames[frames.length + TranslateTimeline.PREV_Y] - bone.y) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - let frame = Animation.binarySearch(frames, time, TranslateTimeline.ENTRIES); - let prevX = frames[frame + TranslateTimeline.PREV_X]; - let prevY = frames[frame + TranslateTimeline.PREV_Y]; - let frameTime = frames[frame]; - let percent = this.getCurvePercent(frame / TranslateTimeline.ENTRIES - 1, - 1 - (time - frameTime) / (frames[frame + TranslateTimeline.PREV_TIME] - frameTime)); - - bone.x += (bone.data.x + prevX + (frames[frame + TranslateTimeline.X] - prevX) * percent - bone.x) * alpha; - bone.y += (bone.data.y + prevY + (frames[frame + TranslateTimeline.Y] - prevY) * percent - bone.y) * alpha; - } - } - - export class ScaleTimeline extends TranslateTimeline { - constructor (frameCount: number) { - super(frameCount); - } - - apply (skeleton: Skeleton, lastTime: number, time: number, events: Array, alpha: number) { - let frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - let bone = skeleton.bones[this.boneIndex]; - if (time >= frames[frames.length - ScaleTimeline.ENTRIES]) { // Time is after last frame. - bone.scaleX += (bone.data.scaleX * frames[frames.length + ScaleTimeline.PREV_X] - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY * frames[frames.length + ScaleTimeline.PREV_Y] - bone.scaleY) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - let frame = Animation.binarySearch(frames, time, ScaleTimeline.ENTRIES); - let prevX = frames[frame + ScaleTimeline.PREV_X]; - let prevY = frames[frame + ScaleTimeline.PREV_Y]; - let frameTime = frames[frame]; - let percent = this.getCurvePercent(frame / ScaleTimeline.ENTRIES - 1, - 1 - (time - frameTime) / (frames[frame + ScaleTimeline.PREV_TIME] - frameTime)); - - bone.scaleX += (bone.data.scaleX * (prevX + (frames[frame + ScaleTimeline.X] - prevX) * percent) - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY * (prevY + (frames[frame + ScaleTimeline.Y] - prevY) * percent) - bone.scaleY) * alpha; - } - } - - export class ShearTimeline extends TranslateTimeline { - constructor (frameCount: number) { - super(frameCount); - } - - apply (skeleton: Skeleton, lastTime: number, time: number, events: Array, alpha: number) { - let frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - let bone = skeleton.bones[this.boneIndex]; - if (time >= frames[frames.length - ShearTimeline.ENTRIES]) { // Time is after last frame. - bone.shearX += (bone.data.shearX + frames[frames.length + ShearTimeline.PREV_X] - bone.shearX) * alpha; - bone.shearY += (bone.data.shearY + frames[frames.length + ShearTimeline.PREV_Y] - bone.shearY) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - let frame = Animation.binarySearch(frames, time, ShearTimeline.ENTRIES); - let prevX = frames[frame + ShearTimeline.PREV_X]; - let prevY = frames[frame + ShearTimeline.PREV_Y]; - let frameTime = frames[frame]; - let percent = this.getCurvePercent(frame / ShearTimeline.ENTRIES - 1, - 1 - (time - frameTime) / (frames[frame + ShearTimeline.PREV_TIME] - frameTime)); - - bone.shearX += (bone.data.shearX + (prevX + (frames[frame + ShearTimeline.X] - prevX) * percent) - bone.shearX) * alpha; - bone.shearY += (bone.data.shearY + (prevY + (frames[frame + ShearTimeline.Y] - prevY) * percent) - bone.shearY) * alpha; - } - } - - export class ColorTimeline extends CurveTimeline { - static ENTRIES = 5; - static PREV_TIME = -5; static PREV_R = -4; static PREV_G = -3; static PREV_B = -2; static PREV_A = -1; - static R = 1; static G = 2; static B = 3; static A = 4; - - slotIndex: number; - frames: ArrayLike; // time, r, g, b, a, ... - - constructor (frameCount: number) { - super(frameCount); - this.frames = Utils.newFloatArray(frameCount * ColorTimeline.ENTRIES); - } - - /** Sets the time and value of the specified keyframe. */ - setFrame (frameIndex: number, time: number, r: number, g: number, b: number, a: number) { - frameIndex *= ColorTimeline.ENTRIES; - this.frames[frameIndex] = time; - this.frames[frameIndex + ColorTimeline.R] = r; - this.frames[frameIndex + ColorTimeline.G] = g; - this.frames[frameIndex + ColorTimeline.B] = b; - this.frames[frameIndex + ColorTimeline.A] = a; - } - - apply (skeleton: Skeleton, lastTime: number, time: number, events: Array, alpha: number) { - let frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - let r = 0, g = 0, b = 0, a = 0; - if (time >= frames[frames.length - ColorTimeline.ENTRIES]) { // Time is after last frame. - let i = frames.length; - r = frames[i + ColorTimeline.PREV_R]; - g = frames[i + ColorTimeline.PREV_G]; - b = frames[i + ColorTimeline.PREV_B]; - a = frames[i + ColorTimeline.PREV_A]; - } else { - // Interpolate between the previous frame and the current frame. - let frame = Animation.binarySearch(frames, time, ColorTimeline.ENTRIES); - r = frames[frame + ColorTimeline.PREV_R]; - g = frames[frame + ColorTimeline.PREV_G]; - b = frames[frame + ColorTimeline.PREV_B]; - a = frames[frame + ColorTimeline.PREV_A]; - let frameTime = frames[frame]; - let percent = this.getCurvePercent(frame / ColorTimeline.ENTRIES - 1, - 1 - (time - frameTime) / (frames[frame + ColorTimeline.PREV_TIME] - frameTime)); - - r += (frames[frame + ColorTimeline.R] - r) * percent; - g += (frames[frame + ColorTimeline.G] - g) * percent; - b += (frames[frame + ColorTimeline.B] - b) * percent; - a += (frames[frame + ColorTimeline.A] - a) * percent; - } - let color: Color = skeleton.slots[this.slotIndex].color; - if (alpha < 1) - color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha); - else - color.set(r, g, b, a); - } - } - - export class AttachmentTimeline implements Timeline { - slotIndex: number; - frames: ArrayLike // time, ... - attachmentNames: Array; - - constructor (frameCount: number) { - this.frames = Utils.newFloatArray(frameCount); - this.attachmentNames = new Array(frameCount); - } - - getFrameCount () { - return this.frames.length; - } - - /** Sets the time and value of the specified keyframe. */ - setFrame (frameIndex: number, time: number, attachmentName: string) { - this.frames[frameIndex] = time; - this.attachmentNames[frameIndex] = attachmentName; - } - - apply (skeleton: Skeleton, lastTime: number, time: number, events: Array, alpha: number) { - let frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - let frameIndex = 0; - if (time >= frames[frames.length - 1]) // Time is after last frame. - frameIndex = frames.length - 1; - else - frameIndex = Animation.binarySearch(frames, time, 1) - 1; - - let attachmentName = this.attachmentNames[frameIndex]; - skeleton.slots[this.slotIndex] - .setAttachment(attachmentName == null ? null : skeleton.getAttachment(this.slotIndex, attachmentName)); - } - } - - export class EventTimeline implements Timeline { - frames: ArrayLike; // time, ... - events: Array; - - constructor (frameCount: number) { - this.frames = Utils.newFloatArray(frameCount); - this.events = new Array(frameCount); - } - - getFrameCount () { - return this.frames.length; - } - - /** Sets the time of the specified keyframe. */ - setFrame (frameIndex: number, event: Event) { - this.frames[frameIndex] = event.time; - this.events[frameIndex] = event; - } - - /** Fires events for frames > lastTime and <= time. */ - apply (skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array, alpha: number) { - if (firedEvents == null) return; - let frames = this.frames; - let frameCount = this.frames.length; - - if (lastTime > time) { // Fire events after last time for looped animations. - this.apply(skeleton, lastTime, Number.MAX_VALUE, firedEvents, alpha); - lastTime = -1; - } else if (lastTime >= frames[frameCount - 1]) // Last time is after last frame. - return; - if (time < frames[0]) return; // Time is before first frame. - - let frame = 0; - if (lastTime < frames[0]) - frame = 0; - else { - frame = Animation.binarySearch(frames, lastTime); - let frameTime = frames[frame]; - while (frame > 0) { // Fire multiple events with the same frame. - if (frames[frame - 1] != frameTime) break; - frame--; - } - } - for (; frame < frameCount && time >= frames[frame]; frame++) - firedEvents.push(this.events[frame]); - } - } - - export class DrawOrderTimeline implements Timeline { - frames: ArrayLike; // time, ... - drawOrders: Array>; - - constructor (frameCount: number) { - this.frames = Utils.newFloatArray(frameCount); - this.drawOrders = new Array>(frameCount); - } - - getFrameCount () { - return this.frames.length; - } - - /** Sets the time of the specified keyframe. - * @param drawOrder May be null to use bind pose draw order. */ - setFrame (frameIndex: number, time: number, drawOrder: Array) { - this.frames[frameIndex] = time; - this.drawOrders[frameIndex] = drawOrder; - } - - apply (skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array, alpha: number) { - let frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - let frame = 0; - if (time >= frames[frames.length - 1]) // Time is after last frame. - frame = frames.length - 1; - else - frame = Animation.binarySearch(frames, time) - 1; - - let drawOrder: Array = skeleton.drawOrder; - let slots: Array = skeleton.slots; - let drawOrderToSetupIndex = this.drawOrders[frame]; - if (drawOrderToSetupIndex == null) - Utils.arrayCopy(slots, 0, drawOrder, 0, slots.length); - else { - for (let i = 0, n = drawOrderToSetupIndex.length; i < n; i++) - drawOrder[i] = slots[drawOrderToSetupIndex[i]]; - } - } - } - - export class DeformTimeline extends CurveTimeline { - frames: ArrayLike; // time, ... - frameVertices: Array>; - slotIndex: number; - attachment: VertexAttachment; - - constructor (frameCount: number) { - super(frameCount); - this.frames = Utils.newFloatArray(frameCount); - this.frameVertices = new Array>(frameCount); - } - - /** Sets the time of the specified keyframe. */ - setFrame (frameIndex: number, time: number, vertices: ArrayLike) { - this.frames[frameIndex] = time; - this.frameVertices[frameIndex] = vertices; - } - - apply (skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array, alpha: number) { - let slot: Slot = skeleton.slots[this.slotIndex]; - let slotAttachment: Attachment = slot.getAttachment(); - if (!(slotAttachment instanceof VertexAttachment) || !(slotAttachment).applyDeform(this.attachment)) return; - - let frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - let frameVertices = this.frameVertices; - let vertexCount = frameVertices[0].length; - - let verticesArray: Array = slot.attachmentVertices; - if (verticesArray.length != vertexCount) alpha = 1; // Don't mix from uninitialized slot vertices. - let vertices: Array = Utils.setArraySize(verticesArray, vertexCount); - - if (time >= frames[frames.length - 1]) { // Time is after last frame. - let lastVertices = frameVertices[frames.length - 1]; - if (alpha < 1) { - for (let i = 0; i < vertexCount; i++) - vertices[i] += (lastVertices[i] - vertices[i]) * alpha; - } else - Utils.arrayCopy(lastVertices, 0, vertices, 0, vertexCount); - return; - } - - // Interpolate between the previous frame and the current frame. - let frame = Animation.binarySearch(frames, time); - let prevVertices = frameVertices[frame - 1]; - let nextVertices = frameVertices[frame]; - let frameTime = frames[frame]; - let percent = this.getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime)); - - if (alpha < 1) { - for (let i = 0; i < vertexCount; i++) { - let prev = prevVertices[i]; - vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha; - } - } else { - for (let i = 0; i < vertexCount; i++) { - let prev = prevVertices[i]; - vertices[i] = prev + (nextVertices[i] - prev) * percent; - } - } - } - } - - export class IkConstraintTimeline extends CurveTimeline { - static ENTRIES = 3; - static PREV_TIME = -3; static PREV_MIX = -2; static PREV_BEND_DIRECTION = -1; - static MIX = 1; static BEND_DIRECTION = 2; - - ikConstraintIndex: number; - frames: ArrayLike; // time, mix, bendDirection, ... - - constructor (frameCount: number) { - super(frameCount); - this.frames = Utils.newFloatArray(frameCount * IkConstraintTimeline.ENTRIES); - } - - /** Sets the time, mix and bend direction of the specified keyframe. */ - setFrame (frameIndex: number, time: number, mix: number, bendDirection: number) { - frameIndex *= IkConstraintTimeline.ENTRIES; - this.frames[frameIndex] = time; - this.frames[frameIndex + IkConstraintTimeline.MIX] = mix; - this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection; - } - - apply (skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array, alpha: number) { - let frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - let constraint: IkConstraint = skeleton.ikConstraints[this.ikConstraintIndex]; - - if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) { // Time is after last frame. - constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha; - constraint.bendDirection = Math.floor(frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION]); - return; - } - - // Interpolate between the previous frame and the current frame. - let frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES); - let mix = frames[frame + IkConstraintTimeline.PREV_MIX]; - let frameTime = frames[frame]; - let percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1, - 1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime)); - - constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha; - constraint.bendDirection = Math.floor(frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION]); - } - } - - export class TransformConstraintTimeline extends CurveTimeline { - static ENTRIES = 5; - static PREV_TIME = -5; static PREV_ROTATE = -4; static PREV_TRANSLATE = -3; static PREV_SCALE = -2; static PREV_SHEAR = -1; - static ROTATE = 1; static TRANSLATE = 2; static SCALE = 3; static SHEAR = 4; - - transformConstraintIndex: number; - frames: ArrayLike; // time, rotate mix, translate mix, scale mix, shear mix, ... - - constructor (frameCount: number) { - super(frameCount); - this.frames = Utils.newFloatArray(frameCount * TransformConstraintTimeline.ENTRIES); - } - - /** Sets the time and mixes of the specified keyframe. */ - setFrame (frameIndex: number, time: number, rotateMix: number, translateMix: number, scaleMix: number, shearMix: number) { - frameIndex *= TransformConstraintTimeline.ENTRIES; - this.frames[frameIndex] = time; - this.frames[frameIndex + TransformConstraintTimeline.ROTATE] = rotateMix; - this.frames[frameIndex + TransformConstraintTimeline.TRANSLATE] = translateMix; - this.frames[frameIndex + TransformConstraintTimeline.SCALE] = scaleMix; - this.frames[frameIndex + TransformConstraintTimeline.SHEAR] = shearMix; - } - - apply (skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array, alpha: number) { - let frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - let constraint: TransformConstraint = skeleton.transformConstraints[this.transformConstraintIndex]; - - if (time >= frames[frames.length - TransformConstraintTimeline.ENTRIES]) { // Time is after last frame. - let i = frames.length; - constraint.rotateMix += (frames[i + TransformConstraintTimeline.PREV_ROTATE] - constraint.rotateMix) * alpha; - constraint.translateMix += (frames[i + TransformConstraintTimeline.PREV_TRANSLATE] - constraint.translateMix) * alpha; - constraint.scaleMix += (frames[i + TransformConstraintTimeline.PREV_SCALE] - constraint.scaleMix) * alpha; - constraint.shearMix += (frames[i + TransformConstraintTimeline.PREV_SHEAR] - constraint.shearMix) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - let frame = Animation.binarySearch(frames, time, TransformConstraintTimeline.ENTRIES); - let frameTime = frames[frame]; - let percent = this.getCurvePercent(frame / TransformConstraintTimeline.ENTRIES - 1, - 1 - (time - frameTime) / (frames[frame + TransformConstraintTimeline.PREV_TIME] - frameTime)); - - let rotate = frames[frame + TransformConstraintTimeline.PREV_ROTATE]; - let translate = frames[frame + TransformConstraintTimeline.PREV_TRANSLATE]; - let scale = frames[frame + TransformConstraintTimeline.PREV_SCALE]; - let shear = frames[frame + TransformConstraintTimeline.PREV_SHEAR]; - constraint.rotateMix += (rotate + (frames[frame + TransformConstraintTimeline.ROTATE] - rotate) * percent - constraint.rotateMix) * alpha; - constraint.translateMix += (translate + (frames[frame + TransformConstraintTimeline.TRANSLATE] - translate) * percent - constraint.translateMix) - * alpha; - constraint.scaleMix += (scale + (frames[frame + TransformConstraintTimeline.SCALE] - scale) * percent - constraint.scaleMix) * alpha; - constraint.shearMix += (shear + (frames[frame + TransformConstraintTimeline.SHEAR] - shear) * percent - constraint.shearMix) * alpha; - } - } - - export class PathConstraintPositionTimeline extends CurveTimeline { - static ENTRIES = 2; - static PREV_TIME = -2; static PREV_VALUE = -1; - static VALUE = 1; - - pathConstraintIndex: number; - - frames: ArrayLike; // time, position, ... - - constructor (frameCount: number) { - super(frameCount); - this.frames = Utils.newFloatArray(frameCount * PathConstraintPositionTimeline.ENTRIES); - } - - /** Sets the time and value of the specified keyframe. */ - setFrame (frameIndex: number, time: number, value: number) { - frameIndex *= PathConstraintPositionTimeline.ENTRIES; - this.frames[frameIndex] = time; - this.frames[frameIndex + PathConstraintPositionTimeline.VALUE] = value; - } - - apply (skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array, alpha: number) { - let frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - let constraint: PathConstraint = skeleton.pathConstraints[this.pathConstraintIndex]; - - if (time >= frames[frames.length - PathConstraintPositionTimeline.ENTRIES]) { // Time is after last frame. - let i = frames.length; - constraint.position += (frames[i + PathConstraintPositionTimeline.PREV_VALUE] - constraint.position) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - let frame = Animation.binarySearch(frames, time, PathConstraintPositionTimeline.ENTRIES); - let position = frames[frame + PathConstraintPositionTimeline.PREV_VALUE]; - let frameTime = frames[frame]; - let percent = this.getCurvePercent(frame / PathConstraintPositionTimeline.ENTRIES - 1, - 1 - (time - frameTime) / (frames[frame + PathConstraintPositionTimeline.PREV_TIME] - frameTime)); - - constraint.position += (position + (frames[frame + PathConstraintPositionTimeline.VALUE] - position) * percent - constraint.position) * alpha; - } - } - - export class PathConstraintSpacingTimeline extends PathConstraintPositionTimeline { - constructor (frameCount: number) { - super(frameCount); - } - - apply (skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array, alpha: number) { - let frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - let constraint: PathConstraint = skeleton.pathConstraints[this.pathConstraintIndex]; - - if (time >= frames[frames.length - PathConstraintSpacingTimeline.ENTRIES]) { // Time is after last frame. - let i = frames.length; - constraint.spacing += (frames[i + PathConstraintSpacingTimeline.PREV_VALUE] - constraint.spacing) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - let frame = Animation.binarySearch(frames, time, PathConstraintSpacingTimeline.ENTRIES); - let spacing = frames[frame + PathConstraintSpacingTimeline.PREV_VALUE]; - let frameTime = frames[frame]; - let percent = this.getCurvePercent(frame / PathConstraintSpacingTimeline.ENTRIES - 1, - 1 - (time - frameTime) / (frames[frame + PathConstraintSpacingTimeline.PREV_TIME] - frameTime)); - - constraint.spacing += (spacing + (frames[frame + PathConstraintSpacingTimeline.VALUE] - spacing) * percent - constraint.spacing) * alpha; - } - } - - export class PathConstraintMixTimeline extends CurveTimeline { - static ENTRIES = 3; - static PREV_TIME = -3; static PREV_ROTATE = -2; static PREV_TRANSLATE = -1; - static ROTATE = 1; static TRANSLATE = 2; - - pathConstraintIndex: number; - - frames: ArrayLike; // time, rotate mix, translate mix, ... - - constructor (frameCount: number) { - super(frameCount); - this.frames = Utils.newFloatArray(frameCount * PathConstraintMixTimeline.ENTRIES); - } - - /** Sets the time and mixes of the specified keyframe. */ - setFrame (frameIndex: number, time: number, rotateMix: number, translateMix: number) { - frameIndex *= PathConstraintMixTimeline.ENTRIES; - this.frames[frameIndex] = time; - this.frames[frameIndex + PathConstraintMixTimeline.ROTATE] = rotateMix; - this.frames[frameIndex + PathConstraintMixTimeline.TRANSLATE] = translateMix; - } - - apply (skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array, alpha: number) { - let frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - let constraint: PathConstraint = skeleton.pathConstraints[this.pathConstraintIndex]; - - if (time >= frames[frames.length - PathConstraintMixTimeline.ENTRIES]) { // Time is after last frame. - let i = frames.length; - constraint.rotateMix += (frames[i + PathConstraintMixTimeline.PREV_ROTATE] - constraint.rotateMix) * alpha; - constraint.translateMix += (frames[i + PathConstraintMixTimeline.PREV_TRANSLATE] - constraint.translateMix) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - let frame = Animation.binarySearch(frames, time, PathConstraintMixTimeline.ENTRIES); - let rotate = frames[frame + PathConstraintMixTimeline.PREV_ROTATE]; - let translate = frames[frame + PathConstraintMixTimeline.PREV_TRANSLATE]; - let frameTime = frames[frame]; - let percent = this.getCurvePercent(frame / PathConstraintMixTimeline.ENTRIES - 1, - 1 - (time - frameTime) / (frames[frame + PathConstraintMixTimeline.PREV_TIME] - frameTime)); - - constraint.rotateMix += (rotate + (frames[frame + PathConstraintMixTimeline.ROTATE] - rotate) * percent - constraint.rotateMix) * alpha; - constraint.translateMix += (translate + (frames[frame + PathConstraintMixTimeline.TRANSLATE] - translate) * percent - constraint.translateMix) - * alpha; - } - } +module spine { + export class Animation { + name: string; + timelines: Array; + duration: number; + + constructor (name: string, timelines: Array, duration: number) { + if (name == null) throw new Error("name cannot be null."); + if (timelines == null) throw new Error("timelines cannot be null."); + this.name = name; + this.timelines = timelines; + this.duration = duration; + } + + apply (skeleton: Skeleton, lastTime: number, time: number, loop: boolean, events: Array) { + if (skeleton == null) throw new Error("skeleton cannot be null."); + + if (loop && this.duration != 0) { + time %= this.duration; + if (lastTime > 0) lastTime %= this.duration; + } + + let timelines = this.timelines; + for (let i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, lastTime, time, events, 1); + } + + mix (skeleton: Skeleton, lastTime: number, time: number, loop: boolean, events: Array, alpha: number) { + if (skeleton == null) throw new Error("skeleton cannot be null."); + + if (loop && this.duration != 0) { + time %= this.duration; + if (lastTime > 0) lastTime %= this.duration; + } + + let timelines = this.timelines; + for (let i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, lastTime, time, events, alpha); + } + + static binarySearch (values: ArrayLike, target: number, step: number = 1) { + let low = 0; + let high = values.length / step - 2; + if (high == 0) return step; + let current = high >>> 1; + while (true) { + if (values[(current + 1) * step] <= target) + low = current + 1; + else + high = current; + if (low == high) return (low + 1) * step; + current = (low + high) >>> 1; + } + } + + static linearSearch (values: ArrayLike, target: number, step: number) { + for (let i = 0, last = values.length - step; i <= last; i += step) + if (values[i] > target) return i; + return -1; + } + } + + export interface Timeline { + apply (skeleton: Skeleton, lastTime: number, time: number, events: Array, alpha: number): void; + } + + export abstract class CurveTimeline implements Timeline { + static LINEAR = 0; static STEPPED = 1; static BEZIER = 2; + static BEZIER_SIZE = 10 * 2 - 1; + + private curves: ArrayLike; // type, x, y, ... + + constructor (frameCount: number) { + if (frameCount <= 0) throw new Error("frameCount must be > 0: " + frameCount); + this.curves = Utils.newFloatArray((frameCount - 1) * CurveTimeline.BEZIER_SIZE); + } + + getFrameCount () { + return this.curves.length / CurveTimeline.BEZIER_SIZE + 1; + } + + setLinear (frameIndex: number) { + this.curves[frameIndex * CurveTimeline.BEZIER_SIZE] = CurveTimeline.LINEAR; + } + + setStepped (frameIndex: number) { + this.curves[frameIndex * CurveTimeline.BEZIER_SIZE] = CurveTimeline.STEPPED; + } + + getCurveType (frameIndex: number): number { + let index = frameIndex * CurveTimeline.BEZIER_SIZE; + if (index == this.curves.length) return CurveTimeline.LINEAR; + let type = this.curves[index]; + if (type == CurveTimeline.LINEAR) return CurveTimeline.LINEAR; + if (type == CurveTimeline.STEPPED) return CurveTimeline.STEPPED; + return CurveTimeline.BEZIER; + } + + /** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. + * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of + * the difference between the keyframe's values. */ + setCurve (frameIndex: number, cx1: number, cy1: number, cx2: number, cy2: number) { + let tmpx = (-cx1 * 2 + cx2) * 0.03, tmpy = (-cy1 * 2 + cy2) * 0.03; + let dddfx = ((cx1 - cx2) * 3 + 1) * 0.006, dddfy = ((cy1 - cy2) * 3 + 1) * 0.006; + let ddfx = tmpx * 2 + dddfx, ddfy = tmpy * 2 + dddfy; + let dfx = cx1 * 0.3 + tmpx + dddfx * 0.16666667, dfy = cy1 * 0.3 + tmpy + dddfy * 0.16666667; + + let i = frameIndex * CurveTimeline.BEZIER_SIZE; + let curves = this.curves; + curves[i++] = CurveTimeline.BEZIER; + + let x = dfx, y = dfy; + for (let n = i + CurveTimeline.BEZIER_SIZE - 1; i < n; i += 2) { + curves[i] = x; + curves[i + 1] = y; + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + x += dfx; + y += dfy; + } + } + + getCurvePercent (frameIndex: number, percent: number) { + percent = MathUtils.clamp(percent, 0, 1); + let curves = this.curves; + let i = frameIndex * CurveTimeline.BEZIER_SIZE; + let type = curves[i]; + if (type == CurveTimeline.LINEAR) return percent; + if (type == CurveTimeline.STEPPED) return 0; + i++; + let x = 0; + for (let start = i, n = i + CurveTimeline.BEZIER_SIZE - 1; i < n; i += 2) { + x = curves[i]; + if (x >= percent) { + let prevX: number, prevY: number; + if (i == start) { + prevX = 0; + prevY = 0; + } else { + prevX = curves[i - 2]; + prevY = curves[i - 1]; + } + return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX); + } + } + let y = curves[i - 1]; + return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. + } + + abstract apply (skeleton: Skeleton, lastTime: number, time: number, events: Array, alpha: number): void; + } + + export class RotateTimeline extends CurveTimeline { + static ENTRIES = 2; + static PREV_TIME = -2; static PREV_ROTATION = -1; + static ROTATION = 1; + + boneIndex: number; + frames: ArrayLike; // time, degrees, ... + + constructor (frameCount: number) { + super(frameCount); + this.frames = Utils.newFloatArray(frameCount << 1); + } + + /** Sets the time and angle of the specified keyframe. */ + setFrame (frameIndex: number, time: number, degrees: number) { + frameIndex <<= 1; + this.frames[frameIndex] = time; + this.frames[frameIndex + RotateTimeline.ROTATION] = degrees; + } + + apply (skeleton: Skeleton, lastTime: number, time: number, events: Array, alpha: number) { + let frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + let bone = skeleton.bones[this.boneIndex]; + + if (time >= frames[frames.length - RotateTimeline.ENTRIES]) { // Time is after last frame. + let amount = bone.data.rotation + frames[frames.length + RotateTimeline.PREV_ROTATION] - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + let frame = Animation.binarySearch(frames, time, RotateTimeline.ENTRIES); + let prevRotation = frames[frame + RotateTimeline.PREV_ROTATION]; + let frameTime = frames[frame]; + let percent = this.getCurvePercent((frame >> 1) - 1, + 1 - (time - frameTime) / (frames[frame + RotateTimeline.PREV_TIME] - frameTime)); + + let amount = frames[frame + RotateTimeline.ROTATION] - prevRotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + amount = bone.data.rotation + (prevRotation + amount * percent) - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + } + } + + export class TranslateTimeline extends CurveTimeline { + static ENTRIES = 3; + static PREV_TIME = -3; static PREV_X = -2; static PREV_Y = -1; + static X = 1; static Y = 2; + + boneIndex: number; + frames: ArrayLike; // time, x, y, ... + + constructor (frameCount: number) { + super(frameCount); + this.frames = Utils.newFloatArray(frameCount * TranslateTimeline.ENTRIES); + } + + /** Sets the time and value of the specified keyframe. */ + setFrame (frameIndex: number, time: number, x: number, y: number) { + frameIndex *= TranslateTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + TranslateTimeline.X] = x; + this.frames[frameIndex + TranslateTimeline.Y] = y; + } + + apply (skeleton: Skeleton, lastTime: number, time: number, events: Array, alpha: number) { + let frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + let bone = skeleton.bones[this.boneIndex]; + + if (time >= frames[frames.length - TranslateTimeline.ENTRIES]) { // Time is after last frame. + bone.x += (bone.data.x + frames[frames.length + TranslateTimeline.PREV_X] - bone.x) * alpha; + bone.y += (bone.data.y + frames[frames.length + TranslateTimeline.PREV_Y] - bone.y) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + let frame = Animation.binarySearch(frames, time, TranslateTimeline.ENTRIES); + let prevX = frames[frame + TranslateTimeline.PREV_X]; + let prevY = frames[frame + TranslateTimeline.PREV_Y]; + let frameTime = frames[frame]; + let percent = this.getCurvePercent(frame / TranslateTimeline.ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + TranslateTimeline.PREV_TIME] - frameTime)); + + bone.x += (bone.data.x + prevX + (frames[frame + TranslateTimeline.X] - prevX) * percent - bone.x) * alpha; + bone.y += (bone.data.y + prevY + (frames[frame + TranslateTimeline.Y] - prevY) * percent - bone.y) * alpha; + } + } + + export class ScaleTimeline extends TranslateTimeline { + constructor (frameCount: number) { + super(frameCount); + } + + apply (skeleton: Skeleton, lastTime: number, time: number, events: Array, alpha: number) { + let frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + let bone = skeleton.bones[this.boneIndex]; + if (time >= frames[frames.length - ScaleTimeline.ENTRIES]) { // Time is after last frame. + bone.scaleX += (bone.data.scaleX * frames[frames.length + ScaleTimeline.PREV_X] - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY * frames[frames.length + ScaleTimeline.PREV_Y] - bone.scaleY) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + let frame = Animation.binarySearch(frames, time, ScaleTimeline.ENTRIES); + let prevX = frames[frame + ScaleTimeline.PREV_X]; + let prevY = frames[frame + ScaleTimeline.PREV_Y]; + let frameTime = frames[frame]; + let percent = this.getCurvePercent(frame / ScaleTimeline.ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + ScaleTimeline.PREV_TIME] - frameTime)); + + bone.scaleX += (bone.data.scaleX * (prevX + (frames[frame + ScaleTimeline.X] - prevX) * percent) - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY * (prevY + (frames[frame + ScaleTimeline.Y] - prevY) * percent) - bone.scaleY) * alpha; + } + } + + export class ShearTimeline extends TranslateTimeline { + constructor (frameCount: number) { + super(frameCount); + } + + apply (skeleton: Skeleton, lastTime: number, time: number, events: Array, alpha: number) { + let frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + let bone = skeleton.bones[this.boneIndex]; + if (time >= frames[frames.length - ShearTimeline.ENTRIES]) { // Time is after last frame. + bone.shearX += (bone.data.shearX + frames[frames.length + ShearTimeline.PREV_X] - bone.shearX) * alpha; + bone.shearY += (bone.data.shearY + frames[frames.length + ShearTimeline.PREV_Y] - bone.shearY) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + let frame = Animation.binarySearch(frames, time, ShearTimeline.ENTRIES); + let prevX = frames[frame + ShearTimeline.PREV_X]; + let prevY = frames[frame + ShearTimeline.PREV_Y]; + let frameTime = frames[frame]; + let percent = this.getCurvePercent(frame / ShearTimeline.ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + ShearTimeline.PREV_TIME] - frameTime)); + + bone.shearX += (bone.data.shearX + (prevX + (frames[frame + ShearTimeline.X] - prevX) * percent) - bone.shearX) * alpha; + bone.shearY += (bone.data.shearY + (prevY + (frames[frame + ShearTimeline.Y] - prevY) * percent) - bone.shearY) * alpha; + } + } + + export class ColorTimeline extends CurveTimeline { + static ENTRIES = 5; + static PREV_TIME = -5; static PREV_R = -4; static PREV_G = -3; static PREV_B = -2; static PREV_A = -1; + static R = 1; static G = 2; static B = 3; static A = 4; + + slotIndex: number; + frames: ArrayLike; // time, r, g, b, a, ... + + constructor (frameCount: number) { + super(frameCount); + this.frames = Utils.newFloatArray(frameCount * ColorTimeline.ENTRIES); + } + + /** Sets the time and value of the specified keyframe. */ + setFrame (frameIndex: number, time: number, r: number, g: number, b: number, a: number) { + frameIndex *= ColorTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + ColorTimeline.R] = r; + this.frames[frameIndex + ColorTimeline.G] = g; + this.frames[frameIndex + ColorTimeline.B] = b; + this.frames[frameIndex + ColorTimeline.A] = a; + } + + apply (skeleton: Skeleton, lastTime: number, time: number, events: Array, alpha: number) { + let frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + let r = 0, g = 0, b = 0, a = 0; + if (time >= frames[frames.length - ColorTimeline.ENTRIES]) { // Time is after last frame. + let i = frames.length; + r = frames[i + ColorTimeline.PREV_R]; + g = frames[i + ColorTimeline.PREV_G]; + b = frames[i + ColorTimeline.PREV_B]; + a = frames[i + ColorTimeline.PREV_A]; + } else { + // Interpolate between the previous frame and the current frame. + let frame = Animation.binarySearch(frames, time, ColorTimeline.ENTRIES); + r = frames[frame + ColorTimeline.PREV_R]; + g = frames[frame + ColorTimeline.PREV_G]; + b = frames[frame + ColorTimeline.PREV_B]; + a = frames[frame + ColorTimeline.PREV_A]; + let frameTime = frames[frame]; + let percent = this.getCurvePercent(frame / ColorTimeline.ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + ColorTimeline.PREV_TIME] - frameTime)); + + r += (frames[frame + ColorTimeline.R] - r) * percent; + g += (frames[frame + ColorTimeline.G] - g) * percent; + b += (frames[frame + ColorTimeline.B] - b) * percent; + a += (frames[frame + ColorTimeline.A] - a) * percent; + } + let color: Color = skeleton.slots[this.slotIndex].color; + if (alpha < 1) + color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha); + else + color.set(r, g, b, a); + } + } + + export class AttachmentTimeline implements Timeline { + slotIndex: number; + frames: ArrayLike // time, ... + attachmentNames: Array; + + constructor (frameCount: number) { + this.frames = Utils.newFloatArray(frameCount); + this.attachmentNames = new Array(frameCount); + } + + getFrameCount () { + return this.frames.length; + } + + /** Sets the time and value of the specified keyframe. */ + setFrame (frameIndex: number, time: number, attachmentName: string) { + this.frames[frameIndex] = time; + this.attachmentNames[frameIndex] = attachmentName; + } + + apply (skeleton: Skeleton, lastTime: number, time: number, events: Array, alpha: number) { + let frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + let frameIndex = 0; + if (time >= frames[frames.length - 1]) // Time is after last frame. + frameIndex = frames.length - 1; + else + frameIndex = Animation.binarySearch(frames, time, 1) - 1; + + let attachmentName = this.attachmentNames[frameIndex]; + skeleton.slots[this.slotIndex] + .setAttachment(attachmentName == null ? null : skeleton.getAttachment(this.slotIndex, attachmentName)); + } + } + + export class EventTimeline implements Timeline { + frames: ArrayLike; // time, ... + events: Array; + + constructor (frameCount: number) { + this.frames = Utils.newFloatArray(frameCount); + this.events = new Array(frameCount); + } + + getFrameCount () { + return this.frames.length; + } + + /** Sets the time of the specified keyframe. */ + setFrame (frameIndex: number, event: Event) { + this.frames[frameIndex] = event.time; + this.events[frameIndex] = event; + } + + /** Fires events for frames > lastTime and <= time. */ + apply (skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array, alpha: number) { + if (firedEvents == null) return; + let frames = this.frames; + let frameCount = this.frames.length; + + if (lastTime > time) { // Fire events after last time for looped animations. + this.apply(skeleton, lastTime, Number.MAX_VALUE, firedEvents, alpha); + lastTime = -1; + } else if (lastTime >= frames[frameCount - 1]) // Last time is after last frame. + return; + if (time < frames[0]) return; // Time is before first frame. + + let frame = 0; + if (lastTime < frames[0]) + frame = 0; + else { + frame = Animation.binarySearch(frames, lastTime); + let frameTime = frames[frame]; + while (frame > 0) { // Fire multiple events with the same frame. + if (frames[frame - 1] != frameTime) break; + frame--; + } + } + for (; frame < frameCount && time >= frames[frame]; frame++) + firedEvents.push(this.events[frame]); + } + } + + export class DrawOrderTimeline implements Timeline { + frames: ArrayLike; // time, ... + drawOrders: Array>; + + constructor (frameCount: number) { + this.frames = Utils.newFloatArray(frameCount); + this.drawOrders = new Array>(frameCount); + } + + getFrameCount () { + return this.frames.length; + } + + /** Sets the time of the specified keyframe. + * @param drawOrder May be null to use bind pose draw order. */ + setFrame (frameIndex: number, time: number, drawOrder: Array) { + this.frames[frameIndex] = time; + this.drawOrders[frameIndex] = drawOrder; + } + + apply (skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array, alpha: number) { + let frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + let frame = 0; + if (time >= frames[frames.length - 1]) // Time is after last frame. + frame = frames.length - 1; + else + frame = Animation.binarySearch(frames, time) - 1; + + let drawOrder: Array = skeleton.drawOrder; + let slots: Array = skeleton.slots; + let drawOrderToSetupIndex = this.drawOrders[frame]; + if (drawOrderToSetupIndex == null) + Utils.arrayCopy(slots, 0, drawOrder, 0, slots.length); + else { + for (let i = 0, n = drawOrderToSetupIndex.length; i < n; i++) + drawOrder[i] = slots[drawOrderToSetupIndex[i]]; + } + } + } + + export class DeformTimeline extends CurveTimeline { + frames: ArrayLike; // time, ... + frameVertices: Array>; + slotIndex: number; + attachment: VertexAttachment; + + constructor (frameCount: number) { + super(frameCount); + this.frames = Utils.newFloatArray(frameCount); + this.frameVertices = new Array>(frameCount); + } + + /** Sets the time of the specified keyframe. */ + setFrame (frameIndex: number, time: number, vertices: ArrayLike) { + this.frames[frameIndex] = time; + this.frameVertices[frameIndex] = vertices; + } + + apply (skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array, alpha: number) { + let slot: Slot = skeleton.slots[this.slotIndex]; + let slotAttachment: Attachment = slot.getAttachment(); + if (!(slotAttachment instanceof VertexAttachment) || !(slotAttachment).applyDeform(this.attachment)) return; + + let frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + let frameVertices = this.frameVertices; + let vertexCount = frameVertices[0].length; + + let verticesArray: Array = slot.attachmentVertices; + if (verticesArray.length != vertexCount) alpha = 1; // Don't mix from uninitialized slot vertices. + let vertices: Array = Utils.setArraySize(verticesArray, vertexCount); + + if (time >= frames[frames.length - 1]) { // Time is after last frame. + let lastVertices = frameVertices[frames.length - 1]; + if (alpha < 1) { + for (let i = 0; i < vertexCount; i++) + vertices[i] += (lastVertices[i] - vertices[i]) * alpha; + } else + Utils.arrayCopy(lastVertices, 0, vertices, 0, vertexCount); + return; + } + + // Interpolate between the previous frame and the current frame. + let frame = Animation.binarySearch(frames, time); + let prevVertices = frameVertices[frame - 1]; + let nextVertices = frameVertices[frame]; + let frameTime = frames[frame]; + let percent = this.getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime)); + + if (alpha < 1) { + for (let i = 0; i < vertexCount; i++) { + let prev = prevVertices[i]; + vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha; + } + } else { + for (let i = 0; i < vertexCount; i++) { + let prev = prevVertices[i]; + vertices[i] = prev + (nextVertices[i] - prev) * percent; + } + } + } + } + + export class IkConstraintTimeline extends CurveTimeline { + static ENTRIES = 3; + static PREV_TIME = -3; static PREV_MIX = -2; static PREV_BEND_DIRECTION = -1; + static MIX = 1; static BEND_DIRECTION = 2; + + ikConstraintIndex: number; + frames: ArrayLike; // time, mix, bendDirection, ... + + constructor (frameCount: number) { + super(frameCount); + this.frames = Utils.newFloatArray(frameCount * IkConstraintTimeline.ENTRIES); + } + + /** Sets the time, mix and bend direction of the specified keyframe. */ + setFrame (frameIndex: number, time: number, mix: number, bendDirection: number) { + frameIndex *= IkConstraintTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + IkConstraintTimeline.MIX] = mix; + this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection; + } + + apply (skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array, alpha: number) { + let frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + let constraint: IkConstraint = skeleton.ikConstraints[this.ikConstraintIndex]; + + if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) { // Time is after last frame. + constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha; + constraint.bendDirection = Math.floor(frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION]); + return; + } + + // Interpolate between the previous frame and the current frame. + let frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES); + let mix = frames[frame + IkConstraintTimeline.PREV_MIX]; + let frameTime = frames[frame]; + let percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime)); + + constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha; + constraint.bendDirection = Math.floor(frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION]); + } + } + + export class TransformConstraintTimeline extends CurveTimeline { + static ENTRIES = 5; + static PREV_TIME = -5; static PREV_ROTATE = -4; static PREV_TRANSLATE = -3; static PREV_SCALE = -2; static PREV_SHEAR = -1; + static ROTATE = 1; static TRANSLATE = 2; static SCALE = 3; static SHEAR = 4; + + transformConstraintIndex: number; + frames: ArrayLike; // time, rotate mix, translate mix, scale mix, shear mix, ... + + constructor (frameCount: number) { + super(frameCount); + this.frames = Utils.newFloatArray(frameCount * TransformConstraintTimeline.ENTRIES); + } + + /** Sets the time and mixes of the specified keyframe. */ + setFrame (frameIndex: number, time: number, rotateMix: number, translateMix: number, scaleMix: number, shearMix: number) { + frameIndex *= TransformConstraintTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + TransformConstraintTimeline.ROTATE] = rotateMix; + this.frames[frameIndex + TransformConstraintTimeline.TRANSLATE] = translateMix; + this.frames[frameIndex + TransformConstraintTimeline.SCALE] = scaleMix; + this.frames[frameIndex + TransformConstraintTimeline.SHEAR] = shearMix; + } + + apply (skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array, alpha: number) { + let frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + let constraint: TransformConstraint = skeleton.transformConstraints[this.transformConstraintIndex]; + + if (time >= frames[frames.length - TransformConstraintTimeline.ENTRIES]) { // Time is after last frame. + let i = frames.length; + constraint.rotateMix += (frames[i + TransformConstraintTimeline.PREV_ROTATE] - constraint.rotateMix) * alpha; + constraint.translateMix += (frames[i + TransformConstraintTimeline.PREV_TRANSLATE] - constraint.translateMix) * alpha; + constraint.scaleMix += (frames[i + TransformConstraintTimeline.PREV_SCALE] - constraint.scaleMix) * alpha; + constraint.shearMix += (frames[i + TransformConstraintTimeline.PREV_SHEAR] - constraint.shearMix) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + let frame = Animation.binarySearch(frames, time, TransformConstraintTimeline.ENTRIES); + let frameTime = frames[frame]; + let percent = this.getCurvePercent(frame / TransformConstraintTimeline.ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + TransformConstraintTimeline.PREV_TIME] - frameTime)); + + let rotate = frames[frame + TransformConstraintTimeline.PREV_ROTATE]; + let translate = frames[frame + TransformConstraintTimeline.PREV_TRANSLATE]; + let scale = frames[frame + TransformConstraintTimeline.PREV_SCALE]; + let shear = frames[frame + TransformConstraintTimeline.PREV_SHEAR]; + constraint.rotateMix += (rotate + (frames[frame + TransformConstraintTimeline.ROTATE] - rotate) * percent - constraint.rotateMix) * alpha; + constraint.translateMix += (translate + (frames[frame + TransformConstraintTimeline.TRANSLATE] - translate) * percent - constraint.translateMix) + * alpha; + constraint.scaleMix += (scale + (frames[frame + TransformConstraintTimeline.SCALE] - scale) * percent - constraint.scaleMix) * alpha; + constraint.shearMix += (shear + (frames[frame + TransformConstraintTimeline.SHEAR] - shear) * percent - constraint.shearMix) * alpha; + } + } + + export class PathConstraintPositionTimeline extends CurveTimeline { + static ENTRIES = 2; + static PREV_TIME = -2; static PREV_VALUE = -1; + static VALUE = 1; + + pathConstraintIndex: number; + + frames: ArrayLike; // time, position, ... + + constructor (frameCount: number) { + super(frameCount); + this.frames = Utils.newFloatArray(frameCount * PathConstraintPositionTimeline.ENTRIES); + } + + /** Sets the time and value of the specified keyframe. */ + setFrame (frameIndex: number, time: number, value: number) { + frameIndex *= PathConstraintPositionTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + PathConstraintPositionTimeline.VALUE] = value; + } + + apply (skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array, alpha: number) { + let frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + let constraint: PathConstraint = skeleton.pathConstraints[this.pathConstraintIndex]; + + if (time >= frames[frames.length - PathConstraintPositionTimeline.ENTRIES]) { // Time is after last frame. + let i = frames.length; + constraint.position += (frames[i + PathConstraintPositionTimeline.PREV_VALUE] - constraint.position) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + let frame = Animation.binarySearch(frames, time, PathConstraintPositionTimeline.ENTRIES); + let position = frames[frame + PathConstraintPositionTimeline.PREV_VALUE]; + let frameTime = frames[frame]; + let percent = this.getCurvePercent(frame / PathConstraintPositionTimeline.ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + PathConstraintPositionTimeline.PREV_TIME] - frameTime)); + + constraint.position += (position + (frames[frame + PathConstraintPositionTimeline.VALUE] - position) * percent - constraint.position) * alpha; + } + } + + export class PathConstraintSpacingTimeline extends PathConstraintPositionTimeline { + constructor (frameCount: number) { + super(frameCount); + } + + apply (skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array, alpha: number) { + let frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + let constraint: PathConstraint = skeleton.pathConstraints[this.pathConstraintIndex]; + + if (time >= frames[frames.length - PathConstraintSpacingTimeline.ENTRIES]) { // Time is after last frame. + let i = frames.length; + constraint.spacing += (frames[i + PathConstraintSpacingTimeline.PREV_VALUE] - constraint.spacing) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + let frame = Animation.binarySearch(frames, time, PathConstraintSpacingTimeline.ENTRIES); + let spacing = frames[frame + PathConstraintSpacingTimeline.PREV_VALUE]; + let frameTime = frames[frame]; + let percent = this.getCurvePercent(frame / PathConstraintSpacingTimeline.ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + PathConstraintSpacingTimeline.PREV_TIME] - frameTime)); + + constraint.spacing += (spacing + (frames[frame + PathConstraintSpacingTimeline.VALUE] - spacing) * percent - constraint.spacing) * alpha; + } + } + + export class PathConstraintMixTimeline extends CurveTimeline { + static ENTRIES = 3; + static PREV_TIME = -3; static PREV_ROTATE = -2; static PREV_TRANSLATE = -1; + static ROTATE = 1; static TRANSLATE = 2; + + pathConstraintIndex: number; + + frames: ArrayLike; // time, rotate mix, translate mix, ... + + constructor (frameCount: number) { + super(frameCount); + this.frames = Utils.newFloatArray(frameCount * PathConstraintMixTimeline.ENTRIES); + } + + /** Sets the time and mixes of the specified keyframe. */ + setFrame (frameIndex: number, time: number, rotateMix: number, translateMix: number) { + frameIndex *= PathConstraintMixTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + PathConstraintMixTimeline.ROTATE] = rotateMix; + this.frames[frameIndex + PathConstraintMixTimeline.TRANSLATE] = translateMix; + } + + apply (skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array, alpha: number) { + let frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + let constraint: PathConstraint = skeleton.pathConstraints[this.pathConstraintIndex]; + + if (time >= frames[frames.length - PathConstraintMixTimeline.ENTRIES]) { // Time is after last frame. + let i = frames.length; + constraint.rotateMix += (frames[i + PathConstraintMixTimeline.PREV_ROTATE] - constraint.rotateMix) * alpha; + constraint.translateMix += (frames[i + PathConstraintMixTimeline.PREV_TRANSLATE] - constraint.translateMix) * alpha; + return; + } + + // Interpolate between the previous frame and the current frame. + let frame = Animation.binarySearch(frames, time, PathConstraintMixTimeline.ENTRIES); + let rotate = frames[frame + PathConstraintMixTimeline.PREV_ROTATE]; + let translate = frames[frame + PathConstraintMixTimeline.PREV_TRANSLATE]; + let frameTime = frames[frame]; + let percent = this.getCurvePercent(frame / PathConstraintMixTimeline.ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + PathConstraintMixTimeline.PREV_TIME] - frameTime)); + + constraint.rotateMix += (rotate + (frames[frame + PathConstraintMixTimeline.ROTATE] - rotate) * percent - constraint.rotateMix) * alpha; + constraint.translateMix += (translate + (frames[frame + PathConstraintMixTimeline.TRANSLATE] - translate) * percent - constraint.translateMix) + * alpha; + } + } } diff --git a/spine-ts/core/src/AnimationState.ts b/spine-ts/core/src/AnimationState.ts index 22b25d1bf6..db50d44040 100644 --- a/spine-ts/core/src/AnimationState.ts +++ b/spine-ts/core/src/AnimationState.ts @@ -1,321 +1,320 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class AnimationState { - data: AnimationStateData; - tracks = new Array(); - events = new Array(); - listeners = new Array(); - timeScale = 1; - - constructor (data: AnimationStateData = null) { - if (data == null) throw new Error("data cannot be null."); - this.data = data; - } - - update (delta: number) { - delta *= this.timeScale; - for (let i = 0; i < this.tracks.length; i++) { - let current = this.tracks[i]; - if (current == null) continue; - - let next = current.next; - if (next != null) { - let nextTime = current.lastTime - next.delay; - if (nextTime >= 0) { - let nextDelta = delta * next.timeScale; - next.time = nextTime + nextDelta; // For start event to see correct time. - current.time += delta * current.timeScale; // For end event to see correct time. - this.setCurrent(i, next); - next.time -= nextDelta; // Prevent increasing time twice, below. - current = next; - } - } else if (!current.loop && current.lastTime >= current.endTime) { - // End non-looping animation when it reaches its end time and there is no next entry. - this.clearTrack(i); - continue; - } - - current.time += delta * current.timeScale; - if (current.previous != null) { - let previousDelta = delta * current.previous.timeScale; - current.previous.time += previousDelta; - current.mixTime += previousDelta; - } - } - } - - apply (skeleton: Skeleton) { - let events = this.events; - let listenerCount = this.listeners.length; - - for (let i = 0; i < this.tracks.length; i++) { - let current = this.tracks[i]; - if (current == null) continue; - - events.length = 0; - - let time = current.time; - let lastTime = current.lastTime; - let endTime = current.endTime; - let loop = current.loop; - if (!loop && time > endTime) time = endTime; - - let previous = current.previous; - if (previous == null) - current.animation.mix(skeleton, lastTime, time, loop, events, current.mix); - else { - let previousTime = previous.time; - if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; - previous.animation.apply(skeleton, previousTime, previousTime, previous.loop, null); - - let alpha = current.mixTime / current.mixDuration * current.mix; - if (alpha >= 1) { - alpha = 1; - current.previous = null; - } - current.animation.mix(skeleton, lastTime, time, loop, events, alpha); - } - - for (let ii = 0, nn = events.length; ii < nn; ii++) { - let event = events[ii]; - if (current.listener != null && current.listener.event != null) current.listener.event(i, event); - for (let iii = 0; iii < listenerCount; iii++) - if (this.listeners[iii].event) this.listeners[iii].event(i, event); - } - - // Check if completed the animation or a loop iteration. - if (loop ? (lastTime % endTime > time % endTime) : (lastTime < endTime && time >= endTime)) { - let count = MathUtils.toInt(time / endTime); - if (current.listener != null && current.listener.complete) current.listener.complete(i, count); - for (let ii = 0, nn = this.listeners.length; ii < nn; ii++) - if (this.listeners[ii].complete) this.listeners[ii].complete(i, count); - } - - current.lastTime = current.time; - } - } - - clearTracks () { - for (let i = 0, n = this.tracks.length; i < n; i++) - this.clearTrack(i); - this.tracks.length = 0; - } - - clearTrack (trackIndex: number) { - if (trackIndex >= this.tracks.length) return; - let current = this.tracks[trackIndex]; - if (current == null) return; - - if (current.listener != null && current.listener.end != null) current.listener.end(trackIndex); - for (let i = 0, n = this.listeners.length; i < n; i++) - if (this.listeners[i].end) this.listeners[i].end(trackIndex); - - this.tracks[trackIndex] = null; - - this.freeAll(current); - } - - freeAll (entry: TrackEntry) { - while (entry != null) { - let next = entry.next; - entry = next; - } - } - - expandToIndex (index: number) { - if (index < this.tracks.length) return this.tracks[index]; - Utils.setArraySize(this.tracks, index - this.tracks.length + 1, null); - this.tracks.length = index + 1; - return null; - } - - setCurrent (index: number, entry: TrackEntry) { - let current = this.expandToIndex(index); - if (current != null) { - let previous = current.previous; - current.previous = null; - - if (current.listener != null && current.listener.end != null) current.listener.end(index); - for (let i = 0, n = this.listeners.length; i < n; i++) - if (this.listeners[i].end) this.listeners[i].end(index); - - entry.mixDuration = this.data.getMix(current.animation, entry.animation); - if (entry.mixDuration > 0) { - entry.mixTime = 0; - // If a mix is in progress, mix from the closest animation. - if (previous != null && current.mixTime / current.mixDuration < 0.5) { - entry.previous = previous; - previous = current; - } else - entry.previous = current; - } - } - - this.tracks[index] = entry; - - if (entry.listener != null && entry.listener.start != null) entry.listener.start(index); - for (let i = 0, n = this.listeners.length; i < n; i++) - if (this.listeners[i].start) this.listeners[i].start(index); - } - - /** @see #setAnimation(int, Animation, boolean) */ - setAnimation (trackIndex: number, animationName: string, loop: boolean) { - let animation = this.data.skeletonData.findAnimation(animationName); - if (animation == null) throw new Error("Animation not found: " + animationName); - return this.setAnimationWith(trackIndex, animation, loop); - } - - /** Set the current animation. Any queued animations are cleared. */ - setAnimationWith (trackIndex: number, animation: Animation, loop: boolean) { - let current = this.expandToIndex(trackIndex); - if (current != null) this.freeAll(current.next); - - let entry = new TrackEntry(); - entry.animation = animation; - entry.loop = loop; - entry.endTime = animation.duration; - this.setCurrent(trackIndex, entry); - return entry; - } - - /** {@link #addAnimation(int, Animation, boolean, float)} */ - addAnimation (trackIndex: number, animationName: string, loop: boolean, delay: number) { - let animation = this.data.skeletonData.findAnimation(animationName); - if (animation == null) throw new Error("Animation not found: " + animationName); - return this.addAnimationWith(trackIndex, animation, loop, delay); - } - - /** Adds an animation to be played delay seconds after the current or last queued animation. - * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */ - addAnimationWith (trackIndex: number, animation: Animation, loop: boolean, delay: number) { - let entry = new TrackEntry(); - entry.animation = animation; - entry.loop = loop; - entry.endTime = animation.duration; - - let last = this.expandToIndex(trackIndex); - if (last != null) { - while (last.next != null) - last = last.next; - last.next = entry; - } else - this.tracks[trackIndex] = entry; - - if (delay <= 0) { - if (last != null) - delay += last.endTime - this.data.getMix(last.animation, animation); - else - delay = 0; - } - entry.delay = delay; - - return entry; - } - - /** @return May be null. */ - getCurrent (trackIndex: number) { - if (trackIndex >= this.tracks.length) return null; - return this.tracks[trackIndex]; - } - - /** Adds a listener to receive events for all animations. */ - addListener (listener: AnimationStateListener) { - if (listener == null) throw new Error("listener cannot be null."); - this.listeners.push(listener); - } - - /** Removes the listener added with {@link #addListener(AnimationStateListener)}. */ - removeListener (listener: AnimationStateListener) { - let index = this.listeners.indexOf(listener); - if (index >= 0) this.listeners.splice(index, 1); - } - - clearListeners () { - this.listeners.length = 0; - } - } - - export class TrackEntry { - next: TrackEntry; previous: TrackEntry; - animation: Animation; - loop = false; - delay = 0; time = 0; lastTime = -1; endTime = 0; timeScale = 1; - mixTime = 0; mixDuration = 0; - listener: AnimationStateListener; - mix = 1; - - reset () { - this.next = null; - this.previous = null; - this.animation = null; - this.listener = null; - this.timeScale = 1; - this.lastTime = -1; // Trigger events on frame zero. - this.time = 0; - } - - /** Returns true if the current time is greater than the end time, regardless of looping. */ - isComplete () : boolean { - return this.time >= this.endTime; - } - } - - export abstract class AnimationStateAdapter implements AnimationStateListener { - event (trackIndex: number, event: Event) { - } - - complete (trackIndex: number, loopCount: number) { - } - - start (trackIndex: number) { - } - - end (trackIndex: number) { - } - } - - export interface AnimationStateListener { - /** Invoked when the current animation triggers an event. */ - event (trackIndex: number, event: Event): void; - - /** Invoked when the current animation has completed. - * @param loopCount The number of times the animation reached the end. */ - complete (trackIndex: number, loopCount: number): void; - - /** Invoked just after the current animation is set. */ - start (trackIndex: number): void; - - /** Invoked just before the current animation is replaced. */ - end (trackIndex: number): void; - } +module spine { + export class AnimationState { + data: AnimationStateData; + tracks = new Array(); + events = new Array(); + listeners = new Array(); + timeScale = 1; + + constructor (data: AnimationStateData = null) { + if (data == null) throw new Error("data cannot be null."); + this.data = data; + } + + update (delta: number) { + delta *= this.timeScale; + for (let i = 0; i < this.tracks.length; i++) { + let current = this.tracks[i]; + if (current == null) continue; + + let next = current.next; + if (next != null) { + let nextTime = current.lastTime - next.delay; + if (nextTime >= 0) { + let nextDelta = delta * next.timeScale; + next.time = nextTime + nextDelta; // For start event to see correct time. + current.time += delta * current.timeScale; // For end event to see correct time. + this.setCurrent(i, next); + next.time -= nextDelta; // Prevent increasing time twice, below. + current = next; + } + } else if (!current.loop && current.lastTime >= current.endTime) { + // End non-looping animation when it reaches its end time and there is no next entry. + this.clearTrack(i); + continue; + } + + current.time += delta * current.timeScale; + if (current.previous != null) { + let previousDelta = delta * current.previous.timeScale; + current.previous.time += previousDelta; + current.mixTime += previousDelta; + } + } + } + + apply (skeleton: Skeleton) { + let events = this.events; + let listenerCount = this.listeners.length; + + for (let i = 0; i < this.tracks.length; i++) { + let current = this.tracks[i]; + if (current == null) continue; + + events.length = 0; + + let time = current.time; + let lastTime = current.lastTime; + let endTime = current.endTime; + let loop = current.loop; + if (!loop && time > endTime) time = endTime; + + let previous = current.previous; + if (previous == null) + current.animation.mix(skeleton, lastTime, time, loop, events, current.mix); + else { + let previousTime = previous.time; + if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; + previous.animation.apply(skeleton, previousTime, previousTime, previous.loop, null); + + let alpha = current.mixTime / current.mixDuration * current.mix; + if (alpha >= 1) { + alpha = 1; + current.previous = null; + } + current.animation.mix(skeleton, lastTime, time, loop, events, alpha); + } + + for (let ii = 0, nn = events.length; ii < nn; ii++) { + let event = events[ii]; + if (current.listener != null && current.listener.event != null) current.listener.event(i, event); + for (let iii = 0; iii < listenerCount; iii++) + if (this.listeners[iii].event) this.listeners[iii].event(i, event); + } + + // Check if completed the animation or a loop iteration. + if (loop ? (lastTime % endTime > time % endTime) : (lastTime < endTime && time >= endTime)) { + let count = MathUtils.toInt(time / endTime); + if (current.listener != null && current.listener.complete) current.listener.complete(i, count); + for (let ii = 0, nn = this.listeners.length; ii < nn; ii++) + if (this.listeners[ii].complete) this.listeners[ii].complete(i, count); + } + + current.lastTime = current.time; + } + } + + clearTracks () { + for (let i = 0, n = this.tracks.length; i < n; i++) + this.clearTrack(i); + this.tracks.length = 0; + } + + clearTrack (trackIndex: number) { + if (trackIndex >= this.tracks.length) return; + let current = this.tracks[trackIndex]; + if (current == null) return; + + if (current.listener != null && current.listener.end != null) current.listener.end(trackIndex); + for (let i = 0, n = this.listeners.length; i < n; i++) + if (this.listeners[i].end) this.listeners[i].end(trackIndex); + + this.tracks[trackIndex] = null; + + this.freeAll(current); + } + + freeAll (entry: TrackEntry) { + while (entry != null) { + let next = entry.next; + entry = next; + } + } + + expandToIndex (index: number) { + if (index < this.tracks.length) return this.tracks[index]; + Utils.setArraySize(this.tracks, index - this.tracks.length + 1, null); + this.tracks.length = index + 1; + return null; + } + + setCurrent (index: number, entry: TrackEntry) { + let current = this.expandToIndex(index); + if (current != null) { + let previous = current.previous; + current.previous = null; + + if (current.listener != null && current.listener.end != null) current.listener.end(index); + for (let i = 0, n = this.listeners.length; i < n; i++) + if (this.listeners[i].end) this.listeners[i].end(index); + + entry.mixDuration = this.data.getMix(current.animation, entry.animation); + if (entry.mixDuration > 0) { + entry.mixTime = 0; + // If a mix is in progress, mix from the closest animation. + if (previous != null && current.mixTime / current.mixDuration < 0.5) { + entry.previous = previous; + previous = current; + } else + entry.previous = current; + } + } + + this.tracks[index] = entry; + + if (entry.listener != null && entry.listener.start != null) entry.listener.start(index); + for (let i = 0, n = this.listeners.length; i < n; i++) + if (this.listeners[i].start) this.listeners[i].start(index); + } + + /** @see #setAnimation(int, Animation, boolean) */ + setAnimation (trackIndex: number, animationName: string, loop: boolean) { + let animation = this.data.skeletonData.findAnimation(animationName); + if (animation == null) throw new Error("Animation not found: " + animationName); + return this.setAnimationWith(trackIndex, animation, loop); + } + + /** Set the current animation. Any queued animations are cleared. */ + setAnimationWith (trackIndex: number, animation: Animation, loop: boolean) { + let current = this.expandToIndex(trackIndex); + if (current != null) this.freeAll(current.next); + + let entry = new TrackEntry(); + entry.animation = animation; + entry.loop = loop; + entry.endTime = animation.duration; + this.setCurrent(trackIndex, entry); + return entry; + } + + /** {@link #addAnimation(int, Animation, boolean, float)} */ + addAnimation (trackIndex: number, animationName: string, loop: boolean, delay: number) { + let animation = this.data.skeletonData.findAnimation(animationName); + if (animation == null) throw new Error("Animation not found: " + animationName); + return this.addAnimationWith(trackIndex, animation, loop, delay); + } + + /** Adds an animation to be played delay seconds after the current or last queued animation. + * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */ + addAnimationWith (trackIndex: number, animation: Animation, loop: boolean, delay: number) { + let entry = new TrackEntry(); + entry.animation = animation; + entry.loop = loop; + entry.endTime = animation.duration; + + let last = this.expandToIndex(trackIndex); + if (last != null) { + while (last.next != null) + last = last.next; + last.next = entry; + } else + this.tracks[trackIndex] = entry; + + if (delay <= 0) { + if (last != null) + delay += last.endTime - this.data.getMix(last.animation, animation); + else + delay = 0; + } + entry.delay = delay; + + return entry; + } + + /** @return May be null. */ + getCurrent (trackIndex: number) { + if (trackIndex >= this.tracks.length) return null; + return this.tracks[trackIndex]; + } + + /** Adds a listener to receive events for all animations. */ + addListener (listener: AnimationStateListener) { + if (listener == null) throw new Error("listener cannot be null."); + this.listeners.push(listener); + } + + /** Removes the listener added with {@link #addListener(AnimationStateListener)}. */ + removeListener (listener: AnimationStateListener) { + let index = this.listeners.indexOf(listener); + if (index >= 0) this.listeners.splice(index, 1); + } + + clearListeners () { + this.listeners.length = 0; + } + } + + export class TrackEntry { + next: TrackEntry; previous: TrackEntry; + animation: Animation; + loop = false; + delay = 0; time = 0; lastTime = -1; endTime = 0; timeScale = 1; + mixTime = 0; mixDuration = 0; + listener: AnimationStateListener; + mix = 1; + + reset () { + this.next = null; + this.previous = null; + this.animation = null; + this.listener = null; + this.timeScale = 1; + this.lastTime = -1; // Trigger events on frame zero. + this.time = 0; + } + + /** Returns true if the current time is greater than the end time, regardless of looping. */ + isComplete () : boolean { + return this.time >= this.endTime; + } + } + + export abstract class AnimationStateAdapter implements AnimationStateListener { + event (trackIndex: number, event: Event) { + } + + complete (trackIndex: number, loopCount: number) { + } + + start (trackIndex: number) { + } + + end (trackIndex: number) { + } + } + + export interface AnimationStateListener { + /** Invoked when the current animation triggers an event. */ + event (trackIndex: number, event: Event): void; + + /** Invoked when the current animation has completed. + * @param loopCount The number of times the animation reached the end. */ + complete (trackIndex: number, loopCount: number): void; + + /** Invoked just after the current animation is set. */ + start (trackIndex: number): void; + + /** Invoked just before the current animation is replaced. */ + end (trackIndex: number): void; + } } diff --git a/spine-ts/core/src/AnimationStateData.ts b/spine-ts/core/src/AnimationStateData.ts index 632d59b82a..e9628f6041 100644 --- a/spine-ts/core/src/AnimationStateData.ts +++ b/spine-ts/core/src/AnimationStateData.ts @@ -1,64 +1,63 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class AnimationStateData { - skeletonData: SkeletonData; - animationToMixTime: Map = { }; - defaultMix = 0; - - constructor (skeletonData: SkeletonData) { - if (skeletonData == null) throw new Error("skeletonData cannot be null."); - this.skeletonData = skeletonData; - } - - setMix (fromName: string, toName: string, duration: number) { - let from = this.skeletonData.findAnimation(fromName); - if (from == null) throw new Error("Animation not found: " + fromName); - let to = this.skeletonData.findAnimation(toName); - if (to == null) throw new Error("Animation not found: " + toName); - this.setMixWith(from, to, duration); - } - - setMixWith (from: Animation, to: Animation, duration: number) { - if (from == null) throw new Error("from cannot be null."); - if (to == null) throw new Error("to cannot be null."); - let key = from.name + to.name; - this.animationToMixTime[key] = duration; - } - - getMix (from: Animation, to: Animation) { - let key = from.name + to.name; - let value = this.animationToMixTime[key]; - return value === undefined ? this.defaultMix : value; - } - } +module spine { + export class AnimationStateData { + skeletonData: SkeletonData; + animationToMixTime: Map = { }; + defaultMix = 0; + + constructor (skeletonData: SkeletonData) { + if (skeletonData == null) throw new Error("skeletonData cannot be null."); + this.skeletonData = skeletonData; + } + + setMix (fromName: string, toName: string, duration: number) { + let from = this.skeletonData.findAnimation(fromName); + if (from == null) throw new Error("Animation not found: " + fromName); + let to = this.skeletonData.findAnimation(toName); + if (to == null) throw new Error("Animation not found: " + toName); + this.setMixWith(from, to, duration); + } + + setMixWith (from: Animation, to: Animation, duration: number) { + if (from == null) throw new Error("from cannot be null."); + if (to == null) throw new Error("to cannot be null."); + let key = from.name + to.name; + this.animationToMixTime[key] = duration; + } + + getMix (from: Animation, to: Animation) { + let key = from.name + to.name; + let value = this.animationToMixTime[key]; + return value === undefined ? this.defaultMix : value; + } + } } diff --git a/spine-ts/core/src/AssetManager.ts b/spine-ts/core/src/AssetManager.ts index 926f24decd..430562aee2 100644 --- a/spine-ts/core/src/AssetManager.ts +++ b/spine-ts/core/src/AssetManager.ts @@ -1,138 +1,137 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class AssetManager implements Disposable { - private pathPrefix: string; - private textureLoader: (image: HTMLImageElement) => any; - private assets: Map = {}; - private errors: Map = {}; - private toLoad = 0; - private loaded = 0; - - constructor (textureLoader: (image: HTMLImageElement) => any, pathPrefix: string = "") { - this.textureLoader = textureLoader; - this.pathPrefix = pathPrefix; - } - - loadText(path: string, - success: (path: string, text: string) => void = null, - error: (path: string, error: string) => void = null - ) { - path = this.pathPrefix + path; - this.toLoad++; - let request = new XMLHttpRequest(); - request.onreadystatechange = () => { - if (request.readyState == XMLHttpRequest.DONE) { - if (request.status >= 200 && request.status < 300) { - if (success) success(path, request.responseText); - this.assets[path] = request.responseText; - } else { - if (error) error(path, `Couldn't load text ${path}: status ${request.status}, ${request.responseText}`); - this.errors[path] = `Couldn't load text ${path}: status ${request.status}, ${request.responseText}`; - } - this.toLoad--; - this.loaded++; - } - }; - request.open("GET", path, true); - request.send(); - } - - loadTexture (path: string, - success: (path: string, image: HTMLImageElement) => void = null, - error: (path: string, error: string) => void = null - ) { - path = this.pathPrefix + path; - this.toLoad++; - let img = new Image(); - img.src = path; - img.crossOrigin = "anonymous"; - img.onload = (ev) => { - if (success) success(path, img); - let texture = this.textureLoader(img); - this.assets[path] = texture; - this.toLoad--; - this.loaded++; - } - img.onerror = (ev) => { - if (error) error(path, `Couldn't load image ${path}`); - this.errors[path] = `Couldn't load image ${path}`; - this.toLoad--; - this.loaded++; - } - } - - get (path: string) { - path = this.pathPrefix + path; - return this.assets[path]; - } - - remove (path: string) { - path = this.pathPrefix + path; - let asset = this.assets[path]; - if ((asset).dispose) (asset).dispose(); - this.assets[path] = null; - } - - removeAll () { - for (let key in this.assets) { - let asset = this.assets[key]; - if ((asset).dispose) (asset).dispose(); - } - this.assets = {}; - } - - isLoadingComplete (): boolean { - return this.toLoad == 0; - } - - getToLoad (): number { - return this.toLoad; - } - - getLoaded (): number { - return this.loaded; - } - - dispose () { - this.removeAll(); - } - - hasErrors() { - return Object.keys(this.errors).length > 0; - } - - getErrors() { - return this.errors; - } - } +module spine { + export class AssetManager implements Disposable { + private pathPrefix: string; + private textureLoader: (image: HTMLImageElement) => any; + private assets: Map = {}; + private errors: Map = {}; + private toLoad = 0; + private loaded = 0; + + constructor (textureLoader: (image: HTMLImageElement) => any, pathPrefix: string = "") { + this.textureLoader = textureLoader; + this.pathPrefix = pathPrefix; + } + + loadText(path: string, + success: (path: string, text: string) => void = null, + error: (path: string, error: string) => void = null + ) { + path = this.pathPrefix + path; + this.toLoad++; + let request = new XMLHttpRequest(); + request.onreadystatechange = () => { + if (request.readyState == XMLHttpRequest.DONE) { + if (request.status >= 200 && request.status < 300) { + if (success) success(path, request.responseText); + this.assets[path] = request.responseText; + } else { + if (error) error(path, `Couldn't load text ${path}: status ${request.status}, ${request.responseText}`); + this.errors[path] = `Couldn't load text ${path}: status ${request.status}, ${request.responseText}`; + } + this.toLoad--; + this.loaded++; + } + }; + request.open("GET", path, true); + request.send(); + } + + loadTexture (path: string, + success: (path: string, image: HTMLImageElement) => void = null, + error: (path: string, error: string) => void = null + ) { + path = this.pathPrefix + path; + this.toLoad++; + let img = new Image(); + img.src = path; + img.crossOrigin = "anonymous"; + img.onload = (ev) => { + if (success) success(path, img); + let texture = this.textureLoader(img); + this.assets[path] = texture; + this.toLoad--; + this.loaded++; + } + img.onerror = (ev) => { + if (error) error(path, `Couldn't load image ${path}`); + this.errors[path] = `Couldn't load image ${path}`; + this.toLoad--; + this.loaded++; + } + } + + get (path: string) { + path = this.pathPrefix + path; + return this.assets[path]; + } + + remove (path: string) { + path = this.pathPrefix + path; + let asset = this.assets[path]; + if ((asset).dispose) (asset).dispose(); + this.assets[path] = null; + } + + removeAll () { + for (let key in this.assets) { + let asset = this.assets[key]; + if ((asset).dispose) (asset).dispose(); + } + this.assets = {}; + } + + isLoadingComplete (): boolean { + return this.toLoad == 0; + } + + getToLoad (): number { + return this.toLoad; + } + + getLoaded (): number { + return this.loaded; + } + + dispose () { + this.removeAll(); + } + + hasErrors() { + return Object.keys(this.errors).length > 0; + } + + getErrors() { + return this.errors; + } + } } diff --git a/spine-ts/core/src/BlendMode.ts b/spine-ts/core/src/BlendMode.ts index a1ce7ae926..963b01a578 100644 --- a/spine-ts/core/src/BlendMode.ts +++ b/spine-ts/core/src/BlendMode.ts @@ -1,39 +1,38 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export enum BlendMode { - Normal, - Additive, - Multiply, - Screen - } +module spine { + export enum BlendMode { + Normal, + Additive, + Multiply, + Screen + } } diff --git a/spine-ts/core/src/Bone.ts b/spine-ts/core/src/Bone.ts index 1b935a9b7b..a91ae39786 100644 --- a/spine-ts/core/src/Bone.ts +++ b/spine-ts/core/src/Bone.ts @@ -1,293 +1,292 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class Bone implements Updatable { - data: BoneData; - skeleton: Skeleton; - parent: Bone; - children = new Array(); - x = 0; y = 0; rotation = 0; scaleX = 0; scaleY = 0; shearX = 0; shearY = 0; - appliedRotation = 0; - - a = 0; b = 0; worldX = 0; - c = 0; d = 0; worldY = 0; - worldSignX = 0; worldSignY = 0; - - sorted = false; - - /** @param parent May be null. */ - constructor (data: BoneData, skeleton: Skeleton, parent: Bone) { - if (data == null) throw new Error("data cannot be null."); - if (skeleton == null) throw new Error("skeleton cannot be null."); - this.data = data; - this.skeleton = skeleton; - this.parent = parent; - this.setToSetupPose(); - } - - /** Same as {@link #updateWorldTransform()}. This method exists for Bone to implement {@link Updatable}. */ - update () { - this.updateWorldTransformWith(this.x, this.y, this.rotation, this.scaleX, this.scaleY, this.shearX, this.shearY); - } - - /** Computes the world transform using the parent bone and this bone's local transform. */ - updateWorldTransform () { - this.updateWorldTransformWith(this.x, this.y, this.rotation, this.scaleX, this.scaleY, this.shearX, this.shearY); - } - - /** Computes the world transform using the parent bone and the specified local transform. */ - updateWorldTransformWith (x: number, y: number, rotation: number, scaleX: number, scaleY: number, shearX: number, shearY: number) { - this.appliedRotation = rotation; - - let rotationY = rotation + 90 + shearY; - let la = MathUtils.cosDeg(rotation + shearX) * scaleX, lb = MathUtils.cosDeg(rotationY) * scaleY; - let lc = MathUtils.sinDeg(rotation + shearX) * scaleX, ld = MathUtils.sinDeg(rotationY) * scaleY; - - let parent = this.parent; - if (parent == null) { // Root bone. - let skeleton = this.skeleton; - if (skeleton.flipX) { - x = -x; - la = -la; - lb = -lb; - } - if (skeleton.flipY) { - y = -y; - lc = -lc; - ld = -ld; - } - this.a = la; - this.b = lb; - this.c = lc; - this.d = ld; - this.worldX = x; - this.worldY = y; - this.worldSignX = MathUtils.signum(scaleX); - this.worldSignY = MathUtils.signum(scaleY); - return; - } - - let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; - this.worldX = pa * x + pb * y + parent.worldX; - this.worldY = pc * x + pd * y + parent.worldY; - this.worldSignX = parent.worldSignX * MathUtils.signum(scaleX); - this.worldSignY = parent.worldSignY * MathUtils.signum(scaleY); - - if (this.data.inheritRotation && this.data.inheritScale) { - this.a = pa * la + pb * lc; - this.b = pa * lb + pb * ld; - this.c = pc * la + pd * lc; - this.d = pc * lb + pd * ld; - } else { - if (this.data.inheritRotation) { // No scale inheritance. - pa = 1; - pb = 0; - pc = 0; - pd = 1; - do { - let cos = MathUtils.cosDeg(parent.appliedRotation), sin = MathUtils.sinDeg(parent.appliedRotation); - let temp = pa * cos + pb * sin; - pb = pb * cos - pa * sin; - pa = temp; - temp = pc * cos + pd * sin; - pd = pd * cos - pc * sin; - pc = temp; - - if (!parent.data.inheritRotation) break; - parent = parent.parent; - } while (parent != null); - this.a = pa * la + pb * lc; - this.b = pa * lb + pb * ld; - this.c = pc * la + pd * lc; - this.d = pc * lb + pd * ld; - } else if (this.data.inheritScale) { // No rotation inheritance. - pa = 1; - pb = 0; - pc = 0; - pd = 1; - do { - let cos = MathUtils.cosDeg(parent.appliedRotation), sin = MathUtils.sinDeg(parent.appliedRotation); - let psx = parent.scaleX, psy = parent.scaleY; - let za = cos * psx, zb = sin * psy, zc = sin * psx, zd = cos * psy; - let temp = pa * za + pb * zc; - pb = pb * zd - pa * zb; - pa = temp; - temp = pc * za + pd * zc; - pd = pd * zd - pc * zb; - pc = temp; - - if (psx >= 0) sin = -sin; - temp = pa * cos + pb * sin; - pb = pb * cos - pa * sin; - pa = temp; - temp = pc * cos + pd * sin; - pd = pd * cos - pc * sin; - pc = temp; - - if (!parent.data.inheritScale) break; - parent = parent.parent; - } while (parent != null); - this.a = pa * la + pb * lc; - this.b = pa * lb + pb * ld; - this.c = pc * la + pd * lc; - this.d = pc * lb + pd * ld; - } else { - this.a = la; - this.b = lb; - this.c = lc; - this.d = ld; - } - if (this.skeleton.flipX) { - this.a = -this.a; - this.b = -this.b; - } - if (this.skeleton.flipY) { - this.c = -this.c; - this.d = -this.d; - } - } - } - - setToSetupPose () { - let data = this.data; - this.x = data.x; - this.y = data.y; - this.rotation = data.rotation; - this.scaleX = data.scaleX; - this.scaleY = data.scaleY; - this.shearX = data.shearX; - this.shearY = data.shearY; - } - - getWorldRotationX () { - return Math.atan2(this.c, this.a) * MathUtils.radDeg; - } - - getWorldRotationY () { - return Math.atan2(this.d, this.b) * MathUtils.radDeg; - } - - getWorldScaleX () { - return Math.sqrt(this.a * this.a + this.b * this.b) * this.worldSignX; - } - - getWorldScaleY () { - return Math.sqrt(this.c * this.c + this.d * this.d) * this.worldSignY; - } - - worldToLocalRotationX () { - let parent = this.parent; - if (parent == null) return this.rotation; - let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, a = this.a, c = this.c; - return Math.atan2(pa * c - pc * a, pd * a - pb * c) * MathUtils.radDeg; - } - - worldToLocalRotationY () { - let parent = this.parent; - if (parent == null) return this.rotation; - let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, b = this.b, d = this.d; - return Math.atan2(pa * d - pc * b, pd * b - pb * d) * MathUtils.radDeg; - } - - rotateWorld (degrees: number) { - let a = this.a, b = this.b, c = this.c, d = this.d; - let cos = MathUtils.cosDeg(degrees), sin = MathUtils.sinDeg(degrees); - this.a = cos * a - sin * c; - this.b = cos * b - sin * d; - this.c = sin * a + cos * c; - this.d = sin * b + cos * d; - } - - /** Computes the local transform from the world transform. This can be useful to perform processing on the local transform - * after the world transform has been modified directly (eg, by a constraint). - *

- * Some redundant information is lost by the world transform, such as -1,-1 scale versus 180 rotation. The computed local - * transform values may differ from the original values but are functionally the same. */ - updateLocalTransform () { - let parent = this.parent; - if (parent == null) { - this.x = this.worldX; - this.y = this.worldY; - this.rotation = Math.atan2(this.c, this.a) * MathUtils.radDeg; - this.scaleX = Math.sqrt(this.a * this.a + this.c * this.c); - this.scaleY = Math.sqrt(this.b * this.b + this.d * this.d); - let det = this.a * this.d - this.b * this.c; - this.shearX = 0; - this.shearY = Math.atan2(this.a * this.b + this.c * this.d, det) * MathUtils.radDeg; - return; - } - let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; - let pid = 1 / (pa * pd - pb * pc); - let dx = this.worldX - parent.worldX, dy = this.worldY - parent.worldY; - this.x = (dx * pd * pid - dy * pb * pid); - this.y = (dy * pa * pid - dx * pc * pid); - let ia = pid * pd; - let id = pid * pa; - let ib = pid * pb; - let ic = pid * pc; - let ra = ia * this.a - ib * this.c; - let rb = ia * this.b - ib * this.d; - let rc = id * this.c - ic * this.a; - let rd = id * this.d - ic * this.b; - this.shearX = 0; - this.scaleX = Math.sqrt(ra * ra + rc * rc); - if (this.scaleX > 0.0001) { - let det = ra * rd - rb * rc; - this.scaleY = det / this.scaleX; - this.shearY = Math.atan2(ra * rb + rc * rd, det) * MathUtils.radDeg; - this.rotation = Math.atan2(rc, ra) * MathUtils.radDeg; - } else { - this.scaleX = 0; - this.scaleY = Math.sqrt(rb * rb + rd * rd); - this.shearY = 0; - this.rotation = 90 - Math.atan2(rd, rb) * MathUtils.radDeg; - } - this.appliedRotation = this.rotation; - } - - worldToLocal (world: Vector2) { - let a = this.a, b = this.b, c = this.c, d = this.d; - let invDet = 1 / (a * d - b * c); - let x = world.x - this.worldX, y = world.y - this.worldY; - world.x = (x * d * invDet - y * b * invDet); - world.y = (y * a * invDet - x * c * invDet); - return world; - } - - localToWorld (local: Vector2) { - let x = local.x, y = local.y; - local.x = x * this.a + y * this.b + this.worldX; - local.y = x * this.c + y * this.d + this.worldY; - return local; - } - } +module spine { + export class Bone implements Updatable { + data: BoneData; + skeleton: Skeleton; + parent: Bone; + children = new Array(); + x = 0; y = 0; rotation = 0; scaleX = 0; scaleY = 0; shearX = 0; shearY = 0; + appliedRotation = 0; + + a = 0; b = 0; worldX = 0; + c = 0; d = 0; worldY = 0; + worldSignX = 0; worldSignY = 0; + + sorted = false; + + /** @param parent May be null. */ + constructor (data: BoneData, skeleton: Skeleton, parent: Bone) { + if (data == null) throw new Error("data cannot be null."); + if (skeleton == null) throw new Error("skeleton cannot be null."); + this.data = data; + this.skeleton = skeleton; + this.parent = parent; + this.setToSetupPose(); + } + + /** Same as {@link #updateWorldTransform()}. This method exists for Bone to implement {@link Updatable}. */ + update () { + this.updateWorldTransformWith(this.x, this.y, this.rotation, this.scaleX, this.scaleY, this.shearX, this.shearY); + } + + /** Computes the world transform using the parent bone and this bone's local transform. */ + updateWorldTransform () { + this.updateWorldTransformWith(this.x, this.y, this.rotation, this.scaleX, this.scaleY, this.shearX, this.shearY); + } + + /** Computes the world transform using the parent bone and the specified local transform. */ + updateWorldTransformWith (x: number, y: number, rotation: number, scaleX: number, scaleY: number, shearX: number, shearY: number) { + this.appliedRotation = rotation; + + let rotationY = rotation + 90 + shearY; + let la = MathUtils.cosDeg(rotation + shearX) * scaleX, lb = MathUtils.cosDeg(rotationY) * scaleY; + let lc = MathUtils.sinDeg(rotation + shearX) * scaleX, ld = MathUtils.sinDeg(rotationY) * scaleY; + + let parent = this.parent; + if (parent == null) { // Root bone. + let skeleton = this.skeleton; + if (skeleton.flipX) { + x = -x; + la = -la; + lb = -lb; + } + if (skeleton.flipY) { + y = -y; + lc = -lc; + ld = -ld; + } + this.a = la; + this.b = lb; + this.c = lc; + this.d = ld; + this.worldX = x; + this.worldY = y; + this.worldSignX = MathUtils.signum(scaleX); + this.worldSignY = MathUtils.signum(scaleY); + return; + } + + let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + this.worldX = pa * x + pb * y + parent.worldX; + this.worldY = pc * x + pd * y + parent.worldY; + this.worldSignX = parent.worldSignX * MathUtils.signum(scaleX); + this.worldSignY = parent.worldSignY * MathUtils.signum(scaleY); + + if (this.data.inheritRotation && this.data.inheritScale) { + this.a = pa * la + pb * lc; + this.b = pa * lb + pb * ld; + this.c = pc * la + pd * lc; + this.d = pc * lb + pd * ld; + } else { + if (this.data.inheritRotation) { // No scale inheritance. + pa = 1; + pb = 0; + pc = 0; + pd = 1; + do { + let cos = MathUtils.cosDeg(parent.appliedRotation), sin = MathUtils.sinDeg(parent.appliedRotation); + let temp = pa * cos + pb * sin; + pb = pb * cos - pa * sin; + pa = temp; + temp = pc * cos + pd * sin; + pd = pd * cos - pc * sin; + pc = temp; + + if (!parent.data.inheritRotation) break; + parent = parent.parent; + } while (parent != null); + this.a = pa * la + pb * lc; + this.b = pa * lb + pb * ld; + this.c = pc * la + pd * lc; + this.d = pc * lb + pd * ld; + } else if (this.data.inheritScale) { // No rotation inheritance. + pa = 1; + pb = 0; + pc = 0; + pd = 1; + do { + let cos = MathUtils.cosDeg(parent.appliedRotation), sin = MathUtils.sinDeg(parent.appliedRotation); + let psx = parent.scaleX, psy = parent.scaleY; + let za = cos * psx, zb = sin * psy, zc = sin * psx, zd = cos * psy; + let temp = pa * za + pb * zc; + pb = pb * zd - pa * zb; + pa = temp; + temp = pc * za + pd * zc; + pd = pd * zd - pc * zb; + pc = temp; + + if (psx >= 0) sin = -sin; + temp = pa * cos + pb * sin; + pb = pb * cos - pa * sin; + pa = temp; + temp = pc * cos + pd * sin; + pd = pd * cos - pc * sin; + pc = temp; + + if (!parent.data.inheritScale) break; + parent = parent.parent; + } while (parent != null); + this.a = pa * la + pb * lc; + this.b = pa * lb + pb * ld; + this.c = pc * la + pd * lc; + this.d = pc * lb + pd * ld; + } else { + this.a = la; + this.b = lb; + this.c = lc; + this.d = ld; + } + if (this.skeleton.flipX) { + this.a = -this.a; + this.b = -this.b; + } + if (this.skeleton.flipY) { + this.c = -this.c; + this.d = -this.d; + } + } + } + + setToSetupPose () { + let data = this.data; + this.x = data.x; + this.y = data.y; + this.rotation = data.rotation; + this.scaleX = data.scaleX; + this.scaleY = data.scaleY; + this.shearX = data.shearX; + this.shearY = data.shearY; + } + + getWorldRotationX () { + return Math.atan2(this.c, this.a) * MathUtils.radDeg; + } + + getWorldRotationY () { + return Math.atan2(this.d, this.b) * MathUtils.radDeg; + } + + getWorldScaleX () { + return Math.sqrt(this.a * this.a + this.b * this.b) * this.worldSignX; + } + + getWorldScaleY () { + return Math.sqrt(this.c * this.c + this.d * this.d) * this.worldSignY; + } + + worldToLocalRotationX () { + let parent = this.parent; + if (parent == null) return this.rotation; + let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, a = this.a, c = this.c; + return Math.atan2(pa * c - pc * a, pd * a - pb * c) * MathUtils.radDeg; + } + + worldToLocalRotationY () { + let parent = this.parent; + if (parent == null) return this.rotation; + let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, b = this.b, d = this.d; + return Math.atan2(pa * d - pc * b, pd * b - pb * d) * MathUtils.radDeg; + } + + rotateWorld (degrees: number) { + let a = this.a, b = this.b, c = this.c, d = this.d; + let cos = MathUtils.cosDeg(degrees), sin = MathUtils.sinDeg(degrees); + this.a = cos * a - sin * c; + this.b = cos * b - sin * d; + this.c = sin * a + cos * c; + this.d = sin * b + cos * d; + } + + /** Computes the local transform from the world transform. This can be useful to perform processing on the local transform + * after the world transform has been modified directly (eg, by a constraint). + *

+ * Some redundant information is lost by the world transform, such as -1,-1 scale versus 180 rotation. The computed local + * transform values may differ from the original values but are functionally the same. */ + updateLocalTransform () { + let parent = this.parent; + if (parent == null) { + this.x = this.worldX; + this.y = this.worldY; + this.rotation = Math.atan2(this.c, this.a) * MathUtils.radDeg; + this.scaleX = Math.sqrt(this.a * this.a + this.c * this.c); + this.scaleY = Math.sqrt(this.b * this.b + this.d * this.d); + let det = this.a * this.d - this.b * this.c; + this.shearX = 0; + this.shearY = Math.atan2(this.a * this.b + this.c * this.d, det) * MathUtils.radDeg; + return; + } + let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + let pid = 1 / (pa * pd - pb * pc); + let dx = this.worldX - parent.worldX, dy = this.worldY - parent.worldY; + this.x = (dx * pd * pid - dy * pb * pid); + this.y = (dy * pa * pid - dx * pc * pid); + let ia = pid * pd; + let id = pid * pa; + let ib = pid * pb; + let ic = pid * pc; + let ra = ia * this.a - ib * this.c; + let rb = ia * this.b - ib * this.d; + let rc = id * this.c - ic * this.a; + let rd = id * this.d - ic * this.b; + this.shearX = 0; + this.scaleX = Math.sqrt(ra * ra + rc * rc); + if (this.scaleX > 0.0001) { + let det = ra * rd - rb * rc; + this.scaleY = det / this.scaleX; + this.shearY = Math.atan2(ra * rb + rc * rd, det) * MathUtils.radDeg; + this.rotation = Math.atan2(rc, ra) * MathUtils.radDeg; + } else { + this.scaleX = 0; + this.scaleY = Math.sqrt(rb * rb + rd * rd); + this.shearY = 0; + this.rotation = 90 - Math.atan2(rd, rb) * MathUtils.radDeg; + } + this.appliedRotation = this.rotation; + } + + worldToLocal (world: Vector2) { + let a = this.a, b = this.b, c = this.c, d = this.d; + let invDet = 1 / (a * d - b * c); + let x = world.x - this.worldX, y = world.y - this.worldY; + world.x = (x * d * invDet - y * b * invDet); + world.y = (y * a * invDet - x * c * invDet); + return world; + } + + localToWorld (local: Vector2) { + let x = local.x, y = local.y; + local.x = x * this.a + y * this.b + this.worldX; + local.y = x * this.c + y * this.d + this.worldY; + return local; + } + } } diff --git a/spine-ts/core/src/BoneData.ts b/spine-ts/core/src/BoneData.ts index 84a9d9483d..e292997767 100644 --- a/spine-ts/core/src/BoneData.ts +++ b/spine-ts/core/src/BoneData.ts @@ -1,49 +1,48 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class BoneData { - index: number; - name: string; - parent: BoneData; - length: number; - x = 0; y = 0; rotation = 0; scaleX = 1; scaleY = 1; shearX = 0; shearY = 0; - inheritRotation = true; inheritScale = true; - - constructor (index: number, name: string, parent: BoneData) { - if (index < 0) throw new Error("index must be >= 0."); - if (name == null) throw new Error("name cannot be null."); - this.index = index; - this.name = name; - this.parent = parent; - } - } +module spine { + export class BoneData { + index: number; + name: string; + parent: BoneData; + length: number; + x = 0; y = 0; rotation = 0; scaleX = 1; scaleY = 1; shearX = 0; shearY = 0; + inheritRotation = true; inheritScale = true; + + constructor (index: number, name: string, parent: BoneData) { + if (index < 0) throw new Error("index must be >= 0."); + if (name == null) throw new Error("name cannot be null."); + this.index = index; + this.name = name; + this.parent = parent; + } + } } diff --git a/spine-ts/core/src/Event.ts b/spine-ts/core/src/Event.ts index 445e03989f..fb58c32b24 100644 --- a/spine-ts/core/src/Event.ts +++ b/spine-ts/core/src/Event.ts @@ -1,46 +1,45 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class Event { - data: EventData; - intValue: number; - floatValue: number; - stringValue: string; - time: number; - - constructor (time: number, data: EventData) { - if (data == null) throw new Error("data cannot be null."); - this.time = time; - this.data = data; - } - } +module spine { + export class Event { + data: EventData; + intValue: number; + floatValue: number; + stringValue: string; + time: number; + + constructor (time: number, data: EventData) { + if (data == null) throw new Error("data cannot be null."); + this.time = time; + this.data = data; + } + } } diff --git a/spine-ts/core/src/EventData.ts b/spine-ts/core/src/EventData.ts index fd8cbcc5d8..63a0f4d3f8 100644 --- a/spine-ts/core/src/EventData.ts +++ b/spine-ts/core/src/EventData.ts @@ -1,43 +1,42 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class EventData { - name: string; - intValue: number; - floatValue: number; - stringValue: string; - - constructor (name: string) { - this.name = name; - } - } +module spine { + export class EventData { + name: string; + intValue: number; + floatValue: number; + stringValue: string; + + constructor (name: string) { + this.name = name; + } + } } diff --git a/spine-ts/core/src/IkConstraint.ts b/spine-ts/core/src/IkConstraint.ts index 3c5a9fa8d5..c0d1fa61f2 100644 --- a/spine-ts/core/src/IkConstraint.ts +++ b/spine-ts/core/src/IkConstraint.ts @@ -1,223 +1,222 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class IkConstraint implements Updatable { - data: IkConstraintData; - bones: Array; - target: Bone; - mix = 1; - bendDirection = 0; - - level = 0; - - constructor (data: IkConstraintData, skeleton: Skeleton) { - if (data == null) throw new Error("data cannot be null."); - if (skeleton == null) throw new Error("skeleton cannot be null."); - this.data = data; - this.mix = data.mix; - this.bendDirection = data.bendDirection; - - this.bones = new Array(); - for (let i = 0; i < data.bones.length; i++) - this.bones.push(skeleton.findBone(data.bones[i].name)); - this.target = skeleton.findBone(data.target.name); - } - - apply () { - this.update(); - } - - update () { - let target = this.target; - let bones = this.bones; - switch (bones.length) { - case 1: - this.apply1(bones[0], target.worldX, target.worldY, this.mix); - break; - case 2: - this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.mix); - break; - } - } - - /** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world - * coordinate system. */ - apply1 (bone: Bone, targetX: number, targetY: number, alpha: number) { - let pp = bone.parent; - let id = 1 / (pp.a * pp.d - pp.b * pp.c); - let x = targetX - pp.worldX, y = targetY - pp.worldY; - let tx = (x * pp.d - y * pp.b) * id - bone.x, ty = (y * pp.a - x * pp.c) * id - bone.y; - let rotationIK = Math.atan2(ty, tx) * MathUtils.radDeg - bone.shearX - bone.rotation; - if (bone.scaleX < 0) rotationIK += 180; - if (rotationIK > 180) - rotationIK -= 360; - else if (rotationIK < -180) rotationIK += 360; - bone.updateWorldTransformWith(bone.x, bone.y, bone.rotation + rotationIK * alpha, bone.scaleX, bone.scaleY, bone.shearX, - bone.shearY); - } - - /** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The - * target is specified in the world coordinate system. - * @param child A direct descendant of the parent bone. */ - apply2 (parent: Bone, child: Bone, targetX: number, targetY: number, bendDir: number, alpha: number) { - if (alpha == 0) { - child.updateWorldTransform(); - return; - } - let px = parent.x, py = parent.y, psx = parent.scaleX, psy = parent.scaleY, csx = child.scaleX; - let os1 = 0, os2 = 0, s2 = 0; - if (psx < 0) { - psx = -psx; - os1 = 180; - s2 = -1; - } else { - os1 = 0; - s2 = 1; - } - if (psy < 0) { - psy = -psy; - s2 = -s2; - } - if (csx < 0) { - csx = -csx; - os2 = 180; - } else - os2 = 0; - let cx = child.x, cy = 0, cwx = 0, cwy = 0, a = parent.a, b = parent.b, c = parent.c, d = parent.d; - let u = Math.abs(psx - psy) <= 0.0001; - if (!u) { - cy = 0; - cwx = a * cx + parent.worldX; - cwy = c * cx + parent.worldY; - } else { - cy = child.y; - cwx = a * cx + b * cy + parent.worldX; - cwy = c * cx + d * cy + parent.worldY; - } - let pp = parent.parent; - a = pp.a; - b = pp.b; - c = pp.c; - d = pp.d; - let id = 1 / (a * d - b * c), x = targetX - pp.worldX, y = targetY - pp.worldY; - let tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py; - x = cwx - pp.worldX; - y = cwy - pp.worldY; - let dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; - let l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1 = 0, a2 = 0; - outer: - if (u) { - l2 *= psx; - let cos = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2); - if (cos < -1) - cos = -1; - else if (cos > 1) cos = 1; - a2 = Math.acos(cos) * bendDir; - a = l1 + l2 * cos; - b = l2 * Math.sin(a2); - a1 = Math.atan2(ty * a - tx * b, tx * a + ty * b); - } else { - a = psx * l2; - b = psy * l2; - let aa = a * a, bb = b * b, dd = tx * tx + ty * ty, ta = Math.atan2(ty, tx); - c = bb * l1 * l1 + aa * dd - aa * bb; - let c1 = -2 * bb * l1, c2 = bb - aa; - d = c1 * c1 - 4 * c2 * c; - if (d >= 0) { - let q = Math.sqrt(d); - if (c1 < 0) q = -q; - q = -(c1 + q) / 2; - let r0 = q / c2, r1 = c / q; - let r = Math.abs(r0) < Math.abs(r1) ? r0 : r1; - if (r * r <= dd) { - y = Math.sqrt(dd - r * r) * bendDir; - a1 = ta - Math.atan2(y, r); - a2 = Math.atan2(y / psy, (r - l1) / psx); - break outer; - } - } - let minAngle = 0, minDist = Number.MAX_VALUE, minX = 0, minY = 0; - let maxAngle = 0, maxDist = 0, maxX = 0, maxY = 0; - x = l1 + a; - d = x * x; - if (d > maxDist) { - maxAngle = 0; - maxDist = d; - maxX = x; - } - x = l1 - a; - d = x * x; - if (d < minDist) { - minAngle = MathUtils.PI; - minDist = d; - minX = x; - } - let angle = Math.acos(-a * l1 / (aa - bb)); - x = a * Math.cos(angle) + l1; - y = b * Math.sin(angle); - d = x * x + y * y; - if (d < minDist) { - minAngle = angle; - minDist = d; - minX = x; - minY = y; - } - if (d > maxDist) { - maxAngle = angle; - maxDist = d; - maxX = x; - maxY = y; - } - if (dd <= (minDist + maxDist) / 2) { - a1 = ta - Math.atan2(minY * bendDir, minX); - a2 = minAngle * bendDir; - } else { - a1 = ta - Math.atan2(maxY * bendDir, maxX); - a2 = maxAngle * bendDir; - } - } - let os = Math.atan2(cy, cx) * s2; - let rotation = parent.rotation; - a1 = (a1 - os) * MathUtils.radDeg + os1 - rotation; - if (a1 > 180) - a1 -= 360; - else if (a1 < -180) a1 += 360; - parent.updateWorldTransformWith(px, py, rotation + a1 * alpha, parent.scaleX, parent.scaleY, 0, 0); - rotation = child.rotation; - a2 = ((a2 + os) * MathUtils.radDeg - child.shearX) * s2 + os2 - rotation; - if (a2 > 180) - a2 -= 360; - else if (a2 < -180) a2 += 360; - child.updateWorldTransformWith(cx, cy, rotation + a2 * alpha, child.scaleX, child.scaleY, child.shearX, child.shearY); - } - } +module spine { + export class IkConstraint implements Updatable { + data: IkConstraintData; + bones: Array; + target: Bone; + mix = 1; + bendDirection = 0; + + level = 0; + + constructor (data: IkConstraintData, skeleton: Skeleton) { + if (data == null) throw new Error("data cannot be null."); + if (skeleton == null) throw new Error("skeleton cannot be null."); + this.data = data; + this.mix = data.mix; + this.bendDirection = data.bendDirection; + + this.bones = new Array(); + for (let i = 0; i < data.bones.length; i++) + this.bones.push(skeleton.findBone(data.bones[i].name)); + this.target = skeleton.findBone(data.target.name); + } + + apply () { + this.update(); + } + + update () { + let target = this.target; + let bones = this.bones; + switch (bones.length) { + case 1: + this.apply1(bones[0], target.worldX, target.worldY, this.mix); + break; + case 2: + this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.mix); + break; + } + } + + /** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world + * coordinate system. */ + apply1 (bone: Bone, targetX: number, targetY: number, alpha: number) { + let pp = bone.parent; + let id = 1 / (pp.a * pp.d - pp.b * pp.c); + let x = targetX - pp.worldX, y = targetY - pp.worldY; + let tx = (x * pp.d - y * pp.b) * id - bone.x, ty = (y * pp.a - x * pp.c) * id - bone.y; + let rotationIK = Math.atan2(ty, tx) * MathUtils.radDeg - bone.shearX - bone.rotation; + if (bone.scaleX < 0) rotationIK += 180; + if (rotationIK > 180) + rotationIK -= 360; + else if (rotationIK < -180) rotationIK += 360; + bone.updateWorldTransformWith(bone.x, bone.y, bone.rotation + rotationIK * alpha, bone.scaleX, bone.scaleY, bone.shearX, + bone.shearY); + } + + /** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The + * target is specified in the world coordinate system. + * @param child A direct descendant of the parent bone. */ + apply2 (parent: Bone, child: Bone, targetX: number, targetY: number, bendDir: number, alpha: number) { + if (alpha == 0) { + child.updateWorldTransform(); + return; + } + let px = parent.x, py = parent.y, psx = parent.scaleX, psy = parent.scaleY, csx = child.scaleX; + let os1 = 0, os2 = 0, s2 = 0; + if (psx < 0) { + psx = -psx; + os1 = 180; + s2 = -1; + } else { + os1 = 0; + s2 = 1; + } + if (psy < 0) { + psy = -psy; + s2 = -s2; + } + if (csx < 0) { + csx = -csx; + os2 = 180; + } else + os2 = 0; + let cx = child.x, cy = 0, cwx = 0, cwy = 0, a = parent.a, b = parent.b, c = parent.c, d = parent.d; + let u = Math.abs(psx - psy) <= 0.0001; + if (!u) { + cy = 0; + cwx = a * cx + parent.worldX; + cwy = c * cx + parent.worldY; + } else { + cy = child.y; + cwx = a * cx + b * cy + parent.worldX; + cwy = c * cx + d * cy + parent.worldY; + } + let pp = parent.parent; + a = pp.a; + b = pp.b; + c = pp.c; + d = pp.d; + let id = 1 / (a * d - b * c), x = targetX - pp.worldX, y = targetY - pp.worldY; + let tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py; + x = cwx - pp.worldX; + y = cwy - pp.worldY; + let dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; + let l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1 = 0, a2 = 0; + outer: + if (u) { + l2 *= psx; + let cos = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2); + if (cos < -1) + cos = -1; + else if (cos > 1) cos = 1; + a2 = Math.acos(cos) * bendDir; + a = l1 + l2 * cos; + b = l2 * Math.sin(a2); + a1 = Math.atan2(ty * a - tx * b, tx * a + ty * b); + } else { + a = psx * l2; + b = psy * l2; + let aa = a * a, bb = b * b, dd = tx * tx + ty * ty, ta = Math.atan2(ty, tx); + c = bb * l1 * l1 + aa * dd - aa * bb; + let c1 = -2 * bb * l1, c2 = bb - aa; + d = c1 * c1 - 4 * c2 * c; + if (d >= 0) { + let q = Math.sqrt(d); + if (c1 < 0) q = -q; + q = -(c1 + q) / 2; + let r0 = q / c2, r1 = c / q; + let r = Math.abs(r0) < Math.abs(r1) ? r0 : r1; + if (r * r <= dd) { + y = Math.sqrt(dd - r * r) * bendDir; + a1 = ta - Math.atan2(y, r); + a2 = Math.atan2(y / psy, (r - l1) / psx); + break outer; + } + } + let minAngle = 0, minDist = Number.MAX_VALUE, minX = 0, minY = 0; + let maxAngle = 0, maxDist = 0, maxX = 0, maxY = 0; + x = l1 + a; + d = x * x; + if (d > maxDist) { + maxAngle = 0; + maxDist = d; + maxX = x; + } + x = l1 - a; + d = x * x; + if (d < minDist) { + minAngle = MathUtils.PI; + minDist = d; + minX = x; + } + let angle = Math.acos(-a * l1 / (aa - bb)); + x = a * Math.cos(angle) + l1; + y = b * Math.sin(angle); + d = x * x + y * y; + if (d < minDist) { + minAngle = angle; + minDist = d; + minX = x; + minY = y; + } + if (d > maxDist) { + maxAngle = angle; + maxDist = d; + maxX = x; + maxY = y; + } + if (dd <= (minDist + maxDist) / 2) { + a1 = ta - Math.atan2(minY * bendDir, minX); + a2 = minAngle * bendDir; + } else { + a1 = ta - Math.atan2(maxY * bendDir, maxX); + a2 = maxAngle * bendDir; + } + } + let os = Math.atan2(cy, cx) * s2; + let rotation = parent.rotation; + a1 = (a1 - os) * MathUtils.radDeg + os1 - rotation; + if (a1 > 180) + a1 -= 360; + else if (a1 < -180) a1 += 360; + parent.updateWorldTransformWith(px, py, rotation + a1 * alpha, parent.scaleX, parent.scaleY, 0, 0); + rotation = child.rotation; + a2 = ((a2 + os) * MathUtils.radDeg - child.shearX) * s2 + os2 - rotation; + if (a2 > 180) + a2 -= 360; + else if (a2 < -180) a2 += 360; + child.updateWorldTransformWith(cx, cy, rotation + a2 * alpha, child.scaleX, child.scaleY, child.shearX, child.shearY); + } + } } diff --git a/spine-ts/core/src/IkConstraintData.ts b/spine-ts/core/src/IkConstraintData.ts index de3ea18a94..a6fa87f719 100644 --- a/spine-ts/core/src/IkConstraintData.ts +++ b/spine-ts/core/src/IkConstraintData.ts @@ -1,44 +1,43 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class IkConstraintData { - name: string; - bones = new Array(); - target: BoneData; - bendDirection = 1; - mix = 1; - - constructor (name: string) { - this.name = name; - } - } +module spine { + export class IkConstraintData { + name: string; + bones = new Array(); + target: BoneData; + bendDirection = 1; + mix = 1; + + constructor (name: string) { + this.name = name; + } + } } diff --git a/spine-ts/core/src/PathConstraint.ts b/spine-ts/core/src/PathConstraint.ts index 632cf60f6a..bd18918ad6 100644 --- a/spine-ts/core/src/PathConstraint.ts +++ b/spine-ts/core/src/PathConstraint.ts @@ -1,388 +1,387 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class PathConstraint implements Updatable { - static NONE = -1; static BEFORE = -2; static AFTER = -3; - - data: PathConstraintData; - bones: Array; - target: Slot; - position = 0; spacing = 0; rotateMix = 0; translateMix = 0; - - spaces = new Array(); positions = new Array(); - world = new Array(); curves = new Array(); lengths = new Array(); - segments = new Array(); - - constructor (data: PathConstraintData, skeleton: Skeleton) { - if (data == null) throw new Error("data cannot be null."); - if (skeleton == null) throw new Error("skeleton cannot be null."); - this.data = data; - this.bones = new Array(); - for (let i = 0, n = data.bones.length; i < n; i++) - this.bones.push(skeleton.findBone(data.bones[i].name)); - this.target = skeleton.findSlot(data.target.name); - this.position = data.position; - this.spacing = data.spacing; - this.rotateMix = data.rotateMix; - this.translateMix = data.translateMix; - } - - apply () { - this.update(); - } - - update () { - let attachment = this.target.getAttachment(); - if (!(attachment instanceof PathAttachment)) return; - - let rotateMix = this.rotateMix, translateMix = this.translateMix; - let translate = translateMix > 0, rotate = rotateMix > 0; - if (!translate && !rotate) return; - - let data = this.data; - let spacingMode = data.spacingMode; - let lengthSpacing = spacingMode == SpacingMode.Length; - let rotateMode = data.rotateMode; - let tangents = rotateMode == RotateMode.Tangent, scale = rotateMode == RotateMode.ChainScale; - let boneCount = this.bones.length, spacesCount = tangents ? boneCount : boneCount + 1; - let bones = this.bones; - let spaces = Utils.setArraySize(this.spaces, spacesCount), lengths: Array = null; - let spacing = this.spacing; - if (scale || lengthSpacing) { - if (scale) lengths = Utils.setArraySize(this.lengths, boneCount); - for (let i = 0, n = spacesCount - 1; i < n;) { - let bone = bones[i]; - let length = bone.data.length, x = length * bone.a, y = length * bone.c; - length = Math.sqrt(x * x + y * y); - if (scale) lengths[i] = length; - spaces[++i] = lengthSpacing ? Math.max(0, length + spacing) : spacing; - } - } else { - for (let i = 1; i < spacesCount; i++) - spaces[i] = spacing; - } - - let positions = this.computeWorldPositions(attachment, spacesCount, tangents, - data.positionMode == PositionMode.Percent, spacingMode == SpacingMode.Percent); - let skeleton = this.target.bone.skeleton; - let skeletonX = skeleton.x, skeletonY = skeleton.y; - let boneX = positions[0], boneY = positions[1], offsetRotation = data.offsetRotation; - let tip = rotateMode == RotateMode.Chain && offsetRotation == 0; - for (let i = 0, p = 3; i < boneCount; i++, p += 3) { - let bone = bones[i]; - bone.worldX += (boneX - skeletonX - bone.worldX) * translateMix; - bone.worldY += (boneY - skeletonY - bone.worldY) * translateMix; - let x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY; - if (scale) { - let length = lengths[i]; - if (length != 0) { - let s = (Math.sqrt(dx * dx + dy * dy) / length - 1) * rotateMix + 1; - bone.a *= s; - bone.c *= s; - } - } - boneX = x; - boneY = y; - if (rotate) { - let a = bone.a, b = bone.b, c = bone.c, d = bone.d, r = 0, cos = 0, sin = 0; - if (tangents) - r = positions[p - 1]; - else if (spaces[i + 1] == 0) - r = positions[p + 2]; - else - r = Math.atan2(dy, dx); - r -= Math.atan2(c, a) - offsetRotation * MathUtils.degRad; - if (tip) { - cos = Math.cos(r); - sin = Math.sin(r); - let length = bone.data.length; - boneX += (length * (cos * a - sin * c) - dx) * rotateMix; - boneY += (length * (sin * a + cos * c) - dy) * rotateMix; - } - if (r > MathUtils.PI) - r -= MathUtils.PI2; - else if (r < -MathUtils.PI) // - r += MathUtils.PI2; - r *= rotateMix; - cos = Math.cos(r); - sin = Math.sin(r); - bone.a = cos * a - sin * c; - bone.b = cos * b - sin * d; - bone.c = sin * a + cos * c; - bone.d = sin * b + cos * d; - } - } - } - - computeWorldPositions (path: PathAttachment, spacesCount: number, tangents: boolean, percentPosition: boolean, - percentSpacing: boolean) { - let target = this.target; - let position = this.position; - let spaces = this.spaces, out = Utils.setArraySize(this.positions, spacesCount * 3 + 2), world: Array = null; - let closed = path.closed; - let verticesLength = path.worldVerticesLength, curveCount = verticesLength / 6, prevCurve = PathConstraint.NONE; - - if (!path.constantSpeed) { - let lengths = path.lengths; - curveCount -= closed ? 1 : 2; - let pathLength = lengths[curveCount]; - if (percentPosition) position *= pathLength; - if (percentSpacing) { - for (let i = 0; i < spacesCount; i++) - spaces[i] *= pathLength; - } - world = Utils.setArraySize(this.world, 8); - for (let i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) { - let space = spaces[i]; - position += space; - let p = position; - - if (closed) { - p %= pathLength; - if (p < 0) p += pathLength; - curve = 0; - } else if (p < 0) { - if (prevCurve != PathConstraint.BEFORE) { - prevCurve = PathConstraint.BEFORE; - path.computeWorldVerticesWith(target, 2, 4, world, 0); - } - this.addBeforePosition(p, world, 0, out, o); - continue; - } else if (p > pathLength) { - if (prevCurve != PathConstraint.AFTER) { - prevCurve = PathConstraint.AFTER; - path.computeWorldVerticesWith(target, verticesLength - 6, 4, world, 0); - } - this.addAfterPosition(p - pathLength, world, 0, out, o); - continue; - } - - // Determine curve containing position. - for (;; curve++) { - let length = lengths[curve]; - if (p > length) continue; - if (curve == 0) - p /= length; - else { - let prev = lengths[curve - 1]; - p = (p - prev) / (length - prev); - } - break; - } - if (curve != prevCurve) { - prevCurve = curve; - if (closed && curve == curveCount) { - path.computeWorldVerticesWith(target, verticesLength - 4, 4, world, 0); - path.computeWorldVerticesWith(target, 0, 4, world, 4); - } else - path.computeWorldVerticesWith(target, curve * 6 + 2, 8, world, 0); - } - this.addCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], out, o, - tangents || (i > 0 && space == 0)); - } - return out; - } - - // World vertices. - if (closed) { - verticesLength += 2; - world = Utils.setArraySize(this.world, verticesLength); - path.computeWorldVerticesWith(target, 2, verticesLength - 4, world, 0); - path.computeWorldVerticesWith(target, 0, 2, world, verticesLength - 4); - world[verticesLength - 2] = world[0]; - world[verticesLength - 1] = world[1]; - } else { - curveCount--; - verticesLength -= 4; - world = Utils.setArraySize(this.world, verticesLength); - path.computeWorldVerticesWith(target, 2, verticesLength, world, 0); - } - - // Curve lengths. - let curves = Utils.setArraySize(this.curves, curveCount); - let pathLength = 0; - let x1 = world[0], y1 = world[1], cx1 = 0, cy1 = 0, cx2 = 0, cy2 = 0, x2 = 0, y2 = 0; - let tmpx = 0, tmpy = 0, dddfx = 0, dddfy = 0, ddfx = 0, ddfy = 0, dfx = 0, dfy = 0; - for (let i = 0, w = 2; i < curveCount; i++, w += 6) { - cx1 = world[w]; - cy1 = world[w + 1]; - cx2 = world[w + 2]; - cy2 = world[w + 3]; - x2 = world[w + 4]; - y2 = world[w + 5]; - tmpx = (x1 - cx1 * 2 + cx2) * 0.1875; - tmpy = (y1 - cy1 * 2 + cy2) * 0.1875; - dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375; - dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375; - ddfx = tmpx * 2 + dddfx; - ddfy = tmpy * 2 + dddfy; - dfx = (cx1 - x1) * 0.75 + tmpx + dddfx * 0.16666667; - dfy = (cy1 - y1) * 0.75 + tmpy + dddfy * 0.16666667; - pathLength += Math.sqrt(dfx * dfx + dfy * dfy); - dfx += ddfx; - dfy += ddfy; - ddfx += dddfx; - ddfy += dddfy; - pathLength += Math.sqrt(dfx * dfx + dfy * dfy); - dfx += ddfx; - dfy += ddfy; - pathLength += Math.sqrt(dfx * dfx + dfy * dfy); - dfx += ddfx + dddfx; - dfy += ddfy + dddfy; - pathLength += Math.sqrt(dfx * dfx + dfy * dfy); - curves[i] = pathLength; - x1 = x2; - y1 = y2; - } - if (percentPosition) position *= pathLength; - if (percentSpacing) { - for (let i = 0; i < spacesCount; i++) - spaces[i] *= pathLength; - } - - let segments = this.segments; - let curveLength = 0; - for (let i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) { - let space = spaces[i]; - position += space; - let p = position; - - if (closed) { - p %= pathLength; - if (p < 0) p += pathLength; - curve = 0; - } else if (p < 0) { - this.addBeforePosition(p, world, 0, out, o); - continue; - } else if (p > pathLength) { - this.addAfterPosition(p - pathLength, world, verticesLength - 4, out, o); - continue; - } - - // Determine curve containing position. - for (;; curve++) { - let length = curves[curve]; - if (p > length) continue; - if (curve == 0) - p /= length; - else { - let prev = curves[curve - 1]; - p = (p - prev) / (length - prev); - } - break; - } - - // Curve segment lengths. - if (curve != prevCurve) { - prevCurve = curve; - let ii = curve * 6; - x1 = world[ii]; - y1 = world[ii + 1]; - cx1 = world[ii + 2]; - cy1 = world[ii + 3]; - cx2 = world[ii + 4]; - cy2 = world[ii + 5]; - x2 = world[ii + 6]; - y2 = world[ii + 7]; - tmpx = (x1 - cx1 * 2 + cx2) * 0.03; - tmpy = (y1 - cy1 * 2 + cy2) * 0.03; - dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006; - dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006; - ddfx = tmpx * 2 + dddfx; - ddfy = tmpy * 2 + dddfy; - dfx = (cx1 - x1) * 0.3 + tmpx + dddfx * 0.16666667; - dfy = (cy1 - y1) * 0.3 + tmpy + dddfy * 0.16666667; - curveLength = Math.sqrt(dfx * dfx + dfy * dfy); - segments[0] = curveLength; - for (ii = 1; ii < 8; ii++) { - dfx += ddfx; - dfy += ddfy; - ddfx += dddfx; - ddfy += dddfy; - curveLength += Math.sqrt(dfx * dfx + dfy * dfy); - segments[ii] = curveLength; - } - dfx += ddfx; - dfy += ddfy; - curveLength += Math.sqrt(dfx * dfx + dfy * dfy); - segments[8] = curveLength; - dfx += ddfx + dddfx; - dfy += ddfy + dddfy; - curveLength += Math.sqrt(dfx * dfx + dfy * dfy); - segments[9] = curveLength; - segment = 0; - } - - // Weight by segment length. - p *= curveLength; - for (;; segment++) { - let length = segments[segment]; - if (p > length) continue; - if (segment == 0) - p /= length; - else { - let prev = segments[segment - 1]; - p = segment + (p - prev) / (length - prev); - } - break; - } - this.addCurvePosition(p * 0.1, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || (i > 0 && space == 0)); - } - return out; - } - - addBeforePosition (p: number, temp: Array, i: number, out: Array, o: number) { - let x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = Math.atan2(dy, dx); - out[o] = x1 + p * Math.cos(r); - out[o + 1] = y1 + p * Math.sin(r); - out[o + 2] = r; - } - - addAfterPosition (p: number, temp: Array, i: number, out: Array, o: number) { - let x1 = temp[i + 2], y1 = temp[i + 3], dx = x1 - temp[i], dy = y1 - temp[i + 1], r = Math.atan2(dy, dx); - out[o] = x1 + p * Math.cos(r); - out[o + 1] = y1 + p * Math.sin(r); - out[o + 2] = r; - } - - addCurvePosition (p: number, x1: number, y1: number, cx1: number, cy1: number, cx2: number, cy2: number, x2: number, y2: number, - out: Array, o: number, tangents: boolean) { - if (p == 0) p = 0.0001; - let tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u; - let ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p; - let x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt; - out[o] = x; - out[o + 1] = y; - if (tangents) out[o + 2] = Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); - } - } +module spine { + export class PathConstraint implements Updatable { + static NONE = -1; static BEFORE = -2; static AFTER = -3; + + data: PathConstraintData; + bones: Array; + target: Slot; + position = 0; spacing = 0; rotateMix = 0; translateMix = 0; + + spaces = new Array(); positions = new Array(); + world = new Array(); curves = new Array(); lengths = new Array(); + segments = new Array(); + + constructor (data: PathConstraintData, skeleton: Skeleton) { + if (data == null) throw new Error("data cannot be null."); + if (skeleton == null) throw new Error("skeleton cannot be null."); + this.data = data; + this.bones = new Array(); + for (let i = 0, n = data.bones.length; i < n; i++) + this.bones.push(skeleton.findBone(data.bones[i].name)); + this.target = skeleton.findSlot(data.target.name); + this.position = data.position; + this.spacing = data.spacing; + this.rotateMix = data.rotateMix; + this.translateMix = data.translateMix; + } + + apply () { + this.update(); + } + + update () { + let attachment = this.target.getAttachment(); + if (!(attachment instanceof PathAttachment)) return; + + let rotateMix = this.rotateMix, translateMix = this.translateMix; + let translate = translateMix > 0, rotate = rotateMix > 0; + if (!translate && !rotate) return; + + let data = this.data; + let spacingMode = data.spacingMode; + let lengthSpacing = spacingMode == SpacingMode.Length; + let rotateMode = data.rotateMode; + let tangents = rotateMode == RotateMode.Tangent, scale = rotateMode == RotateMode.ChainScale; + let boneCount = this.bones.length, spacesCount = tangents ? boneCount : boneCount + 1; + let bones = this.bones; + let spaces = Utils.setArraySize(this.spaces, spacesCount), lengths: Array = null; + let spacing = this.spacing; + if (scale || lengthSpacing) { + if (scale) lengths = Utils.setArraySize(this.lengths, boneCount); + for (let i = 0, n = spacesCount - 1; i < n;) { + let bone = bones[i]; + let length = bone.data.length, x = length * bone.a, y = length * bone.c; + length = Math.sqrt(x * x + y * y); + if (scale) lengths[i] = length; + spaces[++i] = lengthSpacing ? Math.max(0, length + spacing) : spacing; + } + } else { + for (let i = 1; i < spacesCount; i++) + spaces[i] = spacing; + } + + let positions = this.computeWorldPositions(attachment, spacesCount, tangents, + data.positionMode == PositionMode.Percent, spacingMode == SpacingMode.Percent); + let skeleton = this.target.bone.skeleton; + let skeletonX = skeleton.x, skeletonY = skeleton.y; + let boneX = positions[0], boneY = positions[1], offsetRotation = data.offsetRotation; + let tip = rotateMode == RotateMode.Chain && offsetRotation == 0; + for (let i = 0, p = 3; i < boneCount; i++, p += 3) { + let bone = bones[i]; + bone.worldX += (boneX - skeletonX - bone.worldX) * translateMix; + bone.worldY += (boneY - skeletonY - bone.worldY) * translateMix; + let x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY; + if (scale) { + let length = lengths[i]; + if (length != 0) { + let s = (Math.sqrt(dx * dx + dy * dy) / length - 1) * rotateMix + 1; + bone.a *= s; + bone.c *= s; + } + } + boneX = x; + boneY = y; + if (rotate) { + let a = bone.a, b = bone.b, c = bone.c, d = bone.d, r = 0, cos = 0, sin = 0; + if (tangents) + r = positions[p - 1]; + else if (spaces[i + 1] == 0) + r = positions[p + 2]; + else + r = Math.atan2(dy, dx); + r -= Math.atan2(c, a) - offsetRotation * MathUtils.degRad; + if (tip) { + cos = Math.cos(r); + sin = Math.sin(r); + let length = bone.data.length; + boneX += (length * (cos * a - sin * c) - dx) * rotateMix; + boneY += (length * (sin * a + cos * c) - dy) * rotateMix; + } + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) // + r += MathUtils.PI2; + r *= rotateMix; + cos = Math.cos(r); + sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + } + } + } + + computeWorldPositions (path: PathAttachment, spacesCount: number, tangents: boolean, percentPosition: boolean, + percentSpacing: boolean) { + let target = this.target; + let position = this.position; + let spaces = this.spaces, out = Utils.setArraySize(this.positions, spacesCount * 3 + 2), world: Array = null; + let closed = path.closed; + let verticesLength = path.worldVerticesLength, curveCount = verticesLength / 6, prevCurve = PathConstraint.NONE; + + if (!path.constantSpeed) { + let lengths = path.lengths; + curveCount -= closed ? 1 : 2; + let pathLength = lengths[curveCount]; + if (percentPosition) position *= pathLength; + if (percentSpacing) { + for (let i = 0; i < spacesCount; i++) + spaces[i] *= pathLength; + } + world = Utils.setArraySize(this.world, 8); + for (let i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) { + let space = spaces[i]; + position += space; + let p = position; + + if (closed) { + p %= pathLength; + if (p < 0) p += pathLength; + curve = 0; + } else if (p < 0) { + if (prevCurve != PathConstraint.BEFORE) { + prevCurve = PathConstraint.BEFORE; + path.computeWorldVerticesWith(target, 2, 4, world, 0); + } + this.addBeforePosition(p, world, 0, out, o); + continue; + } else if (p > pathLength) { + if (prevCurve != PathConstraint.AFTER) { + prevCurve = PathConstraint.AFTER; + path.computeWorldVerticesWith(target, verticesLength - 6, 4, world, 0); + } + this.addAfterPosition(p - pathLength, world, 0, out, o); + continue; + } + + // Determine curve containing position. + for (;; curve++) { + let length = lengths[curve]; + if (p > length) continue; + if (curve == 0) + p /= length; + else { + let prev = lengths[curve - 1]; + p = (p - prev) / (length - prev); + } + break; + } + if (curve != prevCurve) { + prevCurve = curve; + if (closed && curve == curveCount) { + path.computeWorldVerticesWith(target, verticesLength - 4, 4, world, 0); + path.computeWorldVerticesWith(target, 0, 4, world, 4); + } else + path.computeWorldVerticesWith(target, curve * 6 + 2, 8, world, 0); + } + this.addCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], out, o, + tangents || (i > 0 && space == 0)); + } + return out; + } + + // World vertices. + if (closed) { + verticesLength += 2; + world = Utils.setArraySize(this.world, verticesLength); + path.computeWorldVerticesWith(target, 2, verticesLength - 4, world, 0); + path.computeWorldVerticesWith(target, 0, 2, world, verticesLength - 4); + world[verticesLength - 2] = world[0]; + world[verticesLength - 1] = world[1]; + } else { + curveCount--; + verticesLength -= 4; + world = Utils.setArraySize(this.world, verticesLength); + path.computeWorldVerticesWith(target, 2, verticesLength, world, 0); + } + + // Curve lengths. + let curves = Utils.setArraySize(this.curves, curveCount); + let pathLength = 0; + let x1 = world[0], y1 = world[1], cx1 = 0, cy1 = 0, cx2 = 0, cy2 = 0, x2 = 0, y2 = 0; + let tmpx = 0, tmpy = 0, dddfx = 0, dddfy = 0, ddfx = 0, ddfy = 0, dfx = 0, dfy = 0; + for (let i = 0, w = 2; i < curveCount; i++, w += 6) { + cx1 = world[w]; + cy1 = world[w + 1]; + cx2 = world[w + 2]; + cy2 = world[w + 3]; + x2 = world[w + 4]; + y2 = world[w + 5]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.1875; + tmpy = (y1 - cy1 * 2 + cy2) * 0.1875; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.75 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.75 + tmpy + dddfy * 0.16666667; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + curves[i] = pathLength; + x1 = x2; + y1 = y2; + } + if (percentPosition) position *= pathLength; + if (percentSpacing) { + for (let i = 0; i < spacesCount; i++) + spaces[i] *= pathLength; + } + + let segments = this.segments; + let curveLength = 0; + for (let i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) { + let space = spaces[i]; + position += space; + let p = position; + + if (closed) { + p %= pathLength; + if (p < 0) p += pathLength; + curve = 0; + } else if (p < 0) { + this.addBeforePosition(p, world, 0, out, o); + continue; + } else if (p > pathLength) { + this.addAfterPosition(p - pathLength, world, verticesLength - 4, out, o); + continue; + } + + // Determine curve containing position. + for (;; curve++) { + let length = curves[curve]; + if (p > length) continue; + if (curve == 0) + p /= length; + else { + let prev = curves[curve - 1]; + p = (p - prev) / (length - prev); + } + break; + } + + // Curve segment lengths. + if (curve != prevCurve) { + prevCurve = curve; + let ii = curve * 6; + x1 = world[ii]; + y1 = world[ii + 1]; + cx1 = world[ii + 2]; + cy1 = world[ii + 3]; + cx2 = world[ii + 4]; + cy2 = world[ii + 5]; + x2 = world[ii + 6]; + y2 = world[ii + 7]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.03; + tmpy = (y1 - cy1 * 2 + cy2) * 0.03; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.3 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.3 + tmpy + dddfy * 0.16666667; + curveLength = Math.sqrt(dfx * dfx + dfy * dfy); + segments[0] = curveLength; + for (ii = 1; ii < 8; ii++) { + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[ii] = curveLength; + } + dfx += ddfx; + dfy += ddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[8] = curveLength; + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[9] = curveLength; + segment = 0; + } + + // Weight by segment length. + p *= curveLength; + for (;; segment++) { + let length = segments[segment]; + if (p > length) continue; + if (segment == 0) + p /= length; + else { + let prev = segments[segment - 1]; + p = segment + (p - prev) / (length - prev); + } + break; + } + this.addCurvePosition(p * 0.1, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || (i > 0 && space == 0)); + } + return out; + } + + addBeforePosition (p: number, temp: Array, i: number, out: Array, o: number) { + let x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + } + + addAfterPosition (p: number, temp: Array, i: number, out: Array, o: number) { + let x1 = temp[i + 2], y1 = temp[i + 3], dx = x1 - temp[i], dy = y1 - temp[i + 1], r = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + } + + addCurvePosition (p: number, x1: number, y1: number, cx1: number, cy1: number, cx2: number, cy2: number, x2: number, y2: number, + out: Array, o: number, tangents: boolean) { + if (p == 0) p = 0.0001; + let tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u; + let ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p; + let x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt; + out[o] = x; + out[o + 1] = y; + if (tangents) out[o + 2] = Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); + } + } } diff --git a/spine-ts/core/src/PathConstraintData.ts b/spine-ts/core/src/PathConstraintData.ts index 77ba38bbdc..c189e9b5cc 100644 --- a/spine-ts/core/src/PathConstraintData.ts +++ b/spine-ts/core/src/PathConstraintData.ts @@ -1,59 +1,58 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class PathConstraintData { - name: string; - bones = new Array(); - target: SlotData; - positionMode: PositionMode; - spacingMode: SpacingMode; - rotateMode: RotateMode; - offsetRotation: number; - position: number; spacing: number; rotateMix: number; translateMix: number; - - constructor (name: string) { - this.name = name; - } - } - - export enum PositionMode { - Fixed, Percent - } - - export enum SpacingMode { - Length, Fixed, Percent - } - - export enum RotateMode { - Tangent, Chain, ChainScale - } +module spine { + export class PathConstraintData { + name: string; + bones = new Array(); + target: SlotData; + positionMode: PositionMode; + spacingMode: SpacingMode; + rotateMode: RotateMode; + offsetRotation: number; + position: number; spacing: number; rotateMix: number; translateMix: number; + + constructor (name: string) { + this.name = name; + } + } + + export enum PositionMode { + Fixed, Percent + } + + export enum SpacingMode { + Length, Fixed, Percent + } + + export enum RotateMode { + Tangent, Chain, ChainScale + } } diff --git a/spine-ts/core/src/SharedAssetManager.ts b/spine-ts/core/src/SharedAssetManager.ts index 0b56fdb81f..08c2657253 100644 --- a/spine-ts/core/src/SharedAssetManager.ts +++ b/spine-ts/core/src/SharedAssetManager.ts @@ -1,187 +1,186 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - class Assets { - clientId: string; - toLoad = new Array(); - assets: Map = {}; - textureLoader: (image: HTMLImageElement) => any; - - constructor(clientId: string) { - this.clientId = clientId; - } - - loaded() { - var i = 0; - for (var v in this.assets) i++; - return i; - } - } - - export class SharedAssetManager implements Disposable { - private pathPrefix: string; - private clientAssets: Map = {}; - private queuedAssets: Map = {}; - private rawAssets: Map = {} - private errors: Map = {}; - - constructor (pathPrefix: string = "") { - this.pathPrefix = pathPrefix; - } - - private queueAsset(clientId: string, textureLoader: (image: HTMLImageElement) => any, path: string): boolean { - var clientAssets = this.clientAssets[clientId]; - if (clientAssets === null || clientAssets === undefined) { - clientAssets = new Assets(clientId); - this.clientAssets[clientId] = clientAssets; - } - if (textureLoader !== null) clientAssets.textureLoader = textureLoader; - clientAssets.toLoad.push(path); - - // check if already queued, in which case we can skip actual - // loading - if (this.queuedAssets[path] === path) { - return false; - } else { - this.queuedAssets[path] = path; - return true; - } - } - - loadText(clientId: string, path: string) { - path = this.pathPrefix + path; - if (!this.queueAsset(clientId, null, path)) return; - let request = new XMLHttpRequest(); - request.onreadystatechange = () => { - if (request.readyState == XMLHttpRequest.DONE) { - if (request.status >= 200 && request.status < 300) { - this.rawAssets[path] = request.responseText; - } else { - this.errors[path] = `Couldn't load text ${path}: status ${request.status}, ${request.responseText}`; - } - } - }; - request.open("GET", path, true); - request.send(); - } - - loadJson(clientId: string, path: string) { - path = this.pathPrefix + path; - if (!this.queueAsset(clientId, null, path)) return; - let request = new XMLHttpRequest(); - request.onreadystatechange = () => { - if (request.readyState == XMLHttpRequest.DONE) { - if (request.status >= 200 && request.status < 300) { - this.rawAssets[path] = JSON.parse(request.responseText); - } else { - this.errors[path] = `Couldn't load text ${path}: status ${request.status}, ${request.responseText}`; - } - } - }; - request.open("GET", path, true); - request.send(); - } - - loadTexture (clientId: string, textureLoader: (image: HTMLImageElement) => any, path: string) { - path = this.pathPrefix + path; - if (!this.queueAsset(clientId, textureLoader, path)) return; - - let img = new Image(); - img.src = path; - img.crossOrigin = "anonymous"; - img.onload = (ev) => { - this.rawAssets[path] = img; - } - img.onerror = (ev) => { - this.errors[path] = `Couldn't load image ${path}`; - } - } - - get (clientId: string, path: string) { - path = this.pathPrefix + path; - var clientAssets = this.clientAssets[clientId]; - if (clientAssets === null || clientAssets === undefined) return true; - return clientAssets.assets[path]; - } - - private updateClientAssets(clientAssets: Assets): void { - for (var i = 0; i < clientAssets.toLoad.length; i++) { - var path = clientAssets.toLoad[i]; - var asset = clientAssets.assets[path]; - if (asset === null || asset === undefined) { - var rawAsset = this.rawAssets[path]; - if (rawAsset === null || rawAsset === undefined) continue; - if (rawAsset instanceof HTMLImageElement) { - clientAssets.assets[path] = clientAssets.textureLoader(rawAsset); - } else { - clientAssets.assets[path] = rawAsset; - } - } - } - } - - isLoadingComplete (clientId: string): boolean { - var clientAssets = this.clientAssets[clientId]; - if (clientAssets === null || clientAssets === undefined) return true; - this.updateClientAssets(clientAssets); - return clientAssets.toLoad.length == clientAssets.loaded(); - - } - - /*remove (clientId: string, path: string) { - path = this.pathPrefix + path; - let asset = this.assets[path]; - if ((asset).dispose) (asset).dispose(); - this.assets[path] = null; - } - - removeAll () { - for (let key in this.assets) { - let asset = this.assets[key]; - if ((asset).dispose) (asset).dispose(); - } - this.assets = {}; - }*/ - - dispose () { - // this.removeAll(); - } - - hasErrors() { - return Object.keys(this.errors).length > 0; - } - - getErrors() { - return this.errors; - } - } +module spine { + class Assets { + clientId: string; + toLoad = new Array(); + assets: Map = {}; + textureLoader: (image: HTMLImageElement) => any; + + constructor(clientId: string) { + this.clientId = clientId; + } + + loaded() { + var i = 0; + for (var v in this.assets) i++; + return i; + } + } + + export class SharedAssetManager implements Disposable { + private pathPrefix: string; + private clientAssets: Map = {}; + private queuedAssets: Map = {}; + private rawAssets: Map = {} + private errors: Map = {}; + + constructor (pathPrefix: string = "") { + this.pathPrefix = pathPrefix; + } + + private queueAsset(clientId: string, textureLoader: (image: HTMLImageElement) => any, path: string): boolean { + var clientAssets = this.clientAssets[clientId]; + if (clientAssets === null || clientAssets === undefined) { + clientAssets = new Assets(clientId); + this.clientAssets[clientId] = clientAssets; + } + if (textureLoader !== null) clientAssets.textureLoader = textureLoader; + clientAssets.toLoad.push(path); + + // check if already queued, in which case we can skip actual + // loading + if (this.queuedAssets[path] === path) { + return false; + } else { + this.queuedAssets[path] = path; + return true; + } + } + + loadText(clientId: string, path: string) { + path = this.pathPrefix + path; + if (!this.queueAsset(clientId, null, path)) return; + let request = new XMLHttpRequest(); + request.onreadystatechange = () => { + if (request.readyState == XMLHttpRequest.DONE) { + if (request.status >= 200 && request.status < 300) { + this.rawAssets[path] = request.responseText; + } else { + this.errors[path] = `Couldn't load text ${path}: status ${request.status}, ${request.responseText}`; + } + } + }; + request.open("GET", path, true); + request.send(); + } + + loadJson(clientId: string, path: string) { + path = this.pathPrefix + path; + if (!this.queueAsset(clientId, null, path)) return; + let request = new XMLHttpRequest(); + request.onreadystatechange = () => { + if (request.readyState == XMLHttpRequest.DONE) { + if (request.status >= 200 && request.status < 300) { + this.rawAssets[path] = JSON.parse(request.responseText); + } else { + this.errors[path] = `Couldn't load text ${path}: status ${request.status}, ${request.responseText}`; + } + } + }; + request.open("GET", path, true); + request.send(); + } + + loadTexture (clientId: string, textureLoader: (image: HTMLImageElement) => any, path: string) { + path = this.pathPrefix + path; + if (!this.queueAsset(clientId, textureLoader, path)) return; + + let img = new Image(); + img.src = path; + img.crossOrigin = "anonymous"; + img.onload = (ev) => { + this.rawAssets[path] = img; + } + img.onerror = (ev) => { + this.errors[path] = `Couldn't load image ${path}`; + } + } + + get (clientId: string, path: string) { + path = this.pathPrefix + path; + var clientAssets = this.clientAssets[clientId]; + if (clientAssets === null || clientAssets === undefined) return true; + return clientAssets.assets[path]; + } + + private updateClientAssets(clientAssets: Assets): void { + for (var i = 0; i < clientAssets.toLoad.length; i++) { + var path = clientAssets.toLoad[i]; + var asset = clientAssets.assets[path]; + if (asset === null || asset === undefined) { + var rawAsset = this.rawAssets[path]; + if (rawAsset === null || rawAsset === undefined) continue; + if (rawAsset instanceof HTMLImageElement) { + clientAssets.assets[path] = clientAssets.textureLoader(rawAsset); + } else { + clientAssets.assets[path] = rawAsset; + } + } + } + } + + isLoadingComplete (clientId: string): boolean { + var clientAssets = this.clientAssets[clientId]; + if (clientAssets === null || clientAssets === undefined) return true; + this.updateClientAssets(clientAssets); + return clientAssets.toLoad.length == clientAssets.loaded(); + + } + + /*remove (clientId: string, path: string) { + path = this.pathPrefix + path; + let asset = this.assets[path]; + if ((asset).dispose) (asset).dispose(); + this.assets[path] = null; + } + + removeAll () { + for (let key in this.assets) { + let asset = this.assets[key]; + if ((asset).dispose) (asset).dispose(); + } + this.assets = {}; + }*/ + + dispose () { + // this.removeAll(); + } + + hasErrors() { + return Object.keys(this.errors).length > 0; + } + + getErrors() { + return this.errors; + } + } } diff --git a/spine-ts/core/src/Skeleton.ts b/spine-ts/core/src/Skeleton.ts index a74a550049..182355d688 100644 --- a/spine-ts/core/src/Skeleton.ts +++ b/spine-ts/core/src/Skeleton.ts @@ -1,473 +1,472 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class Skeleton { - data: SkeletonData; - bones: Array; - slots: Array; - drawOrder: Array; - ikConstraints: Array; ikConstraintsSorted: Array; - transformConstraints: Array; - pathConstraints: Array; - _updateCache = new Array(); - skin: Skin; - color: Color; - time = 0; - flipX = false; flipY = false; - x = 0; y = 0; - - constructor (data: SkeletonData) { - if (data == null) throw new Error("data cannot be null."); - this.data = data; - - this.bones = new Array(); - for (let i = 0; i < data.bones.length; i++) { - let boneData = data.bones[i]; - let bone: Bone; - if (boneData.parent == null) - bone = new Bone(boneData, this, null); - else { - let parent = this.bones[boneData.parent.index]; - bone = new Bone(boneData, this, parent); - parent.children.push(bone); - } - this.bones.push(bone); - } - - this.slots = new Array(); - this.drawOrder = new Array(); - for (let i = 0; i < data.slots.length; i++) { - let slotData = data.slots[i]; - let bone = this.bones[slotData.boneData.index]; - let slot = new Slot(slotData, bone); - this.slots.push(slot); - this.drawOrder.push(slot); - } - - this.ikConstraints = new Array(); - this.ikConstraintsSorted = new Array(); - for (let i = 0; i < data.ikConstraints.length; i++) { - let ikConstraintData = data.ikConstraints[i]; - this.ikConstraints.push(new IkConstraint(ikConstraintData, this)); - } - - this.transformConstraints = new Array(); - for (let i = 0; i < data.transformConstraints.length; i++) { - let transformConstraintData = data.transformConstraints[i]; - this.transformConstraints.push(new TransformConstraint(transformConstraintData, this)); - } - - this.pathConstraints = new Array(); - for (let i = 0; i < data.pathConstraints.length; i++) { - let pathConstraintData = data.pathConstraints[i]; - this.pathConstraints.push(new PathConstraint(pathConstraintData, this)); - } - - this.color = new Color(1, 1, 1, 1); - this.updateCache(); - } - - updateCache () { - let updateCache = this._updateCache; - updateCache.length = 0; - - let bones = this.bones; - for (let i = 0, n = bones.length; i < n; i++) - bones[i].sorted = false; - - // IK first, lowest hierarchy depth first. - let ikConstraints = this.ikConstraintsSorted; - ikConstraints.length = 0; - for (let i = 0; i < this.ikConstraints.length; i++) - ikConstraints.push(this.ikConstraints[i]); - let ikCount = ikConstraints.length; - for (let i = 0, level = 0, n = ikCount; i < n; i++) { - let ik = ikConstraints[i]; - let bone = ik.bones[0].parent; - for (level = 0; bone != null; level++) - bone = bone.parent; - ik.level = level; - } - for (let i = 1, ii = 0; i < ikCount; i++) { - let ik = ikConstraints[i]; - let level = ik.level; - for (ii = i - 1; ii >= 0; ii--) { - let other = ikConstraints[ii]; - if (other.level < level) break; - ikConstraints[ii + 1] = other; - } - ikConstraints[ii + 1] = ik; - } - for (let i = 0, n = ikConstraints.length; i < n; i++) { - let constraint = ikConstraints[i]; - let target = constraint.target; - this.sortBone(target); - - let constrained = constraint.bones; - let parent = constrained[0]; - this.sortBone(parent); - - updateCache.push(constraint); - - this.sortReset(parent.children); - constrained[constrained.length - 1].sorted = true; - } - - let pathConstraints = this.pathConstraints; - for (let i = 0, n = pathConstraints.length; i < n; i++) { - let constraint = pathConstraints[i]; - - let slot = constraint.target; - let slotIndex = slot.data.index; - let slotBone = slot.bone; - if (this.skin != null) this.sortPathConstraintAttachment(this.skin, slotIndex, slotBone); - if (this.data.defaultSkin != null && this.data.defaultSkin != this.skin) - this.sortPathConstraintAttachment(this.data.defaultSkin, slotIndex, slotBone); - for (let ii = 0, nn = this.data.skins.length; ii < nn; ii++) - this.sortPathConstraintAttachment(this.data.skins[ii], slotIndex, slotBone); - - let attachment = slot.getAttachment(); - if (attachment instanceof PathAttachment) this.sortPathConstraintAttachmentWith(attachment, slotBone); - - let constrained = constraint.bones; - let boneCount = constrained.length; - for (let ii = 0; ii < boneCount; ii++) - this.sortBone(constrained[ii]); - - updateCache.push(constraint); - - for (let ii = 0; ii < boneCount; ii++) - this.sortReset(constrained[ii].children); - for (let ii = 0; ii < boneCount; ii++) - constrained[ii].sorted = true; - } - - let transformConstraints = this.transformConstraints; - for (let i = 0, n = transformConstraints.length; i < n; i++) { - let constraint = transformConstraints[i]; - - this.sortBone(constraint.target); - - let constrained = constraint.bones; - let boneCount = constrained.length; - for (let ii = 0; ii < boneCount; ii++) - this.sortBone(constrained[ii]); - - updateCache.push(constraint); - - for (let ii = 0; ii < boneCount; ii++) - this.sortReset(constrained[ii].children); - for (let ii = 0; ii < boneCount; ii++) - constrained[ii].sorted = true; - } - - for (let i = 0, n = bones.length; i < n; i++) - this.sortBone(bones[i]); - } - - sortPathConstraintAttachment (skin: Skin, slotIndex: number, slotBone: Bone) { - let attachments = skin.attachments[slotIndex]; - if (!attachments) return; - for (let key in attachments) { - this.sortPathConstraintAttachmentWith(attachments[key], slotBone); - } - } - - sortPathConstraintAttachmentWith (attachment: Attachment, slotBone: Bone) { - if (!(attachment instanceof PathAttachment)) return; - let pathBones = (attachment).bones; - if (pathBones == null) - this.sortBone(slotBone); - else { - let bones = this.bones; - let i = 0; - while (i < pathBones.length) { - let boneCount = pathBones[i++]; - for (let n = i + boneCount; i < n; i++) { - let boneIndex = pathBones[i]; - this.sortBone(bones[boneIndex]); - } - } - } - } - - sortBone (bone: Bone) { - if (bone.sorted) return; - let parent = bone.parent; - if (parent != null) this.sortBone(parent); - bone.sorted = true; - this._updateCache.push(bone); - } - - sortReset (bones: Array) { - for (let i = 0, n = bones.length; i < n; i++) { - let bone = bones[i]; - if (bone.sorted) this.sortReset(bone.children); - bone.sorted = false; - } - } - - /** Updates the world transform for each bone and applies constraints. */ - updateWorldTransform () { - let updateCache = this._updateCache; - for (let i = 0, n = updateCache.length; i < n; i++) - updateCache[i].update(); - } - - /** Sets the bones, constraints, and slots to their setup pose values. */ - setToSetupPose () { - this.setBonesToSetupPose(); - this.setSlotsToSetupPose(); - } - - /** Sets the bones and constraints to their setup pose values. */ - setBonesToSetupPose () { - let bones = this.bones; - for (let i = 0, n = bones.length; i < n; i++) - bones[i].setToSetupPose(); - - let ikConstraints = this.ikConstraints; - for (let i = 0, n = ikConstraints.length; i < n; i++) { - let constraint = ikConstraints[i]; - constraint.bendDirection = constraint.data.bendDirection; - constraint.mix = constraint.data.mix; - } - - let transformConstraints = this.transformConstraints; - for (let i = 0, n = transformConstraints.length; i < n; i++) { - let constraint = transformConstraints[i]; - let data = constraint.data; - constraint.rotateMix = data.rotateMix; - constraint.translateMix = data.translateMix; - constraint.scaleMix = data.scaleMix; - constraint.shearMix = data.shearMix; - } - - let pathConstraints = this.pathConstraints; - for (let i = 0, n = pathConstraints.length; i < n; i++) { - let constraint = pathConstraints[i]; - let data = constraint.data; - constraint.position = data.position; - constraint.spacing = data.spacing; - constraint.rotateMix = data.rotateMix; - constraint.translateMix = data.translateMix; - } - } - - setSlotsToSetupPose () { - let slots = this.slots; - Utils.arrayCopy(slots, 0, this.drawOrder, 0, slots.length); - for (let i = 0, n = slots.length; i < n; i++) - slots[i].setToSetupPose(); - } - - /** @return May return null. */ - getRootBone () { - if (this.bones.length == 0) return null; - return this.bones[0]; - } - - /** @return May be null. */ - findBone (boneName: string) { - if (boneName == null) throw new Error("boneName cannot be null."); - let bones = this.bones; - for (let i = 0, n = bones.length; i < n; i++) { - let bone = bones[i]; - if (bone.data.name == boneName) return bone; - } - return null; - } - - /** @return -1 if the bone was not found. */ - findBoneIndex (boneName: string) { - if (boneName == null) throw new Error("boneName cannot be null."); - let bones = this.bones; - for (let i = 0, n = bones.length; i < n; i++) - if (bones[i].data.name == boneName) return i; - return -1; - } - - /** @return May be null. */ - findSlot (slotName: string) { - if (slotName == null) throw new Error("slotName cannot be null."); - let slots = this.slots; - for (let i = 0, n = slots.length; i < n; i++) { - let slot = slots[i]; - if (slot.data.name == slotName) return slot; - } - return null; - } - - /** @return -1 if the bone was not found. */ - findSlotIndex (slotName: string) { - if (slotName == null) throw new Error("slotName cannot be null."); - let slots = this.slots; - for (let i = 0, n = slots.length; i < n; i++) - if (slots[i].data.name == slotName) return i; - return -1; - } - - /** Sets a skin by name. - * @see #setSkin(Skin) */ - setSkinByName (skinName: string) { - let skin = this.data.findSkin(skinName); - if (skin == null) throw new Error("Skin not found: " + skinName); - this.setSkin(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 (newSkin: Skin) { - if (newSkin != null) { - if (this.skin != null) - newSkin.attachAll(this, this.skin); - else { - let slots = this.slots; - for (let i = 0, n = slots.length; i < n; i++) { - let slot = slots[i]; - let name = slot.data.attachmentName; - if (name != null) { - let attachment: Attachment = newSkin.getAttachment(i, name); - if (attachment != null) slot.setAttachment(attachment); - } - } - } - } - this.skin = newSkin; - } - - /** @return May be null. */ - getAttachmentByName (slotName: string, attachmentName: string): Attachment { - return this.getAttachment(this.data.findSlotIndex(slotName), attachmentName); - } - - /** @return May be null. */ - getAttachment (slotIndex: number, attachmentName: string): Attachment { - if (attachmentName == null) throw new Error("attachmentName cannot be null."); - if (this.skin != null) { - let attachment: Attachment = this.skin.getAttachment(slotIndex, attachmentName); - if (attachment != null) return attachment; - } - if (this.data.defaultSkin != null) return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); - return null; - } - - /** @param attachmentName May be null. */ - setAttachment (slotName: string, attachmentName: string) { - if (slotName == null) throw new Error("slotName cannot be null."); - let slots = this.slots; - for (let i = 0, n = slots.length; i < n; i++) { - let slot = slots[i]; - if (slot.data.name == slotName) { - let attachment: Attachment = null; - if (attachmentName != null) { - attachment = this.getAttachment(i, attachmentName); - if (attachment == null) - throw new Error("Attachment not found: " + attachmentName + ", for slot: " + slotName); - } - slot.setAttachment(attachment); - return; - } - } - throw new Error("Slot not found: " + slotName); - } - - /** @return May be null. */ - findIkConstraint (constraintName: string) { - if (constraintName == null) throw new Error("constraintName cannot be null."); - let ikConstraints = this.ikConstraints; - for (let i = 0, n = ikConstraints.length; i < n; i++) { - let ikConstraint = ikConstraints[i]; - if (ikConstraint.data.name == constraintName) return ikConstraint; - } - return null; - } - - /** @return May be null. */ - findTransformConstraint (constraintName: string) { - if (constraintName == null) throw new Error("constraintName cannot be null."); - let transformConstraints = this.transformConstraints; - for (let i = 0, n = transformConstraints.length; i < n; i++) { - let constraint = transformConstraints[i]; - if (constraint.data.name == constraintName) return constraint; - } - return null; - } - - /** @return May be null. */ - findPathConstraint (constraintName: string) { - if (constraintName == null) throw new Error("constraintName cannot be null."); - let pathConstraints = this.pathConstraints; - for (let i = 0, n = pathConstraints.length; i < n; i++) { - let constraint = pathConstraints[i]; - if (constraint.data.name == constraintName) return constraint; - } - return null; - } - - /** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose. - * @param offset The distance from the skeleton origin to the bottom left corner of the AABB. - * @param size The width and height of the AABB. */ - getBounds (offset: Vector2, size: Vector2) { - if (offset == null) throw new Error("offset cannot be null."); - if (size == null) throw new Error("size cannot be null."); - let drawOrder = this.drawOrder; - let minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; - for (let i = 0, n = drawOrder.length; i < n; i++) { - let slot = drawOrder[i]; - let vertices: ArrayLike = null; - let attachment = slot.getAttachment(); - if (attachment instanceof RegionAttachment) - vertices = (attachment).updateWorldVertices(slot, false); - else if (attachment instanceof MeshAttachment) // - vertices = (attachment).updateWorldVertices(slot, true); - if (vertices != null) { - for (let ii = 0, nn = vertices.length; ii < nn; ii += 8) { - let x = vertices[ii], y = vertices[ii + 1]; - minX = Math.min(minX, x); - minY = Math.min(minY, y); - maxX = Math.max(maxX, x); - maxY = Math.max(maxY, y); - } - } - } - offset.set(minX, minY); - size.set(maxX - minX, maxY - minY); - } - - update (delta: number) { - this.time += delta; - } - } +module spine { + export class Skeleton { + data: SkeletonData; + bones: Array; + slots: Array; + drawOrder: Array; + ikConstraints: Array; ikConstraintsSorted: Array; + transformConstraints: Array; + pathConstraints: Array; + _updateCache = new Array(); + skin: Skin; + color: Color; + time = 0; + flipX = false; flipY = false; + x = 0; y = 0; + + constructor (data: SkeletonData) { + if (data == null) throw new Error("data cannot be null."); + this.data = data; + + this.bones = new Array(); + for (let i = 0; i < data.bones.length; i++) { + let boneData = data.bones[i]; + let bone: Bone; + if (boneData.parent == null) + bone = new Bone(boneData, this, null); + else { + let parent = this.bones[boneData.parent.index]; + bone = new Bone(boneData, this, parent); + parent.children.push(bone); + } + this.bones.push(bone); + } + + this.slots = new Array(); + this.drawOrder = new Array(); + for (let i = 0; i < data.slots.length; i++) { + let slotData = data.slots[i]; + let bone = this.bones[slotData.boneData.index]; + let slot = new Slot(slotData, bone); + this.slots.push(slot); + this.drawOrder.push(slot); + } + + this.ikConstraints = new Array(); + this.ikConstraintsSorted = new Array(); + for (let i = 0; i < data.ikConstraints.length; i++) { + let ikConstraintData = data.ikConstraints[i]; + this.ikConstraints.push(new IkConstraint(ikConstraintData, this)); + } + + this.transformConstraints = new Array(); + for (let i = 0; i < data.transformConstraints.length; i++) { + let transformConstraintData = data.transformConstraints[i]; + this.transformConstraints.push(new TransformConstraint(transformConstraintData, this)); + } + + this.pathConstraints = new Array(); + for (let i = 0; i < data.pathConstraints.length; i++) { + let pathConstraintData = data.pathConstraints[i]; + this.pathConstraints.push(new PathConstraint(pathConstraintData, this)); + } + + this.color = new Color(1, 1, 1, 1); + this.updateCache(); + } + + updateCache () { + let updateCache = this._updateCache; + updateCache.length = 0; + + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) + bones[i].sorted = false; + + // IK first, lowest hierarchy depth first. + let ikConstraints = this.ikConstraintsSorted; + ikConstraints.length = 0; + for (let i = 0; i < this.ikConstraints.length; i++) + ikConstraints.push(this.ikConstraints[i]); + let ikCount = ikConstraints.length; + for (let i = 0, level = 0, n = ikCount; i < n; i++) { + let ik = ikConstraints[i]; + let bone = ik.bones[0].parent; + for (level = 0; bone != null; level++) + bone = bone.parent; + ik.level = level; + } + for (let i = 1, ii = 0; i < ikCount; i++) { + let ik = ikConstraints[i]; + let level = ik.level; + for (ii = i - 1; ii >= 0; ii--) { + let other = ikConstraints[ii]; + if (other.level < level) break; + ikConstraints[ii + 1] = other; + } + ikConstraints[ii + 1] = ik; + } + for (let i = 0, n = ikConstraints.length; i < n; i++) { + let constraint = ikConstraints[i]; + let target = constraint.target; + this.sortBone(target); + + let constrained = constraint.bones; + let parent = constrained[0]; + this.sortBone(parent); + + updateCache.push(constraint); + + this.sortReset(parent.children); + constrained[constrained.length - 1].sorted = true; + } + + let pathConstraints = this.pathConstraints; + for (let i = 0, n = pathConstraints.length; i < n; i++) { + let constraint = pathConstraints[i]; + + let slot = constraint.target; + let slotIndex = slot.data.index; + let slotBone = slot.bone; + if (this.skin != null) this.sortPathConstraintAttachment(this.skin, slotIndex, slotBone); + if (this.data.defaultSkin != null && this.data.defaultSkin != this.skin) + this.sortPathConstraintAttachment(this.data.defaultSkin, slotIndex, slotBone); + for (let ii = 0, nn = this.data.skins.length; ii < nn; ii++) + this.sortPathConstraintAttachment(this.data.skins[ii], slotIndex, slotBone); + + let attachment = slot.getAttachment(); + if (attachment instanceof PathAttachment) this.sortPathConstraintAttachmentWith(attachment, slotBone); + + let constrained = constraint.bones; + let boneCount = constrained.length; + for (let ii = 0; ii < boneCount; ii++) + this.sortBone(constrained[ii]); + + updateCache.push(constraint); + + for (let ii = 0; ii < boneCount; ii++) + this.sortReset(constrained[ii].children); + for (let ii = 0; ii < boneCount; ii++) + constrained[ii].sorted = true; + } + + let transformConstraints = this.transformConstraints; + for (let i = 0, n = transformConstraints.length; i < n; i++) { + let constraint = transformConstraints[i]; + + this.sortBone(constraint.target); + + let constrained = constraint.bones; + let boneCount = constrained.length; + for (let ii = 0; ii < boneCount; ii++) + this.sortBone(constrained[ii]); + + updateCache.push(constraint); + + for (let ii = 0; ii < boneCount; ii++) + this.sortReset(constrained[ii].children); + for (let ii = 0; ii < boneCount; ii++) + constrained[ii].sorted = true; + } + + for (let i = 0, n = bones.length; i < n; i++) + this.sortBone(bones[i]); + } + + sortPathConstraintAttachment (skin: Skin, slotIndex: number, slotBone: Bone) { + let attachments = skin.attachments[slotIndex]; + if (!attachments) return; + for (let key in attachments) { + this.sortPathConstraintAttachmentWith(attachments[key], slotBone); + } + } + + sortPathConstraintAttachmentWith (attachment: Attachment, slotBone: Bone) { + if (!(attachment instanceof PathAttachment)) return; + let pathBones = (attachment).bones; + if (pathBones == null) + this.sortBone(slotBone); + else { + let bones = this.bones; + let i = 0; + while (i < pathBones.length) { + let boneCount = pathBones[i++]; + for (let n = i + boneCount; i < n; i++) { + let boneIndex = pathBones[i]; + this.sortBone(bones[boneIndex]); + } + } + } + } + + sortBone (bone: Bone) { + if (bone.sorted) return; + let parent = bone.parent; + if (parent != null) this.sortBone(parent); + bone.sorted = true; + this._updateCache.push(bone); + } + + sortReset (bones: Array) { + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (bone.sorted) this.sortReset(bone.children); + bone.sorted = false; + } + } + + /** Updates the world transform for each bone and applies constraints. */ + updateWorldTransform () { + let updateCache = this._updateCache; + for (let i = 0, n = updateCache.length; i < n; i++) + updateCache[i].update(); + } + + /** Sets the bones, constraints, and slots to their setup pose values. */ + setToSetupPose () { + this.setBonesToSetupPose(); + this.setSlotsToSetupPose(); + } + + /** Sets the bones and constraints to their setup pose values. */ + setBonesToSetupPose () { + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) + bones[i].setToSetupPose(); + + let ikConstraints = this.ikConstraints; + for (let i = 0, n = ikConstraints.length; i < n; i++) { + let constraint = ikConstraints[i]; + constraint.bendDirection = constraint.data.bendDirection; + constraint.mix = constraint.data.mix; + } + + let transformConstraints = this.transformConstraints; + for (let i = 0, n = transformConstraints.length; i < n; i++) { + let constraint = transformConstraints[i]; + let data = constraint.data; + constraint.rotateMix = data.rotateMix; + constraint.translateMix = data.translateMix; + constraint.scaleMix = data.scaleMix; + constraint.shearMix = data.shearMix; + } + + let pathConstraints = this.pathConstraints; + for (let i = 0, n = pathConstraints.length; i < n; i++) { + let constraint = pathConstraints[i]; + let data = constraint.data; + constraint.position = data.position; + constraint.spacing = data.spacing; + constraint.rotateMix = data.rotateMix; + constraint.translateMix = data.translateMix; + } + } + + setSlotsToSetupPose () { + let slots = this.slots; + Utils.arrayCopy(slots, 0, this.drawOrder, 0, slots.length); + for (let i = 0, n = slots.length; i < n; i++) + slots[i].setToSetupPose(); + } + + /** @return May return null. */ + getRootBone () { + if (this.bones.length == 0) return null; + return this.bones[0]; + } + + /** @return May be null. */ + findBone (boneName: string) { + if (boneName == null) throw new Error("boneName cannot be null."); + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (bone.data.name == boneName) return bone; + } + return null; + } + + /** @return -1 if the bone was not found. */ + findBoneIndex (boneName: string) { + if (boneName == null) throw new Error("boneName cannot be null."); + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) + if (bones[i].data.name == boneName) return i; + return -1; + } + + /** @return May be null. */ + findSlot (slotName: string) { + if (slotName == null) throw new Error("slotName cannot be null."); + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + if (slot.data.name == slotName) return slot; + } + return null; + } + + /** @return -1 if the bone was not found. */ + findSlotIndex (slotName: string) { + if (slotName == null) throw new Error("slotName cannot be null."); + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) + if (slots[i].data.name == slotName) return i; + return -1; + } + + /** Sets a skin by name. + * @see #setSkin(Skin) */ + setSkinByName (skinName: string) { + let skin = this.data.findSkin(skinName); + if (skin == null) throw new Error("Skin not found: " + skinName); + this.setSkin(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 (newSkin: Skin) { + if (newSkin != null) { + if (this.skin != null) + newSkin.attachAll(this, this.skin); + else { + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + let name = slot.data.attachmentName; + if (name != null) { + let attachment: Attachment = newSkin.getAttachment(i, name); + if (attachment != null) slot.setAttachment(attachment); + } + } + } + } + this.skin = newSkin; + } + + /** @return May be null. */ + getAttachmentByName (slotName: string, attachmentName: string): Attachment { + return this.getAttachment(this.data.findSlotIndex(slotName), attachmentName); + } + + /** @return May be null. */ + getAttachment (slotIndex: number, attachmentName: string): Attachment { + if (attachmentName == null) throw new Error("attachmentName cannot be null."); + if (this.skin != null) { + let attachment: Attachment = this.skin.getAttachment(slotIndex, attachmentName); + if (attachment != null) return attachment; + } + if (this.data.defaultSkin != null) return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); + return null; + } + + /** @param attachmentName May be null. */ + setAttachment (slotName: string, attachmentName: string) { + if (slotName == null) throw new Error("slotName cannot be null."); + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + if (slot.data.name == slotName) { + let attachment: Attachment = null; + if (attachmentName != null) { + attachment = this.getAttachment(i, attachmentName); + if (attachment == null) + throw new Error("Attachment not found: " + attachmentName + ", for slot: " + slotName); + } + slot.setAttachment(attachment); + return; + } + } + throw new Error("Slot not found: " + slotName); + } + + /** @return May be null. */ + findIkConstraint (constraintName: string) { + if (constraintName == null) throw new Error("constraintName cannot be null."); + let ikConstraints = this.ikConstraints; + for (let i = 0, n = ikConstraints.length; i < n; i++) { + let ikConstraint = ikConstraints[i]; + if (ikConstraint.data.name == constraintName) return ikConstraint; + } + return null; + } + + /** @return May be null. */ + findTransformConstraint (constraintName: string) { + if (constraintName == null) throw new Error("constraintName cannot be null."); + let transformConstraints = this.transformConstraints; + for (let i = 0, n = transformConstraints.length; i < n; i++) { + let constraint = transformConstraints[i]; + if (constraint.data.name == constraintName) return constraint; + } + return null; + } + + /** @return May be null. */ + findPathConstraint (constraintName: string) { + if (constraintName == null) throw new Error("constraintName cannot be null."); + let pathConstraints = this.pathConstraints; + for (let i = 0, n = pathConstraints.length; i < n; i++) { + let constraint = pathConstraints[i]; + if (constraint.data.name == constraintName) return constraint; + } + return null; + } + + /** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose. + * @param offset The distance from the skeleton origin to the bottom left corner of the AABB. + * @param size The width and height of the AABB. */ + getBounds (offset: Vector2, size: Vector2) { + if (offset == null) throw new Error("offset cannot be null."); + if (size == null) throw new Error("size cannot be null."); + let drawOrder = this.drawOrder; + let minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; + for (let i = 0, n = drawOrder.length; i < n; i++) { + let slot = drawOrder[i]; + let vertices: ArrayLike = null; + let attachment = slot.getAttachment(); + if (attachment instanceof RegionAttachment) + vertices = (attachment).updateWorldVertices(slot, false); + else if (attachment instanceof MeshAttachment) // + vertices = (attachment).updateWorldVertices(slot, true); + if (vertices != null) { + for (let ii = 0, nn = vertices.length; ii < nn; ii += 8) { + let x = vertices[ii], y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + } + offset.set(minX, minY); + size.set(maxX - minX, maxY - minY); + } + + update (delta: number) { + this.time += delta; + } + } } diff --git a/spine-ts/core/src/SkeletonBounds.ts b/spine-ts/core/src/SkeletonBounds.ts index 297c0bc2d5..69c5d267b0 100644 --- a/spine-ts/core/src/SkeletonBounds.ts +++ b/spine-ts/core/src/SkeletonBounds.ts @@ -1,201 +1,200 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class SkeletonBounds { - minX = 0; minY = 0; maxX = 0; maxY = 0; - boundingBoxes = new Array(); - polygons = new Array>(); - private polygonPool = new Pool>(() => { - return Utils.newFloatArray(16); - }); - - update (skeleton: Skeleton, updateAabb: boolean) { - if (skeleton == null) throw new Error("skeleton cannot be null."); - let boundingBoxes = this.boundingBoxes; - let polygons = this.polygons; - let polygonPool = this.polygonPool; - let slots = skeleton.slots; - let slotCount = slots.length; - - boundingBoxes.length = 0; - polygonPool.freeAll(polygons); - polygons.length = 0; - - for (let i = 0; i < slotCount; i++) { - let slot = slots[i]; - let attachment = slot.getAttachment(); - if (attachment instanceof BoundingBoxAttachment) { - let boundingBox = attachment as BoundingBoxAttachment; - boundingBoxes.push(boundingBox); - - let polygon = polygonPool.obtain(); - if (polygon.length != boundingBox.worldVerticesLength) { - polygon = Utils.newFloatArray(boundingBox.worldVerticesLength); - } - polygons.push(polygon); - boundingBox.computeWorldVertices(slot, polygon); - } - } - - if (updateAabb) this.aabbCompute(); - } - - aabbCompute () { - let minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; - let polygons = this.polygons; - for (let i = 0, n = polygons.length; i < n; i++) { - let polygon = polygons[i]; - let vertices = polygon; - for (let ii = 0, nn = polygon.length; ii < nn; ii += 2) { - let x = vertices[ii]; - let y = vertices[ii + 1]; - minX = Math.min(minX, x); - minY = Math.min(minY, y); - maxX = Math.max(maxX, x); - maxY = Math.max(maxY, y); - } - } - this.minX = minX; - this.minY = minY; - this.maxX = maxX; - this.maxY = maxY; - } - - /** Returns true if the axis aligned bounding box contains the point. */ - aabbContainsPoint (x: number, y: number) { - return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY; - } - - /** Returns true if the axis aligned bounding box intersects the line segment. */ - aabbIntersectsSegment (x1: number, y1: number, x2: number, y2: number) { - let minX = this.minX; - let minY = this.minY; - let maxX = this.maxX; - let maxY = this.maxY; - if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) - return false; - let m = (y2 - y1) / (x2 - x1); - let y = m * (minX - x1) + y1; - if (y > minY && y < maxY) return true; - y = m * (maxX - x1) + y1; - if (y > minY && y < maxY) return true; - let x = (minY - y1) / m + x1; - if (x > minX && x < maxX) return true; - x = (maxY - y1) / m + x1; - if (x > minX && x < maxX) return true; - return false; - } - - /** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */ - aabbIntersectsSkeleton (bounds: SkeletonBounds) { - return this.minX < bounds.maxX && this.maxX > bounds.minX && this.minY < bounds.maxY && this.maxY > bounds.minY; - } - - /** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more - * efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. */ - containsPoint (x: number, y: number): BoundingBoxAttachment { - let polygons = this.polygons; - for (let i = 0, n = polygons.length; i < n; i++) - if (this.containsPointPolygon(polygons[i], x, y)) return this.boundingBoxes[i]; - return null; - } - - /** Returns true if the polygon contains the point. */ - containsPointPolygon (polygon: ArrayLike, x: number, y: number) { - let vertices = polygon; - let nn = polygon.length; - - let prevIndex = nn - 2; - let inside = false; - for (let ii = 0; ii < nn; ii += 2) { - let vertexY = vertices[ii + 1]; - let prevY = vertices[prevIndex + 1]; - if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { - let vertexX = vertices[ii]; - if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside; - } - prevIndex = ii; - } - return inside; - } - - /** Returns the first bounding box attachment that contains any part of the line segment, or null. When doing many checks, it - * is usually more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns - * true. */ - intersectsSegment (x1: number, y1: number, x2: number, y2: number) { - let polygons = this.polygons; - for (let i = 0, n = polygons.length; i < n; i++) - if (this.intersectsSegmentPolygon(polygons[i], x1, y1, x2, y2)) return this.boundingBoxes[i]; - return null; - } - - /** Returns true if the polygon contains any part of the line segment. */ - intersectsSegmentPolygon (polygon: ArrayLike, x1: number, y1: number, x2: number, y2: number) { - let vertices = polygon; - let nn = polygon.length; - - let width12 = x1 - x2, height12 = y1 - y2; - let det1 = x1 * y2 - y1 * x2; - let x3 = vertices[nn - 2], y3 = vertices[nn - 1]; - for (let ii = 0; ii < nn; ii += 2) { - let x4 = vertices[ii], y4 = vertices[ii + 1]; - let det2 = x3 * y4 - y3 * x4; - let width34 = x3 - x4, height34 = y3 - y4; - let det3 = width12 * height34 - height12 * width34; - let x = (det1 * width34 - width12 * det2) / det3; - if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { - let y = (det1 * height34 - height12 * det2) / det3; - if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; - } - x3 = x4; - y3 = y4; - } - return false; - } - - /** Returns the polygon for the specified bounding box, or null. */ - getPolygon (boundingBox: BoundingBoxAttachment) { - if (boundingBox == null) throw new Error("boundingBox cannot be null."); - let index = this.boundingBoxes.indexOf(boundingBox); - return index == -1 ? null : this.polygons[index]; - } - - getWidth () { - return this.maxX - this.minX; - } - - getHeight () { - return this.maxY - this.minY; - } - } - +module spine { + export class SkeletonBounds { + minX = 0; minY = 0; maxX = 0; maxY = 0; + boundingBoxes = new Array(); + polygons = new Array>(); + private polygonPool = new Pool>(() => { + return Utils.newFloatArray(16); + }); + + update (skeleton: Skeleton, updateAabb: boolean) { + if (skeleton == null) throw new Error("skeleton cannot be null."); + let boundingBoxes = this.boundingBoxes; + let polygons = this.polygons; + let polygonPool = this.polygonPool; + let slots = skeleton.slots; + let slotCount = slots.length; + + boundingBoxes.length = 0; + polygonPool.freeAll(polygons); + polygons.length = 0; + + for (let i = 0; i < slotCount; i++) { + let slot = slots[i]; + let attachment = slot.getAttachment(); + if (attachment instanceof BoundingBoxAttachment) { + let boundingBox = attachment as BoundingBoxAttachment; + boundingBoxes.push(boundingBox); + + let polygon = polygonPool.obtain(); + if (polygon.length != boundingBox.worldVerticesLength) { + polygon = Utils.newFloatArray(boundingBox.worldVerticesLength); + } + polygons.push(polygon); + boundingBox.computeWorldVertices(slot, polygon); + } + } + + if (updateAabb) this.aabbCompute(); + } + + aabbCompute () { + let minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; + let polygons = this.polygons; + for (let i = 0, n = polygons.length; i < n; i++) { + let polygon = polygons[i]; + let vertices = polygon; + for (let ii = 0, nn = polygon.length; ii < nn; ii += 2) { + let x = vertices[ii]; + let y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } + + /** Returns true if the axis aligned bounding box contains the point. */ + aabbContainsPoint (x: number, y: number) { + return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY; + } + + /** Returns true if the axis aligned bounding box intersects the line segment. */ + aabbIntersectsSegment (x1: number, y1: number, x2: number, y2: number) { + let minX = this.minX; + let minY = this.minY; + let maxX = this.maxX; + let maxY = this.maxY; + if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) + return false; + let m = (y2 - y1) / (x2 - x1); + let y = m * (minX - x1) + y1; + if (y > minY && y < maxY) return true; + y = m * (maxX - x1) + y1; + if (y > minY && y < maxY) return true; + let x = (minY - y1) / m + x1; + if (x > minX && x < maxX) return true; + x = (maxY - y1) / m + x1; + if (x > minX && x < maxX) return true; + return false; + } + + /** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */ + aabbIntersectsSkeleton (bounds: SkeletonBounds) { + return this.minX < bounds.maxX && this.maxX > bounds.minX && this.minY < bounds.maxY && this.maxY > bounds.minY; + } + + /** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more + * efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. */ + containsPoint (x: number, y: number): BoundingBoxAttachment { + let polygons = this.polygons; + for (let i = 0, n = polygons.length; i < n; i++) + if (this.containsPointPolygon(polygons[i], x, y)) return this.boundingBoxes[i]; + return null; + } + + /** Returns true if the polygon contains the point. */ + containsPointPolygon (polygon: ArrayLike, x: number, y: number) { + let vertices = polygon; + let nn = polygon.length; + + let prevIndex = nn - 2; + let inside = false; + for (let ii = 0; ii < nn; ii += 2) { + let vertexY = vertices[ii + 1]; + let prevY = vertices[prevIndex + 1]; + if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { + let vertexX = vertices[ii]; + if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside; + } + prevIndex = ii; + } + return inside; + } + + /** Returns the first bounding box attachment that contains any part of the line segment, or null. When doing many checks, it + * is usually more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns + * true. */ + intersectsSegment (x1: number, y1: number, x2: number, y2: number) { + let polygons = this.polygons; + for (let i = 0, n = polygons.length; i < n; i++) + if (this.intersectsSegmentPolygon(polygons[i], x1, y1, x2, y2)) return this.boundingBoxes[i]; + return null; + } + + /** Returns true if the polygon contains any part of the line segment. */ + intersectsSegmentPolygon (polygon: ArrayLike, x1: number, y1: number, x2: number, y2: number) { + let vertices = polygon; + let nn = polygon.length; + + let width12 = x1 - x2, height12 = y1 - y2; + let det1 = x1 * y2 - y1 * x2; + let x3 = vertices[nn - 2], y3 = vertices[nn - 1]; + for (let ii = 0; ii < nn; ii += 2) { + let x4 = vertices[ii], y4 = vertices[ii + 1]; + let det2 = x3 * y4 - y3 * x4; + let width34 = x3 - x4, height34 = y3 - y4; + let det3 = width12 * height34 - height12 * width34; + let x = (det1 * width34 - width12 * det2) / det3; + if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { + let y = (det1 * height34 - height12 * det2) / det3; + if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; + } + x3 = x4; + y3 = y4; + } + return false; + } + + /** Returns the polygon for the specified bounding box, or null. */ + getPolygon (boundingBox: BoundingBoxAttachment) { + if (boundingBox == null) throw new Error("boundingBox cannot be null."); + let index = this.boundingBoxes.indexOf(boundingBox); + return index == -1 ? null : this.polygons[index]; + } + + getWidth () { + return this.maxX - this.minX; + } + + getHeight () { + return this.maxY - this.minY; + } + } + } diff --git a/spine-ts/core/src/SkeletonData.ts b/spine-ts/core/src/SkeletonData.ts index 4eba74c752..a40a9d096c 100644 --- a/spine-ts/core/src/SkeletonData.ts +++ b/spine-ts/core/src/SkeletonData.ts @@ -1,151 +1,150 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class SkeletonData { - name: string; - bones = new Array(); // Ordered parents first. - slots = new Array(); // Setup pose draw order. - skins = new Array(); - defaultSkin: Skin; - events = new Array(); - animations = new Array(); - ikConstraints = new Array(); - transformConstraints = new Array(); - pathConstraints = new Array(); - width: number; height: number; - version: string; hash: string; imagesPath: string; - - findBone (boneName: string) { - if (boneName == null) throw new Error("boneName cannot be null."); - let bones = this.bones; - for (let i = 0, n = bones.length; i < n; i++) { - let bone = bones[i]; - if (bone.name == boneName) return bone; - } - return null; - } - - findBoneIndex (boneName: string) { - if (boneName == null) throw new Error("boneName cannot be null."); - let bones = this.bones; - for (let i = 0, n = bones.length; i < n; i++) - if (bones[i].name == boneName) return i; - return -1; - } - - findSlot (slotName: string) { - if (slotName == null) throw new Error("slotName cannot be null."); - let slots = this.slots; - for (let i = 0, n = slots.length; i < n; i++) { - let slot = slots[i]; - if (slot.name == slotName) return slot; - } - return null; - } - - findSlotIndex (slotName: string) { - if (slotName == null) throw new Error("slotName cannot be null."); - let slots = this.slots; - for (let i = 0, n = slots.length; i < n; i++) - if (slots[i].name == slotName) return i; - return -1; - } - - findSkin (skinName: string) { - if (skinName == null) throw new Error("skinName cannot be null."); - let skins = this.skins; - for (let i = 0, n = skins.length; i < n; i++) { - let skin = skins[i]; - if (skin.name == skinName) return skin; - } - return null; - } - - findEvent (eventDataName: string) { - if (eventDataName == null) throw new Error("eventDataName cannot be null."); - let events = this.events; - for (let i = 0, n = events.length; i < n; i++) { - let event = events[i]; - if (event.name == eventDataName) return event; - } - return null; - } - - findAnimation (animationName: string) { - if (animationName == null) throw new Error("animationName cannot be null."); - let animations = this.animations; - for (let i = 0, n = animations.length; i < n; i++) { - let animation = animations[i]; - if (animation.name == animationName) return animation; - } - return null; - } - - findIkConstraint (constraintName: string) { - if (constraintName == null) throw new Error("constraintName cannot be null."); - let ikConstraints = this.ikConstraints; - for (let i = 0, n = ikConstraints.length; i < n; i++) { - let constraint = ikConstraints[i]; - if (constraint.name == constraintName) return constraint; - } - return null; - } - - findTransformConstraint (constraintName: string) { - if (constraintName == null) throw new Error("constraintName cannot be null."); - let transformConstraints = this.transformConstraints; - for (let i = 0, n = transformConstraints.length; i < n; i++) { - let constraint = transformConstraints[i]; - if (constraint.name == constraintName) return constraint; - } - return null; - } - - findPathConstraint (constraintName: string) { - if (constraintName == null) throw new Error("constraintName cannot be null."); - let pathConstraints = this.pathConstraints; - for (let i = 0, n = pathConstraints.length; i < n; i++) { - let constraint = pathConstraints[i]; - if (constraint.name == constraintName) return constraint; - } - return null; - } - - findPathConstraintIndex (pathConstraintName: string) { - if (pathConstraintName == null) throw new Error("pathConstraintName cannot be null."); - let pathConstraints = this.pathConstraints; - for (let i = 0, n = pathConstraints.length; i < n; i++) - if (pathConstraints[i].name == pathConstraintName) return i; - return -1; - } - } +module spine { + export class SkeletonData { + name: string; + bones = new Array(); // Ordered parents first. + slots = new Array(); // Setup pose draw order. + skins = new Array(); + defaultSkin: Skin; + events = new Array(); + animations = new Array(); + ikConstraints = new Array(); + transformConstraints = new Array(); + pathConstraints = new Array(); + width: number; height: number; + version: string; hash: string; imagesPath: string; + + findBone (boneName: string) { + if (boneName == null) throw new Error("boneName cannot be null."); + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (bone.name == boneName) return bone; + } + return null; + } + + findBoneIndex (boneName: string) { + if (boneName == null) throw new Error("boneName cannot be null."); + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) + if (bones[i].name == boneName) return i; + return -1; + } + + findSlot (slotName: string) { + if (slotName == null) throw new Error("slotName cannot be null."); + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + if (slot.name == slotName) return slot; + } + return null; + } + + findSlotIndex (slotName: string) { + if (slotName == null) throw new Error("slotName cannot be null."); + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) + if (slots[i].name == slotName) return i; + return -1; + } + + findSkin (skinName: string) { + if (skinName == null) throw new Error("skinName cannot be null."); + let skins = this.skins; + for (let i = 0, n = skins.length; i < n; i++) { + let skin = skins[i]; + if (skin.name == skinName) return skin; + } + return null; + } + + findEvent (eventDataName: string) { + if (eventDataName == null) throw new Error("eventDataName cannot be null."); + let events = this.events; + for (let i = 0, n = events.length; i < n; i++) { + let event = events[i]; + if (event.name == eventDataName) return event; + } + return null; + } + + findAnimation (animationName: string) { + if (animationName == null) throw new Error("animationName cannot be null."); + let animations = this.animations; + for (let i = 0, n = animations.length; i < n; i++) { + let animation = animations[i]; + if (animation.name == animationName) return animation; + } + return null; + } + + findIkConstraint (constraintName: string) { + if (constraintName == null) throw new Error("constraintName cannot be null."); + let ikConstraints = this.ikConstraints; + for (let i = 0, n = ikConstraints.length; i < n; i++) { + let constraint = ikConstraints[i]; + if (constraint.name == constraintName) return constraint; + } + return null; + } + + findTransformConstraint (constraintName: string) { + if (constraintName == null) throw new Error("constraintName cannot be null."); + let transformConstraints = this.transformConstraints; + for (let i = 0, n = transformConstraints.length; i < n; i++) { + let constraint = transformConstraints[i]; + if (constraint.name == constraintName) return constraint; + } + return null; + } + + findPathConstraint (constraintName: string) { + if (constraintName == null) throw new Error("constraintName cannot be null."); + let pathConstraints = this.pathConstraints; + for (let i = 0, n = pathConstraints.length; i < n; i++) { + let constraint = pathConstraints[i]; + if (constraint.name == constraintName) return constraint; + } + return null; + } + + findPathConstraintIndex (pathConstraintName: string) { + if (pathConstraintName == null) throw new Error("pathConstraintName cannot be null."); + let pathConstraints = this.pathConstraints; + for (let i = 0, n = pathConstraints.length; i < n; i++) + if (pathConstraints[i].name == pathConstraintName) return i; + return -1; + } + } } diff --git a/spine-ts/core/src/SkeletonJson.ts b/spine-ts/core/src/SkeletonJson.ts index 51a15bb5c1..c9fa98c46b 100644 --- a/spine-ts/core/src/SkeletonJson.ts +++ b/spine-ts/core/src/SkeletonJson.ts @@ -1,720 +1,719 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class SkeletonJson { - attachmentLoader: AttachmentLoader; - scale = 1; - private linkedMeshes = new Array(); - - constructor (attachmentLoader: AttachmentLoader) { - this.attachmentLoader = attachmentLoader; - } - - readSkeletonData (json: string | any ): SkeletonData { - let scale = this.scale; - let skeletonData = new SkeletonData(); - let root = typeof(json) === "string" ? JSON.parse(json) : json; - - // Skeleton - let skeletonMap = root.skeleton; - if (skeletonMap != null) { - skeletonData.hash = skeletonMap.hash; - skeletonData.version = skeletonMap.spine; - skeletonData.width = skeletonMap.width; - skeletonData.height = skeletonMap.height; - skeletonData.imagesPath = skeletonMap.images; - } - - // Bones - if (root.bones) { - for (let i = 0; i < root.bones.length; i++) { - let boneMap = root.bones[i]; - - let parent: BoneData = null; - let parentName: string = this.getValue(boneMap, "parent", null); - if (parentName != null) { - parent = skeletonData.findBone(parentName); - if (parent == null) throw new Error("Parent bone not found: " + parentName); - } - let data = new BoneData(skeletonData.bones.length, boneMap.name, parent); - data.length = this.getValue(boneMap, "length", 0) * scale; - data.x = this.getValue(boneMap, "x", 0) * scale; - data.y = this.getValue(boneMap, "y", 0) * scale; - data.rotation = this.getValue(boneMap, "rotation", 0); - data.scaleX = this.getValue(boneMap, "scaleX", 1); - data.scaleY = this.getValue(boneMap, "scaleY", 1); - data.shearX = this.getValue(boneMap, "shearX", 0); - data.shearY = this.getValue(boneMap, "shearY", 0); - data.inheritRotation = this.getValue(boneMap, "inheritRotation", true); - data.inheritScale = this.getValue(boneMap, "inheritScale", true); - - skeletonData.bones.push(data); - } - } - - // Slots. - if (root.slots) { - for (let i = 0; i < root.slots.length; i++) { - let slotMap = root.slots[i]; - let slotName: string = slotMap.name; - let boneName: string = slotMap.bone; - let boneData = skeletonData.findBone(boneName); - if (boneData == null) throw new Error("Slot bone not found: " + boneName); - let data = new SlotData(skeletonData.slots.length, slotName, boneData); - - let color: string = this.getValue(slotMap, "color", null); - if (color != null) data.color.setFromString(color); - - data.attachmentName = this.getValue(slotMap, "attachment", null); - data.blendMode = SkeletonJson.blendModeFromString(this.getValue(slotMap, "blend", "normal")); - skeletonData.slots.push(data); - } - } - - // IK constraints - if (root.ik) { - for (let i = 0; i < root.ik.length; i++) { - let constraintMap = root.ik[i]; - let data = new IkConstraintData(constraintMap.name); - - for (let j = 0; j < constraintMap.bones.length; j++) { - let boneName = constraintMap.bones[j]; - let bone = skeletonData.findBone(boneName); - if (bone == null) throw new Error("IK bone not found: " + boneName); - data.bones.push(bone); - } - - let targetName: string = constraintMap.target; - data.target = skeletonData.findBone(targetName); - if (data.target == null) throw new Error("IK target bone not found: " + targetName); - - data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1; - data.mix = this.getValue(constraintMap, "mix", 1); - - skeletonData.ikConstraints.push(data); - } - } - - // Transform constraints. - if (root.transform) { - for (let i = 0; i < root.transform.length; i++) { - let constraintMap = root.transform[i]; - let data = new TransformConstraintData(constraintMap.name); - - for (let j = 0; j < constraintMap.bones.length; j++) { - let boneName = constraintMap.bones[j]; - let bone = skeletonData.findBone(boneName); - if (bone == null) throw new Error("Transform constraint bone not found: " + boneName); - data.bones.push(bone); - } - - let targetName: string = constraintMap.target; - data.target = skeletonData.findBone(targetName); - if (data.target == null) throw new Error("Transform constraint target bone not found: " + targetName); - - data.offsetRotation = this.getValue(constraintMap, "rotation", 0); - data.offsetX = this.getValue(constraintMap, "x", 0) * scale; - data.offsetY = this.getValue(constraintMap, "y", 0) * scale; - data.offsetScaleX = this.getValue(constraintMap, "scaleX", 0); - data.offsetScaleY = this.getValue(constraintMap, "scaleY", 0); - data.offsetShearY = this.getValue(constraintMap, "shearY", 0); - - data.rotateMix = this.getValue(constraintMap, "rotateMix", 1); - data.translateMix = this.getValue(constraintMap, "translateMix", 1); - data.scaleMix = this.getValue(constraintMap, "scaleMix", 1); - data.shearMix = this.getValue(constraintMap, "shearMix", 1); - - skeletonData.transformConstraints.push(data); - } - } - - // Path constraints. - if (root.path) { - for (let i = 0; i < root.path.length; i++) { - let constraintMap = root.path[i]; - let data = new PathConstraintData(constraintMap.name); - - for (let j = 0; j < constraintMap.bones.length; j++) { - let boneName = constraintMap.bones[j]; - let bone = skeletonData.findBone(boneName); - if (bone == null) throw new Error("Transform constraint bone not found: " + boneName); - data.bones.push(bone); - } - - let targetName: string = constraintMap.target; - data.target = skeletonData.findSlot(targetName); - if (data.target == null) throw new Error("Path target slot not found: " + targetName); - - data.positionMode = SkeletonJson.positionModeFromString(this.getValue(constraintMap, "positionMode", "percent")); - data.spacingMode = SkeletonJson.spacingModeFromString(this.getValue(constraintMap, "spacingMode", "length")); - data.rotateMode = SkeletonJson.rotateModeFromString(this.getValue(constraintMap, "rotateMode", "tangent")); - data.offsetRotation = this.getValue(constraintMap, "rotation", 0); - data.position = this.getValue(constraintMap, "position", 0); - if (data.positionMode == PositionMode.Fixed) data.position *= scale; - data.spacing = this.getValue(constraintMap, "spacing", 0); - if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed) data.spacing *= scale; - data.rotateMix = this.getValue(constraintMap, "rotateMix", 1); - data.translateMix = this.getValue(constraintMap, "translateMix", 1); - - skeletonData.pathConstraints.push(data); - } - } - - // Skins. - if (root.skins) { - for (let skinName in root.skins) { - let skinMap = root.skins[skinName] - let skin = new Skin(skinName); - for (let slotName in skinMap) { - let slotIndex = skeletonData.findSlotIndex(slotName); - if (slotIndex == -1) throw new Error("Slot not found: " + slotName); - let slotMap = skinMap[slotName]; - for (let entryName in slotMap) { - let attachment = this.readAttachment(slotMap[entryName], skin, slotIndex, entryName); - if (attachment != null) skin.addAttachment(slotIndex, entryName, attachment); - } - } - skeletonData.skins.push(skin); - if (skin.name == "default") skeletonData.defaultSkin = skin; - } - } - - // Linked meshes. - for (let i = 0, n = this.linkedMeshes.length; i < n; i++) { - let linkedMesh = this.linkedMeshes[i]; - let skin = linkedMesh.skin == null ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin); - if (skin == null) throw new Error("Skin not found: " + linkedMesh.skin); - let parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); - if (parent == null) throw new Error("Parent mesh not found: " + linkedMesh.parent); - linkedMesh.mesh.setParentMesh( parent); - linkedMesh.mesh.updateUVs(); - } - this.linkedMeshes.length = 0; - - // Events. - if (root.events) { - for (let eventName in root.events) { - let eventMap = root.events[eventName]; - let data = new EventData(eventName); - data.intValue = this.getValue(eventMap, "int", 0); - data.floatValue = this.getValue(eventMap, "float", 0); - data.stringValue = this.getValue(eventMap, "string", null); - skeletonData.events.push(data); - } - } - - // Animations. - if (root.animations) { - for (let animationName in root.animations) { - let animationMap = root.animations[animationName]; - this.readAnimation(animationMap, animationName, skeletonData); - } - } - - return skeletonData; - } - - readAttachment (map: any, skin: Skin, slotIndex: number, name: string): Attachment { - let scale = this.scale; - name = this.getValue(map, "name", name); - - let type = this.getValue(map, "type", "region"); - - switch (type) { - case "region": { - let path = this.getValue(map, "path", name); - let region = this.attachmentLoader.newRegionAttachment(skin, name, path); - if (region == null) return null; - region.path = path; - region.x = this.getValue(map, "x", 0) * scale; - region.y = this.getValue(map, "y", 0) * scale; - region.scaleX = this.getValue(map, "scaleX", 1); - region.scaleY = this.getValue(map, "scaleY", 1); - region.rotation = this.getValue(map, "rotation", 0); - region.width = map.width * scale; - region.height = map.height * scale; - - let color: string = this.getValue(map, "color", null); - if (color != null) region.color.setFromString(color); - - region.updateOffset(); - return region; - } - case "boundingbox": { - let box = this.attachmentLoader.newBoundingBoxAttachment(skin, name); - if (box == null) return null; - this.readVertices(map, box, map.vertexCount << 1); - let color: string = this.getValue(map, "color", null); - if (color != null) box.color.setFromString(color); - return box; - } - case "mesh": - case "linkedmesh": { - let path = this.getValue(map, "path", name); - let mesh = this.attachmentLoader.newMeshAttachment(skin, name, path); - if (mesh == null) return null; - mesh.path = path; - - let color = this.getValue(map, "color", null); - if (color != null) mesh.color.setFromString(color); - - let parent: string = this.getValue(map, "parent", null); - if (parent != null) { - mesh.inheritDeform = this.getValue(map, "deform", true); - this.linkedMeshes.push(new LinkedMesh(mesh, this.getValue(map, "skin", null), slotIndex, parent)); - return mesh; - } - - let uvs: Array = map.uvs; - this.readVertices(map, mesh, uvs.length); - mesh.triangles = map.triangles; - mesh.regionUVs = uvs; - mesh.updateUVs(); - - mesh.hullLength = this.getValue(map, "hull", 0) * 2; - return mesh; - } - case "path": { - let path = this.attachmentLoader.newPathAttachment(skin, name); - if (path == null) return null; - path.closed = this.getValue(map, "closed", false); - path.constantSpeed = this.getValue(map, "constantSpeed", true); - - let vertexCount = map.vertexCount; - this.readVertices(map, path, vertexCount << 1); - - let lengths: Array = Utils.newArray(vertexCount / 3, 0); - for (let i = 0; i < map.lengths.length; i++) - lengths[i++] = map.lengths[i] * scale; - path.lengths = lengths; - - let color: string = this.getValue(map, "color", null); - if (color != null) path.color.setFromString(color); - return path; - } - } - return null; - } - - readVertices (map: any, attachment: VertexAttachment, verticesLength: number) { - let scale = this.scale; - attachment.worldVerticesLength = verticesLength; - let vertices: Array = map.vertices; - if (verticesLength == vertices.length) { - if (scale != 1) { - for (let i = 0, n = vertices.length; i < n; i++) - vertices[i] *= scale; - } - attachment.vertices = Utils.toFloatArray(vertices); - return; - } - let weights = new Array(); - let bones = new Array(); - for (let i = 0, n = vertices.length; i < n;) { - let boneCount = vertices[i++]; - bones.push(boneCount); - for (let nn = i + boneCount * 4; i < nn; i += 4) { - bones.push(vertices[i]); - weights.push(vertices[i + 1] * scale); - weights.push(vertices[i + 2] * scale); - weights.push(vertices[i + 3]); - } - } - attachment.bones = bones; - attachment.vertices = Utils.toFloatArray(weights); - } - - readAnimation (map: any, name: string, skeletonData: SkeletonData) { - let scale = this.scale; - let timelines = new Array(); - let duration = 0; - - // Slot timelines. - if (map.slots) { - for (let slotName in map.slots) { - let slotMap = map.slots[slotName]; - let slotIndex = skeletonData.findSlotIndex(slotName); - if (slotIndex == -1) throw new Error("Slot not found: " + slotName); - for (let timelineName in slotMap) { - let timelineMap = slotMap[timelineName]; - if (timelineName == "color") { - let timeline = new ColorTimeline(timelineMap.length); - timeline.slotIndex = slotIndex; - - let frameIndex = 0; - for (let i = 0; i < timelineMap.length; i++) { - let valueMap = timelineMap[i]; - let color = new Color(); - color.setFromString(valueMap.color); - timeline.setFrame(frameIndex, valueMap.time, color.r, color.g, color.b, color.a); - this.readCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * ColorTimeline.ENTRIES]); - - } else if (timelineName = "attachment") { - let timeline = new AttachmentTimeline(timelineMap.length); - timeline.slotIndex = slotIndex; - - let frameIndex = 0; - for (let i = 0; i < timelineMap.length; i++) { - let valueMap = timelineMap[i]; - timeline.setFrame(frameIndex++, valueMap.time, valueMap.name); - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); - } else - throw new Error("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"); - } - } - } - - // Bone timelines. - if (map.bones) { - for (let boneName in map.bones) { - let boneMap = map.bones[boneName]; - let boneIndex = skeletonData.findBoneIndex(boneName); - if (boneIndex == -1) throw new Error("Bone not found: " + boneName); - for (let timelineName in boneMap) { - let timelineMap = boneMap[timelineName]; - if (timelineName === "rotate") { - let timeline = new RotateTimeline(timelineMap.length); - timeline.boneIndex = boneIndex; - - let frameIndex = 0; - for (let i = 0; i < timelineMap.length; i++) { - let valueMap = timelineMap[i]; - timeline.setFrame(frameIndex, valueMap.time, valueMap.angle); - this.readCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * RotateTimeline.ENTRIES]); - - } else if (timelineName === "translate" || timelineName === "scale" || timelineName === "shear") { - let timeline: TranslateTimeline = null; - let timelineScale = 1; - if (timelineName === "scale") - timeline = new ScaleTimeline(timelineMap.length); - else if (timelineName === "shear") - timeline = new ShearTimeline(timelineMap.length); - else { - timeline = new TranslateTimeline(timelineMap.length); - timelineScale = scale; - } - timeline.boneIndex = boneIndex; - - let frameIndex = 0; - for (let i = 0; i < timelineMap.length; i++) { - let valueMap = timelineMap[i]; - let x = this.getValue(valueMap, "x", 0), y = this.getValue(valueMap, "y", 0); - timeline.setFrame(frameIndex, valueMap.time, x * timelineScale, y * timelineScale); - this.readCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * TranslateTimeline.ENTRIES]); - - } else - throw new Error("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"); - } - } - } - - // IK constraint timelines. - if (map.ik) { - for (let constraintName in map.ik) { - let constraintMap = map.ik[constraintName]; - let constraint = skeletonData.findIkConstraint(constraintName); - let timeline = new IkConstraintTimeline(constraintMap.length); - timeline.ikConstraintIndex = skeletonData.ikConstraints.indexOf(constraint); - let frameIndex = 0; - for (let i = 0; i < constraintMap.length; i++) { - let valueMap = constraintMap[i]; - timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, "mix", 1), - this.getValue(valueMap, "bendPositive", true) ? 1 : -1); - this.readCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * IkConstraintTimeline.ENTRIES]); - } - } - - // Transform constraint timelines. - if (map.transform) { - for (let constraintName in map.transform) { - let constraintMap = map.transform[constraintName]; - let constraint = skeletonData.findTransformConstraint(constraintName); - let timeline = new TransformConstraintTimeline(constraintMap.length); - timeline.transformConstraintIndex = skeletonData.transformConstraints.indexOf(constraint); - let frameIndex = 0; - for (let i = 0; i < constraintMap.length; i++) { - let valueMap = constraintMap[i]; - timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, "rotateMix", 1), - this.getValue(valueMap, "translateMix", 1), this.getValue(valueMap, "scaleMix", 1), this.getValue(valueMap, "shearMix", 1)); - this.readCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, - timeline.frames[(timeline.getFrameCount() - 1) * TransformConstraintTimeline.ENTRIES]); - } - } - - // Path constraint timelines. - if (map.paths) { - for (let constraintName in map.paths) { - let constraintMap = map.paths[constraintName]; - let index = skeletonData.findPathConstraintIndex(constraintName); - if (index == -1) throw new Error("Path constraint not found: " + constraintName); - let data = skeletonData.pathConstraints[index]; - for (let timelineName in constraintMap) { - let timelineMap = constraintMap[timelineName]; - if (timelineName === "position" || timelineName === "spacing") { - let timeline: PathConstraintPositionTimeline = null; - let timelineScale = 1; - if (timelineName === "spacing") { - timeline = new PathConstraintSpacingTimeline(timelineMap.length); - if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed) timelineScale = scale; - } else { - timeline = new PathConstraintPositionTimeline(timelineMap.length); - if (data.positionMode == PositionMode.Fixed) timelineScale = scale; - } - timeline.pathConstraintIndex = index; - let frameIndex = 0; - for (let i = 0; i < timelineMap.length; i++) { - let valueMap = timelineMap[i]; - timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, timelineName, 0) * timelineScale); - this.readCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, - timeline.frames[(timeline.getFrameCount() - 1) * PathConstraintPositionTimeline.ENTRIES]); - } else if (timelineName === "mix") { - let timeline = new PathConstraintMixTimeline(timelineMap.length); - timeline.pathConstraintIndex = index; - let frameIndex = 0; - for (let i = 0; i < timelineMap.length; i++) { - let valueMap = timelineMap[i]; - timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, "rotateMix", 1), - this.getValue(valueMap, "translateMix", 1)); - this.readCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, - timeline.frames[(timeline.getFrameCount() - 1) * PathConstraintMixTimeline.ENTRIES]); - } - } - } - } - - // Deform timelines. - if (map.deform) { - for (let deformName in map.deform) { - let deformMap = map.deform[deformName]; - let skin = skeletonData.findSkin(deformName); - if (skin == null) throw new Error("Skin not found: " + deformName); - for (let slotName in deformMap) { - let slotMap = deformMap[slotName]; - let slotIndex = skeletonData.findSlotIndex(slotName); - if (slotIndex == -1) throw new Error("Slot not found: " + slotMap.name); - for (let timelineName in slotMap) { - let timelineMap = slotMap[timelineName]; - let attachment = skin.getAttachment(slotIndex, timelineName); - if (attachment == null) throw new Error("Deform attachment not found: " + timelineMap.name); - let weighted = attachment.bones != null; - let vertices = attachment.vertices; - let deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; - - let timeline = new DeformTimeline(timelineMap.length); - timeline.slotIndex = slotIndex; - timeline.attachment = attachment; - - let frameIndex = 0; - for (let j = 0; j < timelineMap.length; j++) { - let valueMap = timelineMap[j]; - let deform: ArrayLike; - let verticesValue: Array = this.getValue(valueMap, "vertices", null); - if (verticesValue == null) - deform = weighted ? Utils.newFloatArray(deformLength) : vertices; - else { - deform = Utils.newFloatArray(deformLength); - let start = this.getValue(valueMap, "offset", 0); - Utils.arrayCopy(verticesValue, 0, deform, start, verticesValue.length); - if (scale != 1) { - for (let i = start, n = i + verticesValue.length; i < n; i++) - deform[i] *= scale; - } - if (!weighted) { - for (let i = 0; i < deformLength; i++) - deform[i] += vertices[i]; - } - } - - timeline.setFrame(frameIndex, valueMap.time, deform); - this.readCurve(valueMap, timeline, frameIndex); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); - } - } - } - } - - // Draw order timeline. - let drawOrderNode = map.drawOrder; - if (drawOrderNode == null) drawOrderNode = map.draworder; - if (drawOrderNode != null) { - let timeline = new DrawOrderTimeline(drawOrderNode.length); - let slotCount = skeletonData.slots.length; - let frameIndex = 0; - for (let j = 0; j < drawOrderNode.length; j++) { - let drawOrderMap = drawOrderNode[j]; - let drawOrder: Array = null; - let offsets = this.getValue(drawOrderMap, "offsets", null); - if (offsets != null) { - drawOrder = Utils.newArray(slotCount, -1); - let unchanged = Utils.newArray(slotCount - offsets.length, 0); - let originalIndex = 0, unchangedIndex = 0; - for (let i = 0; i < offsets.length; i++) { - let offsetMap = offsets[i]; - let slotIndex = skeletonData.findSlotIndex(offsetMap.slot); - if (slotIndex == -1) throw new Error("Slot not found: " + offsetMap.slot); - // Collect unchanged items. - while (originalIndex != slotIndex) - unchanged[unchangedIndex++] = originalIndex++; - // Set changed items. - drawOrder[originalIndex + offsetMap.offset] = originalIndex++; - } - // Collect remaining unchanged items. - while (originalIndex < slotCount) - unchanged[unchangedIndex++] = originalIndex++; - // Fill in unchanged items. - for (let i = slotCount - 1; i >= 0; i--) - if (drawOrder[i] == -1) drawOrder[i] = unchanged[--unchangedIndex]; - } - timeline.setFrame(frameIndex++, drawOrderMap.time, drawOrder); - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); - } - - // Event timeline. - if (map.events) { - let timeline = new EventTimeline(map.events.length); - let frameIndex = 0; - for (let i = 0; i < map.events.length; i++) { - let eventMap = map.events[i]; - let eventData = skeletonData.findEvent(eventMap.name); - if (eventData == null) throw new Error("Event not found: " + eventMap.name); - let event = new Event(eventMap.time, eventData); - event.intValue = this.getValue(eventMap, "int", eventData.intValue); - event.floatValue = this.getValue(eventMap, "float", eventData.floatValue); - event.stringValue = this.getValue(eventMap, "string", eventData.stringValue); - timeline.setFrame(frameIndex++, event); - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); - } - - if (isNaN(duration)) { - throw new Error("Error while parsing animation, duration is NaN"); - } - - skeletonData.animations.push(new Animation(name, timelines, duration)); - } - - readCurve (map: any, timeline: CurveTimeline, frameIndex: number) { - if (!map.curve) return; - if (map.curve === "stepped") - timeline.setStepped(frameIndex); - else if (Object.prototype.toString.call(map.curve) === '[object Array]') { - let curve: Array = map.curve; - timeline.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]); - } - } - - getValue (map: any, prop: string, defaultValue: any) { - return map[prop] !== undefined ? map[prop] : defaultValue; - } - - static blendModeFromString (str: string) { - str = str.toLowerCase(); - if (str == "normal") return BlendMode.Normal; - if (str == "additive") return BlendMode.Additive; - if (str == "multiply") return BlendMode.Multiply; - if (str == "screen") return BlendMode.Screen; - throw new Error(`Unknown blend mode: ${str}`); - } - - static positionModeFromString (str: string) { - str = str.toLowerCase(); - if (str == "fixed") return PositionMode.Fixed; - if (str == "percent") return PositionMode.Percent; - throw new Error(`Unknown position mode: ${str}`); - } - - static spacingModeFromString (str: string) { - str = str.toLowerCase(); - if (str == "length") return SpacingMode.Length; - if (str == "fixed") return SpacingMode.Fixed; - if (str == "percent") return SpacingMode.Percent; - throw new Error(`Unknown position mode: ${str}`); - } - - static rotateModeFromString (str: string) { - str = str.toLowerCase(); - if (str == "tangent") return RotateMode.Tangent; - if (str == "chain") return RotateMode.Chain; - if (str == "chainscale") return RotateMode.ChainScale; - throw new Error(`Unknown rotate mode: ${str}`); - } - } - - class LinkedMesh { - parent: string; skin: string; - slotIndex: number; - mesh: MeshAttachment; - - constructor (mesh: MeshAttachment, skin: string, slotIndex: number, parent: string) { - this.mesh = mesh; - this.skin = skin; - this.slotIndex = slotIndex; - this.parent = parent; - } - } +module spine { + export class SkeletonJson { + attachmentLoader: AttachmentLoader; + scale = 1; + private linkedMeshes = new Array(); + + constructor (attachmentLoader: AttachmentLoader) { + this.attachmentLoader = attachmentLoader; + } + + readSkeletonData (json: string | any ): SkeletonData { + let scale = this.scale; + let skeletonData = new SkeletonData(); + let root = typeof(json) === "string" ? JSON.parse(json) : json; + + // Skeleton + let skeletonMap = root.skeleton; + if (skeletonMap != null) { + skeletonData.hash = skeletonMap.hash; + skeletonData.version = skeletonMap.spine; + skeletonData.width = skeletonMap.width; + skeletonData.height = skeletonMap.height; + skeletonData.imagesPath = skeletonMap.images; + } + + // Bones + if (root.bones) { + for (let i = 0; i < root.bones.length; i++) { + let boneMap = root.bones[i]; + + let parent: BoneData = null; + let parentName: string = this.getValue(boneMap, "parent", null); + if (parentName != null) { + parent = skeletonData.findBone(parentName); + if (parent == null) throw new Error("Parent bone not found: " + parentName); + } + let data = new BoneData(skeletonData.bones.length, boneMap.name, parent); + data.length = this.getValue(boneMap, "length", 0) * scale; + data.x = this.getValue(boneMap, "x", 0) * scale; + data.y = this.getValue(boneMap, "y", 0) * scale; + data.rotation = this.getValue(boneMap, "rotation", 0); + data.scaleX = this.getValue(boneMap, "scaleX", 1); + data.scaleY = this.getValue(boneMap, "scaleY", 1); + data.shearX = this.getValue(boneMap, "shearX", 0); + data.shearY = this.getValue(boneMap, "shearY", 0); + data.inheritRotation = this.getValue(boneMap, "inheritRotation", true); + data.inheritScale = this.getValue(boneMap, "inheritScale", true); + + skeletonData.bones.push(data); + } + } + + // Slots. + if (root.slots) { + for (let i = 0; i < root.slots.length; i++) { + let slotMap = root.slots[i]; + let slotName: string = slotMap.name; + let boneName: string = slotMap.bone; + let boneData = skeletonData.findBone(boneName); + if (boneData == null) throw new Error("Slot bone not found: " + boneName); + let data = new SlotData(skeletonData.slots.length, slotName, boneData); + + let color: string = this.getValue(slotMap, "color", null); + if (color != null) data.color.setFromString(color); + + data.attachmentName = this.getValue(slotMap, "attachment", null); + data.blendMode = SkeletonJson.blendModeFromString(this.getValue(slotMap, "blend", "normal")); + skeletonData.slots.push(data); + } + } + + // IK constraints + if (root.ik) { + for (let i = 0; i < root.ik.length; i++) { + let constraintMap = root.ik[i]; + let data = new IkConstraintData(constraintMap.name); + + for (let j = 0; j < constraintMap.bones.length; j++) { + let boneName = constraintMap.bones[j]; + let bone = skeletonData.findBone(boneName); + if (bone == null) throw new Error("IK bone not found: " + boneName); + data.bones.push(bone); + } + + let targetName: string = constraintMap.target; + data.target = skeletonData.findBone(targetName); + if (data.target == null) throw new Error("IK target bone not found: " + targetName); + + data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1; + data.mix = this.getValue(constraintMap, "mix", 1); + + skeletonData.ikConstraints.push(data); + } + } + + // Transform constraints. + if (root.transform) { + for (let i = 0; i < root.transform.length; i++) { + let constraintMap = root.transform[i]; + let data = new TransformConstraintData(constraintMap.name); + + for (let j = 0; j < constraintMap.bones.length; j++) { + let boneName = constraintMap.bones[j]; + let bone = skeletonData.findBone(boneName); + if (bone == null) throw new Error("Transform constraint bone not found: " + boneName); + data.bones.push(bone); + } + + let targetName: string = constraintMap.target; + data.target = skeletonData.findBone(targetName); + if (data.target == null) throw new Error("Transform constraint target bone not found: " + targetName); + + data.offsetRotation = this.getValue(constraintMap, "rotation", 0); + data.offsetX = this.getValue(constraintMap, "x", 0) * scale; + data.offsetY = this.getValue(constraintMap, "y", 0) * scale; + data.offsetScaleX = this.getValue(constraintMap, "scaleX", 0); + data.offsetScaleY = this.getValue(constraintMap, "scaleY", 0); + data.offsetShearY = this.getValue(constraintMap, "shearY", 0); + + data.rotateMix = this.getValue(constraintMap, "rotateMix", 1); + data.translateMix = this.getValue(constraintMap, "translateMix", 1); + data.scaleMix = this.getValue(constraintMap, "scaleMix", 1); + data.shearMix = this.getValue(constraintMap, "shearMix", 1); + + skeletonData.transformConstraints.push(data); + } + } + + // Path constraints. + if (root.path) { + for (let i = 0; i < root.path.length; i++) { + let constraintMap = root.path[i]; + let data = new PathConstraintData(constraintMap.name); + + for (let j = 0; j < constraintMap.bones.length; j++) { + let boneName = constraintMap.bones[j]; + let bone = skeletonData.findBone(boneName); + if (bone == null) throw new Error("Transform constraint bone not found: " + boneName); + data.bones.push(bone); + } + + let targetName: string = constraintMap.target; + data.target = skeletonData.findSlot(targetName); + if (data.target == null) throw new Error("Path target slot not found: " + targetName); + + data.positionMode = SkeletonJson.positionModeFromString(this.getValue(constraintMap, "positionMode", "percent")); + data.spacingMode = SkeletonJson.spacingModeFromString(this.getValue(constraintMap, "spacingMode", "length")); + data.rotateMode = SkeletonJson.rotateModeFromString(this.getValue(constraintMap, "rotateMode", "tangent")); + data.offsetRotation = this.getValue(constraintMap, "rotation", 0); + data.position = this.getValue(constraintMap, "position", 0); + if (data.positionMode == PositionMode.Fixed) data.position *= scale; + data.spacing = this.getValue(constraintMap, "spacing", 0); + if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed) data.spacing *= scale; + data.rotateMix = this.getValue(constraintMap, "rotateMix", 1); + data.translateMix = this.getValue(constraintMap, "translateMix", 1); + + skeletonData.pathConstraints.push(data); + } + } + + // Skins. + if (root.skins) { + for (let skinName in root.skins) { + let skinMap = root.skins[skinName] + let skin = new Skin(skinName); + for (let slotName in skinMap) { + let slotIndex = skeletonData.findSlotIndex(slotName); + if (slotIndex == -1) throw new Error("Slot not found: " + slotName); + let slotMap = skinMap[slotName]; + for (let entryName in slotMap) { + let attachment = this.readAttachment(slotMap[entryName], skin, slotIndex, entryName); + if (attachment != null) skin.addAttachment(slotIndex, entryName, attachment); + } + } + skeletonData.skins.push(skin); + if (skin.name == "default") skeletonData.defaultSkin = skin; + } + } + + // Linked meshes. + for (let i = 0, n = this.linkedMeshes.length; i < n; i++) { + let linkedMesh = this.linkedMeshes[i]; + let skin = linkedMesh.skin == null ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin); + if (skin == null) throw new Error("Skin not found: " + linkedMesh.skin); + let parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); + if (parent == null) throw new Error("Parent mesh not found: " + linkedMesh.parent); + linkedMesh.mesh.setParentMesh( parent); + linkedMesh.mesh.updateUVs(); + } + this.linkedMeshes.length = 0; + + // Events. + if (root.events) { + for (let eventName in root.events) { + let eventMap = root.events[eventName]; + let data = new EventData(eventName); + data.intValue = this.getValue(eventMap, "int", 0); + data.floatValue = this.getValue(eventMap, "float", 0); + data.stringValue = this.getValue(eventMap, "string", null); + skeletonData.events.push(data); + } + } + + // Animations. + if (root.animations) { + for (let animationName in root.animations) { + let animationMap = root.animations[animationName]; + this.readAnimation(animationMap, animationName, skeletonData); + } + } + + return skeletonData; + } + + readAttachment (map: any, skin: Skin, slotIndex: number, name: string): Attachment { + let scale = this.scale; + name = this.getValue(map, "name", name); + + let type = this.getValue(map, "type", "region"); + + switch (type) { + case "region": { + let path = this.getValue(map, "path", name); + let region = this.attachmentLoader.newRegionAttachment(skin, name, path); + if (region == null) return null; + region.path = path; + region.x = this.getValue(map, "x", 0) * scale; + region.y = this.getValue(map, "y", 0) * scale; + region.scaleX = this.getValue(map, "scaleX", 1); + region.scaleY = this.getValue(map, "scaleY", 1); + region.rotation = this.getValue(map, "rotation", 0); + region.width = map.width * scale; + region.height = map.height * scale; + + let color: string = this.getValue(map, "color", null); + if (color != null) region.color.setFromString(color); + + region.updateOffset(); + return region; + } + case "boundingbox": { + let box = this.attachmentLoader.newBoundingBoxAttachment(skin, name); + if (box == null) return null; + this.readVertices(map, box, map.vertexCount << 1); + let color: string = this.getValue(map, "color", null); + if (color != null) box.color.setFromString(color); + return box; + } + case "mesh": + case "linkedmesh": { + let path = this.getValue(map, "path", name); + let mesh = this.attachmentLoader.newMeshAttachment(skin, name, path); + if (mesh == null) return null; + mesh.path = path; + + let color = this.getValue(map, "color", null); + if (color != null) mesh.color.setFromString(color); + + let parent: string = this.getValue(map, "parent", null); + if (parent != null) { + mesh.inheritDeform = this.getValue(map, "deform", true); + this.linkedMeshes.push(new LinkedMesh(mesh, this.getValue(map, "skin", null), slotIndex, parent)); + return mesh; + } + + let uvs: Array = map.uvs; + this.readVertices(map, mesh, uvs.length); + mesh.triangles = map.triangles; + mesh.regionUVs = uvs; + mesh.updateUVs(); + + mesh.hullLength = this.getValue(map, "hull", 0) * 2; + return mesh; + } + case "path": { + let path = this.attachmentLoader.newPathAttachment(skin, name); + if (path == null) return null; + path.closed = this.getValue(map, "closed", false); + path.constantSpeed = this.getValue(map, "constantSpeed", true); + + let vertexCount = map.vertexCount; + this.readVertices(map, path, vertexCount << 1); + + let lengths: Array = Utils.newArray(vertexCount / 3, 0); + for (let i = 0; i < map.lengths.length; i++) + lengths[i++] = map.lengths[i] * scale; + path.lengths = lengths; + + let color: string = this.getValue(map, "color", null); + if (color != null) path.color.setFromString(color); + return path; + } + } + return null; + } + + readVertices (map: any, attachment: VertexAttachment, verticesLength: number) { + let scale = this.scale; + attachment.worldVerticesLength = verticesLength; + let vertices: Array = map.vertices; + if (verticesLength == vertices.length) { + if (scale != 1) { + for (let i = 0, n = vertices.length; i < n; i++) + vertices[i] *= scale; + } + attachment.vertices = Utils.toFloatArray(vertices); + return; + } + let weights = new Array(); + let bones = new Array(); + for (let i = 0, n = vertices.length; i < n;) { + let boneCount = vertices[i++]; + bones.push(boneCount); + for (let nn = i + boneCount * 4; i < nn; i += 4) { + bones.push(vertices[i]); + weights.push(vertices[i + 1] * scale); + weights.push(vertices[i + 2] * scale); + weights.push(vertices[i + 3]); + } + } + attachment.bones = bones; + attachment.vertices = Utils.toFloatArray(weights); + } + + readAnimation (map: any, name: string, skeletonData: SkeletonData) { + let scale = this.scale; + let timelines = new Array(); + let duration = 0; + + // Slot timelines. + if (map.slots) { + for (let slotName in map.slots) { + let slotMap = map.slots[slotName]; + let slotIndex = skeletonData.findSlotIndex(slotName); + if (slotIndex == -1) throw new Error("Slot not found: " + slotName); + for (let timelineName in slotMap) { + let timelineMap = slotMap[timelineName]; + if (timelineName == "color") { + let timeline = new ColorTimeline(timelineMap.length); + timeline.slotIndex = slotIndex; + + let frameIndex = 0; + for (let i = 0; i < timelineMap.length; i++) { + let valueMap = timelineMap[i]; + let color = new Color(); + color.setFromString(valueMap.color); + timeline.setFrame(frameIndex, valueMap.time, color.r, color.g, color.b, color.a); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * ColorTimeline.ENTRIES]); + + } else if (timelineName = "attachment") { + let timeline = new AttachmentTimeline(timelineMap.length); + timeline.slotIndex = slotIndex; + + let frameIndex = 0; + for (let i = 0; i < timelineMap.length; i++) { + let valueMap = timelineMap[i]; + timeline.setFrame(frameIndex++, valueMap.time, valueMap.name); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } else + throw new Error("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"); + } + } + } + + // Bone timelines. + if (map.bones) { + for (let boneName in map.bones) { + let boneMap = map.bones[boneName]; + let boneIndex = skeletonData.findBoneIndex(boneName); + if (boneIndex == -1) throw new Error("Bone not found: " + boneName); + for (let timelineName in boneMap) { + let timelineMap = boneMap[timelineName]; + if (timelineName === "rotate") { + let timeline = new RotateTimeline(timelineMap.length); + timeline.boneIndex = boneIndex; + + let frameIndex = 0; + for (let i = 0; i < timelineMap.length; i++) { + let valueMap = timelineMap[i]; + timeline.setFrame(frameIndex, valueMap.time, valueMap.angle); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * RotateTimeline.ENTRIES]); + + } else if (timelineName === "translate" || timelineName === "scale" || timelineName === "shear") { + let timeline: TranslateTimeline = null; + let timelineScale = 1; + if (timelineName === "scale") + timeline = new ScaleTimeline(timelineMap.length); + else if (timelineName === "shear") + timeline = new ShearTimeline(timelineMap.length); + else { + timeline = new TranslateTimeline(timelineMap.length); + timelineScale = scale; + } + timeline.boneIndex = boneIndex; + + let frameIndex = 0; + for (let i = 0; i < timelineMap.length; i++) { + let valueMap = timelineMap[i]; + let x = this.getValue(valueMap, "x", 0), y = this.getValue(valueMap, "y", 0); + timeline.setFrame(frameIndex, valueMap.time, x * timelineScale, y * timelineScale); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * TranslateTimeline.ENTRIES]); + + } else + throw new Error("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"); + } + } + } + + // IK constraint timelines. + if (map.ik) { + for (let constraintName in map.ik) { + let constraintMap = map.ik[constraintName]; + let constraint = skeletonData.findIkConstraint(constraintName); + let timeline = new IkConstraintTimeline(constraintMap.length); + timeline.ikConstraintIndex = skeletonData.ikConstraints.indexOf(constraint); + let frameIndex = 0; + for (let i = 0; i < constraintMap.length; i++) { + let valueMap = constraintMap[i]; + timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, "mix", 1), + this.getValue(valueMap, "bendPositive", true) ? 1 : -1); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * IkConstraintTimeline.ENTRIES]); + } + } + + // Transform constraint timelines. + if (map.transform) { + for (let constraintName in map.transform) { + let constraintMap = map.transform[constraintName]; + let constraint = skeletonData.findTransformConstraint(constraintName); + let timeline = new TransformConstraintTimeline(constraintMap.length); + timeline.transformConstraintIndex = skeletonData.transformConstraints.indexOf(constraint); + let frameIndex = 0; + for (let i = 0; i < constraintMap.length; i++) { + let valueMap = constraintMap[i]; + timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, "rotateMix", 1), + this.getValue(valueMap, "translateMix", 1), this.getValue(valueMap, "scaleMix", 1), this.getValue(valueMap, "shearMix", 1)); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, + timeline.frames[(timeline.getFrameCount() - 1) * TransformConstraintTimeline.ENTRIES]); + } + } + + // Path constraint timelines. + if (map.paths) { + for (let constraintName in map.paths) { + let constraintMap = map.paths[constraintName]; + let index = skeletonData.findPathConstraintIndex(constraintName); + if (index == -1) throw new Error("Path constraint not found: " + constraintName); + let data = skeletonData.pathConstraints[index]; + for (let timelineName in constraintMap) { + let timelineMap = constraintMap[timelineName]; + if (timelineName === "position" || timelineName === "spacing") { + let timeline: PathConstraintPositionTimeline = null; + let timelineScale = 1; + if (timelineName === "spacing") { + timeline = new PathConstraintSpacingTimeline(timelineMap.length); + if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed) timelineScale = scale; + } else { + timeline = new PathConstraintPositionTimeline(timelineMap.length); + if (data.positionMode == PositionMode.Fixed) timelineScale = scale; + } + timeline.pathConstraintIndex = index; + let frameIndex = 0; + for (let i = 0; i < timelineMap.length; i++) { + let valueMap = timelineMap[i]; + timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, timelineName, 0) * timelineScale); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, + timeline.frames[(timeline.getFrameCount() - 1) * PathConstraintPositionTimeline.ENTRIES]); + } else if (timelineName === "mix") { + let timeline = new PathConstraintMixTimeline(timelineMap.length); + timeline.pathConstraintIndex = index; + let frameIndex = 0; + for (let i = 0; i < timelineMap.length; i++) { + let valueMap = timelineMap[i]; + timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, "rotateMix", 1), + this.getValue(valueMap, "translateMix", 1)); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, + timeline.frames[(timeline.getFrameCount() - 1) * PathConstraintMixTimeline.ENTRIES]); + } + } + } + } + + // Deform timelines. + if (map.deform) { + for (let deformName in map.deform) { + let deformMap = map.deform[deformName]; + let skin = skeletonData.findSkin(deformName); + if (skin == null) throw new Error("Skin not found: " + deformName); + for (let slotName in deformMap) { + let slotMap = deformMap[slotName]; + let slotIndex = skeletonData.findSlotIndex(slotName); + if (slotIndex == -1) throw new Error("Slot not found: " + slotMap.name); + for (let timelineName in slotMap) { + let timelineMap = slotMap[timelineName]; + let attachment = skin.getAttachment(slotIndex, timelineName); + if (attachment == null) throw new Error("Deform attachment not found: " + timelineMap.name); + let weighted = attachment.bones != null; + let vertices = attachment.vertices; + let deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; + + let timeline = new DeformTimeline(timelineMap.length); + timeline.slotIndex = slotIndex; + timeline.attachment = attachment; + + let frameIndex = 0; + for (let j = 0; j < timelineMap.length; j++) { + let valueMap = timelineMap[j]; + let deform: ArrayLike; + let verticesValue: Array = this.getValue(valueMap, "vertices", null); + if (verticesValue == null) + deform = weighted ? Utils.newFloatArray(deformLength) : vertices; + else { + deform = Utils.newFloatArray(deformLength); + let start = this.getValue(valueMap, "offset", 0); + Utils.arrayCopy(verticesValue, 0, deform, start, verticesValue.length); + if (scale != 1) { + for (let i = start, n = i + verticesValue.length; i < n; i++) + deform[i] *= scale; + } + if (!weighted) { + for (let i = 0; i < deformLength; i++) + deform[i] += vertices[i]; + } + } + + timeline.setFrame(frameIndex, valueMap.time, deform); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } + } + } + } + + // Draw order timeline. + let drawOrderNode = map.drawOrder; + if (drawOrderNode == null) drawOrderNode = map.draworder; + if (drawOrderNode != null) { + let timeline = new DrawOrderTimeline(drawOrderNode.length); + let slotCount = skeletonData.slots.length; + let frameIndex = 0; + for (let j = 0; j < drawOrderNode.length; j++) { + let drawOrderMap = drawOrderNode[j]; + let drawOrder: Array = null; + let offsets = this.getValue(drawOrderMap, "offsets", null); + if (offsets != null) { + drawOrder = Utils.newArray(slotCount, -1); + let unchanged = Utils.newArray(slotCount - offsets.length, 0); + let originalIndex = 0, unchangedIndex = 0; + for (let i = 0; i < offsets.length; i++) { + let offsetMap = offsets[i]; + let slotIndex = skeletonData.findSlotIndex(offsetMap.slot); + if (slotIndex == -1) throw new Error("Slot not found: " + offsetMap.slot); + // Collect unchanged items. + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + // Set changed items. + drawOrder[originalIndex + offsetMap.offset] = originalIndex++; + } + // Collect remaining unchanged items. + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + // Fill in unchanged items. + for (let i = slotCount - 1; i >= 0; i--) + if (drawOrder[i] == -1) drawOrder[i] = unchanged[--unchangedIndex]; + } + timeline.setFrame(frameIndex++, drawOrderMap.time, drawOrder); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } + + // Event timeline. + if (map.events) { + let timeline = new EventTimeline(map.events.length); + let frameIndex = 0; + for (let i = 0; i < map.events.length; i++) { + let eventMap = map.events[i]; + let eventData = skeletonData.findEvent(eventMap.name); + if (eventData == null) throw new Error("Event not found: " + eventMap.name); + let event = new Event(eventMap.time, eventData); + event.intValue = this.getValue(eventMap, "int", eventData.intValue); + event.floatValue = this.getValue(eventMap, "float", eventData.floatValue); + event.stringValue = this.getValue(eventMap, "string", eventData.stringValue); + timeline.setFrame(frameIndex++, event); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } + + if (isNaN(duration)) { + throw new Error("Error while parsing animation, duration is NaN"); + } + + skeletonData.animations.push(new Animation(name, timelines, duration)); + } + + readCurve (map: any, timeline: CurveTimeline, frameIndex: number) { + if (!map.curve) return; + if (map.curve === "stepped") + timeline.setStepped(frameIndex); + else if (Object.prototype.toString.call(map.curve) === '[object Array]') { + let curve: Array = map.curve; + timeline.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]); + } + } + + getValue (map: any, prop: string, defaultValue: any) { + return map[prop] !== undefined ? map[prop] : defaultValue; + } + + static blendModeFromString (str: string) { + str = str.toLowerCase(); + if (str == "normal") return BlendMode.Normal; + if (str == "additive") return BlendMode.Additive; + if (str == "multiply") return BlendMode.Multiply; + if (str == "screen") return BlendMode.Screen; + throw new Error(`Unknown blend mode: ${str}`); + } + + static positionModeFromString (str: string) { + str = str.toLowerCase(); + if (str == "fixed") return PositionMode.Fixed; + if (str == "percent") return PositionMode.Percent; + throw new Error(`Unknown position mode: ${str}`); + } + + static spacingModeFromString (str: string) { + str = str.toLowerCase(); + if (str == "length") return SpacingMode.Length; + if (str == "fixed") return SpacingMode.Fixed; + if (str == "percent") return SpacingMode.Percent; + throw new Error(`Unknown position mode: ${str}`); + } + + static rotateModeFromString (str: string) { + str = str.toLowerCase(); + if (str == "tangent") return RotateMode.Tangent; + if (str == "chain") return RotateMode.Chain; + if (str == "chainscale") return RotateMode.ChainScale; + throw new Error(`Unknown rotate mode: ${str}`); + } + } + + class LinkedMesh { + parent: string; skin: string; + slotIndex: number; + mesh: MeshAttachment; + + constructor (mesh: MeshAttachment, skin: string, slotIndex: number, parent: string) { + this.mesh = mesh; + this.skin = skin; + this.slotIndex = slotIndex; + this.parent = parent; + } + } } diff --git a/spine-ts/core/src/Skin.ts b/spine-ts/core/src/Skin.ts index 94905641e2..cbc14168f2 100644 --- a/spine-ts/core/src/Skin.ts +++ b/spine-ts/core/src/Skin.ts @@ -1,77 +1,76 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class Skin { - name: string; - attachments = new Array>(); - - constructor (name: string) { - if (name == null) throw new Error("name cannot be null."); - this.name = name; - } - - addAttachment (slotIndex: number, name: string, attachment: Attachment) { - if (attachment == null) throw new Error("attachment cannot be null."); - let attachments = this.attachments; - if (slotIndex >= attachments.length) attachments.length = slotIndex + 1; - if (!attachments[slotIndex]) attachments[slotIndex] = { }; - attachments[slotIndex][name] = attachment; - } - - /** @return May be null. */ - getAttachment (slotIndex: number, name: string): Attachment { - let dictionary = this.attachments[slotIndex]; - return dictionary ? dictionary[name] : null; - } - - /** Attach each attachment in this skin if the corresponding attachment in the old skin is currently attached. */ - attachAll (skeleton: Skeleton, oldSkin: Skin) { - let slotIndex = 0; - for (let i = 0; i < skeleton.slots.length; i++) { - let slot = skeleton.slots[i]; - let slotAttachment = slot.getAttachment(); - if (slotAttachment && slotIndex < oldSkin.attachments.length) { - let dictionary = oldSkin.attachments[slotIndex]; - for (let key in dictionary) { - let skinAttachment:Attachment = dictionary[key]; - if (slotAttachment == skinAttachment) { - let attachment = this.getAttachment(slotIndex, key); - if (attachment != null) slot.setAttachment(attachment); - break; - } - } - } - slotIndex++; - } - } - } +module spine { + export class Skin { + name: string; + attachments = new Array>(); + + constructor (name: string) { + if (name == null) throw new Error("name cannot be null."); + this.name = name; + } + + addAttachment (slotIndex: number, name: string, attachment: Attachment) { + if (attachment == null) throw new Error("attachment cannot be null."); + let attachments = this.attachments; + if (slotIndex >= attachments.length) attachments.length = slotIndex + 1; + if (!attachments[slotIndex]) attachments[slotIndex] = { }; + attachments[slotIndex][name] = attachment; + } + + /** @return May be null. */ + getAttachment (slotIndex: number, name: string): Attachment { + let dictionary = this.attachments[slotIndex]; + return dictionary ? dictionary[name] : null; + } + + /** Attach each attachment in this skin if the corresponding attachment in the old skin is currently attached. */ + attachAll (skeleton: Skeleton, oldSkin: Skin) { + let slotIndex = 0; + for (let i = 0; i < skeleton.slots.length; i++) { + let slot = skeleton.slots[i]; + let slotAttachment = slot.getAttachment(); + if (slotAttachment && slotIndex < oldSkin.attachments.length) { + let dictionary = oldSkin.attachments[slotIndex]; + for (let key in dictionary) { + let skinAttachment:Attachment = dictionary[key]; + if (slotAttachment == skinAttachment) { + let attachment = this.getAttachment(slotIndex, key); + if (attachment != null) slot.setAttachment(attachment); + break; + } + } + } + slotIndex++; + } + } + } } diff --git a/spine-ts/core/src/Slot.ts b/spine-ts/core/src/Slot.ts index 3a761f0824..da636eb71c 100644 --- a/spine-ts/core/src/Slot.ts +++ b/spine-ts/core/src/Slot.ts @@ -1,83 +1,82 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class Slot { - data: SlotData; - bone: Bone; - color: Color; - private attachment: Attachment; - private attachmentTime: number; - attachmentVertices = new Array(); - - constructor (data: SlotData, bone: Bone) { - if (data == null) throw new Error("data cannot be null."); - if (bone == null) throw new Error("bone cannot be null."); - this.data = data; - this.bone = bone; - this.color = new Color(); - this.setToSetupPose(); - } - - /** @return May be null. */ - getAttachment (): Attachment { - return this.attachment; - } - - /** Sets the attachment and if it changed, resets {@link #getAttachmentTime()} and clears {@link #getAttachmentVertices()}. - * @param attachment May be null. */ - setAttachment (attachment: Attachment) { - if (this.attachment == attachment) return; - this.attachment = attachment; - this.attachmentTime = this.bone.skeleton.time; - this.attachmentVertices.length = 0; - } - - setAttachmentTime (time: number) { - this.attachmentTime = this.bone.skeleton.time - time; - } - - /** Returns the time since the attachment was set. */ - getAttachmentTime (): number { - return this.bone.skeleton.time - this.attachmentTime; - } - - setToSetupPose () { - this.color.setFromColor(this.data.color); - if (this.data.attachmentName == null) - this.attachment = null; - else { - this.attachment = null; - this.setAttachment(this.bone.skeleton.getAttachment(this.data.index, this.data.attachmentName)); - } - } - } +module spine { + export class Slot { + data: SlotData; + bone: Bone; + color: Color; + private attachment: Attachment; + private attachmentTime: number; + attachmentVertices = new Array(); + + constructor (data: SlotData, bone: Bone) { + if (data == null) throw new Error("data cannot be null."); + if (bone == null) throw new Error("bone cannot be null."); + this.data = data; + this.bone = bone; + this.color = new Color(); + this.setToSetupPose(); + } + + /** @return May be null. */ + getAttachment (): Attachment { + return this.attachment; + } + + /** Sets the attachment and if it changed, resets {@link #getAttachmentTime()} and clears {@link #getAttachmentVertices()}. + * @param attachment May be null. */ + setAttachment (attachment: Attachment) { + if (this.attachment == attachment) return; + this.attachment = attachment; + this.attachmentTime = this.bone.skeleton.time; + this.attachmentVertices.length = 0; + } + + setAttachmentTime (time: number) { + this.attachmentTime = this.bone.skeleton.time - time; + } + + /** Returns the time since the attachment was set. */ + getAttachmentTime (): number { + return this.bone.skeleton.time - this.attachmentTime; + } + + setToSetupPose () { + this.color.setFromColor(this.data.color); + if (this.data.attachmentName == null) + this.attachment = null; + else { + this.attachment = null; + this.setAttachment(this.bone.skeleton.getAttachment(this.data.index, this.data.attachmentName)); + } + } + } } diff --git a/spine-ts/core/src/SlotData.ts b/spine-ts/core/src/SlotData.ts index ac14a4b317..b93a8c9024 100644 --- a/spine-ts/core/src/SlotData.ts +++ b/spine-ts/core/src/SlotData.ts @@ -1,50 +1,49 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class SlotData { - index: number; - name: string; - boneData: BoneData; - color = new Color(1, 1, 1, 1); - attachmentName: string; - blendMode: BlendMode; - - constructor (index: number, name: string, boneData: BoneData) { - if (index < 0) throw new Error("index must be >= 0."); - if (name == null) throw new Error("name cannot be null."); - if (boneData == null) throw new Error("boneData cannot be null."); - this.index = index; - this.name = name; - this.boneData = boneData; - } - } +module spine { + export class SlotData { + index: number; + name: string; + boneData: BoneData; + color = new Color(1, 1, 1, 1); + attachmentName: string; + blendMode: BlendMode; + + constructor (index: number, name: string, boneData: BoneData) { + if (index < 0) throw new Error("index must be >= 0."); + if (name == null) throw new Error("name cannot be null."); + if (boneData == null) throw new Error("boneData cannot be null."); + this.index = index; + this.name = name; + this.boneData = boneData; + } + } } diff --git a/spine-ts/core/src/Texture.ts b/spine-ts/core/src/Texture.ts index 9ec7215484..c21f795c2d 100644 --- a/spine-ts/core/src/Texture.ts +++ b/spine-ts/core/src/Texture.ts @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ module spine { diff --git a/spine-ts/core/src/TextureAtlas.ts b/spine-ts/core/src/TextureAtlas.ts index 001e416bca..3d64dced66 100644 --- a/spine-ts/core/src/TextureAtlas.ts +++ b/spine-ts/core/src/TextureAtlas.ts @@ -1,213 +1,212 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class TextureAtlas implements Disposable { - pages = new Array(); - regions = new Array(); - - constructor (atlasText: string, textureLoader: (path: string) => any) { - this.load(atlasText, textureLoader); - } - - private load (atlasText: string, textureLoader: (path: string) => any) { - if (textureLoader == null) - throw new Error("textureLoader cannot be null."); - - let reader = new TextureAtlasReader(atlasText); - let tuple = new Array(4); - let page:TextureAtlasPage = null; - while (true) { - let line = reader.readLine(); - if (line == null) - break; - line = line.trim(); - if (line.length == 0) - page = null; - else if (!page) { - page = new TextureAtlasPage(); - page.name = line; - - if (reader.readTuple(tuple) == 2) { // size is only optional for an atlas packed with an old TexturePacker. - page.width = parseInt(tuple[0]); - page.height = parseInt(tuple[1]); - reader.readTuple(tuple); - } - // page.format = Format[tuple[0]]; we don't need format in WebGL - - reader.readTuple(tuple); - page.minFilter = Texture.filterFromString(tuple[0]); - page.magFilter = Texture.filterFromString(tuple[1]); - - let direction= reader.readValue(); - page.uWrap = TextureWrap.ClampToEdge; - page.vWrap = TextureWrap.ClampToEdge; - if (direction == "x") - page.uWrap = TextureWrap.Repeat; - else if (direction == "y") - page.vWrap = TextureWrap.Repeat; - else if (direction == "xy") - page.uWrap = page.vWrap = TextureWrap.Repeat; - - page.texture = textureLoader(line); - page.texture.setFilters(page.minFilter, page.magFilter); - page.texture.setWraps(page.uWrap, page.vWrap); - page.width = page.texture.getImage().width; - page.height = page.texture.getImage().height; - this.pages.push(page); - } else { - let region:TextureAtlasRegion = new TextureAtlasRegion(); - region.name = line; - region.page = page; - - region.rotate = reader.readValue() == "true"; - - reader.readTuple(tuple); - let x = parseInt(tuple[0]); - let y = parseInt(tuple[1]); - - reader.readTuple(tuple); - let width = parseInt(tuple[0]); - let height = parseInt(tuple[1]); - - region.u = x / page.width; - region.v = y / page.height; - if (region.rotate) { - region.u2 = (x + height) / page.width; - region.v2 = (y + width) / page.height; - } else { - region.u2 = (x + width) / page.width; - region.v2 = (y + height) / page.height; - } - region.x = x; - region.y = y; - region.width = Math.abs(width); - region.height = Math.abs(height); - - if (reader.readTuple(tuple) == 4) { // split is optional - // region.splits = new Vector.(parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])); - if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits - //region.pads = Vector.(parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])); - reader.readTuple(tuple); - } - } - - region.originalWidth = parseInt(tuple[0]); - region.originalHeight = parseInt(tuple[1]); - - reader.readTuple(tuple); - region.offsetX = parseInt(tuple[0]); - region.offsetY = parseInt(tuple[1]); - - region.index = parseInt(reader.readValue()); - - region.texture = page.texture; - this.regions.push(region); - } - } - } - - findRegion (name: string): TextureAtlasRegion { - for (let i = 0; i < this.regions.length; i++) { - if (this.regions[i].name == name) { - return this.regions[i]; - } - } - return null; - } - - dispose () { - for (let i = 0; i < this.pages.length; i++) { - this.pages[i].texture.dispose(); - } - } - } - - class TextureAtlasReader { - lines: Array; - index: number = 0; - - constructor (text: string) { - this.lines = text.split(/\r\n|\r|\n/); - } - - readLine (): string { - if (this.index >= this.lines.length) - return null; - return this.lines[this.index++]; - } - - readValue (): string { - let line = this.readLine(); - let colon= line.indexOf(":"); - if (colon == -1) - throw new Error("Invalid line: " + line); - return line.substring(colon + 1).trim(); - } - - readTuple (tuple: Array): number { - let line = this.readLine(); - let colon = line.indexOf(":"); - if (colon == -1) - throw new Error("Invalid line: " + line); - let i = 0, lastMatch = colon + 1; - for (; i < 3; i++) { - let comma = line.indexOf(",", lastMatch); - if (comma == -1) break; - tuple[i] = line.substr(lastMatch, comma - lastMatch).trim(); - lastMatch = comma + 1; - } - tuple[i] = line.substring(lastMatch).trim(); - return i + 1; - } - } - - export class TextureAtlasPage { - name: string; - minFilter: TextureFilter; - magFilter: TextureFilter; - uWrap: TextureWrap; - vWrap: TextureWrap; - texture: Texture; - width: number; - height: number; - } - - export class TextureAtlasRegion extends TextureRegion { - page: TextureAtlasPage; - name: string; - x: number; - y: number; - index: number; - rotate: boolean; - texture: Texture; - } +module spine { + export class TextureAtlas implements Disposable { + pages = new Array(); + regions = new Array(); + + constructor (atlasText: string, textureLoader: (path: string) => any) { + this.load(atlasText, textureLoader); + } + + private load (atlasText: string, textureLoader: (path: string) => any) { + if (textureLoader == null) + throw new Error("textureLoader cannot be null."); + + let reader = new TextureAtlasReader(atlasText); + let tuple = new Array(4); + let page:TextureAtlasPage = null; + while (true) { + let line = reader.readLine(); + if (line == null) + break; + line = line.trim(); + if (line.length == 0) + page = null; + else if (!page) { + page = new TextureAtlasPage(); + page.name = line; + + if (reader.readTuple(tuple) == 2) { // size is only optional for an atlas packed with an old TexturePacker. + page.width = parseInt(tuple[0]); + page.height = parseInt(tuple[1]); + reader.readTuple(tuple); + } + // page.format = Format[tuple[0]]; we don't need format in WebGL + + reader.readTuple(tuple); + page.minFilter = Texture.filterFromString(tuple[0]); + page.magFilter = Texture.filterFromString(tuple[1]); + + let direction= reader.readValue(); + page.uWrap = TextureWrap.ClampToEdge; + page.vWrap = TextureWrap.ClampToEdge; + if (direction == "x") + page.uWrap = TextureWrap.Repeat; + else if (direction == "y") + page.vWrap = TextureWrap.Repeat; + else if (direction == "xy") + page.uWrap = page.vWrap = TextureWrap.Repeat; + + page.texture = textureLoader(line); + page.texture.setFilters(page.minFilter, page.magFilter); + page.texture.setWraps(page.uWrap, page.vWrap); + page.width = page.texture.getImage().width; + page.height = page.texture.getImage().height; + this.pages.push(page); + } else { + let region:TextureAtlasRegion = new TextureAtlasRegion(); + region.name = line; + region.page = page; + + region.rotate = reader.readValue() == "true"; + + reader.readTuple(tuple); + let x = parseInt(tuple[0]); + let y = parseInt(tuple[1]); + + reader.readTuple(tuple); + let width = parseInt(tuple[0]); + let height = parseInt(tuple[1]); + + region.u = x / page.width; + region.v = y / page.height; + if (region.rotate) { + region.u2 = (x + height) / page.width; + region.v2 = (y + width) / page.height; + } else { + region.u2 = (x + width) / page.width; + region.v2 = (y + height) / page.height; + } + region.x = x; + region.y = y; + region.width = Math.abs(width); + region.height = Math.abs(height); + + if (reader.readTuple(tuple) == 4) { // split is optional + // region.splits = new Vector.(parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])); + if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits + //region.pads = Vector.(parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])); + reader.readTuple(tuple); + } + } + + region.originalWidth = parseInt(tuple[0]); + region.originalHeight = parseInt(tuple[1]); + + reader.readTuple(tuple); + region.offsetX = parseInt(tuple[0]); + region.offsetY = parseInt(tuple[1]); + + region.index = parseInt(reader.readValue()); + + region.texture = page.texture; + this.regions.push(region); + } + } + } + + findRegion (name: string): TextureAtlasRegion { + for (let i = 0; i < this.regions.length; i++) { + if (this.regions[i].name == name) { + return this.regions[i]; + } + } + return null; + } + + dispose () { + for (let i = 0; i < this.pages.length; i++) { + this.pages[i].texture.dispose(); + } + } + } + + class TextureAtlasReader { + lines: Array; + index: number = 0; + + constructor (text: string) { + this.lines = text.split(/\r\n|\r|\n/); + } + + readLine (): string { + if (this.index >= this.lines.length) + return null; + return this.lines[this.index++]; + } + + readValue (): string { + let line = this.readLine(); + let colon= line.indexOf(":"); + if (colon == -1) + throw new Error("Invalid line: " + line); + return line.substring(colon + 1).trim(); + } + + readTuple (tuple: Array): number { + let line = this.readLine(); + let colon = line.indexOf(":"); + if (colon == -1) + throw new Error("Invalid line: " + line); + let i = 0, lastMatch = colon + 1; + for (; i < 3; i++) { + let comma = line.indexOf(",", lastMatch); + if (comma == -1) break; + tuple[i] = line.substr(lastMatch, comma - lastMatch).trim(); + lastMatch = comma + 1; + } + tuple[i] = line.substring(lastMatch).trim(); + return i + 1; + } + } + + export class TextureAtlasPage { + name: string; + minFilter: TextureFilter; + magFilter: TextureFilter; + uWrap: TextureWrap; + vWrap: TextureWrap; + texture: Texture; + width: number; + height: number; + } + + export class TextureAtlasRegion extends TextureRegion { + page: TextureAtlasPage; + name: string; + x: number; + y: number; + index: number; + rotate: boolean; + texture: Texture; + } } diff --git a/spine-ts/core/src/TextureAtlasAttachmentLoader.ts b/spine-ts/core/src/TextureAtlasAttachmentLoader.ts index f43d79ee0b..7cb7228c18 100644 --- a/spine-ts/core/src/TextureAtlasAttachmentLoader.ts +++ b/spine-ts/core/src/TextureAtlasAttachmentLoader.ts @@ -1,70 +1,69 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class TextureAtlasAttachmentLoader implements AttachmentLoader { - atlas: TextureAtlas; - - constructor (atlas: TextureAtlas) { - this.atlas = atlas; - } - - /** @return May be null to not load an attachment. */ - newRegionAttachment (skin: Skin, name: string, path: string): RegionAttachment { - let region = this.atlas.findRegion(path); - if (region == null) throw new Error("Region not found in atlas: " + path + " (region attachment: " + name + ")"); - region.renderObject = region; - let attachment = new RegionAttachment(name); - attachment.setRegion(region); - return attachment; - } - - /** @return May be null to not load an attachment. */ - newMeshAttachment (skin: Skin, name: string, path: string) : MeshAttachment { - let region = this.atlas.findRegion(path); - if (region == null) throw new Error("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); - region.renderObject = region; - let attachment = new MeshAttachment(name); - attachment.region = region; - return attachment; - } - - /** @return May be null to not load an attachment. */ - newBoundingBoxAttachment (skin: Skin, name: string) : BoundingBoxAttachment { - return new BoundingBoxAttachment(name); - } - - /** @return May be null to not load an attachment */ - newPathAttachment (skin: Skin, name: string): PathAttachment { - return new PathAttachment(name); - } - } +module spine { + export class TextureAtlasAttachmentLoader implements AttachmentLoader { + atlas: TextureAtlas; + + constructor (atlas: TextureAtlas) { + this.atlas = atlas; + } + + /** @return May be null to not load an attachment. */ + newRegionAttachment (skin: Skin, name: string, path: string): RegionAttachment { + let region = this.atlas.findRegion(path); + if (region == null) throw new Error("Region not found in atlas: " + path + " (region attachment: " + name + ")"); + region.renderObject = region; + let attachment = new RegionAttachment(name); + attachment.setRegion(region); + return attachment; + } + + /** @return May be null to not load an attachment. */ + newMeshAttachment (skin: Skin, name: string, path: string) : MeshAttachment { + let region = this.atlas.findRegion(path); + if (region == null) throw new Error("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); + region.renderObject = region; + let attachment = new MeshAttachment(name); + attachment.region = region; + return attachment; + } + + /** @return May be null to not load an attachment. */ + newBoundingBoxAttachment (skin: Skin, name: string) : BoundingBoxAttachment { + return new BoundingBoxAttachment(name); + } + + /** @return May be null to not load an attachment */ + newPathAttachment (skin: Skin, name: string): PathAttachment { + return new PathAttachment(name); + } + } } diff --git a/spine-ts/core/src/TransformConstraint.ts b/spine-ts/core/src/TransformConstraint.ts index dc628ba355..37417fc0c1 100644 --- a/spine-ts/core/src/TransformConstraint.ts +++ b/spine-ts/core/src/TransformConstraint.ts @@ -1,117 +1,116 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class TransformConstraint implements Updatable { - data: TransformConstraintData; - bones: Array; - target: Bone; - rotateMix = 0; translateMix = 0; scaleMix = 0; shearMix = 0; - temp = new Vector2(); - - constructor (data: TransformConstraintData, skeleton: Skeleton) { - if (data == null) throw new Error("data cannot be null."); - if (skeleton == null) throw new Error("skeleton cannot be null."); - this.data = data; - this.rotateMix = data.rotateMix; - this.translateMix = data.translateMix; - this.scaleMix = data.scaleMix; - this.shearMix = data.shearMix; - this.bones = new Array(); - for (let i = 0; i < data.bones.length; i++) - this.bones.push(skeleton.findBone(data.bones[i].name)); - this.target = skeleton.findBone(data.target.name); - } - - apply () { - this.update(); - } - - update () { - let rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; - let target = this.target; - let ta = target.a, tb = target.b, tc = target.c, td = target.d; - let bones = this.bones; - for (let i = 0, n = bones.length; i < n; i++) { - let bone = bones[i]; - - if (rotateMix > 0) { - let a = bone.a, b = bone.b, c = bone.c, d = bone.d; - let r = Math.atan2(tc, ta) - Math.atan2(c, a) + this.data.offsetRotation * MathUtils.degRad; - if (r > MathUtils.PI) - r -= MathUtils.PI2; - else if (r < -MathUtils.PI) - r += MathUtils.PI2; - r *= rotateMix; - let cos = Math.cos(r), sin = Math.sin(r); - bone.a = cos * a - sin * c; - bone.b = cos * b - sin * d; - bone.c = sin * a + cos * c; - bone.d = sin * b + cos * d; - } - - if (translateMix > 0) { - let temp = this.temp; - target.localToWorld(temp.set(this.data.offsetX, this.data.offsetY)); - bone.worldX += (temp.x - bone.worldX) * translateMix; - bone.worldY += (temp.y - bone.worldY) * translateMix; - } - - if (scaleMix > 0) { - let bs = Math.sqrt(bone.a * bone.a + bone.c * bone.c); - let ts = Math.sqrt(ta * ta + tc * tc); - let s = bs > 0.00001 ? (bs + (ts - bs + this.data.offsetScaleX) * scaleMix) / bs : 0; - bone.a *= s; - bone.c *= s; - bs = Math.sqrt(bone.b * bone.b + bone.d * bone.d); - ts = Math.sqrt(tb * tb + td * td); - s = bs > 0.00001 ? (bs + (ts - bs + this.data.offsetScaleY) * scaleMix) / bs : 0; - bone.b *= s; - bone.d *= s; - } - - if (shearMix > 0) { - let b = bone.b, d = bone.d; - let by = Math.atan2(d, b); - let r = Math.atan2(td, tb) - Math.atan2(tc, ta) - (by - Math.atan2(bone.c, bone.a)); - if (r > MathUtils.PI) - r -= MathUtils.PI2; - else if (r < -MathUtils.PI) - r += MathUtils.PI2; - r = by + (r + this.data.offsetShearY * MathUtils.degRad) * shearMix; - let s = Math.sqrt(b * b + d * d); - bone.b = Math.cos(r) * s; - bone.d = Math.sin(r) * s; - } - } - } - } +module spine { + export class TransformConstraint implements Updatable { + data: TransformConstraintData; + bones: Array; + target: Bone; + rotateMix = 0; translateMix = 0; scaleMix = 0; shearMix = 0; + temp = new Vector2(); + + constructor (data: TransformConstraintData, skeleton: Skeleton) { + if (data == null) throw new Error("data cannot be null."); + if (skeleton == null) throw new Error("skeleton cannot be null."); + this.data = data; + this.rotateMix = data.rotateMix; + this.translateMix = data.translateMix; + this.scaleMix = data.scaleMix; + this.shearMix = data.shearMix; + this.bones = new Array(); + for (let i = 0; i < data.bones.length; i++) + this.bones.push(skeleton.findBone(data.bones[i].name)); + this.target = skeleton.findBone(data.target.name); + } + + apply () { + this.update(); + } + + update () { + let rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; + let target = this.target; + let ta = target.a, tb = target.b, tc = target.c, td = target.d; + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + + if (rotateMix > 0) { + let a = bone.a, b = bone.b, c = bone.c, d = bone.d; + let r = Math.atan2(tc, ta) - Math.atan2(c, a) + this.data.offsetRotation * MathUtils.degRad; + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + r *= rotateMix; + let cos = Math.cos(r), sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + } + + if (translateMix > 0) { + let temp = this.temp; + target.localToWorld(temp.set(this.data.offsetX, this.data.offsetY)); + bone.worldX += (temp.x - bone.worldX) * translateMix; + bone.worldY += (temp.y - bone.worldY) * translateMix; + } + + if (scaleMix > 0) { + let bs = Math.sqrt(bone.a * bone.a + bone.c * bone.c); + let ts = Math.sqrt(ta * ta + tc * tc); + let s = bs > 0.00001 ? (bs + (ts - bs + this.data.offsetScaleX) * scaleMix) / bs : 0; + bone.a *= s; + bone.c *= s; + bs = Math.sqrt(bone.b * bone.b + bone.d * bone.d); + ts = Math.sqrt(tb * tb + td * td); + s = bs > 0.00001 ? (bs + (ts - bs + this.data.offsetScaleY) * scaleMix) / bs : 0; + bone.b *= s; + bone.d *= s; + } + + if (shearMix > 0) { + let b = bone.b, d = bone.d; + let by = Math.atan2(d, b); + let r = Math.atan2(td, tb) - Math.atan2(tc, ta) - (by - Math.atan2(bone.c, bone.a)); + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + r = by + (r + this.data.offsetShearY * MathUtils.degRad) * shearMix; + let s = Math.sqrt(b * b + d * d); + bone.b = Math.cos(r) * s; + bone.d = Math.sin(r) * s; + } + } + } + } } diff --git a/spine-ts/core/src/TransformConstraintData.ts b/spine-ts/core/src/TransformConstraintData.ts index e2144646b0..47f51589d7 100644 --- a/spine-ts/core/src/TransformConstraintData.ts +++ b/spine-ts/core/src/TransformConstraintData.ts @@ -1,45 +1,44 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class TransformConstraintData { - name: string; - bones = new Array(); - target: BoneData; - rotateMix = 0; translateMix = 0; scaleMix = 0; shearMix = 0; - offsetRotation = 0; offsetX = 0; offsetY = 0; offsetScaleX = 0; offsetScaleY = 0; offsetShearY = 0; - - constructor (name: string) { - if (name == null) throw new Error("name cannot be null."); - this.name = name; - } - } +module spine { + export class TransformConstraintData { + name: string; + bones = new Array(); + target: BoneData; + rotateMix = 0; translateMix = 0; scaleMix = 0; shearMix = 0; + offsetRotation = 0; offsetX = 0; offsetY = 0; offsetScaleX = 0; offsetScaleY = 0; offsetShearY = 0; + + constructor (name: string) { + if (name == null) throw new Error("name cannot be null."); + this.name = name; + } + } } diff --git a/spine-ts/core/src/Updatable.ts b/spine-ts/core/src/Updatable.ts index ec2267ebbf..4f05e03fb3 100644 --- a/spine-ts/core/src/Updatable.ts +++ b/spine-ts/core/src/Updatable.ts @@ -1,36 +1,35 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export interface Updatable { - update(): void; - } +module spine { + export interface Updatable { + update(): void; + } } diff --git a/spine-ts/core/src/Utils.ts b/spine-ts/core/src/Utils.ts index 32e10a2410..63aa5b862b 100644 --- a/spine-ts/core/src/Utils.ts +++ b/spine-ts/core/src/Utils.ts @@ -1,269 +1,268 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export interface Map { - [key: string]: T; - } - - export interface Disposable { - dispose (): void; - } - - export class Color { - public static WHITE = new Color(1, 1, 1, 1); - public static RED = new Color(1, 0, 0, 1); - public static GREEN = new Color(0, 1, 0, 1); - public static BLUE = new Color(0, 0, 1, 1); - public static MAGENTA = new Color(1, 0, 1, 1); - - constructor (public r: number = 0, public g: number = 0, public b: number = 0, public a: number = 0) { - } - - set (r: number, g: number, b: number, a: number) { - this.r = r; - this.g = g; - this.b = b; - this.a = a; - this.clamp(); - return this; - } - - setFromColor (c: Color) { - this.r = c.r; - this.g = c.g; - this.b = c.b; - this.a = c.a; - return this; - } - - setFromString (hex: string) { - hex = hex.charAt(0) == '#' ? hex.substr(1) : hex; - this.r = parseInt(hex.substr(0, 2), 16) / 255.0; - this.g = parseInt(hex.substr(2, 2), 16) / 255.0; - this.b = parseInt(hex.substr(4, 2), 16) / 255.0; - this.a = (hex.length != 8 ? 255 : parseInt(hex.substr(6, 2), 16)) / 255.0; - return this; - } - - add (r: number, g: number, b: number, a: number) { - this.r += r; - this.g += g; - this.b += b; - this.a += a; - this.clamp(); - return this; - } - - clamp () { - if (this.r < 0) this.r = 0; - else if (this.r > 1) this.r = 1; - - if (this.g < 0) this.g = 0; - else if (this.g > 1) this.g = 1; - - if (this.b < 0) this.b = 0; - else if (this.b > 1) this.b = 1; - - if (this.a < 0) this.a = 0; - else if (this.a > 1) this.a = 1; - return this; - } - } - - export class MathUtils { - static PI = 3.1415927; - static PI2 = MathUtils.PI * 2; - static radiansToDegrees = 180 / MathUtils.PI; - static radDeg = MathUtils.radiansToDegrees; - static degreesToRadians = MathUtils.PI / 180; - static degRad = MathUtils.degreesToRadians; - - static clamp (value: number, min: number, max: number) { - if (value < min) return min; - if (value > max) return max; - return value; - } - - static cosDeg (degrees: number) { - return Math.cos(degrees * MathUtils.degRad); - } - - static sinDeg (degrees: number) { - return Math.sin(degrees * MathUtils.degRad); - } - - static signum (value: number): number { - return value >= 0 ? 1 : -1; - } - - static toInt (x: number) { - return x > 0 ? Math.floor(x) : Math.ceil(x); - } - - static cbrt (x: number) { - var y = Math.pow(Math.abs(x), 1/3); - return x < 0 ? -y : y; - } - } - - export class Utils { - static SUPPORTS_TYPED_ARRAYS = typeof(Float32Array) !== "undefined"; - - static arrayCopy (source: ArrayLike, sourceStart: number, dest: ArrayLike, destStart: number, numElements: number) { - for (let i = sourceStart, j = destStart; i < sourceStart + numElements; i++, j++) { - dest[j] = source[i]; - } - } - - static setArraySize (array: Array, size: number, value: any = 0): Array { - let oldSize = array.length; - if (oldSize == size) return array; - array.length = size; - if (oldSize < size) { - for (let i = oldSize; i < size; i++) array[i] = value; - } - return array; - } - - static newArray (size: number, defaultValue: T): Array { - let array = new Array(size); - for (let i = 0; i < size; i++) array[i] = defaultValue; - return array; - } - - static newFloatArray (size: number): ArrayLike { - if (Utils.SUPPORTS_TYPED_ARRAYS) { - return new Float32Array(size) - } else { - let array = new Array(size); - for (let i = 0; i < array.length; i++) array[i] = 0; - return array; - } - } - - static toFloatArray (array: Array) { - return Utils.SUPPORTS_TYPED_ARRAYS ? new Float32Array(array) : array; - } - } - - export class DebugUtils { - static logBones(skeleton: Skeleton) { - for (let i = 0; i < skeleton.bones.length; i++) { - let bone = skeleton.bones[i]; - console.log(bone.data.name + ", " + bone.a + ", " + bone.b + ", " + bone.c + ", " + bone.d + ", " + bone.worldX + ", " + bone.worldY); - } - } - } - - export class Pool { - private items = new Array(); - private instantiator: () => T; - - constructor (instantiator: () => T) { - this.instantiator = instantiator; - } - - obtain () { - return this.items.length > 0 ? this.items.pop() : this.instantiator(); - } - - free (item: T) { - this.items.push(item); - } - - freeAll (items: ArrayLike) { - for (let i = 0; i < items.length; i++) this.items[i] = items[i]; - } - - clear () { - this.items.length = 0; - } - } - - export class Vector2 { - constructor (public x = 0, public y = 0) { - } - - set (x: number, y: number): Vector2 { - this.x = x; - this.y = y; - return this; - } - - length () { - let x = this.x; - let y = this.y; - return Math.sqrt(x * x + y * y); - } - - normalize () { - let len = this.length(); - if (len != 0) { - this.x /= len; - this.y /= len; - } - return this; - } - } - - export class TimeKeeper { - maxDelta = 0.064; - framesPerSecond = 0; - delta = 0; - totalTime = 0; - - private lastTime = Date.now() / 1000; - private frameCount = 0; - private frameTime = 0; - - update () { - var now = Date.now() / 1000; - this.delta = now - this.lastTime; - this.frameTime += this.delta; - this.totalTime += this.delta; - if (this.delta > this.maxDelta) this.delta = this.maxDelta; - this.lastTime = now; - - this.frameCount++; - if (this.frameTime > 1) { - this.framesPerSecond = this.frameCount / this.frameTime; - this.frameTime = 0; - this.frameCount = 0; - } - } - } - - export interface ArrayLike { - length: number; - [n: number]: T; - } +module spine { + export interface Map { + [key: string]: T; + } + + export interface Disposable { + dispose (): void; + } + + export class Color { + public static WHITE = new Color(1, 1, 1, 1); + public static RED = new Color(1, 0, 0, 1); + public static GREEN = new Color(0, 1, 0, 1); + public static BLUE = new Color(0, 0, 1, 1); + public static MAGENTA = new Color(1, 0, 1, 1); + + constructor (public r: number = 0, public g: number = 0, public b: number = 0, public a: number = 0) { + } + + set (r: number, g: number, b: number, a: number) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + this.clamp(); + return this; + } + + setFromColor (c: Color) { + this.r = c.r; + this.g = c.g; + this.b = c.b; + this.a = c.a; + return this; + } + + setFromString (hex: string) { + hex = hex.charAt(0) == '#' ? hex.substr(1) : hex; + this.r = parseInt(hex.substr(0, 2), 16) / 255.0; + this.g = parseInt(hex.substr(2, 2), 16) / 255.0; + this.b = parseInt(hex.substr(4, 2), 16) / 255.0; + this.a = (hex.length != 8 ? 255 : parseInt(hex.substr(6, 2), 16)) / 255.0; + return this; + } + + add (r: number, g: number, b: number, a: number) { + this.r += r; + this.g += g; + this.b += b; + this.a += a; + this.clamp(); + return this; + } + + clamp () { + if (this.r < 0) this.r = 0; + else if (this.r > 1) this.r = 1; + + if (this.g < 0) this.g = 0; + else if (this.g > 1) this.g = 1; + + if (this.b < 0) this.b = 0; + else if (this.b > 1) this.b = 1; + + if (this.a < 0) this.a = 0; + else if (this.a > 1) this.a = 1; + return this; + } + } + + export class MathUtils { + static PI = 3.1415927; + static PI2 = MathUtils.PI * 2; + static radiansToDegrees = 180 / MathUtils.PI; + static radDeg = MathUtils.radiansToDegrees; + static degreesToRadians = MathUtils.PI / 180; + static degRad = MathUtils.degreesToRadians; + + static clamp (value: number, min: number, max: number) { + if (value < min) return min; + if (value > max) return max; + return value; + } + + static cosDeg (degrees: number) { + return Math.cos(degrees * MathUtils.degRad); + } + + static sinDeg (degrees: number) { + return Math.sin(degrees * MathUtils.degRad); + } + + static signum (value: number): number { + return value >= 0 ? 1 : -1; + } + + static toInt (x: number) { + return x > 0 ? Math.floor(x) : Math.ceil(x); + } + + static cbrt (x: number) { + var y = Math.pow(Math.abs(x), 1/3); + return x < 0 ? -y : y; + } + } + + export class Utils { + static SUPPORTS_TYPED_ARRAYS = typeof(Float32Array) !== "undefined"; + + static arrayCopy (source: ArrayLike, sourceStart: number, dest: ArrayLike, destStart: number, numElements: number) { + for (let i = sourceStart, j = destStart; i < sourceStart + numElements; i++, j++) { + dest[j] = source[i]; + } + } + + static setArraySize (array: Array, size: number, value: any = 0): Array { + let oldSize = array.length; + if (oldSize == size) return array; + array.length = size; + if (oldSize < size) { + for (let i = oldSize; i < size; i++) array[i] = value; + } + return array; + } + + static newArray (size: number, defaultValue: T): Array { + let array = new Array(size); + for (let i = 0; i < size; i++) array[i] = defaultValue; + return array; + } + + static newFloatArray (size: number): ArrayLike { + if (Utils.SUPPORTS_TYPED_ARRAYS) { + return new Float32Array(size) + } else { + let array = new Array(size); + for (let i = 0; i < array.length; i++) array[i] = 0; + return array; + } + } + + static toFloatArray (array: Array) { + return Utils.SUPPORTS_TYPED_ARRAYS ? new Float32Array(array) : array; + } + } + + export class DebugUtils { + static logBones(skeleton: Skeleton) { + for (let i = 0; i < skeleton.bones.length; i++) { + let bone = skeleton.bones[i]; + console.log(bone.data.name + ", " + bone.a + ", " + bone.b + ", " + bone.c + ", " + bone.d + ", " + bone.worldX + ", " + bone.worldY); + } + } + } + + export class Pool { + private items = new Array(); + private instantiator: () => T; + + constructor (instantiator: () => T) { + this.instantiator = instantiator; + } + + obtain () { + return this.items.length > 0 ? this.items.pop() : this.instantiator(); + } + + free (item: T) { + this.items.push(item); + } + + freeAll (items: ArrayLike) { + for (let i = 0; i < items.length; i++) this.items[i] = items[i]; + } + + clear () { + this.items.length = 0; + } + } + + export class Vector2 { + constructor (public x = 0, public y = 0) { + } + + set (x: number, y: number): Vector2 { + this.x = x; + this.y = y; + return this; + } + + length () { + let x = this.x; + let y = this.y; + return Math.sqrt(x * x + y * y); + } + + normalize () { + let len = this.length(); + if (len != 0) { + this.x /= len; + this.y /= len; + } + return this; + } + } + + export class TimeKeeper { + maxDelta = 0.064; + framesPerSecond = 0; + delta = 0; + totalTime = 0; + + private lastTime = Date.now() / 1000; + private frameCount = 0; + private frameTime = 0; + + update () { + var now = Date.now() / 1000; + this.delta = now - this.lastTime; + this.frameTime += this.delta; + this.totalTime += this.delta; + if (this.delta > this.maxDelta) this.delta = this.maxDelta; + this.lastTime = now; + + this.frameCount++; + if (this.frameTime > 1) { + this.framesPerSecond = this.frameCount / this.frameTime; + this.frameTime = 0; + this.frameCount = 0; + } + } + } + + export interface ArrayLike { + length: number; + [n: number]: T; + } } diff --git a/spine-ts/core/src/attachments/Attachment.ts b/spine-ts/core/src/attachments/Attachment.ts index dfadbaa3c0..cbfd3aa301 100644 --- a/spine-ts/core/src/attachments/Attachment.ts +++ b/spine-ts/core/src/attachments/Attachment.ts @@ -1,124 +1,123 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export abstract class Attachment { - name: string; - - constructor (name: string) { - if (name == null) throw new Error("name cannot be null."); - this.name = name; - } - } - - export abstract class VertexAttachment extends Attachment { - bones: Array; - vertices: ArrayLike; - worldVerticesLength = 0; - - constructor (name: string) { - super(name); - } - - computeWorldVertices (slot: Slot, worldVertices: ArrayLike) { - this.computeWorldVerticesWith(slot, 0, this.worldVerticesLength, worldVertices, 0); - } - - /** Transforms local vertices to world coordinates. - * @param start The index of the first local vertex value to transform. Each vertex has 2 values, x and y. - * @param count The number of world vertex values to output. Must be <= {@link #getWorldVerticesLength()} - start. - * @param worldVertices The output world vertices. Must have a length >= offset + count. - * @param offset The worldVertices index to begin writing values. */ - computeWorldVerticesWith (slot: Slot, start: number, count: number, worldVertices: ArrayLike, offset: number) { - count += offset; - let skeleton = slot.bone.skeleton; - let x = skeleton.x, y = skeleton.y; - let deformArray = slot.attachmentVertices; - let vertices = this.vertices; - let bones = this.bones; - if (bones == null) { - if (deformArray.length > 0) vertices = deformArray; - let bone = slot.bone; - x += bone.worldX; - y += bone.worldY; - let a = bone.a, b = bone.b, c = bone.c, d = bone.d; - for (let v = start, w = offset; w < count; v += 2, w += 2) { - let vx = vertices[v], vy = vertices[v + 1]; - worldVertices[w] = vx * a + vy * b + x; - worldVertices[w + 1] = vx * c + vy * d + y; - } - return; - } - let v = 0, skip = 0; - for (let i = 0; i < start; i += 2) { - let n = bones[v]; - v += n + 1; - skip += n; - } - let skeletonBones = skeleton.bones; - if (deformArray.length == 0) { - for (let w = offset, b = skip * 3; w < count; w += 2) { - let wx = x, wy = y; - let n = bones[v++]; - n += v; - for (; v < n; v++, b += 3) { - let bone = skeletonBones[bones[v]]; - let vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; - wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; - wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; - } - worldVertices[w] = wx; - worldVertices[w + 1] = wy; - } - } else { - let deform = deformArray; - for (let w = offset, b = skip * 3, f = skip << 1; w < count; w += 2) { - let wx = x, wy = y; - let n = bones[v++]; - n += v; - for (; v < n; v++, b += 3, f += 2) { - let bone = skeletonBones[bones[v]]; - let vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; - wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; - wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; - } - worldVertices[w] = wx; - worldVertices[w + 1] = wy; - } - } - } - - /** Returns true if a deform originally applied to the specified attachment should be applied to this attachment. */ - applyDeform (sourceAttachment: VertexAttachment) { - return this == sourceAttachment; - } - } +module spine { + export abstract class Attachment { + name: string; + + constructor (name: string) { + if (name == null) throw new Error("name cannot be null."); + this.name = name; + } + } + + export abstract class VertexAttachment extends Attachment { + bones: Array; + vertices: ArrayLike; + worldVerticesLength = 0; + + constructor (name: string) { + super(name); + } + + computeWorldVertices (slot: Slot, worldVertices: ArrayLike) { + this.computeWorldVerticesWith(slot, 0, this.worldVerticesLength, worldVertices, 0); + } + + /** Transforms local vertices to world coordinates. + * @param start The index of the first local vertex value to transform. Each vertex has 2 values, x and y. + * @param count The number of world vertex values to output. Must be <= {@link #getWorldVerticesLength()} - start. + * @param worldVertices The output world vertices. Must have a length >= offset + count. + * @param offset The worldVertices index to begin writing values. */ + computeWorldVerticesWith (slot: Slot, start: number, count: number, worldVertices: ArrayLike, offset: number) { + count += offset; + let skeleton = slot.bone.skeleton; + let x = skeleton.x, y = skeleton.y; + let deformArray = slot.attachmentVertices; + let vertices = this.vertices; + let bones = this.bones; + if (bones == null) { + if (deformArray.length > 0) vertices = deformArray; + let bone = slot.bone; + x += bone.worldX; + y += bone.worldY; + let a = bone.a, b = bone.b, c = bone.c, d = bone.d; + for (let v = start, w = offset; w < count; v += 2, w += 2) { + let vx = vertices[v], vy = vertices[v + 1]; + worldVertices[w] = vx * a + vy * b + x; + worldVertices[w + 1] = vx * c + vy * d + y; + } + return; + } + let v = 0, skip = 0; + for (let i = 0; i < start; i += 2) { + let n = bones[v]; + v += n + 1; + skip += n; + } + let skeletonBones = skeleton.bones; + if (deformArray.length == 0) { + for (let w = offset, b = skip * 3; w < count; w += 2) { + let wx = x, wy = y; + let n = bones[v++]; + n += v; + for (; v < n; v++, b += 3) { + let bone = skeletonBones[bones[v]]; + let vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } else { + let deform = deformArray; + for (let w = offset, b = skip * 3, f = skip << 1; w < count; w += 2) { + let wx = x, wy = y; + let n = bones[v++]; + n += v; + for (; v < n; v++, b += 3, f += 2) { + let bone = skeletonBones[bones[v]]; + let vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } + } + + /** Returns true if a deform originally applied to the specified attachment should be applied to this attachment. */ + applyDeform (sourceAttachment: VertexAttachment) { + return this == sourceAttachment; + } + } } diff --git a/spine-ts/core/src/attachments/AttachmentLoader.ts b/spine-ts/core/src/attachments/AttachmentLoader.ts index d75dd33ed4..69a5d2eea2 100644 --- a/spine-ts/core/src/attachments/AttachmentLoader.ts +++ b/spine-ts/core/src/attachments/AttachmentLoader.ts @@ -1,46 +1,45 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export interface AttachmentLoader { - /** @return May be null to not load an attachment. */ - newRegionAttachment (skin: Skin, name: string, path: string): RegionAttachment; - - /** @return May be null to not load an attachment. */ - newMeshAttachment (skin: Skin, name: string, path: string) : MeshAttachment; - - /** @return May be null to not load an attachment. */ - newBoundingBoxAttachment (skin: Skin, name: string) : BoundingBoxAttachment; - - /** @return May be null to not load an attachment */ - newPathAttachment(skin: Skin, name: string): PathAttachment; - } +module spine { + export interface AttachmentLoader { + /** @return May be null to not load an attachment. */ + newRegionAttachment (skin: Skin, name: string, path: string): RegionAttachment; + + /** @return May be null to not load an attachment. */ + newMeshAttachment (skin: Skin, name: string, path: string) : MeshAttachment; + + /** @return May be null to not load an attachment. */ + newBoundingBoxAttachment (skin: Skin, name: string) : BoundingBoxAttachment; + + /** @return May be null to not load an attachment */ + newPathAttachment(skin: Skin, name: string): PathAttachment; + } } diff --git a/spine-ts/core/src/attachments/AttachmentType.ts b/spine-ts/core/src/attachments/AttachmentType.ts index ea01e62a86..3f5722eff4 100644 --- a/spine-ts/core/src/attachments/AttachmentType.ts +++ b/spine-ts/core/src/attachments/AttachmentType.ts @@ -1,36 +1,35 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export enum AttachmentType { - Region, BoundingBox, Mesh, LinkedMesh, Path - } +module spine { + export enum AttachmentType { + Region, BoundingBox, Mesh, LinkedMesh, Path + } } diff --git a/spine-ts/core/src/attachments/BoundingBoxAttachment.ts b/spine-ts/core/src/attachments/BoundingBoxAttachment.ts index 5c0aa6ebdd..9e7b3cc628 100644 --- a/spine-ts/core/src/attachments/BoundingBoxAttachment.ts +++ b/spine-ts/core/src/attachments/BoundingBoxAttachment.ts @@ -1,40 +1,39 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class BoundingBoxAttachment extends VertexAttachment { - color = new Color(1, 1, 1, 1); - - constructor (name: string) { - super(name); - } - } +module spine { + export class BoundingBoxAttachment extends VertexAttachment { + color = new Color(1, 1, 1, 1); + + constructor (name: string) { + super(name); + } + } } diff --git a/spine-ts/core/src/attachments/MeshAttachment.ts b/spine-ts/core/src/attachments/MeshAttachment.ts index e1cea39fee..645d7d6281 100644 --- a/spine-ts/core/src/attachments/MeshAttachment.ts +++ b/spine-ts/core/src/attachments/MeshAttachment.ts @@ -1,173 +1,172 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class MeshAttachment extends VertexAttachment { - region: TextureRegion; - path: string; - regionUVs: ArrayLike; worldVertices: ArrayLike; - triangles: Array; - color = new Color(1, 1, 1, 1); - hullLength: number; - private parentMesh: MeshAttachment; - inheritDeform = false; - tempColor = new Color(0, 0, 0, 0); - - constructor (name: string) { - super(name); - } - - updateUVs () { - let regionUVs = this.regionUVs; - let verticesLength = regionUVs.length; - let worldVerticesLength = (verticesLength >> 1) * 8; - if (this.worldVertices == null || this.worldVertices.length != worldVerticesLength) - this.worldVertices = Utils.newFloatArray(worldVerticesLength); - - let u = 0, v = 0, width = 0, height = 0; - if (this.region == null) { - u = v = 0; - width = height = 1; - } else { - u = this.region.u; - v = this.region.v; - width = this.region.u2 - u; - height = this.region.v2 - v; - } - if (this.region.rotate) { - for (let i = 0, w = 6; i < verticesLength; i += 2, w += 8) { - this.worldVertices[w] = u + regionUVs[i + 1] * width; - this.worldVertices[w + 1] = v + height - regionUVs[i] * height; - } - } else { - for (let i = 0, w = 6; i < verticesLength; i += 2, w += 8) { - this.worldVertices[w] = u + regionUVs[i] * width; - this.worldVertices[w + 1] = v + regionUVs[i + 1] * height; - } - } - } - - /** @return The updated world vertices. */ - updateWorldVertices (slot: Slot, premultipliedAlpha: boolean) { - let skeleton = slot.bone.skeleton; - let skeletonColor = skeleton.color, slotColor = slot.color, meshColor = this.color; - let alpha = skeletonColor.a * slotColor.a * meshColor.a; - let multiplier = premultipliedAlpha ? alpha : 1; - let color = this.tempColor; - color.set(skeletonColor.r * slotColor.r * meshColor.r * multiplier, - skeletonColor.g * slotColor.g * meshColor.g * multiplier, - skeletonColor.b * slotColor.b * meshColor.b * multiplier, - alpha); - - let x = skeleton.x, y = skeleton.y; - let deformArray = slot.attachmentVertices; - let vertices = this.vertices, worldVertices = this.worldVertices; - let bones = this.bones; - if (bones == null) { - let verticesLength = vertices.length; - if (deformArray.length > 0) vertices = deformArray; - let bone = slot.bone; - x += bone.worldX; - y += bone.worldY; - let a = bone.a, b = bone.b, c = bone.c, d = bone.d; - for (let v = 0, w = 0; v < verticesLength; v += 2, w += 8) { - let vx = vertices[v], vy = vertices[v + 1]; - worldVertices[w] = vx * a + vy * b + x; - worldVertices[w + 1] = vx * c + vy * d + y; - worldVertices[w + 2] = color.r; - worldVertices[w + 3] = color.g; - worldVertices[w + 4] = color.b; - worldVertices[w + 5] = color.a; - } - return worldVertices; - } - let skeletonBones = skeleton.bones; - if (deformArray.length == 0) { - for (let w = 0, v = 0, b = 0, n = bones.length; v < n; w += 8) { - let wx = x, wy = y; - let nn = bones[v++] + v; - for (; v < nn; v++, b += 3) { - let bone = skeletonBones[bones[v]]; - let vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; - wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; - wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; - } - worldVertices[w] = wx; - worldVertices[w + 1] = wy; - worldVertices[w + 2] = color.r; - worldVertices[w + 3] = color.g; - worldVertices[w + 4] = color.b; - worldVertices[w + 5] = color.a; - } - } else { - let deform = deformArray; - for (let w = 0, v = 0, b = 0, f = 0, n = bones.length; v < n; w += 8) { - let wx = x, wy = y; - let nn = bones[v++] + v; - for (; v < nn; v++, b += 3, f += 2) { - let bone = skeletonBones[bones[v]]; - let vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; - wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; - wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; - } - worldVertices[w] = wx; - worldVertices[w + 1] = wy; - worldVertices[w + 2] = color.r; - worldVertices[w + 3] = color.g; - worldVertices[w + 4] = color.b; - worldVertices[w + 5] = color.a; - } - } - return worldVertices; - } - - applyDeform (sourceAttachment: VertexAttachment): boolean { - return this == sourceAttachment || (this.inheritDeform && this.parentMesh == sourceAttachment); - } - - getParentMesh () { - return this.parentMesh; - } - - /** @param parentMesh May be null. */ - setParentMesh (parentMesh: MeshAttachment) { - this.parentMesh = parentMesh; - if (parentMesh != null) { - this.bones = parentMesh.bones; - this.vertices = parentMesh.vertices; - this.regionUVs = parentMesh.regionUVs; - this.triangles = parentMesh.triangles; - this.hullLength = parentMesh.hullLength; - } - } - } - +module spine { + export class MeshAttachment extends VertexAttachment { + region: TextureRegion; + path: string; + regionUVs: ArrayLike; worldVertices: ArrayLike; + triangles: Array; + color = new Color(1, 1, 1, 1); + hullLength: number; + private parentMesh: MeshAttachment; + inheritDeform = false; + tempColor = new Color(0, 0, 0, 0); + + constructor (name: string) { + super(name); + } + + updateUVs () { + let regionUVs = this.regionUVs; + let verticesLength = regionUVs.length; + let worldVerticesLength = (verticesLength >> 1) * 8; + if (this.worldVertices == null || this.worldVertices.length != worldVerticesLength) + this.worldVertices = Utils.newFloatArray(worldVerticesLength); + + let u = 0, v = 0, width = 0, height = 0; + if (this.region == null) { + u = v = 0; + width = height = 1; + } else { + u = this.region.u; + v = this.region.v; + width = this.region.u2 - u; + height = this.region.v2 - v; + } + if (this.region.rotate) { + for (let i = 0, w = 6; i < verticesLength; i += 2, w += 8) { + this.worldVertices[w] = u + regionUVs[i + 1] * width; + this.worldVertices[w + 1] = v + height - regionUVs[i] * height; + } + } else { + for (let i = 0, w = 6; i < verticesLength; i += 2, w += 8) { + this.worldVertices[w] = u + regionUVs[i] * width; + this.worldVertices[w + 1] = v + regionUVs[i + 1] * height; + } + } + } + + /** @return The updated world vertices. */ + updateWorldVertices (slot: Slot, premultipliedAlpha: boolean) { + let skeleton = slot.bone.skeleton; + let skeletonColor = skeleton.color, slotColor = slot.color, meshColor = this.color; + let alpha = skeletonColor.a * slotColor.a * meshColor.a; + let multiplier = premultipliedAlpha ? alpha : 1; + let color = this.tempColor; + color.set(skeletonColor.r * slotColor.r * meshColor.r * multiplier, + skeletonColor.g * slotColor.g * meshColor.g * multiplier, + skeletonColor.b * slotColor.b * meshColor.b * multiplier, + alpha); + + let x = skeleton.x, y = skeleton.y; + let deformArray = slot.attachmentVertices; + let vertices = this.vertices, worldVertices = this.worldVertices; + let bones = this.bones; + if (bones == null) { + let verticesLength = vertices.length; + if (deformArray.length > 0) vertices = deformArray; + let bone = slot.bone; + x += bone.worldX; + y += bone.worldY; + let a = bone.a, b = bone.b, c = bone.c, d = bone.d; + for (let v = 0, w = 0; v < verticesLength; v += 2, w += 8) { + let vx = vertices[v], vy = vertices[v + 1]; + worldVertices[w] = vx * a + vy * b + x; + worldVertices[w + 1] = vx * c + vy * d + y; + worldVertices[w + 2] = color.r; + worldVertices[w + 3] = color.g; + worldVertices[w + 4] = color.b; + worldVertices[w + 5] = color.a; + } + return worldVertices; + } + let skeletonBones = skeleton.bones; + if (deformArray.length == 0) { + for (let w = 0, v = 0, b = 0, n = bones.length; v < n; w += 8) { + let wx = x, wy = y; + let nn = bones[v++] + v; + for (; v < nn; v++, b += 3) { + let bone = skeletonBones[bones[v]]; + let vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + worldVertices[w + 2] = color.r; + worldVertices[w + 3] = color.g; + worldVertices[w + 4] = color.b; + worldVertices[w + 5] = color.a; + } + } else { + let deform = deformArray; + for (let w = 0, v = 0, b = 0, f = 0, n = bones.length; v < n; w += 8) { + let wx = x, wy = y; + let nn = bones[v++] + v; + for (; v < nn; v++, b += 3, f += 2) { + let bone = skeletonBones[bones[v]]; + let vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + worldVertices[w + 2] = color.r; + worldVertices[w + 3] = color.g; + worldVertices[w + 4] = color.b; + worldVertices[w + 5] = color.a; + } + } + return worldVertices; + } + + applyDeform (sourceAttachment: VertexAttachment): boolean { + return this == sourceAttachment || (this.inheritDeform && this.parentMesh == sourceAttachment); + } + + getParentMesh () { + return this.parentMesh; + } + + /** @param parentMesh May be null. */ + setParentMesh (parentMesh: MeshAttachment) { + this.parentMesh = parentMesh; + if (parentMesh != null) { + this.bones = parentMesh.bones; + this.vertices = parentMesh.vertices; + this.regionUVs = parentMesh.regionUVs; + this.triangles = parentMesh.triangles; + this.hullLength = parentMesh.hullLength; + } + } + } + } diff --git a/spine-ts/core/src/attachments/PathAttachment.ts b/spine-ts/core/src/attachments/PathAttachment.ts index 4f6a5a4629..ed6e424fc5 100644 --- a/spine-ts/core/src/attachments/PathAttachment.ts +++ b/spine-ts/core/src/attachments/PathAttachment.ts @@ -1,42 +1,41 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class PathAttachment extends VertexAttachment { - lengths: Array; - closed = false; constantSpeed = false; - color = new Color(1, 1, 1, 1); - - constructor (name: string) { - super(name); - } - } +module spine { + export class PathAttachment extends VertexAttachment { + lengths: Array; + closed = false; constantSpeed = false; + color = new Color(1, 1, 1, 1); + + constructor (name: string) { + super(name); + } + } } diff --git a/spine-ts/core/src/attachments/RegionAttachment.ts b/spine-ts/core/src/attachments/RegionAttachment.ts index fadc330690..891a44e931 100644 --- a/spine-ts/core/src/attachments/RegionAttachment.ts +++ b/spine-ts/core/src/attachments/RegionAttachment.ts @@ -1,207 +1,206 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class RegionAttachment extends Attachment { - static OX1 = 0; - static OY1 = 1; - static OX2 = 2; - static OY2 = 3; - static OX3 = 4; - static OY3 = 5; - static OX4 = 6; - static OY4 = 7; - - static X1 = 0; - static Y1 = 1; - static C1R = 2; - static C1G = 3; - static C1B = 4; - static C1A = 5; - static U1 = 6; - static V1 = 7; - - static X2 = 8; - static Y2 = 9; - static C2R = 10; - static C2G = 11; - static C2B = 12; - static C2A = 13; - static U2 = 14; - static V2 = 15; - - static X3 = 16; - static Y3 = 17; - static C3R = 18; - static C3G = 19; - static C3B = 20; - static C3A = 21; - static U3 = 22; - static V3 = 23; - - static X4 = 24; - static Y4 = 25; - static C4R = 26; - static C4G = 27; - static C4B = 28; - static C4A = 29; - static U4 = 30; - static V4 = 31; - - x = 0; y = 0; scaleX = 1; scaleY = 1; rotation = 0; width = 0; height = 0; - color = new Color(1, 1, 1, 1); - - path: string; - rendererObject: any; - region: TextureRegion; - - offset = Utils.newFloatArray(8); - vertices = Utils.newFloatArray(8 * 4); - - tempColor = new Color(1, 1, 1, 1); - - constructor (name:string) { - super(name); - } - - setRegion (region: TextureRegion) : void { - let vertices = this.vertices; - if (region.rotate) { - vertices[RegionAttachment.U2] = region.u; - vertices[RegionAttachment.V2] = region.v2; - vertices[RegionAttachment.U3] = region.u; - vertices[RegionAttachment.V3] = region.v; - vertices[RegionAttachment.U4] = region.u2; - vertices[RegionAttachment.V4] = region.v; - vertices[RegionAttachment.U1] = region.u2; - vertices[RegionAttachment.V1] = region.v2; - } else { - vertices[RegionAttachment.U1] = region.u; - vertices[RegionAttachment.V1] = region.v2; - vertices[RegionAttachment.U2] = region.u; - vertices[RegionAttachment.V2] = region.v; - vertices[RegionAttachment.U3] = region.u2; - vertices[RegionAttachment.V3] = region.v; - vertices[RegionAttachment.U4] = region.u2; - vertices[RegionAttachment.V4] = region.v2; - } - this.region = region; - } - - updateOffset () : void { - let regionScaleX = this.width / this.region.originalWidth * this.scaleX; - let regionScaleY = this.height / this.region.originalHeight * this.scaleY; - let localX = -this.width / 2 * this.scaleX + this.region.offsetX * regionScaleX; - let localY = -this.height / 2 * this.scaleY + this.region.offsetY * regionScaleY; - let localX2 = localX + this.region.width * regionScaleX; - let localY2 = localY + this.region.height * regionScaleY; - let radians = this.rotation * Math.PI / 180; - let cos = Math.cos(radians); - let sin = Math.sin(radians); - let localXCos = localX * cos + this.x; - let localXSin = localX * sin; - let localYCos = localY * cos + this.y; - let localYSin = localY * sin; - let localX2Cos = localX2 * cos + this.x; - let localX2Sin = localX2 * sin; - let localY2Cos = localY2 * cos + this.y; - let localY2Sin = localY2 * sin; - let offset = this.offset; - offset[RegionAttachment.OX1] = localXCos - localYSin; - offset[RegionAttachment.OY1] = localYCos + localXSin; - offset[RegionAttachment.OX2] = localXCos - localY2Sin; - offset[RegionAttachment.OY2] = localY2Cos + localXSin; - offset[RegionAttachment.OX3] = localX2Cos - localY2Sin; - offset[RegionAttachment.OY3] = localY2Cos + localX2Sin; - offset[RegionAttachment.OX4] = localX2Cos - localYSin; - offset[RegionAttachment.OY4] = localYCos + localX2Sin; - } - - updateWorldVertices (slot: Slot, premultipliedAlpha: boolean) { - let skeleton = slot.bone.skeleton; - let skeletonColor = skeleton.color; - let slotColor = slot.color; - let regionColor = this.color; - let alpha = skeletonColor.a * slotColor.a * regionColor.a; - let multiplier = premultipliedAlpha ? alpha : 1; - let color = this.tempColor; - color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier, - skeletonColor.g * slotColor.g * regionColor.g * multiplier, - skeletonColor.b * slotColor.b * regionColor.b * multiplier, - alpha); - - let vertices = this.vertices; - let offset = this.offset; - let bone = slot.bone; - let x = skeleton.x + bone.worldX, y = skeleton.y + bone.worldY; - let a = bone.a, b = bone.b, c = bone.c, d = bone.d; - let offsetX = 0, offsetY = 0; - - offsetX = offset[RegionAttachment.OX1]; - offsetY = offset[RegionAttachment.OY1]; - vertices[RegionAttachment.X1] = offsetX * a + offsetY * b + x; // br - vertices[RegionAttachment.Y1] = offsetX * c + offsetY * d + y; - vertices[RegionAttachment.C1R] = color.r; - vertices[RegionAttachment.C1G] = color.g; - vertices[RegionAttachment.C1B] = color.b; - vertices[RegionAttachment.C1A] = color.a; - - offsetX = offset[RegionAttachment.OX2]; - offsetY = offset[RegionAttachment.OY2]; - vertices[RegionAttachment.X2] = offsetX * a + offsetY * b + x; // bl - vertices[RegionAttachment.Y2] = offsetX * c + offsetY * d + y; - vertices[RegionAttachment.C2R] = color.r; - vertices[RegionAttachment.C2G] = color.g; - vertices[RegionAttachment.C2B] = color.b; - vertices[RegionAttachment.C2A] = color.a; - - offsetX = offset[RegionAttachment.OX3]; - offsetY = offset[RegionAttachment.OY3]; - vertices[RegionAttachment.X3] = offsetX * a + offsetY * b + x; // ul - vertices[RegionAttachment.Y3] = offsetX * c + offsetY * d + y; - vertices[RegionAttachment.C3R] = color.r; - vertices[RegionAttachment.C3G] = color.g; - vertices[RegionAttachment.C3B] = color.b; - vertices[RegionAttachment.C3A] = color.a; - - offsetX = offset[RegionAttachment.OX4]; - offsetY = offset[RegionAttachment.OY4]; - vertices[RegionAttachment.X4] = offsetX * a + offsetY * b + x; // ur - vertices[RegionAttachment.Y4] = offsetX * c + offsetY * d + y; - vertices[RegionAttachment.C4R] = color.r; - vertices[RegionAttachment.C4G] = color.g; - vertices[RegionAttachment.C4B] = color.b; - vertices[RegionAttachment.C4A] = color.a; - - return vertices; - } - } +module spine { + export class RegionAttachment extends Attachment { + static OX1 = 0; + static OY1 = 1; + static OX2 = 2; + static OY2 = 3; + static OX3 = 4; + static OY3 = 5; + static OX4 = 6; + static OY4 = 7; + + static X1 = 0; + static Y1 = 1; + static C1R = 2; + static C1G = 3; + static C1B = 4; + static C1A = 5; + static U1 = 6; + static V1 = 7; + + static X2 = 8; + static Y2 = 9; + static C2R = 10; + static C2G = 11; + static C2B = 12; + static C2A = 13; + static U2 = 14; + static V2 = 15; + + static X3 = 16; + static Y3 = 17; + static C3R = 18; + static C3G = 19; + static C3B = 20; + static C3A = 21; + static U3 = 22; + static V3 = 23; + + static X4 = 24; + static Y4 = 25; + static C4R = 26; + static C4G = 27; + static C4B = 28; + static C4A = 29; + static U4 = 30; + static V4 = 31; + + x = 0; y = 0; scaleX = 1; scaleY = 1; rotation = 0; width = 0; height = 0; + color = new Color(1, 1, 1, 1); + + path: string; + rendererObject: any; + region: TextureRegion; + + offset = Utils.newFloatArray(8); + vertices = Utils.newFloatArray(8 * 4); + + tempColor = new Color(1, 1, 1, 1); + + constructor (name:string) { + super(name); + } + + setRegion (region: TextureRegion) : void { + let vertices = this.vertices; + if (region.rotate) { + vertices[RegionAttachment.U2] = region.u; + vertices[RegionAttachment.V2] = region.v2; + vertices[RegionAttachment.U3] = region.u; + vertices[RegionAttachment.V3] = region.v; + vertices[RegionAttachment.U4] = region.u2; + vertices[RegionAttachment.V4] = region.v; + vertices[RegionAttachment.U1] = region.u2; + vertices[RegionAttachment.V1] = region.v2; + } else { + vertices[RegionAttachment.U1] = region.u; + vertices[RegionAttachment.V1] = region.v2; + vertices[RegionAttachment.U2] = region.u; + vertices[RegionAttachment.V2] = region.v; + vertices[RegionAttachment.U3] = region.u2; + vertices[RegionAttachment.V3] = region.v; + vertices[RegionAttachment.U4] = region.u2; + vertices[RegionAttachment.V4] = region.v2; + } + this.region = region; + } + + updateOffset () : void { + let regionScaleX = this.width / this.region.originalWidth * this.scaleX; + let regionScaleY = this.height / this.region.originalHeight * this.scaleY; + let localX = -this.width / 2 * this.scaleX + this.region.offsetX * regionScaleX; + let localY = -this.height / 2 * this.scaleY + this.region.offsetY * regionScaleY; + let localX2 = localX + this.region.width * regionScaleX; + let localY2 = localY + this.region.height * regionScaleY; + let radians = this.rotation * Math.PI / 180; + let cos = Math.cos(radians); + let sin = Math.sin(radians); + let localXCos = localX * cos + this.x; + let localXSin = localX * sin; + let localYCos = localY * cos + this.y; + let localYSin = localY * sin; + let localX2Cos = localX2 * cos + this.x; + let localX2Sin = localX2 * sin; + let localY2Cos = localY2 * cos + this.y; + let localY2Sin = localY2 * sin; + let offset = this.offset; + offset[RegionAttachment.OX1] = localXCos - localYSin; + offset[RegionAttachment.OY1] = localYCos + localXSin; + offset[RegionAttachment.OX2] = localXCos - localY2Sin; + offset[RegionAttachment.OY2] = localY2Cos + localXSin; + offset[RegionAttachment.OX3] = localX2Cos - localY2Sin; + offset[RegionAttachment.OY3] = localY2Cos + localX2Sin; + offset[RegionAttachment.OX4] = localX2Cos - localYSin; + offset[RegionAttachment.OY4] = localYCos + localX2Sin; + } + + updateWorldVertices (slot: Slot, premultipliedAlpha: boolean) { + let skeleton = slot.bone.skeleton; + let skeletonColor = skeleton.color; + let slotColor = slot.color; + let regionColor = this.color; + let alpha = skeletonColor.a * slotColor.a * regionColor.a; + let multiplier = premultipliedAlpha ? alpha : 1; + let color = this.tempColor; + color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier, + skeletonColor.g * slotColor.g * regionColor.g * multiplier, + skeletonColor.b * slotColor.b * regionColor.b * multiplier, + alpha); + + let vertices = this.vertices; + let offset = this.offset; + let bone = slot.bone; + let x = skeleton.x + bone.worldX, y = skeleton.y + bone.worldY; + let a = bone.a, b = bone.b, c = bone.c, d = bone.d; + let offsetX = 0, offsetY = 0; + + offsetX = offset[RegionAttachment.OX1]; + offsetY = offset[RegionAttachment.OY1]; + vertices[RegionAttachment.X1] = offsetX * a + offsetY * b + x; // br + vertices[RegionAttachment.Y1] = offsetX * c + offsetY * d + y; + vertices[RegionAttachment.C1R] = color.r; + vertices[RegionAttachment.C1G] = color.g; + vertices[RegionAttachment.C1B] = color.b; + vertices[RegionAttachment.C1A] = color.a; + + offsetX = offset[RegionAttachment.OX2]; + offsetY = offset[RegionAttachment.OY2]; + vertices[RegionAttachment.X2] = offsetX * a + offsetY * b + x; // bl + vertices[RegionAttachment.Y2] = offsetX * c + offsetY * d + y; + vertices[RegionAttachment.C2R] = color.r; + vertices[RegionAttachment.C2G] = color.g; + vertices[RegionAttachment.C2B] = color.b; + vertices[RegionAttachment.C2A] = color.a; + + offsetX = offset[RegionAttachment.OX3]; + offsetY = offset[RegionAttachment.OY3]; + vertices[RegionAttachment.X3] = offsetX * a + offsetY * b + x; // ul + vertices[RegionAttachment.Y3] = offsetX * c + offsetY * d + y; + vertices[RegionAttachment.C3R] = color.r; + vertices[RegionAttachment.C3G] = color.g; + vertices[RegionAttachment.C3B] = color.b; + vertices[RegionAttachment.C3A] = color.a; + + offsetX = offset[RegionAttachment.OX4]; + offsetY = offset[RegionAttachment.OY4]; + vertices[RegionAttachment.X4] = offsetX * a + offsetY * b + x; // ur + vertices[RegionAttachment.Y4] = offsetX * c + offsetY * d + y; + vertices[RegionAttachment.C4R] = color.r; + vertices[RegionAttachment.C4G] = color.g; + vertices[RegionAttachment.C4B] = color.b; + vertices[RegionAttachment.C4A] = color.a; + + return vertices; + } + } } diff --git a/spine-ts/threejs/src/AssetManager.ts b/spine-ts/threejs/src/AssetManager.ts index a25f54b4ee..50a0e84ea6 100644 --- a/spine-ts/threejs/src/AssetManager.ts +++ b/spine-ts/threejs/src/AssetManager.ts @@ -1,40 +1,39 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.threejs { - export class AssetManager extends spine.AssetManager { - constructor (pathPrefix: string = "") { - super((image: HTMLImageElement) => { - return new ThreeJsTexture(image); - }, pathPrefix); - } - } -} \ No newline at end of file +module spine.threejs { + export class AssetManager extends spine.AssetManager { + constructor (pathPrefix: string = "") { + super((image: HTMLImageElement) => { + return new ThreeJsTexture(image); + }, pathPrefix); + } + } +} diff --git a/spine-ts/threejs/src/MeshBatcher.ts b/spine-ts/threejs/src/MeshBatcher.ts index 9a74e4c1b5..11e70f4ff1 100644 --- a/spine-ts/threejs/src/MeshBatcher.ts +++ b/spine-ts/threejs/src/MeshBatcher.ts @@ -1,103 +1,102 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.threejs { - export class MeshBatcher { - mesh: THREE.Mesh; - - private static VERTEX_SIZE = 9; - private vertexBuffer: THREE.InterleavedBuffer; - private vertices: Float32Array; - private verticesLength = 0; - private indices: Uint16Array; - private indicesLength = 0; - - constructor (mesh: THREE.Mesh, maxVertices: number = 10920) { - if (maxVertices > 10920) throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices); - - let vertices = this.vertices = new Float32Array(maxVertices * MeshBatcher.VERTEX_SIZE); - let indices = this.indices = new Uint16Array(maxVertices * 3); - this.mesh = mesh; - let geo = new THREE.BufferGeometry(); - let vertexBuffer = this.vertexBuffer = new THREE.InterleavedBuffer(vertices, MeshBatcher.VERTEX_SIZE); - vertexBuffer.dynamic = true; - geo.addAttribute("position", new THREE.InterleavedBufferAttribute(vertexBuffer, 3, 0, false)); - geo.addAttribute("color", new THREE.InterleavedBufferAttribute(vertexBuffer, 4, 3, false)); - geo.addAttribute("uv", new THREE.InterleavedBufferAttribute(vertexBuffer, 2, 7, false)); - geo.setIndex(new THREE.BufferAttribute(indices, 1)); - geo.getIndex().dynamic = true; - geo.drawRange.start = 0; - geo.drawRange.count = 0; - mesh.geometry = geo; - } - - begin () { - this.verticesLength = 0; - this.indicesLength = 0; - } - - batch (vertices: ArrayLike, indices: ArrayLike, z: number = 0) { - let indexStart = this.verticesLength / MeshBatcher.VERTEX_SIZE; - let vertexBuffer = this.vertices; - let i = this.verticesLength; - let j = 0; - for (;j < vertices.length;) { - vertexBuffer[i++] = vertices[j++]; - vertexBuffer[i++] = vertices[j++]; - vertexBuffer[i++] = z; - vertexBuffer[i++] = vertices[j++]; - vertexBuffer[i++] = vertices[j++]; - vertexBuffer[i++] = vertices[j++]; - vertexBuffer[i++] = vertices[j++]; - vertexBuffer[i++] = vertices[j++]; - vertexBuffer[i++] = vertices[j++]; - } - this.verticesLength = i; - - let indicesArray = this.indices; - for (i = this.indicesLength, j = 0; j < indices.length; i++, j++) - indicesArray[i] = indices[j] + indexStart; - this.indicesLength += indices.length; - } - - end () { - this.vertexBuffer.needsUpdate = true; - this.vertexBuffer.updateRange.offset = 0; - this.vertexBuffer.updateRange.count = this.verticesLength; - let geo = (this.mesh.geometry); - geo.getIndex().needsUpdate = true; - geo.getIndex().updateRange.offset = 0; - geo.getIndex().updateRange.count = this.indicesLength; - geo.drawRange.start = 0; - geo.drawRange.count = this.indicesLength; - } - } -} \ No newline at end of file +module spine.threejs { + export class MeshBatcher { + mesh: THREE.Mesh; + + private static VERTEX_SIZE = 9; + private vertexBuffer: THREE.InterleavedBuffer; + private vertices: Float32Array; + private verticesLength = 0; + private indices: Uint16Array; + private indicesLength = 0; + + constructor (mesh: THREE.Mesh, maxVertices: number = 10920) { + if (maxVertices > 10920) throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices); + + let vertices = this.vertices = new Float32Array(maxVertices * MeshBatcher.VERTEX_SIZE); + let indices = this.indices = new Uint16Array(maxVertices * 3); + this.mesh = mesh; + let geo = new THREE.BufferGeometry(); + let vertexBuffer = this.vertexBuffer = new THREE.InterleavedBuffer(vertices, MeshBatcher.VERTEX_SIZE); + vertexBuffer.dynamic = true; + geo.addAttribute("position", new THREE.InterleavedBufferAttribute(vertexBuffer, 3, 0, false)); + geo.addAttribute("color", new THREE.InterleavedBufferAttribute(vertexBuffer, 4, 3, false)); + geo.addAttribute("uv", new THREE.InterleavedBufferAttribute(vertexBuffer, 2, 7, false)); + geo.setIndex(new THREE.BufferAttribute(indices, 1)); + geo.getIndex().dynamic = true; + geo.drawRange.start = 0; + geo.drawRange.count = 0; + mesh.geometry = geo; + } + + begin () { + this.verticesLength = 0; + this.indicesLength = 0; + } + + batch (vertices: ArrayLike, indices: ArrayLike, z: number = 0) { + let indexStart = this.verticesLength / MeshBatcher.VERTEX_SIZE; + let vertexBuffer = this.vertices; + let i = this.verticesLength; + let j = 0; + for (;j < vertices.length;) { + vertexBuffer[i++] = vertices[j++]; + vertexBuffer[i++] = vertices[j++]; + vertexBuffer[i++] = z; + vertexBuffer[i++] = vertices[j++]; + vertexBuffer[i++] = vertices[j++]; + vertexBuffer[i++] = vertices[j++]; + vertexBuffer[i++] = vertices[j++]; + vertexBuffer[i++] = vertices[j++]; + vertexBuffer[i++] = vertices[j++]; + } + this.verticesLength = i; + + let indicesArray = this.indices; + for (i = this.indicesLength, j = 0; j < indices.length; i++, j++) + indicesArray[i] = indices[j] + indexStart; + this.indicesLength += indices.length; + } + + end () { + this.vertexBuffer.needsUpdate = true; + this.vertexBuffer.updateRange.offset = 0; + this.vertexBuffer.updateRange.count = this.verticesLength; + let geo = (this.mesh.geometry); + geo.getIndex().needsUpdate = true; + geo.getIndex().updateRange.offset = 0; + geo.getIndex().updateRange.count = this.indicesLength; + geo.drawRange.start = 0; + geo.drawRange.count = this.indicesLength; + } + } +} diff --git a/spine-ts/threejs/src/SkeletonMesh.ts b/spine-ts/threejs/src/SkeletonMesh.ts index b06aaaae55..bd5488cbae 100644 --- a/spine-ts/threejs/src/SkeletonMesh.ts +++ b/spine-ts/threejs/src/SkeletonMesh.ts @@ -1,152 +1,151 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.threejs { - export class SkeletonMesh extends THREE.Mesh { - - skeleton: Skeleton; - state: AnimationState; - zOffset: number = 0.1; - - private batcher: MeshBatcher; - - static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; - - constructor (skeletonData: SkeletonData) { - super(); - - this.skeleton = new Skeleton(skeletonData); - let animData = new AnimationStateData(skeletonData); - this.state = new AnimationState(animData); - - let material = this.material = new THREE.MeshBasicMaterial(); - material.side = THREE.DoubleSide; - material.transparent = true; - material.alphaTest = 0.5; - this.batcher = new MeshBatcher(this); - } - - update(deltaTime: number) { - let state = this.state; - let skeleton = this.skeleton; - - state.update(deltaTime); - state.apply(skeleton); - skeleton.updateWorldTransform(); - - this.updateGeometry(); - } - - private updateGeometry() { - let geometry = this.geometry; - var numVertices = 0; - var verticesLength = 0; - var indicesLength = 0; - - let blendMode: BlendMode = null; - - let vertices: ArrayLike = null; - let triangles: Array = null; - let drawOrder = this.skeleton.drawOrder; - let batcher = this.batcher; - batcher.begin(); - let z = 0; - let zOffset = this.zOffset; - for (let i = 0, n = drawOrder.length; i < n; i++) { - let slot = drawOrder[i]; - let attachment = slot.getAttachment(); - let texture: ThreeJsTexture = null; - if (attachment instanceof RegionAttachment) { - let region = attachment; - vertices = region.updateWorldVertices(slot, false); - triangles = SkeletonMesh.QUAD_TRIANGLES; - texture = (region.region.renderObject).texture; - - } else if (attachment instanceof MeshAttachment) { - let mesh = attachment; - vertices = mesh.updateWorldVertices(slot, false); - triangles = mesh.triangles; - texture = (mesh.region.renderObject).texture; - } else continue; - - if (texture != null) { - if (!(this.material).map) { - let mat = this.material; - mat.map = texture.texture; - mat.needsUpdate = true; - } - // FIXME per slot blending would require multiple material support - //let slotBlendMode = slot.data.blendMode; - //if (slotBlendMode != blendMode) { - // blendMode = slotBlendMode; - // batcher.setBlendMode(getSourceGLBlendMode(this._gl, blendMode, premultipliedAlpha), getDestGLBlendMode(this._gl, blendMode)); - //} - - this.batcher.batch(vertices, triangles, z); - z += zOffset; - } - } - - batcher.end(); - } - - static createMesh(map: THREE.Texture) { - let geo = new THREE.BufferGeometry(); - let vertices = new Float32Array(1024); - vertices.set([ - -200, -200, 1, 0, 0, 1, 0, 0, - 200, -200, 0, 1, 0, 1, 1, 0, - 200, 200, 0, 0, 1, 1, 1, 1, - -200, 200, 1, 1, 0, 0.1, 0, 1 - ], 0); - let vb = new THREE.InterleavedBuffer(vertices, 8); - var positions = new THREE.InterleavedBufferAttribute(vb, 2, 0, false); - geo.addAttribute("position", positions); - var colors = new THREE.InterleavedBufferAttribute(vb, 4, 2, false); - geo.addAttribute("color", colors); - var uvs = new THREE.InterleavedBufferAttribute(vb, 2, 6, false); - geo.addAttribute("uv", colors); - - var indices = new Uint16Array(1024); - indices.set([0, 1, 2, 2, 3, 0], 0); - geo.setIndex(new THREE.BufferAttribute(indices, 1)); - geo.drawRange.start = 0; - geo.drawRange.count = 6; - - let mat = new THREE.MeshBasicMaterial(); - mat.vertexColors = THREE.VertexColors; - mat.transparent = true; - mat.map = map; - let mesh = new THREE.Mesh(geo, mat); - return mesh; - } - } -} \ No newline at end of file +module spine.threejs { + export class SkeletonMesh extends THREE.Mesh { + + skeleton: Skeleton; + state: AnimationState; + zOffset: number = 0.1; + + private batcher: MeshBatcher; + + static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; + + constructor (skeletonData: SkeletonData) { + super(); + + this.skeleton = new Skeleton(skeletonData); + let animData = new AnimationStateData(skeletonData); + this.state = new AnimationState(animData); + + let material = this.material = new THREE.MeshBasicMaterial(); + material.side = THREE.DoubleSide; + material.transparent = true; + material.alphaTest = 0.5; + this.batcher = new MeshBatcher(this); + } + + update(deltaTime: number) { + let state = this.state; + let skeleton = this.skeleton; + + state.update(deltaTime); + state.apply(skeleton); + skeleton.updateWorldTransform(); + + this.updateGeometry(); + } + + private updateGeometry() { + let geometry = this.geometry; + var numVertices = 0; + var verticesLength = 0; + var indicesLength = 0; + + let blendMode: BlendMode = null; + + let vertices: ArrayLike = null; + let triangles: Array = null; + let drawOrder = this.skeleton.drawOrder; + let batcher = this.batcher; + batcher.begin(); + let z = 0; + let zOffset = this.zOffset; + for (let i = 0, n = drawOrder.length; i < n; i++) { + let slot = drawOrder[i]; + let attachment = slot.getAttachment(); + let texture: ThreeJsTexture = null; + if (attachment instanceof RegionAttachment) { + let region = attachment; + vertices = region.updateWorldVertices(slot, false); + triangles = SkeletonMesh.QUAD_TRIANGLES; + texture = (region.region.renderObject).texture; + + } else if (attachment instanceof MeshAttachment) { + let mesh = attachment; + vertices = mesh.updateWorldVertices(slot, false); + triangles = mesh.triangles; + texture = (mesh.region.renderObject).texture; + } else continue; + + if (texture != null) { + if (!(this.material).map) { + let mat = this.material; + mat.map = texture.texture; + mat.needsUpdate = true; + } + // FIXME per slot blending would require multiple material support + //let slotBlendMode = slot.data.blendMode; + //if (slotBlendMode != blendMode) { + // blendMode = slotBlendMode; + // batcher.setBlendMode(getSourceGLBlendMode(this._gl, blendMode, premultipliedAlpha), getDestGLBlendMode(this._gl, blendMode)); + //} + + this.batcher.batch(vertices, triangles, z); + z += zOffset; + } + } + + batcher.end(); + } + + static createMesh(map: THREE.Texture) { + let geo = new THREE.BufferGeometry(); + let vertices = new Float32Array(1024); + vertices.set([ + -200, -200, 1, 0, 0, 1, 0, 0, + 200, -200, 0, 1, 0, 1, 1, 0, + 200, 200, 0, 0, 1, 1, 1, 1, + -200, 200, 1, 1, 0, 0.1, 0, 1 + ], 0); + let vb = new THREE.InterleavedBuffer(vertices, 8); + var positions = new THREE.InterleavedBufferAttribute(vb, 2, 0, false); + geo.addAttribute("position", positions); + var colors = new THREE.InterleavedBufferAttribute(vb, 4, 2, false); + geo.addAttribute("color", colors); + var uvs = new THREE.InterleavedBufferAttribute(vb, 2, 6, false); + geo.addAttribute("uv", colors); + + var indices = new Uint16Array(1024); + indices.set([0, 1, 2, 2, 3, 0], 0); + geo.setIndex(new THREE.BufferAttribute(indices, 1)); + geo.drawRange.start = 0; + geo.drawRange.count = 6; + + let mat = new THREE.MeshBasicMaterial(); + mat.vertexColors = THREE.VertexColors; + mat.transparent = true; + mat.map = map; + let mesh = new THREE.Mesh(geo, mat); + return mesh; + } + } +} diff --git a/spine-ts/threejs/src/ThreeJsTexture.ts b/spine-ts/threejs/src/ThreeJsTexture.ts index a80b178c91..966a62dda8 100644 --- a/spine-ts/threejs/src/ThreeJsTexture.ts +++ b/spine-ts/threejs/src/ThreeJsTexture.ts @@ -1,74 +1,73 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.threejs { - export class ThreeJsTexture extends Texture { - texture: THREE.Texture; - - constructor (image: HTMLImageElement) { - super(image); - this.texture = new THREE.Texture(image); - this.texture.flipY = false; - this.texture.needsUpdate = true; - } - - setFilters (minFilter: TextureFilter, magFilter: TextureFilter) { - this.texture.minFilter = ThreeJsTexture.toThreeJsTextureFilter(minFilter); - this.texture.magFilter = ThreeJsTexture.toThreeJsTextureFilter(magFilter); - } - - setWraps (uWrap: TextureWrap, vWrap: TextureWrap) { - this.texture.wrapS = ThreeJsTexture.toThreeJsTextureWrap(uWrap); - this.texture.wrapT = ThreeJsTexture.toThreeJsTextureWrap(vWrap); - } - - dispose () { - this.texture.dispose(); - } - - static toThreeJsTextureFilter(filter: TextureFilter) { - if (filter === TextureFilter.Linear) return THREE.LinearFilter; - else if (filter === TextureFilter.MipMap) return THREE.LinearMipMapLinearFilter; // also includes TextureFilter.MipMapLinearLinear - else if (filter === TextureFilter.MipMapLinearNearest) return THREE.LinearMipMapNearestFilter; - else if (filter === TextureFilter.MipMapNearestLinear) return THREE.NearestMipMapLinearFilter; - else if (filter === TextureFilter.MipMapNearestNearest) return THREE.NearestMipMapNearestFilter; - else if (filter === TextureFilter.Nearest) return THREE.NearestFilter; - else throw new Error("Unknown texture filter: " + filter); - } - - static toThreeJsTextureWrap(wrap: TextureWrap) { - if (wrap === TextureWrap.ClampToEdge) return THREE.ClampToEdgeWrapping; - else if (wrap === TextureWrap.MirroredRepeat) return THREE.MirroredRepeatWrapping; - else if (wrap === TextureWrap.Repeat) return THREE.RepeatWrapping; - else throw new Error("Unknown texture wrap: " + wrap); - } - } -} \ No newline at end of file +module spine.threejs { + export class ThreeJsTexture extends Texture { + texture: THREE.Texture; + + constructor (image: HTMLImageElement) { + super(image); + this.texture = new THREE.Texture(image); + this.texture.flipY = false; + this.texture.needsUpdate = true; + } + + setFilters (minFilter: TextureFilter, magFilter: TextureFilter) { + this.texture.minFilter = ThreeJsTexture.toThreeJsTextureFilter(minFilter); + this.texture.magFilter = ThreeJsTexture.toThreeJsTextureFilter(magFilter); + } + + setWraps (uWrap: TextureWrap, vWrap: TextureWrap) { + this.texture.wrapS = ThreeJsTexture.toThreeJsTextureWrap(uWrap); + this.texture.wrapT = ThreeJsTexture.toThreeJsTextureWrap(vWrap); + } + + dispose () { + this.texture.dispose(); + } + + static toThreeJsTextureFilter(filter: TextureFilter) { + if (filter === TextureFilter.Linear) return THREE.LinearFilter; + else if (filter === TextureFilter.MipMap) return THREE.LinearMipMapLinearFilter; // also includes TextureFilter.MipMapLinearLinear + else if (filter === TextureFilter.MipMapLinearNearest) return THREE.LinearMipMapNearestFilter; + else if (filter === TextureFilter.MipMapNearestLinear) return THREE.NearestMipMapLinearFilter; + else if (filter === TextureFilter.MipMapNearestNearest) return THREE.NearestMipMapNearestFilter; + else if (filter === TextureFilter.Nearest) return THREE.NearestFilter; + else throw new Error("Unknown texture filter: " + filter); + } + + static toThreeJsTextureWrap(wrap: TextureWrap) { + if (wrap === TextureWrap.ClampToEdge) return THREE.ClampToEdgeWrapping; + else if (wrap === TextureWrap.MirroredRepeat) return THREE.MirroredRepeatWrapping; + else if (wrap === TextureWrap.Repeat) return THREE.RepeatWrapping; + else throw new Error("Unknown texture wrap: " + wrap); + } + } +} diff --git a/spine-ts/webgl/src/AssetManager.ts b/spine-ts/webgl/src/AssetManager.ts index e6488db1db..ef6416ab00 100644 --- a/spine-ts/webgl/src/AssetManager.ts +++ b/spine-ts/webgl/src/AssetManager.ts @@ -1,40 +1,39 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.webgl { - export class AssetManager extends spine.AssetManager { - constructor (gl: WebGLRenderingContext, pathPrefix: string = "") { - super((image: HTMLImageElement) => { - return new spine.webgl.GLTexture(gl, image); - }, pathPrefix); - } - } -} \ No newline at end of file +module spine.webgl { + export class AssetManager extends spine.AssetManager { + constructor (gl: WebGLRenderingContext, pathPrefix: string = "") { + super((image: HTMLImageElement) => { + return new spine.webgl.GLTexture(gl, image); + }, pathPrefix); + } + } +} diff --git a/spine-ts/webgl/src/Camera.ts b/spine-ts/webgl/src/Camera.ts index ce68a18f0e..22ba83353b 100644 --- a/spine-ts/webgl/src/Camera.ts +++ b/spine-ts/webgl/src/Camera.ts @@ -1,86 +1,85 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.webgl { - export class OrthoCamera { - position = new Vector3(0, 0, 0); - direction = new Vector3(0, 0, -1); - up = new Vector3(0, 1, 0); - near = 0; - far = 100; - zoom = 1; - viewportWidth = 0; - viewportHeight = 0; - projectionView = new Matrix4(); - inverseProjectionView = new Matrix4(); - projection = new Matrix4(); - view = new Matrix4(); - - private tmp = new Vector3(); - - constructor (viewportWidth: number, viewportHeight: number) { - this.viewportWidth = viewportWidth; - this.viewportHeight = viewportHeight; - this.update(); - } - - update () { - let projection = this.projection; - let view = this.view; - let projectionView = this.projectionView; - let inverseProjectionView = this.inverseProjectionView; - let zoom = this.zoom, viewportWidth = this.viewportWidth, viewportHeight = this.viewportHeight; - projection.ortho(zoom * (-viewportWidth / 2), zoom * (viewportWidth / 2), - zoom * (-viewportHeight / 2), zoom * (viewportHeight / 2), - this.near, this.far); - view.lookAt(this.position, this.direction, this.up); - projectionView.set(projection.values); - projectionView.multiply(view); - inverseProjectionView.set(projectionView.values).invert(); - } - - screenToWorld (screenCoords: Vector3, screenWidth: number, screenHeight: number) { - let x = screenCoords.x, y = screenHeight - screenCoords.y - 1; - let tmp = this.tmp; - tmp.x = (2 * x) / screenWidth - 1; - tmp.y = (2 * y) / screenHeight - 1; - tmp.z = (2 * screenCoords.z) - 1; - tmp.project(this.inverseProjectionView); - screenCoords.set(tmp.x, tmp.y, tmp.z); - return screenCoords; - } - - setViewport(viewportWidth: number, viewportHeight: number) { - this.viewportWidth = viewportWidth; - this.viewportHeight = viewportHeight; - } - } -} \ No newline at end of file +module spine.webgl { + export class OrthoCamera { + position = new Vector3(0, 0, 0); + direction = new Vector3(0, 0, -1); + up = new Vector3(0, 1, 0); + near = 0; + far = 100; + zoom = 1; + viewportWidth = 0; + viewportHeight = 0; + projectionView = new Matrix4(); + inverseProjectionView = new Matrix4(); + projection = new Matrix4(); + view = new Matrix4(); + + private tmp = new Vector3(); + + constructor (viewportWidth: number, viewportHeight: number) { + this.viewportWidth = viewportWidth; + this.viewportHeight = viewportHeight; + this.update(); + } + + update () { + let projection = this.projection; + let view = this.view; + let projectionView = this.projectionView; + let inverseProjectionView = this.inverseProjectionView; + let zoom = this.zoom, viewportWidth = this.viewportWidth, viewportHeight = this.viewportHeight; + projection.ortho(zoom * (-viewportWidth / 2), zoom * (viewportWidth / 2), + zoom * (-viewportHeight / 2), zoom * (viewportHeight / 2), + this.near, this.far); + view.lookAt(this.position, this.direction, this.up); + projectionView.set(projection.values); + projectionView.multiply(view); + inverseProjectionView.set(projectionView.values).invert(); + } + + screenToWorld (screenCoords: Vector3, screenWidth: number, screenHeight: number) { + let x = screenCoords.x, y = screenHeight - screenCoords.y - 1; + let tmp = this.tmp; + tmp.x = (2 * x) / screenWidth - 1; + tmp.y = (2 * y) / screenHeight - 1; + tmp.z = (2 * screenCoords.z) - 1; + tmp.project(this.inverseProjectionView); + screenCoords.set(tmp.x, tmp.y, tmp.z); + return screenCoords; + } + + setViewport(viewportWidth: number, viewportHeight: number) { + this.viewportWidth = viewportWidth; + this.viewportHeight = viewportHeight; + } + } +} diff --git a/spine-ts/webgl/src/GLTexture.ts b/spine-ts/webgl/src/GLTexture.ts index d2e61e72c0..35e42747a9 100644 --- a/spine-ts/webgl/src/GLTexture.ts +++ b/spine-ts/webgl/src/GLTexture.ts @@ -1,88 +1,87 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.webgl { - export class GLTexture extends Texture implements Disposable { - private gl: WebGLRenderingContext; - private texture: WebGLTexture; - private boundUnit = 0; - - constructor (gl: WebGLRenderingContext, image: HTMLImageElement, useMipMaps: boolean = false) { - super(image); - this.gl = gl; - this.texture = gl.createTexture(); - this.update(useMipMaps); - } - - setFilters (minFilter: TextureFilter, magFilter: TextureFilter) { - let gl = this.gl; - this.bind(); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magFilter); - } - - setWraps (uWrap: TextureWrap, vWrap: TextureWrap) { - let gl = this.gl; - this.bind(); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, uWrap); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, vWrap); - } - - update (useMipMaps: boolean) { - let gl = this.gl; - this.bind(); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._image); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, useMipMaps ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - if (useMipMaps) gl.generateMipmap(gl.TEXTURE_2D); - } - - bind (unit: number = 0) { - let gl = this.gl; - this.boundUnit = unit; - gl.activeTexture(gl.TEXTURE0 + unit); - gl.bindTexture(gl.TEXTURE_2D, this.texture); - } - - unbind () { - let gl = this.gl; - gl.activeTexture(gl.TEXTURE0 + this.boundUnit); - gl.bindTexture(gl.TEXTURE_2D, null); - } - - dispose () { - let gl = this.gl; - gl.deleteTexture(this.texture); - } - } +module spine.webgl { + export class GLTexture extends Texture implements Disposable { + private gl: WebGLRenderingContext; + private texture: WebGLTexture; + private boundUnit = 0; + + constructor (gl: WebGLRenderingContext, image: HTMLImageElement, useMipMaps: boolean = false) { + super(image); + this.gl = gl; + this.texture = gl.createTexture(); + this.update(useMipMaps); + } + + setFilters (minFilter: TextureFilter, magFilter: TextureFilter) { + let gl = this.gl; + this.bind(); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magFilter); + } + + setWraps (uWrap: TextureWrap, vWrap: TextureWrap) { + let gl = this.gl; + this.bind(); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, uWrap); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, vWrap); + } + + update (useMipMaps: boolean) { + let gl = this.gl; + this.bind(); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, useMipMaps ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + if (useMipMaps) gl.generateMipmap(gl.TEXTURE_2D); + } + + bind (unit: number = 0) { + let gl = this.gl; + this.boundUnit = unit; + gl.activeTexture(gl.TEXTURE0 + unit); + gl.bindTexture(gl.TEXTURE_2D, this.texture); + } + + unbind () { + let gl = this.gl; + gl.activeTexture(gl.TEXTURE0 + this.boundUnit); + gl.bindTexture(gl.TEXTURE_2D, null); + } + + dispose () { + let gl = this.gl; + gl.deleteTexture(this.texture); + } + } } diff --git a/spine-ts/webgl/src/Input.ts b/spine-ts/webgl/src/Input.ts index 080c1b6eb5..adc3286bfd 100644 --- a/spine-ts/webgl/src/Input.ts +++ b/spine-ts/webgl/src/Input.ts @@ -1,221 +1,220 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.webgl { - export class Input { - element: HTMLElement; - lastX = 0; - lastY = 0; - buttonDown = false; - currTouch: Touch = null; - touchesPool = new Pool(() => { - return new spine.webgl.Touch(0, 0, 0); - }); - - private listeners = new Array(); - constructor (element: HTMLElement) { - this.element = element; - this.setupCallbacks(element); - } - - private setupCallbacks(element: HTMLElement) { - element.addEventListener("mousedown", (ev: UIEvent) => { - if (ev instanceof MouseEvent) { - let rect = element.getBoundingClientRect(); - let x = ev.clientX - rect.left; - let y = ev.clientY - rect.top; - - let listeners = this.listeners; - for (let i = 0; i < listeners.length; i++) { - listeners[i].down(x, y); - } - - this.lastX = x; - this.lastY = y; - this.buttonDown = true; - } - }, true); - element.addEventListener("mousemove", (ev: UIEvent) => { - if (ev instanceof MouseEvent) { - let rect = element.getBoundingClientRect(); - let x = ev.clientX - rect.left; - let y = ev.clientY - rect.top; - - let listeners = this.listeners; - for (let i = 0; i < listeners.length; i++) { - if (this.buttonDown) { - listeners[i].dragged(x, y); - } else { - listeners[i].moved(x, y); - } - } - - this.lastX = x; - this.lastY = y; - } - }, true); - element.addEventListener("mouseup", (ev: UIEvent) => { - if (ev instanceof MouseEvent) { - let rect = element.getBoundingClientRect(); - let x = ev.clientX - rect.left; - let y = ev.clientY - rect.top; - - let listeners = this.listeners; - for (let i = 0; i < listeners.length; i++) { - listeners[i].up(x, y); - } - - this.lastX = x; - this.lastY = y; - this.buttonDown = false; - } - }, true); - element.addEventListener("touchstart", (ev: TouchEvent) => { - if (this.currTouch != null) return; - - var touches = ev.changedTouches; - for (var i = 0; i < touches.length; i++) { - var touch = touches[i]; - let rect = element.getBoundingClientRect(); - let x = touch.clientX - rect.left; - let y = touch.clientY - rect.top; - this.currTouch = this.touchesPool.obtain(); - this.currTouch.identifier = touch.identifier; - this.currTouch.x = x; - this.currTouch.y = y; - break; - } - - let listeners = this.listeners; - for (let i = 0; i < listeners.length; i++) { - listeners[i].down(this.currTouch.x, this.currTouch.y); - } - console.log("Start " + this.currTouch.x + ", " + this.currTouch.y); - this.lastX = this.currTouch.x; - this.lastY = this.currTouch.y; - this.buttonDown = true; - ev.preventDefault(); - }, false); - element.addEventListener("touchend", (ev: TouchEvent) => { - var touches = ev.changedTouches; - for (var i = 0; i < touches.length; i++) { - var touch = touches[i]; - if (this.currTouch.identifier === touch.identifier) { - let rect = element.getBoundingClientRect(); - let x = this.currTouch.x = touch.clientX - rect.left; - let y = this.currTouch.y = touch.clientY - rect.top; - this.touchesPool.free(this.currTouch); - let listeners = this.listeners; - for (let i = 0; i < listeners.length; i++) { - listeners[i].up(x, y); - } - console.log("End " + x + ", " + y); - this.lastX = x; - this.lastY = y; - this.buttonDown = false; - this.currTouch = null; - break; - } - } - ev.preventDefault(); - }, false); - element.addEventListener("touchcancel", (ev: TouchEvent) => { - var touches = ev.changedTouches; - for (var i = 0; i < touches.length; i++) { - var touch = touches[i]; - if (this.currTouch.identifier === touch.identifier) { - let rect = element.getBoundingClientRect(); - let x = this.currTouch.x = touch.clientX - rect.left; - let y = this.currTouch.y = touch.clientY - rect.top; - this.touchesPool.free(this.currTouch); - let listeners = this.listeners; - for (let i = 0; i < listeners.length; i++) { - listeners[i].up(x, y); - } - console.log("End " + x + ", " + y); - this.lastX = x; - this.lastY = y; - this.buttonDown = false; - this.currTouch = null; - break; - } - } - ev.preventDefault(); - }, false); - element.addEventListener("touchmove", (ev: TouchEvent) => { - if (this.currTouch == null) return; - - var touches = ev.changedTouches; - for (var i = 0; i < touches.length; i++) { - var touch = touches[i]; - if (this.currTouch.identifier === touch.identifier) { - let rect = element.getBoundingClientRect(); - let x = touch.clientX - rect.left; - let y = touch.clientY - rect.top; - - let listeners = this.listeners; - for (let i = 0; i < listeners.length; i++) { - listeners[i].dragged(x, y); - } - console.log("Drag " + x + ", " + y); - this.lastX = this.currTouch.x = x; - this.lastY = this.currTouch.y = y; - break; - } - } - ev.preventDefault(); - }, false); - } - - addListener(listener: InputListener) { - this.listeners.push(listener); - } - - removeListener(listener: InputListener) { - let idx = this.listeners.indexOf(listener); - if (idx > -1) { - this.listeners.splice(idx, 1); - } - } - } - - export class Touch { - constructor(public identifier: number, public x: number, public y: number) { - } - } - - export interface InputListener { - down(x: number, y: number): void; - up(x: number, y: number): void; - moved(x: number, y: number): void; - dragged(x: number, y: number): void; - } -} \ No newline at end of file +module spine.webgl { + export class Input { + element: HTMLElement; + lastX = 0; + lastY = 0; + buttonDown = false; + currTouch: Touch = null; + touchesPool = new Pool(() => { + return new spine.webgl.Touch(0, 0, 0); + }); + + private listeners = new Array(); + constructor (element: HTMLElement) { + this.element = element; + this.setupCallbacks(element); + } + + private setupCallbacks(element: HTMLElement) { + element.addEventListener("mousedown", (ev: UIEvent) => { + if (ev instanceof MouseEvent) { + let rect = element.getBoundingClientRect(); + let x = ev.clientX - rect.left; + let y = ev.clientY - rect.top; + + let listeners = this.listeners; + for (let i = 0; i < listeners.length; i++) { + listeners[i].down(x, y); + } + + this.lastX = x; + this.lastY = y; + this.buttonDown = true; + } + }, true); + element.addEventListener("mousemove", (ev: UIEvent) => { + if (ev instanceof MouseEvent) { + let rect = element.getBoundingClientRect(); + let x = ev.clientX - rect.left; + let y = ev.clientY - rect.top; + + let listeners = this.listeners; + for (let i = 0; i < listeners.length; i++) { + if (this.buttonDown) { + listeners[i].dragged(x, y); + } else { + listeners[i].moved(x, y); + } + } + + this.lastX = x; + this.lastY = y; + } + }, true); + element.addEventListener("mouseup", (ev: UIEvent) => { + if (ev instanceof MouseEvent) { + let rect = element.getBoundingClientRect(); + let x = ev.clientX - rect.left; + let y = ev.clientY - rect.top; + + let listeners = this.listeners; + for (let i = 0; i < listeners.length; i++) { + listeners[i].up(x, y); + } + + this.lastX = x; + this.lastY = y; + this.buttonDown = false; + } + }, true); + element.addEventListener("touchstart", (ev: TouchEvent) => { + if (this.currTouch != null) return; + + var touches = ev.changedTouches; + for (var i = 0; i < touches.length; i++) { + var touch = touches[i]; + let rect = element.getBoundingClientRect(); + let x = touch.clientX - rect.left; + let y = touch.clientY - rect.top; + this.currTouch = this.touchesPool.obtain(); + this.currTouch.identifier = touch.identifier; + this.currTouch.x = x; + this.currTouch.y = y; + break; + } + + let listeners = this.listeners; + for (let i = 0; i < listeners.length; i++) { + listeners[i].down(this.currTouch.x, this.currTouch.y); + } + console.log("Start " + this.currTouch.x + ", " + this.currTouch.y); + this.lastX = this.currTouch.x; + this.lastY = this.currTouch.y; + this.buttonDown = true; + ev.preventDefault(); + }, false); + element.addEventListener("touchend", (ev: TouchEvent) => { + var touches = ev.changedTouches; + for (var i = 0; i < touches.length; i++) { + var touch = touches[i]; + if (this.currTouch.identifier === touch.identifier) { + let rect = element.getBoundingClientRect(); + let x = this.currTouch.x = touch.clientX - rect.left; + let y = this.currTouch.y = touch.clientY - rect.top; + this.touchesPool.free(this.currTouch); + let listeners = this.listeners; + for (let i = 0; i < listeners.length; i++) { + listeners[i].up(x, y); + } + console.log("End " + x + ", " + y); + this.lastX = x; + this.lastY = y; + this.buttonDown = false; + this.currTouch = null; + break; + } + } + ev.preventDefault(); + }, false); + element.addEventListener("touchcancel", (ev: TouchEvent) => { + var touches = ev.changedTouches; + for (var i = 0; i < touches.length; i++) { + var touch = touches[i]; + if (this.currTouch.identifier === touch.identifier) { + let rect = element.getBoundingClientRect(); + let x = this.currTouch.x = touch.clientX - rect.left; + let y = this.currTouch.y = touch.clientY - rect.top; + this.touchesPool.free(this.currTouch); + let listeners = this.listeners; + for (let i = 0; i < listeners.length; i++) { + listeners[i].up(x, y); + } + console.log("End " + x + ", " + y); + this.lastX = x; + this.lastY = y; + this.buttonDown = false; + this.currTouch = null; + break; + } + } + ev.preventDefault(); + }, false); + element.addEventListener("touchmove", (ev: TouchEvent) => { + if (this.currTouch == null) return; + + var touches = ev.changedTouches; + for (var i = 0; i < touches.length; i++) { + var touch = touches[i]; + if (this.currTouch.identifier === touch.identifier) { + let rect = element.getBoundingClientRect(); + let x = touch.clientX - rect.left; + let y = touch.clientY - rect.top; + + let listeners = this.listeners; + for (let i = 0; i < listeners.length; i++) { + listeners[i].dragged(x, y); + } + console.log("Drag " + x + ", " + y); + this.lastX = this.currTouch.x = x; + this.lastY = this.currTouch.y = y; + break; + } + } + ev.preventDefault(); + }, false); + } + + addListener(listener: InputListener) { + this.listeners.push(listener); + } + + removeListener(listener: InputListener) { + let idx = this.listeners.indexOf(listener); + if (idx > -1) { + this.listeners.splice(idx, 1); + } + } + } + + export class Touch { + constructor(public identifier: number, public x: number, public y: number) { + } + } + + export interface InputListener { + down(x: number, y: number): void; + up(x: number, y: number): void; + moved(x: number, y: number): void; + dragged(x: number, y: number): void; + } +} diff --git a/spine-ts/webgl/src/LoadingScreen.ts b/spine-ts/webgl/src/LoadingScreen.ts index a3f78cf698..81e6fe5bd5 100644 --- a/spine-ts/webgl/src/LoadingScreen.ts +++ b/spine-ts/webgl/src/LoadingScreen.ts @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ module spine.webgl { diff --git a/spine-ts/webgl/src/Matrix4.ts b/spine-ts/webgl/src/Matrix4.ts index d74d67b9ab..ab109df18c 100644 --- a/spine-ts/webgl/src/Matrix4.ts +++ b/spine-ts/webgl/src/Matrix4.ts @@ -1,342 +1,341 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.webgl { - export const M00 = 0; - export const M01 = 4; - export const M02 = 8; - export const M03 = 12; - export const M10 = 1; - export const M11 = 5; - export const M12 = 9; - export const M13 = 13; - export const M20 = 2; - export const M21 = 6; - export const M22 = 10; - export const M23 = 14; - export const M30 = 3; - export const M31 = 7; - export const M32 = 11; - export const M33 = 15; - - export class Matrix4 { - temp: Float32Array = new Float32Array(16); - values: Float32Array = new Float32Array(16); - - private static xAxis: Vector3 = null; - private static yAxis: Vector3 = null; - private static zAxis: Vector3 = null; - private static tmpMatrix = new Matrix4(); - - constructor () { - let v = this.values; - v[M00] = 1; - v[M11] = 1; - v[M22] = 1; - v[M33] = 1; - } - - set (values: ArrayLike): Matrix4 { - this.values.set(values); - return this; - } - - transpose (): Matrix4 { - let t = this.temp; - let v = this.values; - t[M00] = v[M00]; - t[M01] = v[M10]; - t[M02] = v[M20]; - t[M03] = v[M30]; - t[M10] = v[M01]; - t[M11] = v[M11]; - t[M12] = v[M21]; - t[M13] = v[M31]; - t[M20] = v[M02]; - t[M21] = v[M12]; - t[M22] = v[M22]; - t[M23] = v[M32]; - t[M30] = v[M03]; - t[M31] = v[M13]; - t[M32] = v[M23]; - t[M33] = v[M33]; - return this.set(t); - } - - identity (): Matrix4 { - let v = this.values; - v[M00] = 1; - v[M01] = 0; - v[M02] = 0; - v[M03] = 0; - v[M10] = 0; - v[M11] = 1; - v[M12] = 0; - v[M13] = 0; - v[M20] = 0; - v[M21] = 0; - v[M22] = 1; - v[M23] = 0; - v[M30] = 0; - v[M31] = 0; - v[M32] = 0; - v[M33] = 1; - return this; - } - - invert (): Matrix4 { - let v = this.values; - let t = this.temp; - let l_det = v[M30] * v[M21] * v[M12] * v[M03] - v[M20] * v[M31] * v[M12] * v[M03] - v[M30] * v[M11] * v[M22] * v[M03] - + v[M10] * v[M31] * v[M22] * v[M03] + v[M20] * v[M11] * v[M32] * v[M03] - v[M10] * v[M21] * v[M32] * v[M03] - - v[M30] * v[M21] * v[M02] * v[M13] + v[M20] * v[M31] * v[M02] * v[M13] + v[M30] * v[M01] * v[M22] * v[M13] - - v[M00] * v[M31] * v[M22] * v[M13] - v[M20] * v[M01] * v[M32] * v[M13] + v[M00] * v[M21] * v[M32] * v[M13] - + v[M30] * v[M11] * v[M02] * v[M23] - v[M10] * v[M31] * v[M02] * v[M23] - v[M30] * v[M01] * v[M12] * v[M23] - + v[M00] * v[M31] * v[M12] * v[M23] + v[M10] * v[M01] * v[M32] * v[M23] - v[M00] * v[M11] * v[M32] * v[M23] - - v[M20] * v[M11] * v[M02] * v[M33] + v[M10] * v[M21] * v[M02] * v[M33] + v[M20] * v[M01] * v[M12] * v[M33] - - v[M00] * v[M21] * v[M12] * v[M33] - v[M10] * v[M01] * v[M22] * v[M33] + v[M00] * v[M11] * v[M22] * v[M33]; - if (l_det == 0) throw new Error("non-invertible matrix"); - let inv_det = 1.0 / l_det; - t[M00] = v[M12] * v[M23] * v[M31] - v[M13] * v[M22] * v[M31] + v[M13] * v[M21] * v[M32] - - v[M11] * v[M23] * v[M32] - v[M12] * v[M21] * v[M33] + v[M11] * v[M22] * v[M33]; - t[M01] = v[M03] * v[M22] * v[M31] - v[M02] * v[M23] * v[M31] - v[M03] * v[M21] * v[M32] - + v[M01] * v[M23] * v[M32] + v[M02] * v[M21] * v[M33] - v[M01] * v[M22] * v[M33]; - t[M02] = v[M02] * v[M13] * v[M31] - v[M03] * v[M12] * v[M31] + v[M03] * v[M11] * v[M32] - - v[M01] * v[M13] * v[M32] - v[M02] * v[M11] * v[M33] + v[M01] * v[M12] * v[M33]; - t[M03] = v[M03] * v[M12] * v[M21] - v[M02] * v[M13] * v[M21] - v[M03] * v[M11] * v[M22] - + v[M01] * v[M13] * v[M22] + v[M02] * v[M11] * v[M23] - v[M01] * v[M12] * v[M23]; - t[M10] = v[M13] * v[M22] * v[M30] - v[M12] * v[M23] * v[M30] - v[M13] * v[M20] * v[M32] - + v[M10] * v[M23] * v[M32] + v[M12] * v[M20] * v[M33] - v[M10] * v[M22] * v[M33]; - t[M11] = v[M02] * v[M23] * v[M30] - v[M03] * v[M22] * v[M30] + v[M03] * v[M20] * v[M32] - - v[M00] * v[M23] * v[M32] - v[M02] * v[M20] * v[M33] + v[M00] * v[M22] * v[M33]; - t[M12] = v[M03] * v[M12] * v[M30] - v[M02] * v[M13] * v[M30] - v[M03] * v[M10] * v[M32] - + v[M00] * v[M13] * v[M32] + v[M02] * v[M10] * v[M33] - v[M00] * v[M12] * v[M33]; - t[M13] = v[M02] * v[M13] * v[M20] - v[M03] * v[M12] * v[M20] + v[M03] * v[M10] * v[M22] - - v[M00] * v[M13] * v[M22] - v[M02] * v[M10] * v[M23] + v[M00] * v[M12] * v[M23]; - t[M20] = v[M11] * v[M23] * v[M30] - v[M13] * v[M21] * v[M30] + v[M13] * v[M20] * v[M31] - - v[M10] * v[M23] * v[M31] - v[M11] * v[M20] * v[M33] + v[M10] * v[M21] * v[M33]; - t[M21] = v[M03] * v[M21] * v[M30] - v[M01] * v[M23] * v[M30] - v[M03] * v[M20] * v[M31] - + v[M00] * v[M23] * v[M31] + v[M01] * v[M20] * v[M33] - v[M00] * v[M21] * v[M33]; - t[M22] = v[M01] * v[M13] * v[M30] - v[M03] * v[M11] * v[M30] + v[M03] * v[M10] * v[M31] - - v[M00] * v[M13] * v[M31] - v[M01] * v[M10] * v[M33] + v[M00] * v[M11] * v[M33]; - t[M23] = v[M03] * v[M11] * v[M20] - v[M01] * v[M13] * v[M20] - v[M03] * v[M10] * v[M21] - + v[M00] * v[M13] * v[M21] + v[M01] * v[M10] * v[M23] - v[M00] * v[M11] * v[M23]; - t[M30] = v[M12] * v[M21] * v[M30] - v[M11] * v[M22] * v[M30] - v[M12] * v[M20] * v[M31] - + v[M10] * v[M22] * v[M31] + v[M11] * v[M20] * v[M32] - v[M10] * v[M21] * v[M32]; - t[M31] = v[M01] * v[M22] * v[M30] - v[M02] * v[M21] * v[M30] + v[M02] * v[M20] * v[M31] - - v[M00] * v[M22] * v[M31] - v[M01] * v[M20] * v[M32] + v[M00] * v[M21] * v[M32]; - t[M32] = v[M02] * v[M11] * v[M30] - v[M01] * v[M12] * v[M30] - v[M02] * v[M10] * v[M31] - + v[M00] * v[M12] * v[M31] + v[M01] * v[M10] * v[M32] - v[M00] * v[M11] * v[M32]; - t[M33] = v[M01] * v[M12] * v[M20] - v[M02] * v[M11] * v[M20] + v[M02] * v[M10] * v[M21] - - v[M00] * v[M12] * v[M21] - v[M01] * v[M10] * v[M22] + v[M00] * v[M11] * v[M22]; - v[M00] = t[M00] * inv_det; - v[M01] = t[M01] * inv_det; - v[M02] = t[M02] * inv_det; - v[M03] = t[M03] * inv_det; - v[M10] = t[M10] * inv_det; - v[M11] = t[M11] * inv_det; - v[M12] = t[M12] * inv_det; - v[M13] = t[M13] * inv_det; - v[M20] = t[M20] * inv_det; - v[M21] = t[M21] * inv_det; - v[M22] = t[M22] * inv_det; - v[M23] = t[M23] * inv_det; - v[M30] = t[M30] * inv_det; - v[M31] = t[M31] * inv_det; - v[M32] = t[M32] * inv_det; - v[M33] = t[M33] * inv_det; - return this; - } - - determinant (): number { - let v = this.values; - return v[M30] * v[M21] * v[M12] * v[M03] - v[M20] * v[M31] * v[M12] * v[M03] - v[M30] * v[M11] * v[M22] * v[M03] - + v[M10] * v[M31] * v[M22] * v[M03] + v[M20] * v[M11] * v[M32] * v[M03] - v[M10] * v[M21] * v[M32] * v[M03] - - v[M30] * v[M21] * v[M02] * v[M13] + v[M20] * v[M31] * v[M02] * v[M13] + v[M30] * v[M01] * v[M22] * v[M13] - - v[M00] * v[M31] * v[M22] * v[M13] - v[M20] * v[M01] * v[M32] * v[M13] + v[M00] * v[M21] * v[M32] * v[M13] - + v[M30] * v[M11] * v[M02] * v[M23] - v[M10] * v[M31] * v[M02] * v[M23] - v[M30] * v[M01] * v[M12] * v[M23] - + v[M00] * v[M31] * v[M12] * v[M23] + v[M10] * v[M01] * v[M32] * v[M23] - v[M00] * v[M11] * v[M32] * v[M23] - - v[M20] * v[M11] * v[M02] * v[M33] + v[M10] * v[M21] * v[M02] * v[M33] + v[M20] * v[M01] * v[M12] * v[M33] - - v[M00] * v[M21] * v[M12] * v[M33] - v[M10] * v[M01] * v[M22] * v[M33] + v[M00] * v[M11] * v[M22] * v[M33]; - } - - translate (x: number, y: number, z: number): Matrix4 { - let v = this.values; - v[M03] += x; - v[M13] += y; - v[M23] += z; - return this; - } - - copy (): Matrix4 { - return new Matrix4().set(this.values); - } - - projection (near: number, far: number, fovy: number, aspectRatio: number): Matrix4 { - this.identity(); - let l_fd = (1.0 / Math.tan((fovy * (Math.PI / 180)) / 2.0)); - let l_a1 = (far + near) / (near - far); - let l_a2 = (2 * far * near) / (near - far); - let v = this.values; - v[M00] = l_fd / aspectRatio; - v[M10] = 0; - v[M20] = 0; - v[M30] = 0; - v[M01] = 0; - v[M11] = l_fd; - v[M21] = 0; - v[M31] = 0; - v[M02] = 0; - v[M12] = 0; - v[M22] = l_a1; - v[M32] = -1; - v[M03] = 0; - v[M13] = 0; - v[M23] = l_a2; - v[M33] = 0; - return this; - } - - ortho2d (x: number, y: number, width: number, height: number): Matrix4 { - return this.ortho(x, x + width, y, y + height, 0, 1); - } - - ortho (left: number, right: number, bottom: number, top: number, near: number, far: number): Matrix4 { - this.identity(); - let x_orth = 2 / (right - left); - let y_orth = 2 / (top - bottom); - let z_orth = -2 / (far - near); - - let tx = -(right + left) / (right - left); - let ty = -(top + bottom) / (top - bottom); - let tz = -(far + near) / (far - near); - - let v = this.values; - v[M00] = x_orth; - v[M10] = 0; - v[M20] = 0; - v[M30] = 0; - v[M01] = 0; - v[M11] = y_orth; - v[M21] = 0; - v[M31] = 0; - v[M02] = 0; - v[M12] = 0; - v[M22] = z_orth; - v[M32] = 0; - v[M03] = tx; - v[M13] = ty; - v[M23] = tz; - v[M33] = 1; - return this; - } - - multiply (matrix: Matrix4): Matrix4 { - let t = this.temp; - let v = this.values; - let m = matrix.values; - t[M00] = v[M00] * m[M00] + v[M01] * m[M10] + v[M02] * m[M20] + v[M03] * m[M30]; - t[M01] = v[M00] * m[M01] + v[M01] * m[M11] + v[M02] * m[M21] + v[M03] * m[M31]; - t[M02] = v[M00] * m[M02] + v[M01] * m[M12] + v[M02] * m[M22] + v[M03] * m[M32]; - t[M03] = v[M00] * m[M03] + v[M01] * m[M13] + v[M02] * m[M23] + v[M03] * m[M33]; - t[M10] = v[M10] * m[M00] + v[M11] * m[M10] + v[M12] * m[M20] + v[M13] * m[M30]; - t[M11] = v[M10] * m[M01] + v[M11] * m[M11] + v[M12] * m[M21] + v[M13] * m[M31]; - t[M12] = v[M10] * m[M02] + v[M11] * m[M12] + v[M12] * m[M22] + v[M13] * m[M32]; - t[M13] = v[M10] * m[M03] + v[M11] * m[M13] + v[M12] * m[M23] + v[M13] * m[M33]; - t[M20] = v[M20] * m[M00] + v[M21] * m[M10] + v[M22] * m[M20] + v[M23] * m[M30]; - t[M21] = v[M20] * m[M01] + v[M21] * m[M11] + v[M22] * m[M21] + v[M23] * m[M31]; - t[M22] = v[M20] * m[M02] + v[M21] * m[M12] + v[M22] * m[M22] + v[M23] * m[M32]; - t[M23] = v[M20] * m[M03] + v[M21] * m[M13] + v[M22] * m[M23] + v[M23] * m[M33]; - t[M30] = v[M30] * m[M00] + v[M31] * m[M10] + v[M32] * m[M20] + v[M33] * m[M30]; - t[M31] = v[M30] * m[M01] + v[M31] * m[M11] + v[M32] * m[M21] + v[M33] * m[M31]; - t[M32] = v[M30] * m[M02] + v[M31] * m[M12] + v[M32] * m[M22] + v[M33] * m[M32]; - t[M33] = v[M30] * m[M03] + v[M31] * m[M13] + v[M32] * m[M23] + v[M33] * m[M33]; - return this.set(this.temp); - } - - multiplyLeft (matrix: Matrix4): Matrix4 { - let t = this.temp; - let v = this.values; - let m = matrix.values; - t[M00] = m[M00] * v[M00] + m[M01] * v[M10] + m[M02] * v[M20] + m[M03] * v[M30]; - t[M01] = m[M00] * v[M01] + m[M01] * v[M11] + m[M02] * v[M21] + m[M03] * v[M31]; - t[M02] = m[M00] * v[M02] + m[M01] * v[M12] + m[M02] * v[M22] + m[M03] * v[M32]; - t[M03] = m[M00] * v[M03] + m[M01] * v[M13] + m[M02] * v[M23] + m[M03] * v[M33]; - t[M10] = m[M10] * v[M00] + m[M11] * v[M10] + m[M12] * v[M20] + m[M13] * v[M30]; - t[M11] = m[M10] * v[M01] + m[M11] * v[M11] + m[M12] * v[M21] + m[M13] * v[M31]; - t[M12] = m[M10] * v[M02] + m[M11] * v[M12] + m[M12] * v[M22] + m[M13] * v[M32]; - t[M13] = m[M10] * v[M03] + m[M11] * v[M13] + m[M12] * v[M23] + m[M13] * v[M33]; - t[M20] = m[M20] * v[M00] + m[M21] * v[M10] + m[M22] * v[M20] + m[M23] * v[M30]; - t[M21] = m[M20] * v[M01] + m[M21] * v[M11] + m[M22] * v[M21] + m[M23] * v[M31]; - t[M22] = m[M20] * v[M02] + m[M21] * v[M12] + m[M22] * v[M22] + m[M23] * v[M32]; - t[M23] = m[M20] * v[M03] + m[M21] * v[M13] + m[M22] * v[M23] + m[M23] * v[M33]; - t[M30] = m[M30] * v[M00] + m[M31] * v[M10] + m[M32] * v[M20] + m[M33] * v[M30]; - t[M31] = m[M30] * v[M01] + m[M31] * v[M11] + m[M32] * v[M21] + m[M33] * v[M31]; - t[M32] = m[M30] * v[M02] + m[M31] * v[M12] + m[M32] * v[M22] + m[M33] * v[M32]; - t[M33] = m[M30] * v[M03] + m[M31] * v[M13] + m[M32] * v[M23] + m[M33] * v[M33]; - return this.set(this.temp); - } - - lookAt (position: Vector3, direction: Vector3, up: Vector3) { - Matrix4.initTemps(); - let xAxis = Matrix4.xAxis, yAxis = Matrix4.yAxis, zAxis = Matrix4.zAxis; - zAxis.setFrom(direction).normalize(); - xAxis.setFrom(direction).normalize(); - xAxis.cross(up).normalize(); - yAxis.setFrom(xAxis).cross(zAxis).normalize(); - this.identity(); - let val = this.values; - val[M00] = xAxis.x; - val[M01] = xAxis.y; - val[M02] = xAxis.z; - val[M10] = yAxis.x; - val[M11] = yAxis.y; - val[M12] = yAxis.z; - val[M20] = -zAxis.x; - val[M21] = -zAxis.y; - val[M22] = -zAxis.z; - - Matrix4.tmpMatrix.identity(); - Matrix4.tmpMatrix.values[M03] = -position.x; - Matrix4.tmpMatrix.values[M13] = -position.y; - Matrix4.tmpMatrix.values[M23] = -position.z; - this.multiply(Matrix4.tmpMatrix) - - return this; - } - - static initTemps() { - if (Matrix4.xAxis === null) Matrix4.xAxis = new Vector3(); - if (Matrix4.yAxis === null) Matrix4.yAxis = new Vector3(); - if (Matrix4.zAxis === null) Matrix4.zAxis = new Vector3(); - } - } +module spine.webgl { + export const M00 = 0; + export const M01 = 4; + export const M02 = 8; + export const M03 = 12; + export const M10 = 1; + export const M11 = 5; + export const M12 = 9; + export const M13 = 13; + export const M20 = 2; + export const M21 = 6; + export const M22 = 10; + export const M23 = 14; + export const M30 = 3; + export const M31 = 7; + export const M32 = 11; + export const M33 = 15; + + export class Matrix4 { + temp: Float32Array = new Float32Array(16); + values: Float32Array = new Float32Array(16); + + private static xAxis: Vector3 = null; + private static yAxis: Vector3 = null; + private static zAxis: Vector3 = null; + private static tmpMatrix = new Matrix4(); + + constructor () { + let v = this.values; + v[M00] = 1; + v[M11] = 1; + v[M22] = 1; + v[M33] = 1; + } + + set (values: ArrayLike): Matrix4 { + this.values.set(values); + return this; + } + + transpose (): Matrix4 { + let t = this.temp; + let v = this.values; + t[M00] = v[M00]; + t[M01] = v[M10]; + t[M02] = v[M20]; + t[M03] = v[M30]; + t[M10] = v[M01]; + t[M11] = v[M11]; + t[M12] = v[M21]; + t[M13] = v[M31]; + t[M20] = v[M02]; + t[M21] = v[M12]; + t[M22] = v[M22]; + t[M23] = v[M32]; + t[M30] = v[M03]; + t[M31] = v[M13]; + t[M32] = v[M23]; + t[M33] = v[M33]; + return this.set(t); + } + + identity (): Matrix4 { + let v = this.values; + v[M00] = 1; + v[M01] = 0; + v[M02] = 0; + v[M03] = 0; + v[M10] = 0; + v[M11] = 1; + v[M12] = 0; + v[M13] = 0; + v[M20] = 0; + v[M21] = 0; + v[M22] = 1; + v[M23] = 0; + v[M30] = 0; + v[M31] = 0; + v[M32] = 0; + v[M33] = 1; + return this; + } + + invert (): Matrix4 { + let v = this.values; + let t = this.temp; + let l_det = v[M30] * v[M21] * v[M12] * v[M03] - v[M20] * v[M31] * v[M12] * v[M03] - v[M30] * v[M11] * v[M22] * v[M03] + + v[M10] * v[M31] * v[M22] * v[M03] + v[M20] * v[M11] * v[M32] * v[M03] - v[M10] * v[M21] * v[M32] * v[M03] + - v[M30] * v[M21] * v[M02] * v[M13] + v[M20] * v[M31] * v[M02] * v[M13] + v[M30] * v[M01] * v[M22] * v[M13] + - v[M00] * v[M31] * v[M22] * v[M13] - v[M20] * v[M01] * v[M32] * v[M13] + v[M00] * v[M21] * v[M32] * v[M13] + + v[M30] * v[M11] * v[M02] * v[M23] - v[M10] * v[M31] * v[M02] * v[M23] - v[M30] * v[M01] * v[M12] * v[M23] + + v[M00] * v[M31] * v[M12] * v[M23] + v[M10] * v[M01] * v[M32] * v[M23] - v[M00] * v[M11] * v[M32] * v[M23] + - v[M20] * v[M11] * v[M02] * v[M33] + v[M10] * v[M21] * v[M02] * v[M33] + v[M20] * v[M01] * v[M12] * v[M33] + - v[M00] * v[M21] * v[M12] * v[M33] - v[M10] * v[M01] * v[M22] * v[M33] + v[M00] * v[M11] * v[M22] * v[M33]; + if (l_det == 0) throw new Error("non-invertible matrix"); + let inv_det = 1.0 / l_det; + t[M00] = v[M12] * v[M23] * v[M31] - v[M13] * v[M22] * v[M31] + v[M13] * v[M21] * v[M32] + - v[M11] * v[M23] * v[M32] - v[M12] * v[M21] * v[M33] + v[M11] * v[M22] * v[M33]; + t[M01] = v[M03] * v[M22] * v[M31] - v[M02] * v[M23] * v[M31] - v[M03] * v[M21] * v[M32] + + v[M01] * v[M23] * v[M32] + v[M02] * v[M21] * v[M33] - v[M01] * v[M22] * v[M33]; + t[M02] = v[M02] * v[M13] * v[M31] - v[M03] * v[M12] * v[M31] + v[M03] * v[M11] * v[M32] + - v[M01] * v[M13] * v[M32] - v[M02] * v[M11] * v[M33] + v[M01] * v[M12] * v[M33]; + t[M03] = v[M03] * v[M12] * v[M21] - v[M02] * v[M13] * v[M21] - v[M03] * v[M11] * v[M22] + + v[M01] * v[M13] * v[M22] + v[M02] * v[M11] * v[M23] - v[M01] * v[M12] * v[M23]; + t[M10] = v[M13] * v[M22] * v[M30] - v[M12] * v[M23] * v[M30] - v[M13] * v[M20] * v[M32] + + v[M10] * v[M23] * v[M32] + v[M12] * v[M20] * v[M33] - v[M10] * v[M22] * v[M33]; + t[M11] = v[M02] * v[M23] * v[M30] - v[M03] * v[M22] * v[M30] + v[M03] * v[M20] * v[M32] + - v[M00] * v[M23] * v[M32] - v[M02] * v[M20] * v[M33] + v[M00] * v[M22] * v[M33]; + t[M12] = v[M03] * v[M12] * v[M30] - v[M02] * v[M13] * v[M30] - v[M03] * v[M10] * v[M32] + + v[M00] * v[M13] * v[M32] + v[M02] * v[M10] * v[M33] - v[M00] * v[M12] * v[M33]; + t[M13] = v[M02] * v[M13] * v[M20] - v[M03] * v[M12] * v[M20] + v[M03] * v[M10] * v[M22] + - v[M00] * v[M13] * v[M22] - v[M02] * v[M10] * v[M23] + v[M00] * v[M12] * v[M23]; + t[M20] = v[M11] * v[M23] * v[M30] - v[M13] * v[M21] * v[M30] + v[M13] * v[M20] * v[M31] + - v[M10] * v[M23] * v[M31] - v[M11] * v[M20] * v[M33] + v[M10] * v[M21] * v[M33]; + t[M21] = v[M03] * v[M21] * v[M30] - v[M01] * v[M23] * v[M30] - v[M03] * v[M20] * v[M31] + + v[M00] * v[M23] * v[M31] + v[M01] * v[M20] * v[M33] - v[M00] * v[M21] * v[M33]; + t[M22] = v[M01] * v[M13] * v[M30] - v[M03] * v[M11] * v[M30] + v[M03] * v[M10] * v[M31] + - v[M00] * v[M13] * v[M31] - v[M01] * v[M10] * v[M33] + v[M00] * v[M11] * v[M33]; + t[M23] = v[M03] * v[M11] * v[M20] - v[M01] * v[M13] * v[M20] - v[M03] * v[M10] * v[M21] + + v[M00] * v[M13] * v[M21] + v[M01] * v[M10] * v[M23] - v[M00] * v[M11] * v[M23]; + t[M30] = v[M12] * v[M21] * v[M30] - v[M11] * v[M22] * v[M30] - v[M12] * v[M20] * v[M31] + + v[M10] * v[M22] * v[M31] + v[M11] * v[M20] * v[M32] - v[M10] * v[M21] * v[M32]; + t[M31] = v[M01] * v[M22] * v[M30] - v[M02] * v[M21] * v[M30] + v[M02] * v[M20] * v[M31] + - v[M00] * v[M22] * v[M31] - v[M01] * v[M20] * v[M32] + v[M00] * v[M21] * v[M32]; + t[M32] = v[M02] * v[M11] * v[M30] - v[M01] * v[M12] * v[M30] - v[M02] * v[M10] * v[M31] + + v[M00] * v[M12] * v[M31] + v[M01] * v[M10] * v[M32] - v[M00] * v[M11] * v[M32]; + t[M33] = v[M01] * v[M12] * v[M20] - v[M02] * v[M11] * v[M20] + v[M02] * v[M10] * v[M21] + - v[M00] * v[M12] * v[M21] - v[M01] * v[M10] * v[M22] + v[M00] * v[M11] * v[M22]; + v[M00] = t[M00] * inv_det; + v[M01] = t[M01] * inv_det; + v[M02] = t[M02] * inv_det; + v[M03] = t[M03] * inv_det; + v[M10] = t[M10] * inv_det; + v[M11] = t[M11] * inv_det; + v[M12] = t[M12] * inv_det; + v[M13] = t[M13] * inv_det; + v[M20] = t[M20] * inv_det; + v[M21] = t[M21] * inv_det; + v[M22] = t[M22] * inv_det; + v[M23] = t[M23] * inv_det; + v[M30] = t[M30] * inv_det; + v[M31] = t[M31] * inv_det; + v[M32] = t[M32] * inv_det; + v[M33] = t[M33] * inv_det; + return this; + } + + determinant (): number { + let v = this.values; + return v[M30] * v[M21] * v[M12] * v[M03] - v[M20] * v[M31] * v[M12] * v[M03] - v[M30] * v[M11] * v[M22] * v[M03] + + v[M10] * v[M31] * v[M22] * v[M03] + v[M20] * v[M11] * v[M32] * v[M03] - v[M10] * v[M21] * v[M32] * v[M03] + - v[M30] * v[M21] * v[M02] * v[M13] + v[M20] * v[M31] * v[M02] * v[M13] + v[M30] * v[M01] * v[M22] * v[M13] + - v[M00] * v[M31] * v[M22] * v[M13] - v[M20] * v[M01] * v[M32] * v[M13] + v[M00] * v[M21] * v[M32] * v[M13] + + v[M30] * v[M11] * v[M02] * v[M23] - v[M10] * v[M31] * v[M02] * v[M23] - v[M30] * v[M01] * v[M12] * v[M23] + + v[M00] * v[M31] * v[M12] * v[M23] + v[M10] * v[M01] * v[M32] * v[M23] - v[M00] * v[M11] * v[M32] * v[M23] + - v[M20] * v[M11] * v[M02] * v[M33] + v[M10] * v[M21] * v[M02] * v[M33] + v[M20] * v[M01] * v[M12] * v[M33] + - v[M00] * v[M21] * v[M12] * v[M33] - v[M10] * v[M01] * v[M22] * v[M33] + v[M00] * v[M11] * v[M22] * v[M33]; + } + + translate (x: number, y: number, z: number): Matrix4 { + let v = this.values; + v[M03] += x; + v[M13] += y; + v[M23] += z; + return this; + } + + copy (): Matrix4 { + return new Matrix4().set(this.values); + } + + projection (near: number, far: number, fovy: number, aspectRatio: number): Matrix4 { + this.identity(); + let l_fd = (1.0 / Math.tan((fovy * (Math.PI / 180)) / 2.0)); + let l_a1 = (far + near) / (near - far); + let l_a2 = (2 * far * near) / (near - far); + let v = this.values; + v[M00] = l_fd / aspectRatio; + v[M10] = 0; + v[M20] = 0; + v[M30] = 0; + v[M01] = 0; + v[M11] = l_fd; + v[M21] = 0; + v[M31] = 0; + v[M02] = 0; + v[M12] = 0; + v[M22] = l_a1; + v[M32] = -1; + v[M03] = 0; + v[M13] = 0; + v[M23] = l_a2; + v[M33] = 0; + return this; + } + + ortho2d (x: number, y: number, width: number, height: number): Matrix4 { + return this.ortho(x, x + width, y, y + height, 0, 1); + } + + ortho (left: number, right: number, bottom: number, top: number, near: number, far: number): Matrix4 { + this.identity(); + let x_orth = 2 / (right - left); + let y_orth = 2 / (top - bottom); + let z_orth = -2 / (far - near); + + let tx = -(right + left) / (right - left); + let ty = -(top + bottom) / (top - bottom); + let tz = -(far + near) / (far - near); + + let v = this.values; + v[M00] = x_orth; + v[M10] = 0; + v[M20] = 0; + v[M30] = 0; + v[M01] = 0; + v[M11] = y_orth; + v[M21] = 0; + v[M31] = 0; + v[M02] = 0; + v[M12] = 0; + v[M22] = z_orth; + v[M32] = 0; + v[M03] = tx; + v[M13] = ty; + v[M23] = tz; + v[M33] = 1; + return this; + } + + multiply (matrix: Matrix4): Matrix4 { + let t = this.temp; + let v = this.values; + let m = matrix.values; + t[M00] = v[M00] * m[M00] + v[M01] * m[M10] + v[M02] * m[M20] + v[M03] * m[M30]; + t[M01] = v[M00] * m[M01] + v[M01] * m[M11] + v[M02] * m[M21] + v[M03] * m[M31]; + t[M02] = v[M00] * m[M02] + v[M01] * m[M12] + v[M02] * m[M22] + v[M03] * m[M32]; + t[M03] = v[M00] * m[M03] + v[M01] * m[M13] + v[M02] * m[M23] + v[M03] * m[M33]; + t[M10] = v[M10] * m[M00] + v[M11] * m[M10] + v[M12] * m[M20] + v[M13] * m[M30]; + t[M11] = v[M10] * m[M01] + v[M11] * m[M11] + v[M12] * m[M21] + v[M13] * m[M31]; + t[M12] = v[M10] * m[M02] + v[M11] * m[M12] + v[M12] * m[M22] + v[M13] * m[M32]; + t[M13] = v[M10] * m[M03] + v[M11] * m[M13] + v[M12] * m[M23] + v[M13] * m[M33]; + t[M20] = v[M20] * m[M00] + v[M21] * m[M10] + v[M22] * m[M20] + v[M23] * m[M30]; + t[M21] = v[M20] * m[M01] + v[M21] * m[M11] + v[M22] * m[M21] + v[M23] * m[M31]; + t[M22] = v[M20] * m[M02] + v[M21] * m[M12] + v[M22] * m[M22] + v[M23] * m[M32]; + t[M23] = v[M20] * m[M03] + v[M21] * m[M13] + v[M22] * m[M23] + v[M23] * m[M33]; + t[M30] = v[M30] * m[M00] + v[M31] * m[M10] + v[M32] * m[M20] + v[M33] * m[M30]; + t[M31] = v[M30] * m[M01] + v[M31] * m[M11] + v[M32] * m[M21] + v[M33] * m[M31]; + t[M32] = v[M30] * m[M02] + v[M31] * m[M12] + v[M32] * m[M22] + v[M33] * m[M32]; + t[M33] = v[M30] * m[M03] + v[M31] * m[M13] + v[M32] * m[M23] + v[M33] * m[M33]; + return this.set(this.temp); + } + + multiplyLeft (matrix: Matrix4): Matrix4 { + let t = this.temp; + let v = this.values; + let m = matrix.values; + t[M00] = m[M00] * v[M00] + m[M01] * v[M10] + m[M02] * v[M20] + m[M03] * v[M30]; + t[M01] = m[M00] * v[M01] + m[M01] * v[M11] + m[M02] * v[M21] + m[M03] * v[M31]; + t[M02] = m[M00] * v[M02] + m[M01] * v[M12] + m[M02] * v[M22] + m[M03] * v[M32]; + t[M03] = m[M00] * v[M03] + m[M01] * v[M13] + m[M02] * v[M23] + m[M03] * v[M33]; + t[M10] = m[M10] * v[M00] + m[M11] * v[M10] + m[M12] * v[M20] + m[M13] * v[M30]; + t[M11] = m[M10] * v[M01] + m[M11] * v[M11] + m[M12] * v[M21] + m[M13] * v[M31]; + t[M12] = m[M10] * v[M02] + m[M11] * v[M12] + m[M12] * v[M22] + m[M13] * v[M32]; + t[M13] = m[M10] * v[M03] + m[M11] * v[M13] + m[M12] * v[M23] + m[M13] * v[M33]; + t[M20] = m[M20] * v[M00] + m[M21] * v[M10] + m[M22] * v[M20] + m[M23] * v[M30]; + t[M21] = m[M20] * v[M01] + m[M21] * v[M11] + m[M22] * v[M21] + m[M23] * v[M31]; + t[M22] = m[M20] * v[M02] + m[M21] * v[M12] + m[M22] * v[M22] + m[M23] * v[M32]; + t[M23] = m[M20] * v[M03] + m[M21] * v[M13] + m[M22] * v[M23] + m[M23] * v[M33]; + t[M30] = m[M30] * v[M00] + m[M31] * v[M10] + m[M32] * v[M20] + m[M33] * v[M30]; + t[M31] = m[M30] * v[M01] + m[M31] * v[M11] + m[M32] * v[M21] + m[M33] * v[M31]; + t[M32] = m[M30] * v[M02] + m[M31] * v[M12] + m[M32] * v[M22] + m[M33] * v[M32]; + t[M33] = m[M30] * v[M03] + m[M31] * v[M13] + m[M32] * v[M23] + m[M33] * v[M33]; + return this.set(this.temp); + } + + lookAt (position: Vector3, direction: Vector3, up: Vector3) { + Matrix4.initTemps(); + let xAxis = Matrix4.xAxis, yAxis = Matrix4.yAxis, zAxis = Matrix4.zAxis; + zAxis.setFrom(direction).normalize(); + xAxis.setFrom(direction).normalize(); + xAxis.cross(up).normalize(); + yAxis.setFrom(xAxis).cross(zAxis).normalize(); + this.identity(); + let val = this.values; + val[M00] = xAxis.x; + val[M01] = xAxis.y; + val[M02] = xAxis.z; + val[M10] = yAxis.x; + val[M11] = yAxis.y; + val[M12] = yAxis.z; + val[M20] = -zAxis.x; + val[M21] = -zAxis.y; + val[M22] = -zAxis.z; + + Matrix4.tmpMatrix.identity(); + Matrix4.tmpMatrix.values[M03] = -position.x; + Matrix4.tmpMatrix.values[M13] = -position.y; + Matrix4.tmpMatrix.values[M23] = -position.z; + this.multiply(Matrix4.tmpMatrix) + + return this; + } + + static initTemps() { + if (Matrix4.xAxis === null) Matrix4.xAxis = new Vector3(); + if (Matrix4.yAxis === null) Matrix4.yAxis = new Vector3(); + if (Matrix4.zAxis === null) Matrix4.zAxis = new Vector3(); + } + } } diff --git a/spine-ts/webgl/src/Mesh.ts b/spine-ts/webgl/src/Mesh.ts index 2cb23cc0a1..6d2480ee52 100644 --- a/spine-ts/webgl/src/Mesh.ts +++ b/spine-ts/webgl/src/Mesh.ts @@ -1,184 +1,183 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.webgl { - export class Mesh implements Disposable { - private gl: WebGLRenderingContext; - private vertices:Float32Array; - private verticesBuffer: WebGLBuffer; - private verticesLength = 0; - private dirtyVertices = false; - private indices:Uint16Array; - private indicesBuffer: WebGLBuffer; - private indicesLength = 0; - private dirtyIndices = false; - private elementsPerVertex = 0; - - getAttributes (): VertexAttribute[] { return this.attributes; } - - maxVertices (): number { return this.vertices.length / this.elementsPerVertex; } - numVertices (): number { return this.verticesLength / this.elementsPerVertex; } - setVerticesLength (length: number) { - this.dirtyVertices = true; - this.verticesLength = length; - } - getVertices (): Float32Array { return this.vertices; } - - maxIndices (): number { return this.indices.length; } - numIndices (): number { return this.indicesLength; } - setIndicesLength (length: number) { - this.dirtyIndices = true; - this.indicesLength = length; - } - getIndices (): Uint16Array { return this.indices }; - - constructor (gl: WebGLRenderingContext, private attributes: VertexAttribute[], maxVertices: number, maxIndices: number) { - this.gl = gl; - this.elementsPerVertex = 0; - for (let i = 0; i < attributes.length; i++) { - this.elementsPerVertex += attributes[i].numElements; - } - this.vertices = new Float32Array(maxVertices * this.elementsPerVertex); - this.indices = new Uint16Array(maxIndices); - } - - setVertices (vertices: Array) { - this.dirtyVertices = true; - if (vertices.length > this.vertices.length) throw Error("Mesh can't store more than " + this.maxVertices() + " vertices"); - this.vertices.set(vertices, 0); - this.verticesLength = vertices.length; - } - - setIndices (indices: Array) { - this.dirtyIndices = true; - if (indices.length > this.indices.length) throw Error("Mesh can't store more than " + this.maxIndices() + " indices"); - this.indices.set(indices, 0); - this.indicesLength = indices.length; - } - - draw (shader: Shader, primitiveType: number) { - this.drawWithOffset(shader, primitiveType, 0, this.indicesLength > 0? this.indicesLength: this.verticesLength / this.elementsPerVertex); - } - - drawWithOffset (shader: Shader, primitiveType: number, offset: number, count: number) { - let gl = this.gl; - if (this.dirtyVertices || this.dirtyIndices) this.update(); - this.bind(shader); - if (this.indicesLength > 0) gl.drawElements(primitiveType, count, gl.UNSIGNED_SHORT, offset * 2); - else gl.drawArrays(primitiveType, offset, count); - this.unbind(shader); - } - - bind (shader: Shader) { - let gl = this.gl; - gl.bindBuffer(gl.ARRAY_BUFFER, this.verticesBuffer); - let offset = 0; - for (let i = 0; i < this.attributes.length; i++) { - let attrib = this.attributes[i]; - let location = shader.getAttributeLocation(attrib.name); - gl.enableVertexAttribArray(location); - gl.vertexAttribPointer(location, attrib.numElements, gl.FLOAT, false, this.elementsPerVertex * 4, offset * 4); - offset += attrib.numElements; - } - if (this.indicesLength > 0) gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer); - } - - unbind (shader: Shader) { - let gl = this.gl; - for (let i = 0; i < this.attributes.length; i++) { - let attrib = this.attributes[i]; - let location = shader.getAttributeLocation(attrib.name); - gl.disableVertexAttribArray(location); - } - gl.bindBuffer(gl.ARRAY_BUFFER, null); - if (this.indicesLength > 0) gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); - } - - private update () { - let gl = this.gl; - if (this.dirtyVertices) { - if (!this.verticesBuffer) { - this.verticesBuffer = gl.createBuffer(); - } - gl.bindBuffer(gl.ARRAY_BUFFER, this.verticesBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.vertices.subarray(0, this.verticesLength), gl.STATIC_DRAW); - this.dirtyVertices = false; - } - - if (this.dirtyIndices) { - if (!this.indicesBuffer) { - this.indicesBuffer = gl.createBuffer(); - } - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices.subarray(0, this.indicesLength), gl.STATIC_DRAW); - this.dirtyIndices = false; - } - } - - dispose () { - let gl = this.gl; - gl.deleteBuffer(this.verticesBuffer); - gl.deleteBuffer(this.indicesBuffer); - } - } - - export class VertexAttribute { - constructor (public name: string, public type: VertexAttributeType, public numElements: number) { } - } - - export class Position2Attribute extends VertexAttribute { - constructor () { - super(Shader.POSITION, VertexAttributeType.Float, 2); - } - } - - export class Position3Attribute extends VertexAttribute { - constructor () { - super(Shader.POSITION, VertexAttributeType.Float, 3); - } - } - - export class TexCoordAttribute extends VertexAttribute { - constructor (unit: number = 0) { - super(Shader.TEXCOORDS + (unit == 0? "": unit), VertexAttributeType.Float, 2); - } - } - - export class ColorAttribute extends VertexAttribute { - constructor () { - super(Shader.COLOR, VertexAttributeType.Float, 4); - } - } - - export enum VertexAttributeType { - Float - } +module spine.webgl { + export class Mesh implements Disposable { + private gl: WebGLRenderingContext; + private vertices:Float32Array; + private verticesBuffer: WebGLBuffer; + private verticesLength = 0; + private dirtyVertices = false; + private indices:Uint16Array; + private indicesBuffer: WebGLBuffer; + private indicesLength = 0; + private dirtyIndices = false; + private elementsPerVertex = 0; + + getAttributes (): VertexAttribute[] { return this.attributes; } + + maxVertices (): number { return this.vertices.length / this.elementsPerVertex; } + numVertices (): number { return this.verticesLength / this.elementsPerVertex; } + setVerticesLength (length: number) { + this.dirtyVertices = true; + this.verticesLength = length; + } + getVertices (): Float32Array { return this.vertices; } + + maxIndices (): number { return this.indices.length; } + numIndices (): number { return this.indicesLength; } + setIndicesLength (length: number) { + this.dirtyIndices = true; + this.indicesLength = length; + } + getIndices (): Uint16Array { return this.indices }; + + constructor (gl: WebGLRenderingContext, private attributes: VertexAttribute[], maxVertices: number, maxIndices: number) { + this.gl = gl; + this.elementsPerVertex = 0; + for (let i = 0; i < attributes.length; i++) { + this.elementsPerVertex += attributes[i].numElements; + } + this.vertices = new Float32Array(maxVertices * this.elementsPerVertex); + this.indices = new Uint16Array(maxIndices); + } + + setVertices (vertices: Array) { + this.dirtyVertices = true; + if (vertices.length > this.vertices.length) throw Error("Mesh can't store more than " + this.maxVertices() + " vertices"); + this.vertices.set(vertices, 0); + this.verticesLength = vertices.length; + } + + setIndices (indices: Array) { + this.dirtyIndices = true; + if (indices.length > this.indices.length) throw Error("Mesh can't store more than " + this.maxIndices() + " indices"); + this.indices.set(indices, 0); + this.indicesLength = indices.length; + } + + draw (shader: Shader, primitiveType: number) { + this.drawWithOffset(shader, primitiveType, 0, this.indicesLength > 0? this.indicesLength: this.verticesLength / this.elementsPerVertex); + } + + drawWithOffset (shader: Shader, primitiveType: number, offset: number, count: number) { + let gl = this.gl; + if (this.dirtyVertices || this.dirtyIndices) this.update(); + this.bind(shader); + if (this.indicesLength > 0) gl.drawElements(primitiveType, count, gl.UNSIGNED_SHORT, offset * 2); + else gl.drawArrays(primitiveType, offset, count); + this.unbind(shader); + } + + bind (shader: Shader) { + let gl = this.gl; + gl.bindBuffer(gl.ARRAY_BUFFER, this.verticesBuffer); + let offset = 0; + for (let i = 0; i < this.attributes.length; i++) { + let attrib = this.attributes[i]; + let location = shader.getAttributeLocation(attrib.name); + gl.enableVertexAttribArray(location); + gl.vertexAttribPointer(location, attrib.numElements, gl.FLOAT, false, this.elementsPerVertex * 4, offset * 4); + offset += attrib.numElements; + } + if (this.indicesLength > 0) gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer); + } + + unbind (shader: Shader) { + let gl = this.gl; + for (let i = 0; i < this.attributes.length; i++) { + let attrib = this.attributes[i]; + let location = shader.getAttributeLocation(attrib.name); + gl.disableVertexAttribArray(location); + } + gl.bindBuffer(gl.ARRAY_BUFFER, null); + if (this.indicesLength > 0) gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); + } + + private update () { + let gl = this.gl; + if (this.dirtyVertices) { + if (!this.verticesBuffer) { + this.verticesBuffer = gl.createBuffer(); + } + gl.bindBuffer(gl.ARRAY_BUFFER, this.verticesBuffer); + gl.bufferData(gl.ARRAY_BUFFER, this.vertices.subarray(0, this.verticesLength), gl.STATIC_DRAW); + this.dirtyVertices = false; + } + + if (this.dirtyIndices) { + if (!this.indicesBuffer) { + this.indicesBuffer = gl.createBuffer(); + } + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices.subarray(0, this.indicesLength), gl.STATIC_DRAW); + this.dirtyIndices = false; + } + } + + dispose () { + let gl = this.gl; + gl.deleteBuffer(this.verticesBuffer); + gl.deleteBuffer(this.indicesBuffer); + } + } + + export class VertexAttribute { + constructor (public name: string, public type: VertexAttributeType, public numElements: number) { } + } + + export class Position2Attribute extends VertexAttribute { + constructor () { + super(Shader.POSITION, VertexAttributeType.Float, 2); + } + } + + export class Position3Attribute extends VertexAttribute { + constructor () { + super(Shader.POSITION, VertexAttributeType.Float, 3); + } + } + + export class TexCoordAttribute extends VertexAttribute { + constructor (unit: number = 0) { + super(Shader.TEXCOORDS + (unit == 0? "": unit), VertexAttributeType.Float, 2); + } + } + + export class ColorAttribute extends VertexAttribute { + constructor () { + super(Shader.COLOR, VertexAttributeType.Float, 4); + } + } + + export enum VertexAttributeType { + Float + } } diff --git a/spine-ts/webgl/src/PolygonBatcher.ts b/spine-ts/webgl/src/PolygonBatcher.ts index 3625908aa3..537033e756 100644 --- a/spine-ts/webgl/src/PolygonBatcher.ts +++ b/spine-ts/webgl/src/PolygonBatcher.ts @@ -1,125 +1,124 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.webgl { - export class PolygonBatcher implements Disposable { - private gl: WebGLRenderingContext; - private drawCalls: number; - private isDrawing = false; - private mesh: Mesh; - private shader: Shader = null; - private lastTexture: GLTexture = null; - private verticesLength = 0; - private indicesLength = 0; - private srcBlend: number = WebGLRenderingContext.SRC_ALPHA; - private dstBlend: number = WebGLRenderingContext.ONE_MINUS_SRC_ALPHA; - - constructor (gl: WebGLRenderingContext, maxVertices: number = 10920) { - if (maxVertices > 10920) throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices); - this.gl = gl; - this.mesh = new Mesh(gl, [new Position2Attribute(), new ColorAttribute(), new TexCoordAttribute()], maxVertices, maxVertices * 3); - } - - begin (shader: Shader) { - let gl = this.gl; - if (this.isDrawing) throw new Error("PolygonBatch is already drawing. Call PolygonBatch.end() before calling PolygonBatch.begin()"); - this.drawCalls = 0; - this.shader = shader; - this.lastTexture = null; - this.isDrawing = true; - - gl.enable(gl.BLEND); - gl.blendFunc(this.srcBlend, this.dstBlend); - } - - setBlendMode (srcBlend: number, dstBlend: number) { - let gl = this.gl; - this.srcBlend = srcBlend; - this.dstBlend = dstBlend; - if (this.isDrawing) { - this.flush(); - gl.blendFunc(this.srcBlend, this.dstBlend); - } - } - - draw (texture: GLTexture, vertices: ArrayLike, indices: Array) { - if (texture != this.lastTexture) { - this.flush(); - this.lastTexture = texture; - texture.bind(); - } else if (this.verticesLength + vertices.length > this.mesh.getVertices().length || - this.indicesLength + indices.length > this.mesh.getIndices().length) { - this.flush(); - } - - let indexStart = this.mesh.numVertices(); - this.mesh.getVertices().set(vertices, this.verticesLength); - this.verticesLength += vertices.length; - this.mesh.setVerticesLength(this.verticesLength) - - let indicesArray = this.mesh.getIndices(); - for (let i = this.indicesLength, j = 0; j < indices.length; i++, j++) - indicesArray[i] = indices[j] + indexStart; - this.indicesLength += indices.length; - this.mesh.setIndicesLength(this.indicesLength); - } - - private flush () { - let gl = this.gl; - if (this.verticesLength == 0) return; - - this.mesh.draw(this.shader, gl.TRIANGLES); - - this.verticesLength = 0; - this.indicesLength = 0; - this.mesh.setVerticesLength(0); - this.mesh.setIndicesLength(0); - this.drawCalls++; - } - - end () { - let gl = this.gl; - if (!this.isDrawing) throw new Error("PolygonBatch is not drawing. Call PolygonBatch.begin() before calling PolygonBatch.end()"); - if (this.verticesLength > 0 || this.indicesLength > 0) this.flush(); - this.shader = null; - this.lastTexture = null; - this.isDrawing = false; - - gl.disable(gl.BLEND); - } - - getDrawCalls () { return this.drawCalls; } - - dispose () { - this.mesh.dispose(); - } - } +module spine.webgl { + export class PolygonBatcher implements Disposable { + private gl: WebGLRenderingContext; + private drawCalls: number; + private isDrawing = false; + private mesh: Mesh; + private shader: Shader = null; + private lastTexture: GLTexture = null; + private verticesLength = 0; + private indicesLength = 0; + private srcBlend: number = WebGLRenderingContext.SRC_ALPHA; + private dstBlend: number = WebGLRenderingContext.ONE_MINUS_SRC_ALPHA; + + constructor (gl: WebGLRenderingContext, maxVertices: number = 10920) { + if (maxVertices > 10920) throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices); + this.gl = gl; + this.mesh = new Mesh(gl, [new Position2Attribute(), new ColorAttribute(), new TexCoordAttribute()], maxVertices, maxVertices * 3); + } + + begin (shader: Shader) { + let gl = this.gl; + if (this.isDrawing) throw new Error("PolygonBatch is already drawing. Call PolygonBatch.end() before calling PolygonBatch.begin()"); + this.drawCalls = 0; + this.shader = shader; + this.lastTexture = null; + this.isDrawing = true; + + gl.enable(gl.BLEND); + gl.blendFunc(this.srcBlend, this.dstBlend); + } + + setBlendMode (srcBlend: number, dstBlend: number) { + let gl = this.gl; + this.srcBlend = srcBlend; + this.dstBlend = dstBlend; + if (this.isDrawing) { + this.flush(); + gl.blendFunc(this.srcBlend, this.dstBlend); + } + } + + draw (texture: GLTexture, vertices: ArrayLike, indices: Array) { + if (texture != this.lastTexture) { + this.flush(); + this.lastTexture = texture; + texture.bind(); + } else if (this.verticesLength + vertices.length > this.mesh.getVertices().length || + this.indicesLength + indices.length > this.mesh.getIndices().length) { + this.flush(); + } + + let indexStart = this.mesh.numVertices(); + this.mesh.getVertices().set(vertices, this.verticesLength); + this.verticesLength += vertices.length; + this.mesh.setVerticesLength(this.verticesLength) + + let indicesArray = this.mesh.getIndices(); + for (let i = this.indicesLength, j = 0; j < indices.length; i++, j++) + indicesArray[i] = indices[j] + indexStart; + this.indicesLength += indices.length; + this.mesh.setIndicesLength(this.indicesLength); + } + + private flush () { + let gl = this.gl; + if (this.verticesLength == 0) return; + + this.mesh.draw(this.shader, gl.TRIANGLES); + + this.verticesLength = 0; + this.indicesLength = 0; + this.mesh.setVerticesLength(0); + this.mesh.setIndicesLength(0); + this.drawCalls++; + } + + end () { + let gl = this.gl; + if (!this.isDrawing) throw new Error("PolygonBatch is not drawing. Call PolygonBatch.begin() before calling PolygonBatch.end()"); + if (this.verticesLength > 0 || this.indicesLength > 0) this.flush(); + this.shader = null; + this.lastTexture = null; + this.isDrawing = false; + + gl.disable(gl.BLEND); + } + + getDrawCalls () { return this.drawCalls; } + + dispose () { + this.mesh.dispose(); + } + } } diff --git a/spine-ts/webgl/src/SceneRenderer.ts b/spine-ts/webgl/src/SceneRenderer.ts index 20faed1d3e..3dd4f3ad27 100644 --- a/spine-ts/webgl/src/SceneRenderer.ts +++ b/spine-ts/webgl/src/SceneRenderer.ts @@ -1,370 +1,369 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.webgl { - export class SceneRenderer implements Disposable { - gl: WebGLRenderingContext; - canvas: HTMLCanvasElement; - camera: OrthoCamera; - batcher: PolygonBatcher; - private batcherShader: Shader; - private shapes: ShapeRenderer; - private shapesShader: Shader; - private activeRenderer: PolygonBatcher | ShapeRenderer | SkeletonDebugRenderer = null; - private skeletonRenderer: SkeletonRenderer; - private skeletonDebugRenderer: SkeletonDebugRenderer; - private QUAD = [ - 0, 0, 1, 1, 1, 1, 0, 0, - 0, 0, 1, 1, 1, 1, 0, 0, - 0, 0, 1, 1, 1, 1, 0, 0, - 0, 0, 1, 1, 1, 1, 0, 0, - ]; - private QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; - private WHITE = new Color(1, 1, 1, 1); - - constructor (canvas: HTMLCanvasElement, gl: WebGLRenderingContext) { - this.canvas = canvas; - this.gl = gl; - this.camera = new OrthoCamera(canvas.width, canvas.height); - this.batcherShader = Shader.newColoredTextured(gl); - this.batcher = new PolygonBatcher(gl); - this.shapesShader = Shader.newColored(gl); - this.shapes = new ShapeRenderer(gl); - this.skeletonRenderer = new SkeletonRenderer(gl); - this.skeletonDebugRenderer = new SkeletonDebugRenderer(gl); - } - - begin () { - this.camera.update(); - this.enableRenderer(this.batcher); - } - - drawSkeleton (skeleton: Skeleton, premultipliedAlpha = false) { - this.enableRenderer(this.batcher); - this.skeletonRenderer.premultipliedAlpha = premultipliedAlpha; - this.skeletonRenderer.draw(this.batcher, skeleton); - } - - drawSkeletonDebug(skeleton: Skeleton, premultipliedAlpha = false, ignoredBones: Array = null) { - this.enableRenderer(this.shapes); - this.skeletonDebugRenderer.premultipliedAlpha = premultipliedAlpha; - this.skeletonDebugRenderer.draw(this.shapes, skeleton, ignoredBones); - } - - drawTexture (texture: GLTexture, x: number, y: number, width: number, height: number, color: Color = null) { - this.enableRenderer(this.batcher); - if (color === null) color = this.WHITE; - let quad = this.QUAD; - quad[0] = x; - quad[1] = y; - quad[2] = color.r; - quad[3] = color.g; - quad[4] = color.b; - quad[5] = color.a; - quad[6] = 0; - quad[7] = 1; - quad[8] = x + width; - quad[9] = y; - quad[10] = color.r; - quad[11] = color.g; - quad[12] = color.b; - quad[13] = color.a; - quad[14] = 1; - quad[15] = 1; - quad[16] = x + width; - quad[17] = y + height; - quad[18] = color.r; - quad[19] = color.g; - quad[20] = color.b; - quad[21] = color.a; - quad[22] = 1; - quad[23] = 0; - quad[24] = x; - quad[25] = y + height; - quad[26] = color.r; - quad[27] = color.g; - quad[28] = color.b; - quad[29] = color.a; - quad[30] = 0; - quad[31] = 0; - this.batcher.draw(texture, quad, this.QUAD_TRIANGLES); - } - - drawTextureRotated (texture: GLTexture, x: number, y: number, width: number, height: number, pivotX: number, pivotY: number, angle: number, color: Color = null, premultipliedAlpha: boolean = false) { - this.enableRenderer(this.batcher); - if (color === null) color = this.WHITE; - let quad = this.QUAD; - - // bottom left and top right corner points relative to origin - let worldOriginX = x + pivotX; - let worldOriginY = y + pivotY; - let fx = -pivotX; - let fy = -pivotY; - let fx2 = width - pivotX; - let fy2 = height - pivotY; - - // construct corner points, start from top left and go counter clockwise - let p1x = fx; - let p1y = fy; - let p2x = fx; - let p2y = fy2; - let p3x = fx2; - let p3y = fy2; - let p4x = fx2; - let p4y = fy; - - let x1 = 0; - let y1 = 0; - let x2 = 0; - let y2 = 0; - let x3 = 0; - let y3 = 0; - let x4 = 0; - let y4 = 0; - - // rotate - if (angle != 0) { - let cos = MathUtils.cosDeg(angle); - let sin = MathUtils.sinDeg(angle); - - x1 = cos * p1x - sin * p1y; - y1 = sin * p1x + cos * p1y; - - x4 = cos * p2x - sin * p2y; - y4 = sin * p2x + cos * p2y; - - x3 = cos * p3x - sin * p3y; - y3 = sin * p3x + cos * p3y; - - x2 = x3 + (x1 - x4); - y2 = y3 + (y1 - y4); - } else { - x1 = p1x; - y1 = p1y; - - x4 = p2x; - y4 = p2y; - - x3 = p3x; - y3 = p3y; - - x2 = p4x; - y2 = p4y; - } - - x1 += worldOriginX; - y1 += worldOriginY; - x2 += worldOriginX; - y2 += worldOriginY; - x3 += worldOriginX; - y3 += worldOriginY; - x4 += worldOriginX; - y4 += worldOriginY; - - quad[0] = x1; - quad[1] = y1; - quad[2] = color.r; - quad[3] = color.g; - quad[4] = color.b; - quad[5] = color.a; - quad[6] = 0; - quad[7] = 1; - quad[8] = x2; - quad[9] = y2; - quad[10] = color.r; - quad[11] = color.g; - quad[12] = color.b; - quad[13] = color.a; - quad[14] = 1; - quad[15] = 1; - quad[16] = x3; - quad[17] = y3; - quad[18] = color.r; - quad[19] = color.g; - quad[20] = color.b; - quad[21] = color.a; - quad[22] = 1; - quad[23] = 0; - quad[24] = x4; - quad[25] = y4; - quad[26] = color.r; - quad[27] = color.g; - quad[28] = color.b; - quad[29] = color.a; - quad[30] = 0; - quad[31] = 0; - this.batcher.draw(texture, quad, this.QUAD_TRIANGLES); - } - - drawRegion (region: TextureAtlasRegion, x: number, y: number, width: number, height: number, color: Color = null, premultipliedAlpha: boolean = false) { - this.enableRenderer(this.batcher); - if (color === null) color = this.WHITE; - let quad = this.QUAD; - quad[0] = x; - quad[1] = y; - quad[2] = color.r; - quad[3] = color.g; - quad[4] = color.b; - quad[5] = color.a; - quad[6] = region.u; - quad[7] = region.v2; - quad[8] = x + width; - quad[9] = y; - quad[10] = color.r; - quad[11] = color.g; - quad[12] = color.b; - quad[13] = color.a; - quad[14] = region.u2; - quad[15] = region.v2; - quad[16] = x + width; - quad[17] = y + height; - quad[18] = color.r; - quad[19] = color.g; - quad[20] = color.b; - quad[21] = color.a; - quad[22] = region.u2; - quad[23] = region.v; - quad[24] = x; - quad[25] = y + height; - quad[26] = color.r; - quad[27] = color.g; - quad[28] = color.b; - quad[29] = color.a; - quad[30] = region.u; - quad[31] = region.v; - this.batcher.draw(region.texture, quad, this.QUAD_TRIANGLES); - } - - line (x: number, y: number, x2: number, y2: number, color: Color = null, color2: Color = null) { - this.enableRenderer(this.shapes); - this.shapes.line(x, y, x2, y2, color); - } - - triangle (filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, color: Color = null, color2: Color = null, color3: Color = null) { - this.enableRenderer(this.shapes); - this.shapes.triangle(filled, x, y, x2, y2, x3, y3, color, color2, color3); - } - - quad (filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, color: Color = null, color2: Color = null, color3: Color = null, color4: Color = null) { - this.enableRenderer(this.shapes); - this.shapes.quad(filled, x, y, x2, y2, x3, y3, x4, y4, color, color2, color3, color4); - } - - rect (filled: boolean, x: number, y: number, width: number, height: number, color: Color = null) { - this.enableRenderer(this.shapes); - this.shapes.rect(filled, x, y, width, height, color); - } - - rectLine (filled: boolean, x1: number, y1: number, x2: number, y2: number, width: number, color: Color = null) { - this.enableRenderer(this.shapes); - this.shapes.rectLine(filled, x1, y1, x2, y2, width, color); - } - - polygon (polygonVertices: ArrayLike, offset: number, count: number, color: Color = null) { - this.enableRenderer(this.shapes); - this.shapes.polygon(polygonVertices, offset, count, color); - } - - circle (filled: boolean, x: number, y: number, radius: number, color: Color = null, segments: number = 0) { - this.enableRenderer(this.shapes); - this.shapes.circle(filled, x, y, radius, color, segments); - } - - curve (x1: number, y1: number, cx1: number, cy1: number, cx2: number, cy2: number, x2: number, y2: number, segments: number, color: Color = null) { - this.enableRenderer(this.shapes); - this.shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, segments, color); - } - - end () { - if (this.activeRenderer === this.batcher) this.batcher.end(); - else if (this.activeRenderer === this.shapes) this.shapes.end(); - this.activeRenderer = null; - } - - resize (resizeMode: ResizeMode) { - let canvas = this.canvas; - var w = canvas.clientWidth; - var h = canvas.clientHeight; - if (canvas.width != w || canvas.height != h) { - canvas.width = w; - canvas.height = h; - } - this.gl.viewport(0, 0, canvas.width, canvas.height); - - if (resizeMode === ResizeMode.Stretch) { - // nothing to do, we simply apply the viewport size of the camera - } else if (resizeMode === ResizeMode.Expand) { - this.camera.setViewport(w, h); - } else if (resizeMode === ResizeMode.Fit) { - let sourceWidth = canvas.width, sourceHeight = canvas.height; - let targetWidth = this.camera.viewportWidth, targetHeight = this.camera.viewportHeight; - let targetRatio = targetHeight / targetWidth; - let sourceRatio = sourceHeight / sourceWidth; - let scale = targetRatio < sourceRatio ? targetWidth / sourceWidth : targetHeight / sourceHeight; - this.camera.viewportWidth = sourceWidth * scale; - this.camera.viewportHeight = sourceHeight * scale; - } - this.camera.update(); - } - - private enableRenderer(renderer: PolygonBatcher | ShapeRenderer | SkeletonDebugRenderer) { - if (this.activeRenderer === renderer) return; - this.end(); - if (renderer instanceof PolygonBatcher) { - this.batcherShader.bind(); - this.batcherShader.setUniform4x4f(Shader.MVP_MATRIX, this.camera.projectionView.values); - this.batcher.begin(this.batcherShader); - this.activeRenderer = this.batcher; - } else if (renderer instanceof ShapeRenderer) { - this.shapesShader.bind(); - this.shapesShader.setUniform4x4f(Shader.MVP_MATRIX, this.camera.projectionView.values); - this.shapes.begin(this.shapesShader); - this.activeRenderer = this.shapes; - } else { - this.activeRenderer = this.skeletonDebugRenderer; - } - } - - dispose () { - this.batcher.dispose(); - this.batcherShader.dispose(); - this.shapes.dispose(); - this.shapesShader.dispose(); - this.skeletonDebugRenderer.dispose(); - } - } - - export enum ResizeMode { - Stretch, - Expand, - Fit - } -} \ No newline at end of file +module spine.webgl { + export class SceneRenderer implements Disposable { + gl: WebGLRenderingContext; + canvas: HTMLCanvasElement; + camera: OrthoCamera; + batcher: PolygonBatcher; + private batcherShader: Shader; + private shapes: ShapeRenderer; + private shapesShader: Shader; + private activeRenderer: PolygonBatcher | ShapeRenderer | SkeletonDebugRenderer = null; + private skeletonRenderer: SkeletonRenderer; + private skeletonDebugRenderer: SkeletonDebugRenderer; + private QUAD = [ + 0, 0, 1, 1, 1, 1, 0, 0, + 0, 0, 1, 1, 1, 1, 0, 0, + 0, 0, 1, 1, 1, 1, 0, 0, + 0, 0, 1, 1, 1, 1, 0, 0, + ]; + private QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; + private WHITE = new Color(1, 1, 1, 1); + + constructor (canvas: HTMLCanvasElement, gl: WebGLRenderingContext) { + this.canvas = canvas; + this.gl = gl; + this.camera = new OrthoCamera(canvas.width, canvas.height); + this.batcherShader = Shader.newColoredTextured(gl); + this.batcher = new PolygonBatcher(gl); + this.shapesShader = Shader.newColored(gl); + this.shapes = new ShapeRenderer(gl); + this.skeletonRenderer = new SkeletonRenderer(gl); + this.skeletonDebugRenderer = new SkeletonDebugRenderer(gl); + } + + begin () { + this.camera.update(); + this.enableRenderer(this.batcher); + } + + drawSkeleton (skeleton: Skeleton, premultipliedAlpha = false) { + this.enableRenderer(this.batcher); + this.skeletonRenderer.premultipliedAlpha = premultipliedAlpha; + this.skeletonRenderer.draw(this.batcher, skeleton); + } + + drawSkeletonDebug(skeleton: Skeleton, premultipliedAlpha = false, ignoredBones: Array = null) { + this.enableRenderer(this.shapes); + this.skeletonDebugRenderer.premultipliedAlpha = premultipliedAlpha; + this.skeletonDebugRenderer.draw(this.shapes, skeleton, ignoredBones); + } + + drawTexture (texture: GLTexture, x: number, y: number, width: number, height: number, color: Color = null) { + this.enableRenderer(this.batcher); + if (color === null) color = this.WHITE; + let quad = this.QUAD; + quad[0] = x; + quad[1] = y; + quad[2] = color.r; + quad[3] = color.g; + quad[4] = color.b; + quad[5] = color.a; + quad[6] = 0; + quad[7] = 1; + quad[8] = x + width; + quad[9] = y; + quad[10] = color.r; + quad[11] = color.g; + quad[12] = color.b; + quad[13] = color.a; + quad[14] = 1; + quad[15] = 1; + quad[16] = x + width; + quad[17] = y + height; + quad[18] = color.r; + quad[19] = color.g; + quad[20] = color.b; + quad[21] = color.a; + quad[22] = 1; + quad[23] = 0; + quad[24] = x; + quad[25] = y + height; + quad[26] = color.r; + quad[27] = color.g; + quad[28] = color.b; + quad[29] = color.a; + quad[30] = 0; + quad[31] = 0; + this.batcher.draw(texture, quad, this.QUAD_TRIANGLES); + } + + drawTextureRotated (texture: GLTexture, x: number, y: number, width: number, height: number, pivotX: number, pivotY: number, angle: number, color: Color = null, premultipliedAlpha: boolean = false) { + this.enableRenderer(this.batcher); + if (color === null) color = this.WHITE; + let quad = this.QUAD; + + // bottom left and top right corner points relative to origin + let worldOriginX = x + pivotX; + let worldOriginY = y + pivotY; + let fx = -pivotX; + let fy = -pivotY; + let fx2 = width - pivotX; + let fy2 = height - pivotY; + + // construct corner points, start from top left and go counter clockwise + let p1x = fx; + let p1y = fy; + let p2x = fx; + let p2y = fy2; + let p3x = fx2; + let p3y = fy2; + let p4x = fx2; + let p4y = fy; + + let x1 = 0; + let y1 = 0; + let x2 = 0; + let y2 = 0; + let x3 = 0; + let y3 = 0; + let x4 = 0; + let y4 = 0; + + // rotate + if (angle != 0) { + let cos = MathUtils.cosDeg(angle); + let sin = MathUtils.sinDeg(angle); + + x1 = cos * p1x - sin * p1y; + y1 = sin * p1x + cos * p1y; + + x4 = cos * p2x - sin * p2y; + y4 = sin * p2x + cos * p2y; + + x3 = cos * p3x - sin * p3y; + y3 = sin * p3x + cos * p3y; + + x2 = x3 + (x1 - x4); + y2 = y3 + (y1 - y4); + } else { + x1 = p1x; + y1 = p1y; + + x4 = p2x; + y4 = p2y; + + x3 = p3x; + y3 = p3y; + + x2 = p4x; + y2 = p4y; + } + + x1 += worldOriginX; + y1 += worldOriginY; + x2 += worldOriginX; + y2 += worldOriginY; + x3 += worldOriginX; + y3 += worldOriginY; + x4 += worldOriginX; + y4 += worldOriginY; + + quad[0] = x1; + quad[1] = y1; + quad[2] = color.r; + quad[3] = color.g; + quad[4] = color.b; + quad[5] = color.a; + quad[6] = 0; + quad[7] = 1; + quad[8] = x2; + quad[9] = y2; + quad[10] = color.r; + quad[11] = color.g; + quad[12] = color.b; + quad[13] = color.a; + quad[14] = 1; + quad[15] = 1; + quad[16] = x3; + quad[17] = y3; + quad[18] = color.r; + quad[19] = color.g; + quad[20] = color.b; + quad[21] = color.a; + quad[22] = 1; + quad[23] = 0; + quad[24] = x4; + quad[25] = y4; + quad[26] = color.r; + quad[27] = color.g; + quad[28] = color.b; + quad[29] = color.a; + quad[30] = 0; + quad[31] = 0; + this.batcher.draw(texture, quad, this.QUAD_TRIANGLES); + } + + drawRegion (region: TextureAtlasRegion, x: number, y: number, width: number, height: number, color: Color = null, premultipliedAlpha: boolean = false) { + this.enableRenderer(this.batcher); + if (color === null) color = this.WHITE; + let quad = this.QUAD; + quad[0] = x; + quad[1] = y; + quad[2] = color.r; + quad[3] = color.g; + quad[4] = color.b; + quad[5] = color.a; + quad[6] = region.u; + quad[7] = region.v2; + quad[8] = x + width; + quad[9] = y; + quad[10] = color.r; + quad[11] = color.g; + quad[12] = color.b; + quad[13] = color.a; + quad[14] = region.u2; + quad[15] = region.v2; + quad[16] = x + width; + quad[17] = y + height; + quad[18] = color.r; + quad[19] = color.g; + quad[20] = color.b; + quad[21] = color.a; + quad[22] = region.u2; + quad[23] = region.v; + quad[24] = x; + quad[25] = y + height; + quad[26] = color.r; + quad[27] = color.g; + quad[28] = color.b; + quad[29] = color.a; + quad[30] = region.u; + quad[31] = region.v; + this.batcher.draw(region.texture, quad, this.QUAD_TRIANGLES); + } + + line (x: number, y: number, x2: number, y2: number, color: Color = null, color2: Color = null) { + this.enableRenderer(this.shapes); + this.shapes.line(x, y, x2, y2, color); + } + + triangle (filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, color: Color = null, color2: Color = null, color3: Color = null) { + this.enableRenderer(this.shapes); + this.shapes.triangle(filled, x, y, x2, y2, x3, y3, color, color2, color3); + } + + quad (filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, color: Color = null, color2: Color = null, color3: Color = null, color4: Color = null) { + this.enableRenderer(this.shapes); + this.shapes.quad(filled, x, y, x2, y2, x3, y3, x4, y4, color, color2, color3, color4); + } + + rect (filled: boolean, x: number, y: number, width: number, height: number, color: Color = null) { + this.enableRenderer(this.shapes); + this.shapes.rect(filled, x, y, width, height, color); + } + + rectLine (filled: boolean, x1: number, y1: number, x2: number, y2: number, width: number, color: Color = null) { + this.enableRenderer(this.shapes); + this.shapes.rectLine(filled, x1, y1, x2, y2, width, color); + } + + polygon (polygonVertices: ArrayLike, offset: number, count: number, color: Color = null) { + this.enableRenderer(this.shapes); + this.shapes.polygon(polygonVertices, offset, count, color); + } + + circle (filled: boolean, x: number, y: number, radius: number, color: Color = null, segments: number = 0) { + this.enableRenderer(this.shapes); + this.shapes.circle(filled, x, y, radius, color, segments); + } + + curve (x1: number, y1: number, cx1: number, cy1: number, cx2: number, cy2: number, x2: number, y2: number, segments: number, color: Color = null) { + this.enableRenderer(this.shapes); + this.shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, segments, color); + } + + end () { + if (this.activeRenderer === this.batcher) this.batcher.end(); + else if (this.activeRenderer === this.shapes) this.shapes.end(); + this.activeRenderer = null; + } + + resize (resizeMode: ResizeMode) { + let canvas = this.canvas; + var w = canvas.clientWidth; + var h = canvas.clientHeight; + if (canvas.width != w || canvas.height != h) { + canvas.width = w; + canvas.height = h; + } + this.gl.viewport(0, 0, canvas.width, canvas.height); + + if (resizeMode === ResizeMode.Stretch) { + // nothing to do, we simply apply the viewport size of the camera + } else if (resizeMode === ResizeMode.Expand) { + this.camera.setViewport(w, h); + } else if (resizeMode === ResizeMode.Fit) { + let sourceWidth = canvas.width, sourceHeight = canvas.height; + let targetWidth = this.camera.viewportWidth, targetHeight = this.camera.viewportHeight; + let targetRatio = targetHeight / targetWidth; + let sourceRatio = sourceHeight / sourceWidth; + let scale = targetRatio < sourceRatio ? targetWidth / sourceWidth : targetHeight / sourceHeight; + this.camera.viewportWidth = sourceWidth * scale; + this.camera.viewportHeight = sourceHeight * scale; + } + this.camera.update(); + } + + private enableRenderer(renderer: PolygonBatcher | ShapeRenderer | SkeletonDebugRenderer) { + if (this.activeRenderer === renderer) return; + this.end(); + if (renderer instanceof PolygonBatcher) { + this.batcherShader.bind(); + this.batcherShader.setUniform4x4f(Shader.MVP_MATRIX, this.camera.projectionView.values); + this.batcher.begin(this.batcherShader); + this.activeRenderer = this.batcher; + } else if (renderer instanceof ShapeRenderer) { + this.shapesShader.bind(); + this.shapesShader.setUniform4x4f(Shader.MVP_MATRIX, this.camera.projectionView.values); + this.shapes.begin(this.shapesShader); + this.activeRenderer = this.shapes; + } else { + this.activeRenderer = this.skeletonDebugRenderer; + } + } + + dispose () { + this.batcher.dispose(); + this.batcherShader.dispose(); + this.shapes.dispose(); + this.shapesShader.dispose(); + this.skeletonDebugRenderer.dispose(); + } + } + + export enum ResizeMode { + Stretch, + Expand, + Fit + } +} diff --git a/spine-ts/webgl/src/Shader.ts b/spine-ts/webgl/src/Shader.ts index b9352f1422..7682a66606 100644 --- a/spine-ts/webgl/src/Shader.ts +++ b/spine-ts/webgl/src/Shader.ts @@ -1,240 +1,239 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.webgl { - export class Shader implements Disposable { - public static MVP_MATRIX = "u_projTrans"; - public static POSITION = "a_position"; - public static COLOR = "a_color"; - public static TEXCOORDS = "a_texCoords"; - public static SAMPLER = "u_texture"; - - private gl: WebGLRenderingContext; - private vs: WebGLShader = null; - private fs: WebGLShader = null; - private program: WebGLProgram = null; - private tmp2x2: Float32Array = new Float32Array(2 * 2); - private tmp3x3: Float32Array = new Float32Array(3 * 3); - private tmp4x4: Float32Array = new Float32Array(4 * 4); - - public getProgram () { return this.program; } - public getVertexShader () { return this.vertexShader; } - public getFragmentShader () { return this.fragmentShader; } - - constructor (gl: WebGLRenderingContext, private vertexShader: string, private fragmentShader: string) { - this.gl = gl; - this.compile(); - } - - private compile () { - let gl = this.gl; - try { - this.vs = this.compileShader(gl.VERTEX_SHADER, this.vertexShader); - this.fs = this.compileShader(gl.FRAGMENT_SHADER, this.fragmentShader); - this.program = this.compileProgram(this.vs, this.fs); - } catch (e) { - this.dispose(); - throw e; - } - } - - private compileShader (type: number, source: string) { - let gl = this.gl; - let shader = gl.createShader(type); - gl.shaderSource(shader, source); - gl.compileShader(shader); - if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { - let error = "Couldn't compile shader: " + gl.getShaderInfoLog(shader); - gl.deleteShader(shader); - throw new Error(error); - } - return shader; - } - - private compileProgram (vs: WebGLShader, fs: WebGLShader) { - let gl = this.gl; - let program = gl.createProgram(); - gl.attachShader(program, vs); - gl.attachShader(program, fs); - gl.linkProgram(program); - - if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { - let error = "Couldn't compile shader program: " + gl.getProgramInfoLog(program); - gl.deleteProgram(program); - throw new Error(error); - } - return program; - } - - public bind () { - this.gl.useProgram(this.program); - } - - public unbind () { - this.gl.useProgram(null); - } - - public setUniformi (uniform: string, value: number) { - this.gl.uniform1i(this.getUniformLocation(uniform), value); - } - - public setUniformf (uniform: string, value: number) { - this.gl.uniform1f(this.getUniformLocation(uniform), value); - } - - public setUniform2f (uniform: string, value: number, value2: number) { - this.gl.uniform2f(this.getUniformLocation(uniform), value, value2); - } - - public setUniform3f (uniform: string, value: number, value2: number, value3: number) { - this.gl.uniform3f(this.getUniformLocation(uniform), value, value2, value3); - } - - public setUniform4f (uniform: string, value: number, value2: number, value3: number, value4: number) { - this.gl.uniform4f(this.getUniformLocation(uniform), value, value2, value3, value4); - } - - public setUniform2x2f (uniform: string, value: ArrayLike) { - let gl = this.gl; - this.tmp2x2.set(value); - gl.uniformMatrix2fv(this.getUniformLocation(uniform), false, this.tmp2x2); - } - - public setUniform3x3f (uniform: string, value: ArrayLike) { - let gl = this.gl; - this.tmp3x3.set(value); - gl.uniformMatrix3fv(this.getUniformLocation(uniform), false, this.tmp3x3); - } - - public setUniform4x4f (uniform: string, value: ArrayLike) { - let gl = this.gl; - this.tmp4x4.set(value); - gl.uniformMatrix4fv(this.getUniformLocation(uniform), false, this.tmp4x4); - } - - public getUniformLocation (uniform: string): WebGLUniformLocation { - let gl = this.gl; - let location = gl.getUniformLocation(this.program, uniform); - if (!location) throw new Error(`Couldn't find location for uniform ${uniform}`); - return location; - } - - public getAttributeLocation (attribute: string): number { - let gl = this.gl; - let location = gl.getAttribLocation(this.program, attribute); - if (location == -1) throw new Error(`Couldn't find location for attribute ${attribute}`); - return location; - } - - public dispose () { - let gl = this.gl; - if (this.vs) { - gl.deleteShader(this.vs); - this.vs = null; - } - - if (this.fs) { - gl.deleteShader(this.fs); - this.fs = null; - } - - if (this.program) { - gl.deleteProgram(this.program); - this.program = null; - } - } - - public static newColoredTextured (gl: WebGLRenderingContext): Shader { - let vs = ` - attribute vec4 ${Shader.POSITION}; - attribute vec4 ${Shader.COLOR}; - attribute vec2 ${Shader.TEXCOORDS}; - uniform mat4 ${Shader.MVP_MATRIX}; - varying vec4 v_color; - varying vec2 v_texCoords; - - void main () { - v_color = ${Shader.COLOR}; - v_texCoords = ${Shader.TEXCOORDS}; - gl_Position = ${Shader.MVP_MATRIX} * ${Shader.POSITION}; - } - `; - - let fs = ` - #ifdef GL_ES - #define LOWP lowp - precision mediump float; - #else - #define LOWP - #endif - varying LOWP vec4 v_color; - varying vec2 v_texCoords; - uniform sampler2D u_texture; - - void main () { - gl_FragColor = v_color * texture2D(u_texture, v_texCoords); - } - `; - - return new Shader(gl, vs, fs); - } - - public static newColored (gl: WebGLRenderingContext): Shader { - let vs = ` - attribute vec4 ${Shader.POSITION}; - attribute vec4 ${Shader.COLOR}; - uniform mat4 ${Shader.MVP_MATRIX}; - varying vec4 v_color; - - void main () { - v_color = ${Shader.COLOR}; - gl_Position = ${Shader.MVP_MATRIX} * ${Shader.POSITION}; - } - `; - - let fs = ` - #ifdef GL_ES - #define LOWP lowp - precision mediump float; - #else - #define LOWP - #endif - varying LOWP vec4 v_color; - - void main () { - gl_FragColor = v_color; - } - `; - - return new Shader(gl, vs, fs); - } - } +module spine.webgl { + export class Shader implements Disposable { + public static MVP_MATRIX = "u_projTrans"; + public static POSITION = "a_position"; + public static COLOR = "a_color"; + public static TEXCOORDS = "a_texCoords"; + public static SAMPLER = "u_texture"; + + private gl: WebGLRenderingContext; + private vs: WebGLShader = null; + private fs: WebGLShader = null; + private program: WebGLProgram = null; + private tmp2x2: Float32Array = new Float32Array(2 * 2); + private tmp3x3: Float32Array = new Float32Array(3 * 3); + private tmp4x4: Float32Array = new Float32Array(4 * 4); + + public getProgram () { return this.program; } + public getVertexShader () { return this.vertexShader; } + public getFragmentShader () { return this.fragmentShader; } + + constructor (gl: WebGLRenderingContext, private vertexShader: string, private fragmentShader: string) { + this.gl = gl; + this.compile(); + } + + private compile () { + let gl = this.gl; + try { + this.vs = this.compileShader(gl.VERTEX_SHADER, this.vertexShader); + this.fs = this.compileShader(gl.FRAGMENT_SHADER, this.fragmentShader); + this.program = this.compileProgram(this.vs, this.fs); + } catch (e) { + this.dispose(); + throw e; + } + } + + private compileShader (type: number, source: string) { + let gl = this.gl; + let shader = gl.createShader(type); + gl.shaderSource(shader, source); + gl.compileShader(shader); + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + let error = "Couldn't compile shader: " + gl.getShaderInfoLog(shader); + gl.deleteShader(shader); + throw new Error(error); + } + return shader; + } + + private compileProgram (vs: WebGLShader, fs: WebGLShader) { + let gl = this.gl; + let program = gl.createProgram(); + gl.attachShader(program, vs); + gl.attachShader(program, fs); + gl.linkProgram(program); + + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { + let error = "Couldn't compile shader program: " + gl.getProgramInfoLog(program); + gl.deleteProgram(program); + throw new Error(error); + } + return program; + } + + public bind () { + this.gl.useProgram(this.program); + } + + public unbind () { + this.gl.useProgram(null); + } + + public setUniformi (uniform: string, value: number) { + this.gl.uniform1i(this.getUniformLocation(uniform), value); + } + + public setUniformf (uniform: string, value: number) { + this.gl.uniform1f(this.getUniformLocation(uniform), value); + } + + public setUniform2f (uniform: string, value: number, value2: number) { + this.gl.uniform2f(this.getUniformLocation(uniform), value, value2); + } + + public setUniform3f (uniform: string, value: number, value2: number, value3: number) { + this.gl.uniform3f(this.getUniformLocation(uniform), value, value2, value3); + } + + public setUniform4f (uniform: string, value: number, value2: number, value3: number, value4: number) { + this.gl.uniform4f(this.getUniformLocation(uniform), value, value2, value3, value4); + } + + public setUniform2x2f (uniform: string, value: ArrayLike) { + let gl = this.gl; + this.tmp2x2.set(value); + gl.uniformMatrix2fv(this.getUniformLocation(uniform), false, this.tmp2x2); + } + + public setUniform3x3f (uniform: string, value: ArrayLike) { + let gl = this.gl; + this.tmp3x3.set(value); + gl.uniformMatrix3fv(this.getUniformLocation(uniform), false, this.tmp3x3); + } + + public setUniform4x4f (uniform: string, value: ArrayLike) { + let gl = this.gl; + this.tmp4x4.set(value); + gl.uniformMatrix4fv(this.getUniformLocation(uniform), false, this.tmp4x4); + } + + public getUniformLocation (uniform: string): WebGLUniformLocation { + let gl = this.gl; + let location = gl.getUniformLocation(this.program, uniform); + if (!location) throw new Error(`Couldn't find location for uniform ${uniform}`); + return location; + } + + public getAttributeLocation (attribute: string): number { + let gl = this.gl; + let location = gl.getAttribLocation(this.program, attribute); + if (location == -1) throw new Error(`Couldn't find location for attribute ${attribute}`); + return location; + } + + public dispose () { + let gl = this.gl; + if (this.vs) { + gl.deleteShader(this.vs); + this.vs = null; + } + + if (this.fs) { + gl.deleteShader(this.fs); + this.fs = null; + } + + if (this.program) { + gl.deleteProgram(this.program); + this.program = null; + } + } + + public static newColoredTextured (gl: WebGLRenderingContext): Shader { + let vs = ` + attribute vec4 ${Shader.POSITION}; + attribute vec4 ${Shader.COLOR}; + attribute vec2 ${Shader.TEXCOORDS}; + uniform mat4 ${Shader.MVP_MATRIX}; + varying vec4 v_color; + varying vec2 v_texCoords; + + void main () { + v_color = ${Shader.COLOR}; + v_texCoords = ${Shader.TEXCOORDS}; + gl_Position = ${Shader.MVP_MATRIX} * ${Shader.POSITION}; + } + `; + + let fs = ` + #ifdef GL_ES + #define LOWP lowp + precision mediump float; + #else + #define LOWP + #endif + varying LOWP vec4 v_color; + varying vec2 v_texCoords; + uniform sampler2D u_texture; + + void main () { + gl_FragColor = v_color * texture2D(u_texture, v_texCoords); + } + `; + + return new Shader(gl, vs, fs); + } + + public static newColored (gl: WebGLRenderingContext): Shader { + let vs = ` + attribute vec4 ${Shader.POSITION}; + attribute vec4 ${Shader.COLOR}; + uniform mat4 ${Shader.MVP_MATRIX}; + varying vec4 v_color; + + void main () { + v_color = ${Shader.COLOR}; + gl_Position = ${Shader.MVP_MATRIX} * ${Shader.POSITION}; + } + `; + + let fs = ` + #ifdef GL_ES + #define LOWP lowp + precision mediump float; + #else + #define LOWP + #endif + varying LOWP vec4 v_color; + + void main () { + gl_FragColor = v_color; + } + `; + + return new Shader(gl, vs, fs); + } + } } diff --git a/spine-ts/webgl/src/ShapeRenderer.ts b/spine-ts/webgl/src/ShapeRenderer.ts index 030b5dd822..b5e486e1a1 100644 --- a/spine-ts/webgl/src/ShapeRenderer.ts +++ b/spine-ts/webgl/src/ShapeRenderer.ts @@ -1,344 +1,343 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.webgl { - export class ShapeRenderer implements Disposable { - private gl: WebGLRenderingContext; - private isDrawing = false; - private mesh: Mesh; - private shapeType = ShapeType.Filled; - private color = new Color(1, 1, 1, 1); - private shader: Shader; - private vertexIndex = 0; - private tmp = new Vector2(); - private srcBlend: number = WebGLRenderingContext.SRC_ALPHA; - private dstBlend: number = WebGLRenderingContext.ONE_MINUS_SRC_ALPHA; - - constructor (gl: WebGLRenderingContext, maxVertices: number = 10920) { - if (maxVertices > 10920) throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices); - this.gl = gl; - this.mesh = new Mesh(gl, [new Position2Attribute(), new ColorAttribute()], maxVertices, 0); - } - - begin (shader: Shader) { - if (this.isDrawing) throw new Error("ShapeRenderer.begin() has already been called"); - this.shader = shader; - this.vertexIndex = 0; - this.isDrawing = true; - - let gl = this.gl; - gl.enable(gl.BLEND); - gl.blendFunc(this.srcBlend, this.dstBlend); - } - - setBlendMode (srcBlend: number, dstBlend: number) { - let gl = this.gl; - this.srcBlend = srcBlend; - this.dstBlend = dstBlend; - if (this.isDrawing) { - this.flush(); - gl.blendFunc(this.srcBlend, this.dstBlend); - } - } - - setColor (color: Color) { - this.color.setFromColor(color); - } - - setColorWith (r: number, g: number, b: number, a: number) { - this.color.set(r, g, b, a); - } - - point (x: number, y: number, color: Color = null) { - this.check(ShapeType.Point, 1); - if (color === null) color = this.color; - this.vertex(x, y, color); - } - - line (x: number, y: number, x2: number, y2: number, color: Color = null) { - this.check(ShapeType.Line, 2); - let vertices = this.mesh.getVertices(); - let idx = this.vertexIndex; - if (color === null) color = this.color; - this.vertex(x, y, color); - this.vertex(x2, y2, color); - } - - triangle (filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, color: Color = null, color2: Color = null, color3: Color = null) { - this.check(filled ? ShapeType.Filled : ShapeType.Line, 3); - let vertices = this.mesh.getVertices(); - let idx = this.vertexIndex; - if (color === null) color = this.color; - if (color2 === null) color2 = this.color; - if (color3 === null) color3 = this.color; - if (filled) { - this.vertex(x, y, color); - this.vertex(x2, y2, color2); - this.vertex(x3, y3, color3); - } else { - this.vertex(x, y, color); - this.vertex(x2, y2, color2); - - this.vertex(x2, y2, color); - this.vertex(x3, y3, color2); - - this.vertex(x3, y3, color); - this.vertex(x, y, color2); - } - } - - quad (filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, color: Color = null, color2: Color = null, color3: Color = null, color4: Color = null) { - this.check(filled ? ShapeType.Filled : ShapeType.Line, 3); - let vertices = this.mesh.getVertices(); - let idx = this.vertexIndex; - if (color === null) color = this.color; - if (color2 === null) color2 = this.color; - if (color3 === null) color3 = this.color; - if (color4 === null) color4 = this.color; - if (filled) { - this.vertex(x, y, color); this.vertex(x2, y2, color2); this.vertex(x3, y3, color3); - this.vertex(x3, y3, color3); this.vertex(x4, y4, color4); this.vertex(x, y, color); - } else { - this.vertex(x, y, color); this.vertex(x2, y2, color2); - this.vertex(x2, y2, color2); this.vertex(x3, y3, color3); - this.vertex(x3, y3, color3); this.vertex(x4, y4, color4); - this.vertex(x4, y4, color4); this.vertex(x, y, color); - } - } - - rect (filled: boolean, x: number, y: number, width: number, height: number, color: Color = null) { - this.quad(filled, x, y, x + width, y, x + width, y + height, x, y + height, color, color, color, color); - } - - rectLine (filled: boolean, x1: number, y1: number, x2: number, y2: number, width: number, color: Color = null) { - this.check(filled ? ShapeType.Filled : ShapeType.Line, 8); - if (color === null) color = this.color; - let t = this.tmp.set(y2 - y1, x1 - x2); - t.normalize(); - width *= 0.5; - let tx = t.x * width; - let ty = t.y * width; - if (!filled) { - this.vertex(x1 + tx, y1 + ty, color); - this.vertex(x1 - tx, y1 - ty, color); - this.vertex(x2 + tx, y2 + ty, color); - this.vertex(x2 - tx, y2 - ty, color); - - this.vertex(x2 + tx, y2 + ty, color); - this.vertex(x1 + tx, y1 + ty, color); - - this.vertex(x2 - tx, y2 - ty, color); - this.vertex(x1 - tx, y1 - ty, color); - } else { - this.vertex(x1 + tx, y1 + ty, color); - this.vertex(x1 - tx, y1 - ty, color); - this.vertex(x2 + tx, y2 + ty, color); - - this.vertex(x2 - tx, y2 - ty, color); - this.vertex(x2 + tx, y2 + ty, color); - this.vertex(x1 - tx, y1 - ty, color); - } - } - - x (x: number, y: number, size: number) { - this.line(x - size, y - size, x + size, y + size); - this.line(x - size, y + size, x + size, y - size); - } - - polygon (polygonVertices: ArrayLike, offset: number, count: number, color: Color = null) { - if (count < 3) throw new Error("Polygon must contain at least 3 vertices"); - this.check(ShapeType.Line, count * 2); - if (color === null) color = this.color; - let vertices = this.mesh.getVertices(); - let idx = this.vertexIndex; - - offset <<= 1; - count <<= 1; - - let firstX = polygonVertices[offset]; - let firstY = polygonVertices[offset + 1]; - let last = offset + count; - - for (let i = offset, n = offset + count - 2; i < n; i += 2) { - let x1 = polygonVertices[i]; - let y1 = polygonVertices[i+1]; - - let x2 = 0; - let y2 = 0; - - if (i + 2 >= last) { - x2 = firstX; - y2 = firstY; - } else { - x2 = polygonVertices[i + 2]; - y2 = polygonVertices[i + 3]; - } - - this.vertex(x1, y1, color); - this.vertex(x2, y2, color); - } - } - - circle (filled: boolean, x: number, y: number, radius: number, color: Color = null, segments: number = 0) { - if (segments === 0) segments = Math.max(1, (6 * MathUtils.cbrt(radius)) | 0); - if (segments <= 0) throw new Error("segments must be > 0."); - if (color === null) color = this.color; - let angle = 2 * MathUtils.PI / segments; - let cos = Math.cos(angle); - let sin = Math.sin(angle); - let cx = radius, cy = 0; - if (!filled) { - this.check(ShapeType.Line, segments * 2 + 2); - for (let i = 0; i < segments; i++) { - this.vertex(x + cx, y + cy, color); - let temp = cx; - cx = cos * cx - sin * cy; - cy = sin * temp + cos * cy; - this.vertex(x + cx, y + cy, color); - } - // Ensure the last segment is identical to the first. - this.vertex(x + cx, y + cy, color); - } else { - this.check(ShapeType.Filled, segments * 3 + 3); - segments--; - for (let i = 0; i < segments; i++) { - this.vertex(x, y, color); - this.vertex(x + cx, y + cy, color); - let temp = cx; - cx = cos * cx - sin * cy; - cy = sin * temp + cos * cy; - this.vertex(x + cx, y + cy, color); - } - // Ensure the last segment is identical to the first. - this.vertex(x, y, color); - this.vertex(x + cx, y + cy, color); - } - - let temp = cx; - cx = radius; - cy = 0; - this.vertex(x + cx, y + cy, color); - } - - curve (x1: number, y1: number, cx1: number, cy1: number, cx2: number, cy2: number, x2: number, y2: number, segments: number, color: Color = null) { - this.check(ShapeType.Line, segments * 2 + 2); - if (color === null) color = this.color; - - // Algorithm from: http://www.antigrain.com/research/bezier_interpolation/index.html#PAGE_BEZIER_INTERPOLATION - let subdiv_step = 1 / segments; - let subdiv_step2 = subdiv_step * subdiv_step; - let subdiv_step3 = subdiv_step * subdiv_step * subdiv_step; - - let pre1 = 3 * subdiv_step; - let pre2 = 3 * subdiv_step2; - let pre4 = 6 * subdiv_step2; - let pre5 = 6 * subdiv_step3; - - let tmp1x = x1 - cx1 * 2 + cx2; - let tmp1y = y1 - cy1 * 2 + cy2; - - let tmp2x = (cx1 - cx2) * 3 - x1 + x2; - let tmp2y = (cy1 - cy2) * 3 - y1 + y2; - - let fx = x1; - let fy = y1; - - let dfx = (cx1 - x1) * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3; - let dfy = (cy1 - y1) * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3; - - let ddfx = tmp1x * pre4 + tmp2x * pre5; - let ddfy = tmp1y * pre4 + tmp2y * pre5; - - let dddfx = tmp2x * pre5; - let dddfy = tmp2y * pre5; - - while (segments-- > 0) { - this.vertex(fx, fy, color); - fx += dfx; - fy += dfy; - dfx += ddfx; - dfy += ddfy; - ddfx += dddfx; - ddfy += dddfy; - this.vertex(fx, fy, color); - } - this.vertex(fx, fy, color); - this.vertex(x2, y2, color); - } - - private vertex (x: number, y: number, color: Color) { - let idx = this.vertexIndex; - let vertices = this.mesh.getVertices(); - vertices[idx++] = x; - vertices[idx++] = y; - vertices[idx++] = color.r; - vertices[idx++] = color.g; - vertices[idx++] = color.b; - vertices[idx++] = color.a; - this.vertexIndex = idx; - } - - end () { - if (!this.isDrawing) throw new Error("ShapeRenderer.begin() has not been called"); - this.flush(); - this.gl.disable(this.gl.BLEND); - this.isDrawing = false; - } - - private flush () { - if (this.vertexIndex == 0) return; - this.mesh.setVerticesLength(this.vertexIndex); - this.mesh.draw(this.shader, this.shapeType); - this.vertexIndex = 0; - } - - private check(shapeType: ShapeType, numVertices: number) { - if (!this.isDrawing) throw new Error("ShapeRenderer.begin() has not been called"); - if (this.shapeType == shapeType) { - if (this.mesh.maxVertices() - this.mesh.numVertices() < numVertices) this.flush(); - else return; - } else { - this.flush(); - this.shapeType = shapeType; - } - } - - dispose () { - this.mesh.dispose(); - } - } - - export enum ShapeType { - Point = WebGLRenderingContext.POINTS, - Line = WebGLRenderingContext.LINES, - Filled = WebGLRenderingContext.TRIANGLES - } +module spine.webgl { + export class ShapeRenderer implements Disposable { + private gl: WebGLRenderingContext; + private isDrawing = false; + private mesh: Mesh; + private shapeType = ShapeType.Filled; + private color = new Color(1, 1, 1, 1); + private shader: Shader; + private vertexIndex = 0; + private tmp = new Vector2(); + private srcBlend: number = WebGLRenderingContext.SRC_ALPHA; + private dstBlend: number = WebGLRenderingContext.ONE_MINUS_SRC_ALPHA; + + constructor (gl: WebGLRenderingContext, maxVertices: number = 10920) { + if (maxVertices > 10920) throw new Error("Can't have more than 10920 triangles per batch: " + maxVertices); + this.gl = gl; + this.mesh = new Mesh(gl, [new Position2Attribute(), new ColorAttribute()], maxVertices, 0); + } + + begin (shader: Shader) { + if (this.isDrawing) throw new Error("ShapeRenderer.begin() has already been called"); + this.shader = shader; + this.vertexIndex = 0; + this.isDrawing = true; + + let gl = this.gl; + gl.enable(gl.BLEND); + gl.blendFunc(this.srcBlend, this.dstBlend); + } + + setBlendMode (srcBlend: number, dstBlend: number) { + let gl = this.gl; + this.srcBlend = srcBlend; + this.dstBlend = dstBlend; + if (this.isDrawing) { + this.flush(); + gl.blendFunc(this.srcBlend, this.dstBlend); + } + } + + setColor (color: Color) { + this.color.setFromColor(color); + } + + setColorWith (r: number, g: number, b: number, a: number) { + this.color.set(r, g, b, a); + } + + point (x: number, y: number, color: Color = null) { + this.check(ShapeType.Point, 1); + if (color === null) color = this.color; + this.vertex(x, y, color); + } + + line (x: number, y: number, x2: number, y2: number, color: Color = null) { + this.check(ShapeType.Line, 2); + let vertices = this.mesh.getVertices(); + let idx = this.vertexIndex; + if (color === null) color = this.color; + this.vertex(x, y, color); + this.vertex(x2, y2, color); + } + + triangle (filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, color: Color = null, color2: Color = null, color3: Color = null) { + this.check(filled ? ShapeType.Filled : ShapeType.Line, 3); + let vertices = this.mesh.getVertices(); + let idx = this.vertexIndex; + if (color === null) color = this.color; + if (color2 === null) color2 = this.color; + if (color3 === null) color3 = this.color; + if (filled) { + this.vertex(x, y, color); + this.vertex(x2, y2, color2); + this.vertex(x3, y3, color3); + } else { + this.vertex(x, y, color); + this.vertex(x2, y2, color2); + + this.vertex(x2, y2, color); + this.vertex(x3, y3, color2); + + this.vertex(x3, y3, color); + this.vertex(x, y, color2); + } + } + + quad (filled: boolean, x: number, y: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, color: Color = null, color2: Color = null, color3: Color = null, color4: Color = null) { + this.check(filled ? ShapeType.Filled : ShapeType.Line, 3); + let vertices = this.mesh.getVertices(); + let idx = this.vertexIndex; + if (color === null) color = this.color; + if (color2 === null) color2 = this.color; + if (color3 === null) color3 = this.color; + if (color4 === null) color4 = this.color; + if (filled) { + this.vertex(x, y, color); this.vertex(x2, y2, color2); this.vertex(x3, y3, color3); + this.vertex(x3, y3, color3); this.vertex(x4, y4, color4); this.vertex(x, y, color); + } else { + this.vertex(x, y, color); this.vertex(x2, y2, color2); + this.vertex(x2, y2, color2); this.vertex(x3, y3, color3); + this.vertex(x3, y3, color3); this.vertex(x4, y4, color4); + this.vertex(x4, y4, color4); this.vertex(x, y, color); + } + } + + rect (filled: boolean, x: number, y: number, width: number, height: number, color: Color = null) { + this.quad(filled, x, y, x + width, y, x + width, y + height, x, y + height, color, color, color, color); + } + + rectLine (filled: boolean, x1: number, y1: number, x2: number, y2: number, width: number, color: Color = null) { + this.check(filled ? ShapeType.Filled : ShapeType.Line, 8); + if (color === null) color = this.color; + let t = this.tmp.set(y2 - y1, x1 - x2); + t.normalize(); + width *= 0.5; + let tx = t.x * width; + let ty = t.y * width; + if (!filled) { + this.vertex(x1 + tx, y1 + ty, color); + this.vertex(x1 - tx, y1 - ty, color); + this.vertex(x2 + tx, y2 + ty, color); + this.vertex(x2 - tx, y2 - ty, color); + + this.vertex(x2 + tx, y2 + ty, color); + this.vertex(x1 + tx, y1 + ty, color); + + this.vertex(x2 - tx, y2 - ty, color); + this.vertex(x1 - tx, y1 - ty, color); + } else { + this.vertex(x1 + tx, y1 + ty, color); + this.vertex(x1 - tx, y1 - ty, color); + this.vertex(x2 + tx, y2 + ty, color); + + this.vertex(x2 - tx, y2 - ty, color); + this.vertex(x2 + tx, y2 + ty, color); + this.vertex(x1 - tx, y1 - ty, color); + } + } + + x (x: number, y: number, size: number) { + this.line(x - size, y - size, x + size, y + size); + this.line(x - size, y + size, x + size, y - size); + } + + polygon (polygonVertices: ArrayLike, offset: number, count: number, color: Color = null) { + if (count < 3) throw new Error("Polygon must contain at least 3 vertices"); + this.check(ShapeType.Line, count * 2); + if (color === null) color = this.color; + let vertices = this.mesh.getVertices(); + let idx = this.vertexIndex; + + offset <<= 1; + count <<= 1; + + let firstX = polygonVertices[offset]; + let firstY = polygonVertices[offset + 1]; + let last = offset + count; + + for (let i = offset, n = offset + count - 2; i < n; i += 2) { + let x1 = polygonVertices[i]; + let y1 = polygonVertices[i+1]; + + let x2 = 0; + let y2 = 0; + + if (i + 2 >= last) { + x2 = firstX; + y2 = firstY; + } else { + x2 = polygonVertices[i + 2]; + y2 = polygonVertices[i + 3]; + } + + this.vertex(x1, y1, color); + this.vertex(x2, y2, color); + } + } + + circle (filled: boolean, x: number, y: number, radius: number, color: Color = null, segments: number = 0) { + if (segments === 0) segments = Math.max(1, (6 * MathUtils.cbrt(radius)) | 0); + if (segments <= 0) throw new Error("segments must be > 0."); + if (color === null) color = this.color; + let angle = 2 * MathUtils.PI / segments; + let cos = Math.cos(angle); + let sin = Math.sin(angle); + let cx = radius, cy = 0; + if (!filled) { + this.check(ShapeType.Line, segments * 2 + 2); + for (let i = 0; i < segments; i++) { + this.vertex(x + cx, y + cy, color); + let temp = cx; + cx = cos * cx - sin * cy; + cy = sin * temp + cos * cy; + this.vertex(x + cx, y + cy, color); + } + // Ensure the last segment is identical to the first. + this.vertex(x + cx, y + cy, color); + } else { + this.check(ShapeType.Filled, segments * 3 + 3); + segments--; + for (let i = 0; i < segments; i++) { + this.vertex(x, y, color); + this.vertex(x + cx, y + cy, color); + let temp = cx; + cx = cos * cx - sin * cy; + cy = sin * temp + cos * cy; + this.vertex(x + cx, y + cy, color); + } + // Ensure the last segment is identical to the first. + this.vertex(x, y, color); + this.vertex(x + cx, y + cy, color); + } + + let temp = cx; + cx = radius; + cy = 0; + this.vertex(x + cx, y + cy, color); + } + + curve (x1: number, y1: number, cx1: number, cy1: number, cx2: number, cy2: number, x2: number, y2: number, segments: number, color: Color = null) { + this.check(ShapeType.Line, segments * 2 + 2); + if (color === null) color = this.color; + + // Algorithm from: http://www.antigrain.com/research/bezier_interpolation/index.html#PAGE_BEZIER_INTERPOLATION + let subdiv_step = 1 / segments; + let subdiv_step2 = subdiv_step * subdiv_step; + let subdiv_step3 = subdiv_step * subdiv_step * subdiv_step; + + let pre1 = 3 * subdiv_step; + let pre2 = 3 * subdiv_step2; + let pre4 = 6 * subdiv_step2; + let pre5 = 6 * subdiv_step3; + + let tmp1x = x1 - cx1 * 2 + cx2; + let tmp1y = y1 - cy1 * 2 + cy2; + + let tmp2x = (cx1 - cx2) * 3 - x1 + x2; + let tmp2y = (cy1 - cy2) * 3 - y1 + y2; + + let fx = x1; + let fy = y1; + + let dfx = (cx1 - x1) * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3; + let dfy = (cy1 - y1) * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3; + + let ddfx = tmp1x * pre4 + tmp2x * pre5; + let ddfy = tmp1y * pre4 + tmp2y * pre5; + + let dddfx = tmp2x * pre5; + let dddfy = tmp2y * pre5; + + while (segments-- > 0) { + this.vertex(fx, fy, color); + fx += dfx; + fy += dfy; + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + this.vertex(fx, fy, color); + } + this.vertex(fx, fy, color); + this.vertex(x2, y2, color); + } + + private vertex (x: number, y: number, color: Color) { + let idx = this.vertexIndex; + let vertices = this.mesh.getVertices(); + vertices[idx++] = x; + vertices[idx++] = y; + vertices[idx++] = color.r; + vertices[idx++] = color.g; + vertices[idx++] = color.b; + vertices[idx++] = color.a; + this.vertexIndex = idx; + } + + end () { + if (!this.isDrawing) throw new Error("ShapeRenderer.begin() has not been called"); + this.flush(); + this.gl.disable(this.gl.BLEND); + this.isDrawing = false; + } + + private flush () { + if (this.vertexIndex == 0) return; + this.mesh.setVerticesLength(this.vertexIndex); + this.mesh.draw(this.shader, this.shapeType); + this.vertexIndex = 0; + } + + private check(shapeType: ShapeType, numVertices: number) { + if (!this.isDrawing) throw new Error("ShapeRenderer.begin() has not been called"); + if (this.shapeType == shapeType) { + if (this.mesh.maxVertices() - this.mesh.numVertices() < numVertices) this.flush(); + else return; + } else { + this.flush(); + this.shapeType = shapeType; + } + } + + dispose () { + this.mesh.dispose(); + } + } + + export enum ShapeType { + Point = WebGLRenderingContext.POINTS, + Line = WebGLRenderingContext.LINES, + Filled = WebGLRenderingContext.TRIANGLES + } } diff --git a/spine-ts/webgl/src/SkeletonDebugRenderer.ts b/spine-ts/webgl/src/SkeletonDebugRenderer.ts index e32befc779..f6ff797024 100644 --- a/spine-ts/webgl/src/SkeletonDebugRenderer.ts +++ b/spine-ts/webgl/src/SkeletonDebugRenderer.ts @@ -1,199 +1,198 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.webgl { - export class SkeletonDebugRenderer implements Disposable { - boneLineColor = new Color(1, 0, 0, 1); - boneOriginColor = new Color(0, 1, 0, 1); - attachmentLineColor = new Color(0, 0, 1, 0.5); - triangleLineColor = new Color(1, 0.64, 0, 0.5); - pathColor = new Color().setFromString("FF7F00"); - aabbColor = new Color(0, 1, 0, 0.5); - drawBones = true; - drawRegionAttachments = true; - drawBoundingBoxes = true; - drawMeshHull = true; - drawMeshTriangles = true; - drawPaths = true; - drawSkeletonXY = false; - premultipliedAlpha = false; - scale = 1; - boneWidth = 2; - - private gl: WebGLRenderingContext; - private bounds = new SkeletonBounds(); - private temp = new Array(); - private static LIGHT_GRAY = new Color(192 / 255, 192 / 255, 192 / 255, 1); - private static GREEN = new Color(0, 1, 0, 1); - - constructor (gl: WebGLRenderingContext) { - this.gl = gl; - } - - draw (shapes: ShapeRenderer, skeleton: Skeleton, ignoredBones: Array = null) { - let skeletonX = skeleton.x; - let skeletonY = skeleton.y; - let gl = this.gl; - let srcFunc = this.premultipliedAlpha ? gl.ONE : gl.SRC_ALPHA; - shapes.setBlendMode(srcFunc, gl.ONE_MINUS_SRC_ALPHA); - - let bones = skeleton.bones; - if (this.drawBones) { - shapes.setColor(this.boneLineColor); - for (let i = 0, n = bones.length; i < n; i++) { - let bone = bones[i]; - if (ignoredBones && ignoredBones.indexOf(bone.data.name) > -1) continue; - if (bone.parent == null) continue; - let x = skeletonX + bone.data.length * bone.a + bone.worldX; - let y = skeletonY + bone.data.length * bone.c + bone.worldY; - shapes.rectLine(true, skeletonX + bone.worldX, skeletonY + bone.worldY, x, y, this.boneWidth * this.scale); - } - if (this.drawSkeletonXY) shapes.x(skeletonX, skeletonY, 4 * this.scale); - } - - if (this.drawRegionAttachments) { - shapes.setColor(this.attachmentLineColor); - let slots = skeleton.slots; - for (let i = 0, n = slots.length; i < n; i++) { - let slot = slots[i]; - let attachment = slot.getAttachment(); - if (attachment instanceof RegionAttachment) { - let regionAttachment = attachment; - let vertices = regionAttachment.updateWorldVertices(slot, false); - shapes.line(vertices[RegionAttachment.X1], vertices[RegionAttachment.Y1], vertices[RegionAttachment.X2], vertices[RegionAttachment.Y2]); - shapes.line(vertices[RegionAttachment.X2], vertices[RegionAttachment.Y2], vertices[RegionAttachment.X3], vertices[RegionAttachment.Y3]); - shapes.line(vertices[RegionAttachment.X3], vertices[RegionAttachment.Y3], vertices[RegionAttachment.X4], vertices[RegionAttachment.Y4]); - shapes.line(vertices[RegionAttachment.X4], vertices[RegionAttachment.Y4], vertices[RegionAttachment.X1], vertices[RegionAttachment.Y1]); - } - } - } - - if (this.drawMeshHull || this.drawMeshTriangles) { - let slots = skeleton.slots; - for (let i = 0, n = slots.length; i < n; i++) { - let slot = slots[i]; - let attachment = slot.getAttachment(); - if (!(attachment instanceof MeshAttachment)) continue; - let mesh = attachment; - mesh.updateWorldVertices(slot, false); - let vertices = mesh.worldVertices; - let triangles = mesh.triangles; - let hullLength = mesh.hullLength; - if (this.drawMeshTriangles) { - shapes.setColor(this.triangleLineColor); - for (let ii = 0, nn = triangles.length; ii < nn; ii += 3) { - let v1 = triangles[ii] * 8, v2 = triangles[ii + 1] * 8, v3 = triangles[ii + 2] * 8; - shapes.triangle(false, vertices[v1], vertices[v1 + 1], // - vertices[v2], vertices[v2 + 1], // - vertices[v3], vertices[v3 + 1] // - ); - } - } - if (this.drawMeshHull && hullLength > 0) { - shapes.setColor(this.attachmentLineColor); - hullLength = (hullLength >> 1) * 8; - let lastX = vertices[hullLength - 8], lastY = vertices[hullLength - 7]; - for (let ii = 0, nn = hullLength; ii < nn; ii += 8) { - let x = vertices[ii], y = vertices[ii + 1]; - shapes.line(x, y, lastX, lastY); - lastX = x; - lastY = y; - } - } - } - } - - if (this.drawBoundingBoxes) { - let bounds = this.bounds; - bounds.update(skeleton, true); - shapes.setColor(this.aabbColor); - shapes.rect(false, bounds.minX, bounds.minY, bounds.getWidth(), bounds.getHeight()); - let polygons = bounds.polygons; - let boxes = bounds.boundingBoxes; - for (let i = 0, n = polygons.length; i < n; i++) { - let polygon = polygons[i]; - shapes.setColor(boxes[i].color); - shapes.polygon(polygon, 0, polygon.length); - } - } - - if (this.drawPaths) { - let slots = skeleton.slots; - for (let i = 0, n = slots.length; i < n; i++) { - let slot = slots[i]; - let attachment = slot.getAttachment(); - if (!(attachment instanceof PathAttachment)) continue; - let path = attachment; - let nn = path.worldVerticesLength; - let world = this.temp = Utils.setArraySize(this.temp, nn, 0); - path.computeWorldVertices(slot, world); - let color = this.pathColor; - let x1 = world[2], y1 = world[3], x2 = 0, y2 = 0; - if (path.closed) { - shapes.setColor(color); - let cx1 = world[0], cy1 = world[1], cx2 = world[nn - 2], cy2 = world[nn - 1]; - x2 = world[nn - 4]; - y2 = world[nn - 3]; - shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, 32); - shapes.setColor(SkeletonDebugRenderer.LIGHT_GRAY); - shapes.line(x1, y1, cx1, cy1); - shapes.line(x2, y2, cx2, cy2); - } - nn -= 4; - for (let ii = 4; ii < nn; ii += 6) { - let cx1 = world[ii], cy1 = world[ii + 1], cx2 = world[ii + 2], cy2 = world[ii + 3]; - x2 = world[ii + 4]; - y2 = world[ii + 5]; - shapes.setColor(color); - shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, 32); - shapes.setColor(SkeletonDebugRenderer.LIGHT_GRAY); - shapes.line(x1, y1, cx1, cy1); - shapes.line(x2, y2, cx2, cy2); - x1 = x2; - y1 = y2; - } - } - } - - if (this.drawBones) { - shapes.setColor(this.boneOriginColor); - for (let i = 0, n = bones.length; i < n; i++) { - let bone = bones[i]; - if (ignoredBones && ignoredBones.indexOf(bone.data.name) > -1) continue; - shapes.circle(true, skeletonX + bone.worldX, skeletonY + bone.worldY, 3 * this.scale, SkeletonDebugRenderer.GREEN, 8); - } - } - } - - dispose () { - } - } -} \ No newline at end of file +module spine.webgl { + export class SkeletonDebugRenderer implements Disposable { + boneLineColor = new Color(1, 0, 0, 1); + boneOriginColor = new Color(0, 1, 0, 1); + attachmentLineColor = new Color(0, 0, 1, 0.5); + triangleLineColor = new Color(1, 0.64, 0, 0.5); + pathColor = new Color().setFromString("FF7F00"); + aabbColor = new Color(0, 1, 0, 0.5); + drawBones = true; + drawRegionAttachments = true; + drawBoundingBoxes = true; + drawMeshHull = true; + drawMeshTriangles = true; + drawPaths = true; + drawSkeletonXY = false; + premultipliedAlpha = false; + scale = 1; + boneWidth = 2; + + private gl: WebGLRenderingContext; + private bounds = new SkeletonBounds(); + private temp = new Array(); + private static LIGHT_GRAY = new Color(192 / 255, 192 / 255, 192 / 255, 1); + private static GREEN = new Color(0, 1, 0, 1); + + constructor (gl: WebGLRenderingContext) { + this.gl = gl; + } + + draw (shapes: ShapeRenderer, skeleton: Skeleton, ignoredBones: Array = null) { + let skeletonX = skeleton.x; + let skeletonY = skeleton.y; + let gl = this.gl; + let srcFunc = this.premultipliedAlpha ? gl.ONE : gl.SRC_ALPHA; + shapes.setBlendMode(srcFunc, gl.ONE_MINUS_SRC_ALPHA); + + let bones = skeleton.bones; + if (this.drawBones) { + shapes.setColor(this.boneLineColor); + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (ignoredBones && ignoredBones.indexOf(bone.data.name) > -1) continue; + if (bone.parent == null) continue; + let x = skeletonX + bone.data.length * bone.a + bone.worldX; + let y = skeletonY + bone.data.length * bone.c + bone.worldY; + shapes.rectLine(true, skeletonX + bone.worldX, skeletonY + bone.worldY, x, y, this.boneWidth * this.scale); + } + if (this.drawSkeletonXY) shapes.x(skeletonX, skeletonY, 4 * this.scale); + } + + if (this.drawRegionAttachments) { + shapes.setColor(this.attachmentLineColor); + let slots = skeleton.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + let attachment = slot.getAttachment(); + if (attachment instanceof RegionAttachment) { + let regionAttachment = attachment; + let vertices = regionAttachment.updateWorldVertices(slot, false); + shapes.line(vertices[RegionAttachment.X1], vertices[RegionAttachment.Y1], vertices[RegionAttachment.X2], vertices[RegionAttachment.Y2]); + shapes.line(vertices[RegionAttachment.X2], vertices[RegionAttachment.Y2], vertices[RegionAttachment.X3], vertices[RegionAttachment.Y3]); + shapes.line(vertices[RegionAttachment.X3], vertices[RegionAttachment.Y3], vertices[RegionAttachment.X4], vertices[RegionAttachment.Y4]); + shapes.line(vertices[RegionAttachment.X4], vertices[RegionAttachment.Y4], vertices[RegionAttachment.X1], vertices[RegionAttachment.Y1]); + } + } + } + + if (this.drawMeshHull || this.drawMeshTriangles) { + let slots = skeleton.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + let attachment = slot.getAttachment(); + if (!(attachment instanceof MeshAttachment)) continue; + let mesh = attachment; + mesh.updateWorldVertices(slot, false); + let vertices = mesh.worldVertices; + let triangles = mesh.triangles; + let hullLength = mesh.hullLength; + if (this.drawMeshTriangles) { + shapes.setColor(this.triangleLineColor); + for (let ii = 0, nn = triangles.length; ii < nn; ii += 3) { + let v1 = triangles[ii] * 8, v2 = triangles[ii + 1] * 8, v3 = triangles[ii + 2] * 8; + shapes.triangle(false, vertices[v1], vertices[v1 + 1], // + vertices[v2], vertices[v2 + 1], // + vertices[v3], vertices[v3 + 1] // + ); + } + } + if (this.drawMeshHull && hullLength > 0) { + shapes.setColor(this.attachmentLineColor); + hullLength = (hullLength >> 1) * 8; + let lastX = vertices[hullLength - 8], lastY = vertices[hullLength - 7]; + for (let ii = 0, nn = hullLength; ii < nn; ii += 8) { + let x = vertices[ii], y = vertices[ii + 1]; + shapes.line(x, y, lastX, lastY); + lastX = x; + lastY = y; + } + } + } + } + + if (this.drawBoundingBoxes) { + let bounds = this.bounds; + bounds.update(skeleton, true); + shapes.setColor(this.aabbColor); + shapes.rect(false, bounds.minX, bounds.minY, bounds.getWidth(), bounds.getHeight()); + let polygons = bounds.polygons; + let boxes = bounds.boundingBoxes; + for (let i = 0, n = polygons.length; i < n; i++) { + let polygon = polygons[i]; + shapes.setColor(boxes[i].color); + shapes.polygon(polygon, 0, polygon.length); + } + } + + if (this.drawPaths) { + let slots = skeleton.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + let attachment = slot.getAttachment(); + if (!(attachment instanceof PathAttachment)) continue; + let path = attachment; + let nn = path.worldVerticesLength; + let world = this.temp = Utils.setArraySize(this.temp, nn, 0); + path.computeWorldVertices(slot, world); + let color = this.pathColor; + let x1 = world[2], y1 = world[3], x2 = 0, y2 = 0; + if (path.closed) { + shapes.setColor(color); + let cx1 = world[0], cy1 = world[1], cx2 = world[nn - 2], cy2 = world[nn - 1]; + x2 = world[nn - 4]; + y2 = world[nn - 3]; + shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, 32); + shapes.setColor(SkeletonDebugRenderer.LIGHT_GRAY); + shapes.line(x1, y1, cx1, cy1); + shapes.line(x2, y2, cx2, cy2); + } + nn -= 4; + for (let ii = 4; ii < nn; ii += 6) { + let cx1 = world[ii], cy1 = world[ii + 1], cx2 = world[ii + 2], cy2 = world[ii + 3]; + x2 = world[ii + 4]; + y2 = world[ii + 5]; + shapes.setColor(color); + shapes.curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, 32); + shapes.setColor(SkeletonDebugRenderer.LIGHT_GRAY); + shapes.line(x1, y1, cx1, cy1); + shapes.line(x2, y2, cx2, cy2); + x1 = x2; + y1 = y2; + } + } + } + + if (this.drawBones) { + shapes.setColor(this.boneOriginColor); + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (ignoredBones && ignoredBones.indexOf(bone.data.name) > -1) continue; + shapes.circle(true, skeletonX + bone.worldX, skeletonY + bone.worldY, 3 * this.scale, SkeletonDebugRenderer.GREEN, 8); + } + } + } + + dispose () { + } + } +} diff --git a/spine-ts/webgl/src/SkeletonRenderer.ts b/spine-ts/webgl/src/SkeletonRenderer.ts index 61d7f3bdc9..3c0fb45fec 100644 --- a/spine-ts/webgl/src/SkeletonRenderer.ts +++ b/spine-ts/webgl/src/SkeletonRenderer.ts @@ -1,78 +1,77 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.webgl { - export class SkeletonRenderer { - static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; - - premultipliedAlpha = false; - private gl: WebGLRenderingContext; - - constructor (gl: WebGLRenderingContext) { - this.gl = gl; - } - - draw (batcher: PolygonBatcher, skeleton: Skeleton) { - let premultipliedAlpha = this.premultipliedAlpha; - let blendMode: BlendMode = null; - - let vertices: ArrayLike = null; - let triangles: Array = null; - let drawOrder = skeleton.drawOrder; - for (let i = 0, n = drawOrder.length; i < n; i++) { - let slot = drawOrder[i]; - let attachment = slot.getAttachment(); - let texture: GLTexture = null; - if (attachment instanceof RegionAttachment) { - let region = attachment; - vertices = region.updateWorldVertices(slot, premultipliedAlpha); - triangles = SkeletonRenderer.QUAD_TRIANGLES; - texture = (region.region.renderObject).texture; - - } else if (attachment instanceof MeshAttachment) { - let mesh = attachment; - vertices = mesh.updateWorldVertices(slot, premultipliedAlpha); - triangles = mesh.triangles; - texture = (mesh.region.renderObject).texture; - } else continue; - - if (texture != null) { - let slotBlendMode = slot.data.blendMode; - if (slotBlendMode != blendMode) { - blendMode = slotBlendMode; - batcher.setBlendMode(getSourceGLBlendMode(this.gl, blendMode, premultipliedAlpha), getDestGLBlendMode(this.gl, blendMode)); - } - batcher.draw(texture, vertices, triangles); - } - } - } - } +module spine.webgl { + export class SkeletonRenderer { + static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; + + premultipliedAlpha = false; + private gl: WebGLRenderingContext; + + constructor (gl: WebGLRenderingContext) { + this.gl = gl; + } + + draw (batcher: PolygonBatcher, skeleton: Skeleton) { + let premultipliedAlpha = this.premultipliedAlpha; + let blendMode: BlendMode = null; + + let vertices: ArrayLike = null; + let triangles: Array = null; + let drawOrder = skeleton.drawOrder; + for (let i = 0, n = drawOrder.length; i < n; i++) { + let slot = drawOrder[i]; + let attachment = slot.getAttachment(); + let texture: GLTexture = null; + if (attachment instanceof RegionAttachment) { + let region = attachment; + vertices = region.updateWorldVertices(slot, premultipliedAlpha); + triangles = SkeletonRenderer.QUAD_TRIANGLES; + texture = (region.region.renderObject).texture; + + } else if (attachment instanceof MeshAttachment) { + let mesh = attachment; + vertices = mesh.updateWorldVertices(slot, premultipliedAlpha); + triangles = mesh.triangles; + texture = (mesh.region.renderObject).texture; + } else continue; + + if (texture != null) { + let slotBlendMode = slot.data.blendMode; + if (slotBlendMode != blendMode) { + blendMode = slotBlendMode; + batcher.setBlendMode(getSourceGLBlendMode(this.gl, blendMode, premultipliedAlpha), getDestGLBlendMode(this.gl, blendMode)); + } + batcher.draw(texture, vertices, triangles); + } + } + } + } } diff --git a/spine-ts/webgl/src/Vector3.ts b/spine-ts/webgl/src/Vector3.ts index 62b62df0f6..eaddef892b 100644 --- a/spine-ts/webgl/src/Vector3.ts +++ b/spine-ts/webgl/src/Vector3.ts @@ -1,123 +1,122 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.webgl { - export class Vector3 { - x = 0; - y = 0; - z = 0; - - constructor (x: number = 0, y: number = 0, z: number = 0) { - this.x = x; - this.y = y; - this.z = z; - } - - setFrom(v: Vector3): Vector3 { - this.x = v.x; - this.y = v.y; - this.z = v.z; - return this; - } - - set (x: number, y: number, z: number): Vector3 { - this.x = x; - this.y = y; - this.z = z; - return this; - } - - add (v: Vector3): Vector3 { - this.x += v.x; - this.y += v.y; - this.z += v.z; - return this; - } - - sub (v: Vector3): Vector3 { - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - return this; - } - - scale (s: number): Vector3 { - this.x *= s; - this.y *= s; - this.z *= s; - return this; - } - - normalize (): Vector3 { - let len = this.length(); - if (len == 0) return this; - len = 1 / len; - this.x *= len; - this.y *= len; - this.z *= len; - return this; - } - - cross (v: Vector3): Vector3 { - return this.set(this.y * v.z - this.z * v.y, this.z * v.x - this.x * v.z, this.x * v.y - this.y * v.x) - } - - multiply (matrix: Matrix4): Vector3 { - let l_mat = matrix.values; - return this.set(this.x * l_mat[M00] + this.y * l_mat[M01] + this.z * l_mat[M02] + l_mat[M03], - this.x * l_mat[M10] + this.y * l_mat[M11] + this.z * l_mat[M12] + l_mat[M13], - this.x * l_mat[M20] + this.y * l_mat[M21] + this.z * l_mat[M22] + l_mat[M23]); - } - - project (matrix: Matrix4): Vector3 { - let l_mat = matrix.values; - let l_w = 1 / (this.x * l_mat[M30] + this.y * l_mat[M31] + this.z * l_mat[M32] + l_mat[M33]); - return this.set((this.x * l_mat[M00] + this.y * l_mat[M01] + this.z * l_mat[M02] + l_mat[M03]) * l_w, - (this.x * l_mat[M10] + this.y * l_mat[M11] + this.z * l_mat[M12] + l_mat[M13]) * l_w, - (this.x * l_mat[M20] + this.y * l_mat[M21] + this.z * l_mat[M22] + l_mat[M23]) * l_w); - } - - dot (v: Vector3): number { - return this.x * v.x + this.y * v.y + this.z * v.z; - } - - length (): number { - return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); - } - - distance (v: Vector3): number { - let a = v.x - this.x; - let b = v.y - this.y; - let c = v.z - this.z; - return Math.sqrt(a * a + b * b + c * c); - } - } +module spine.webgl { + export class Vector3 { + x = 0; + y = 0; + z = 0; + + constructor (x: number = 0, y: number = 0, z: number = 0) { + this.x = x; + this.y = y; + this.z = z; + } + + setFrom(v: Vector3): Vector3 { + this.x = v.x; + this.y = v.y; + this.z = v.z; + return this; + } + + set (x: number, y: number, z: number): Vector3 { + this.x = x; + this.y = y; + this.z = z; + return this; + } + + add (v: Vector3): Vector3 { + this.x += v.x; + this.y += v.y; + this.z += v.z; + return this; + } + + sub (v: Vector3): Vector3 { + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + return this; + } + + scale (s: number): Vector3 { + this.x *= s; + this.y *= s; + this.z *= s; + return this; + } + + normalize (): Vector3 { + let len = this.length(); + if (len == 0) return this; + len = 1 / len; + this.x *= len; + this.y *= len; + this.z *= len; + return this; + } + + cross (v: Vector3): Vector3 { + return this.set(this.y * v.z - this.z * v.y, this.z * v.x - this.x * v.z, this.x * v.y - this.y * v.x) + } + + multiply (matrix: Matrix4): Vector3 { + let l_mat = matrix.values; + return this.set(this.x * l_mat[M00] + this.y * l_mat[M01] + this.z * l_mat[M02] + l_mat[M03], + this.x * l_mat[M10] + this.y * l_mat[M11] + this.z * l_mat[M12] + l_mat[M13], + this.x * l_mat[M20] + this.y * l_mat[M21] + this.z * l_mat[M22] + l_mat[M23]); + } + + project (matrix: Matrix4): Vector3 { + let l_mat = matrix.values; + let l_w = 1 / (this.x * l_mat[M30] + this.y * l_mat[M31] + this.z * l_mat[M32] + l_mat[M33]); + return this.set((this.x * l_mat[M00] + this.y * l_mat[M01] + this.z * l_mat[M02] + l_mat[M03]) * l_w, + (this.x * l_mat[M10] + this.y * l_mat[M11] + this.z * l_mat[M12] + l_mat[M13]) * l_w, + (this.x * l_mat[M20] + this.y * l_mat[M21] + this.z * l_mat[M22] + l_mat[M23]) * l_w); + } + + dot (v: Vector3): number { + return this.x * v.x + this.y * v.y + this.z * v.z; + } + + length (): number { + return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); + } + + distance (v: Vector3): number { + let a = v.x - this.x; + let b = v.y - this.y; + let c = v.z - this.z; + return Math.sqrt(a * a + b * b + c * c); + } + } } diff --git a/spine-ts/webgl/src/WebGL.ts b/spine-ts/webgl/src/WebGL.ts index a7a637d81c..02161751a3 100644 --- a/spine-ts/webgl/src/WebGL.ts +++ b/spine-ts/webgl/src/WebGL.ts @@ -1,52 +1,51 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine.webgl { - export function getSourceGLBlendMode (gl: WebGLRenderingContext, blendMode: BlendMode, premultipliedAlpha: boolean = false) { - switch(blendMode) { - case BlendMode.Normal: return premultipliedAlpha? gl.ONE : gl.SRC_ALPHA; - case BlendMode.Additive: return premultipliedAlpha? gl.ONE : gl.SRC_ALPHA; - case BlendMode.Multiply: return gl.DST_COLOR; - case BlendMode.Screen: return gl.ONE; - default: throw new Error("Unknown blend mode: " + blendMode); - } - } - - export function getDestGLBlendMode (gl: WebGLRenderingContext, blendMode: BlendMode) { - switch(blendMode) { - case BlendMode.Normal: return gl.ONE_MINUS_SRC_ALPHA; - case BlendMode.Additive: return gl.ONE; - case BlendMode.Multiply: return gl.ONE_MINUS_SRC_ALPHA; - case BlendMode.Screen: return gl.ONE_MINUS_SRC_ALPHA; - default: throw new Error("Unknown blend mode: " + blendMode); - } - } +module spine.webgl { + export function getSourceGLBlendMode (gl: WebGLRenderingContext, blendMode: BlendMode, premultipliedAlpha: boolean = false) { + switch(blendMode) { + case BlendMode.Normal: return premultipliedAlpha? gl.ONE : gl.SRC_ALPHA; + case BlendMode.Additive: return premultipliedAlpha? gl.ONE : gl.SRC_ALPHA; + case BlendMode.Multiply: return gl.DST_COLOR; + case BlendMode.Screen: return gl.ONE; + default: throw new Error("Unknown blend mode: " + blendMode); + } + } + + export function getDestGLBlendMode (gl: WebGLRenderingContext, blendMode: BlendMode) { + switch(blendMode) { + case BlendMode.Normal: return gl.ONE_MINUS_SRC_ALPHA; + case BlendMode.Additive: return gl.ONE; + case BlendMode.Multiply: return gl.ONE_MINUS_SRC_ALPHA; + case BlendMode.Screen: return gl.ONE_MINUS_SRC_ALPHA; + default: throw new Error("Unknown blend mode: " + blendMode); + } + } } diff --git a/spine-ts/widget/src/Widget.ts b/spine-ts/widget/src/Widget.ts index 239906a06d..64e244c74a 100644 --- a/spine-ts/widget/src/Widget.ts +++ b/spine-ts/widget/src/Widget.ts @@ -1,318 +1,317 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.5 - * - * Copyright (c) 2013-2016, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable, and - * non-transferable license to use, install, execute, and perform the Spine - * Runtimes software and derivative works solely for personal or internal - * use. Without the written permission of Esoteric Software (see Section 2 of - * the Spine Software License Agreement), you may not (a) modify, translate, - * adapt, or develop new applications using the Spine Runtimes or otherwise - * create derivative works or improvements of the Spine Runtimes or (b) remove, - * delete, alter, or obscure any trademarks or any copyright, trademark, patent, - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF - * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER - * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -module spine { - export class SpineWidget { - skeleton: Skeleton; - state: AnimationState; - gl: WebGLRenderingContext; - canvas: HTMLCanvasElement; - debugRenderer: spine.webgl.SkeletonDebugRenderer; - - private config: SpineWidgetConfig; - private assetManager: spine.webgl.AssetManager; - private shader: spine.webgl.Shader; - private batcher: spine.webgl.PolygonBatcher; - private shapes: spine.webgl.ShapeRenderer; - private debugShader: spine.webgl.Shader; - private mvp = new spine.webgl.Matrix4(); - private skeletonRenderer: spine.webgl.SkeletonRenderer; - private paused = false; - private lastFrameTime = Date.now() / 1000.0; - private backgroundColor = new Color(); - private loaded = false; - private bounds = { offset: new Vector2(), size: new Vector2() }; - - constructor (element: HTMLElement | string, config: SpineWidgetConfig) { - if (!element) throw new Error("Please provide a DOM element, e.g. document.getElementById('myelement')"); - if (!config) throw new Error("Please provide a configuration, specifying at least the json file, atlas file and animation name"); - - let elementId = element as string; - if (typeof(element) === "string") element = document.getElementById(element as string); - if (element == null) throw new Error(`Element ${elementId} does not exist`); - - this.validateConfig(config); - - let canvas = this.canvas = document.createElement("canvas"); - canvas.style.width = "100%"; - canvas.style.height = "100%"; - ( element).appendChild(canvas); - canvas.width = (element).clientWidth; - canvas.height = (element).clientHeight; - var webglConfig = { alpha: false }; - let gl = this.gl = (canvas.getContext("webgl", webglConfig) || canvas.getContext("experimental-webgl", webglConfig)); - - this.shader = spine.webgl.Shader.newColoredTextured(gl); - this.batcher = new spine.webgl.PolygonBatcher(gl); - this.mvp.ortho2d(0, 0, canvas.width - 1, canvas.height - 1); - this.skeletonRenderer = new spine.webgl.SkeletonRenderer(gl); - this.debugShader = spine.webgl.Shader.newColored(gl); - this.debugRenderer = new spine.webgl.SkeletonDebugRenderer(gl); - this.shapes = new spine.webgl.ShapeRenderer(gl); - - let assets = this.assetManager = new spine.webgl.AssetManager(gl); - assets.loadText(config.atlas); - assets.loadText(config.json); - assets.loadTexture(config.atlas.replace(".atlas", ".png")); - requestAnimationFrame(() => { this.load(); }); - } - - private validateConfig (config: SpineWidgetConfig) { - if (!config.atlas) throw new Error("Please specify config.atlas"); - if (!config.json) throw new Error("Please specify config.json"); - if (!config.animation) throw new Error("Please specify config.animationName"); - - if (!config.scale) config.scale = 1.0; - if (!config.skin) config.skin = "default"; - if (config.loop === undefined) config.loop = true; - if (!config.x) config.x = 0; - if (!config.y) config.y = 0; - if (config.fitToCanvas === undefined) config.fitToCanvas = true; - if (!config.backgroundColor) config.backgroundColor = "#555555"; - if (!config.imagesPath) { - let index = config.atlas.lastIndexOf("/"); - if (index != -1) { - config.imagesPath = config.atlas.substr(0, index) + "/"; - } else { - config.imagesPath = ""; - } - } - if (!config.premultipliedAlpha === undefined) config.premultipliedAlpha = false; - if (!config.debug === undefined) config.debug = false; - this.backgroundColor.setFromString(config.backgroundColor); - this.config = config; - } - - private load () { - let assetManager = this.assetManager; - let imagesPath = this.config.imagesPath; - let config = this.config; - if (assetManager.isLoadingComplete()) { - if (assetManager.hasErrors()) { - if (config.error) config.error(this, "Failed to load assets: " + JSON.stringify(assetManager.getErrors())); - else throw new Error("Failed to load assets: " + JSON.stringify(assetManager.getErrors())); - } - - let atlas = new spine.TextureAtlas(this.assetManager.get(this.config.atlas) as string, (path: string) => { - let texture = assetManager.get(imagesPath + path) as spine.webgl.GLTexture; - return texture; - }); - - let atlasLoader = new spine.TextureAtlasAttachmentLoader(atlas); - var skeletonJson = new spine.SkeletonJson(atlasLoader); - - // Set the scale to apply during parsing, parse the file, and create a new skeleton. - skeletonJson.scale = config.scale; - var skeletonData = skeletonJson.readSkeletonData(assetManager.get(config.json) as string); - var skeleton = this.skeleton = new spine.Skeleton(skeletonData); - var bounds = this.bounds; - skeleton.setSkinByName(config.skin); - skeleton.setToSetupPose(); - skeleton.updateWorldTransform(); - skeleton.getBounds(bounds.offset, bounds.size); - if (!config.fitToCanvas) { - skeleton.x = config.x; - skeleton.y = config.y; - } - - var animationState = this.state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data)); - animationState.setAnimation(0, config.animation, true); - if (config.success) config.success(this); - this.loaded = true; - requestAnimationFrame(() => { this.render(); }); - } else - requestAnimationFrame(() => { this.load(); }); - } - - private render () { - var now = Date.now() / 1000; - var delta = now - this.lastFrameTime; - if (delta > 0.1) delta = 0; - this.lastFrameTime = now; - - let gl = this.gl; - let color = this.backgroundColor; - this.resize(); - gl.clearColor(color.r, color.g, color.b, color.a); - gl.clear(gl.COLOR_BUFFER_BIT); - - // Apply the animation state based on the delta time. - var state = this.state; - var skeleton = this.skeleton; - var premultipliedAlpha = this.config.premultipliedAlpha; - state.update(delta); - state.apply(skeleton); - skeleton.updateWorldTransform(); - - // Draw the skeleton - let shader = this.shader; - let batcher = this.batcher; - let skeletonRenderer = this.skeletonRenderer; - shader.bind(); - shader.setUniformi(spine.webgl.Shader.SAMPLER, 0); - shader.setUniform4x4f(spine.webgl.Shader.MVP_MATRIX, this.mvp.values); - batcher.begin(shader); - skeletonRenderer.premultipliedAlpha = premultipliedAlpha; - skeletonRenderer.draw(batcher, skeleton); - batcher.end(); - shader.unbind(); - - // Draw debug information if requested via config - if (this.config.debug) { - let shader = this.debugShader; - let shapes = this.shapes; - let renderer = this.debugRenderer; - shader.bind(); - shader.setUniform4x4f(spine.webgl.Shader.MVP_MATRIX, this.mvp.values); - renderer.premultipliedAlpha = premultipliedAlpha; - shapes.begin(shader); - renderer.draw(shapes, skeleton); - shapes.end(); - shader.unbind(); - } - - if (!this.paused) requestAnimationFrame(() => { this.render(); }); - } - - private resize () { - let canvas = this.canvas; - let w = canvas.clientWidth; - let h = canvas.clientHeight; - let bounds = this.bounds; - if (canvas.width != w || canvas.height != h) { - canvas.width = w; - canvas.height = h; - } - - // magic - if (this.config.fitToCanvas) { - var centerX = bounds.offset.x + bounds.size.x / 2; - var centerY = bounds.offset.y + bounds.size.y / 2; - var scaleX = bounds.size.x / canvas.width; - var scaleY = bounds.size.y / canvas.height; - var scale = Math.max(scaleX, scaleY) * 1.2; - if (scale < 1) scale = 1; - var width = canvas.width * scale; - var height = canvas.height * scale; - this.skeleton.x = this.skeleton.y = 0; - this.mvp.ortho2d(centerX - width / 2, centerY - height / 2, width, height); - } else { - this.mvp.ortho2d(0, 0, canvas.width - 1, canvas.height - 1); - } - - this.gl.viewport(0, 0, canvas.width, canvas.height); - } - - pause () { - this.paused = true; - } - - play () { - this.paused = false; - requestAnimationFrame(() => { this.render(); }); - } - - isPlaying () { - return !this.paused; - } - - setAnimation (animationName: string) { - if (!this.loaded) throw new Error("Widget isn't loaded yet"); - this.skeleton.setToSetupPose(); - this.state.setAnimation(0, animationName, this.config.loop); - } - - - static loadWidgets() { - let widgets = document.getElementsByClassName("spine-widget"); - for (var i = 0; i < widgets.length; i++) { - SpineWidget.loadWidget(widgets[i]); - } - } - - static loadWidget(widget: HTMLElement) { - let config = new SpineWidgetConfig(); - config.atlas = widget.getAttribute("data-atlas"); - config.json = widget.getAttribute("data-json"); - config.animation = widget.getAttribute("data-animation"); - if (widget.getAttribute("data-images-path")) config.imagesPath = widget.getAttribute("data-images-path"); - if (widget.getAttribute("data-skin")) config.skin = widget.getAttribute("data-skin"); - if (widget.getAttribute("data-loop")) config.loop = widget.getAttribute("data-loop") === "true"; - if (widget.getAttribute("data-scale")) config.scale = parseFloat(widget.getAttribute("data-scale")); - if (widget.getAttribute("data-x")) config.x = parseFloat(widget.getAttribute("data-x")); - if (widget.getAttribute("data-y")) config.y = parseFloat(widget.getAttribute("data-y")); - if (widget.getAttribute("data-fit-to-canvas")) config.fitToCanvas = widget.getAttribute("data-fit-to-canvas") === "true"; - if (widget.getAttribute("data-background-color")) config.backgroundColor = widget.getAttribute("data-background-color"); - if (widget.getAttribute("data-premultiplied-alpha")) config.premultipliedAlpha = widget.getAttribute("data-premultiplied-alpha") === "true"; - if (widget.getAttribute("data-debug")) config.debug = widget.getAttribute("data-debug") === "true"; - - new spine.SpineWidget(widget, config); - } - - static pageLoaded = false; - private static ready () { - if (SpineWidget.pageLoaded) return; - SpineWidget.pageLoaded = true; - SpineWidget.loadWidgets(); - } - - static setupDOMListener() { - if (document.addEventListener) { - document.addEventListener("DOMContentLoaded", SpineWidget.ready, false); - window.addEventListener("load", SpineWidget.ready, false); - } else { - (document).attachEvent("onreadystatechange", function readyStateChange() { - if (document.readyState === "complete" ) SpineWidget.ready(); - }); - (window).attachEvent("onload", SpineWidget.ready); - } - } - } - - export class SpineWidgetConfig { - json: string; - atlas: string; - animation: string; - imagesPath: string; - skin = "default"; - loop = true; - scale = 1.0; - x = 0; - y = 0; - fitToCanvas = true; - backgroundColor = "#555555"; - premultipliedAlpha = false; - debug = false; - success: (widget: SpineWidget) => void; - error: (widget: SpineWidget, msg: string) => void; - } -} -spine.SpineWidget.setupDOMListener(); \ No newline at end of file +module spine { + export class SpineWidget { + skeleton: Skeleton; + state: AnimationState; + gl: WebGLRenderingContext; + canvas: HTMLCanvasElement; + debugRenderer: spine.webgl.SkeletonDebugRenderer; + + private config: SpineWidgetConfig; + private assetManager: spine.webgl.AssetManager; + private shader: spine.webgl.Shader; + private batcher: spine.webgl.PolygonBatcher; + private shapes: spine.webgl.ShapeRenderer; + private debugShader: spine.webgl.Shader; + private mvp = new spine.webgl.Matrix4(); + private skeletonRenderer: spine.webgl.SkeletonRenderer; + private paused = false; + private lastFrameTime = Date.now() / 1000.0; + private backgroundColor = new Color(); + private loaded = false; + private bounds = { offset: new Vector2(), size: new Vector2() }; + + constructor (element: HTMLElement | string, config: SpineWidgetConfig) { + if (!element) throw new Error("Please provide a DOM element, e.g. document.getElementById('myelement')"); + if (!config) throw new Error("Please provide a configuration, specifying at least the json file, atlas file and animation name"); + + let elementId = element as string; + if (typeof(element) === "string") element = document.getElementById(element as string); + if (element == null) throw new Error(`Element ${elementId} does not exist`); + + this.validateConfig(config); + + let canvas = this.canvas = document.createElement("canvas"); + canvas.style.width = "100%"; + canvas.style.height = "100%"; + ( element).appendChild(canvas); + canvas.width = (element).clientWidth; + canvas.height = (element).clientHeight; + var webglConfig = { alpha: false }; + let gl = this.gl = (canvas.getContext("webgl", webglConfig) || canvas.getContext("experimental-webgl", webglConfig)); + + this.shader = spine.webgl.Shader.newColoredTextured(gl); + this.batcher = new spine.webgl.PolygonBatcher(gl); + this.mvp.ortho2d(0, 0, canvas.width - 1, canvas.height - 1); + this.skeletonRenderer = new spine.webgl.SkeletonRenderer(gl); + this.debugShader = spine.webgl.Shader.newColored(gl); + this.debugRenderer = new spine.webgl.SkeletonDebugRenderer(gl); + this.shapes = new spine.webgl.ShapeRenderer(gl); + + let assets = this.assetManager = new spine.webgl.AssetManager(gl); + assets.loadText(config.atlas); + assets.loadText(config.json); + assets.loadTexture(config.atlas.replace(".atlas", ".png")); + requestAnimationFrame(() => { this.load(); }); + } + + private validateConfig (config: SpineWidgetConfig) { + if (!config.atlas) throw new Error("Please specify config.atlas"); + if (!config.json) throw new Error("Please specify config.json"); + if (!config.animation) throw new Error("Please specify config.animationName"); + + if (!config.scale) config.scale = 1.0; + if (!config.skin) config.skin = "default"; + if (config.loop === undefined) config.loop = true; + if (!config.x) config.x = 0; + if (!config.y) config.y = 0; + if (config.fitToCanvas === undefined) config.fitToCanvas = true; + if (!config.backgroundColor) config.backgroundColor = "#555555"; + if (!config.imagesPath) { + let index = config.atlas.lastIndexOf("/"); + if (index != -1) { + config.imagesPath = config.atlas.substr(0, index) + "/"; + } else { + config.imagesPath = ""; + } + } + if (!config.premultipliedAlpha === undefined) config.premultipliedAlpha = false; + if (!config.debug === undefined) config.debug = false; + this.backgroundColor.setFromString(config.backgroundColor); + this.config = config; + } + + private load () { + let assetManager = this.assetManager; + let imagesPath = this.config.imagesPath; + let config = this.config; + if (assetManager.isLoadingComplete()) { + if (assetManager.hasErrors()) { + if (config.error) config.error(this, "Failed to load assets: " + JSON.stringify(assetManager.getErrors())); + else throw new Error("Failed to load assets: " + JSON.stringify(assetManager.getErrors())); + } + + let atlas = new spine.TextureAtlas(this.assetManager.get(this.config.atlas) as string, (path: string) => { + let texture = assetManager.get(imagesPath + path) as spine.webgl.GLTexture; + return texture; + }); + + let atlasLoader = new spine.TextureAtlasAttachmentLoader(atlas); + var skeletonJson = new spine.SkeletonJson(atlasLoader); + + // Set the scale to apply during parsing, parse the file, and create a new skeleton. + skeletonJson.scale = config.scale; + var skeletonData = skeletonJson.readSkeletonData(assetManager.get(config.json) as string); + var skeleton = this.skeleton = new spine.Skeleton(skeletonData); + var bounds = this.bounds; + skeleton.setSkinByName(config.skin); + skeleton.setToSetupPose(); + skeleton.updateWorldTransform(); + skeleton.getBounds(bounds.offset, bounds.size); + if (!config.fitToCanvas) { + skeleton.x = config.x; + skeleton.y = config.y; + } + + var animationState = this.state = new spine.AnimationState(new spine.AnimationStateData(skeleton.data)); + animationState.setAnimation(0, config.animation, true); + if (config.success) config.success(this); + this.loaded = true; + requestAnimationFrame(() => { this.render(); }); + } else + requestAnimationFrame(() => { this.load(); }); + } + + private render () { + var now = Date.now() / 1000; + var delta = now - this.lastFrameTime; + if (delta > 0.1) delta = 0; + this.lastFrameTime = now; + + let gl = this.gl; + let color = this.backgroundColor; + this.resize(); + gl.clearColor(color.r, color.g, color.b, color.a); + gl.clear(gl.COLOR_BUFFER_BIT); + + // Apply the animation state based on the delta time. + var state = this.state; + var skeleton = this.skeleton; + var premultipliedAlpha = this.config.premultipliedAlpha; + state.update(delta); + state.apply(skeleton); + skeleton.updateWorldTransform(); + + // Draw the skeleton + let shader = this.shader; + let batcher = this.batcher; + let skeletonRenderer = this.skeletonRenderer; + shader.bind(); + shader.setUniformi(spine.webgl.Shader.SAMPLER, 0); + shader.setUniform4x4f(spine.webgl.Shader.MVP_MATRIX, this.mvp.values); + batcher.begin(shader); + skeletonRenderer.premultipliedAlpha = premultipliedAlpha; + skeletonRenderer.draw(batcher, skeleton); + batcher.end(); + shader.unbind(); + + // Draw debug information if requested via config + if (this.config.debug) { + let shader = this.debugShader; + let shapes = this.shapes; + let renderer = this.debugRenderer; + shader.bind(); + shader.setUniform4x4f(spine.webgl.Shader.MVP_MATRIX, this.mvp.values); + renderer.premultipliedAlpha = premultipliedAlpha; + shapes.begin(shader); + renderer.draw(shapes, skeleton); + shapes.end(); + shader.unbind(); + } + + if (!this.paused) requestAnimationFrame(() => { this.render(); }); + } + + private resize () { + let canvas = this.canvas; + let w = canvas.clientWidth; + let h = canvas.clientHeight; + let bounds = this.bounds; + if (canvas.width != w || canvas.height != h) { + canvas.width = w; + canvas.height = h; + } + + // magic + if (this.config.fitToCanvas) { + var centerX = bounds.offset.x + bounds.size.x / 2; + var centerY = bounds.offset.y + bounds.size.y / 2; + var scaleX = bounds.size.x / canvas.width; + var scaleY = bounds.size.y / canvas.height; + var scale = Math.max(scaleX, scaleY) * 1.2; + if (scale < 1) scale = 1; + var width = canvas.width * scale; + var height = canvas.height * scale; + this.skeleton.x = this.skeleton.y = 0; + this.mvp.ortho2d(centerX - width / 2, centerY - height / 2, width, height); + } else { + this.mvp.ortho2d(0, 0, canvas.width - 1, canvas.height - 1); + } + + this.gl.viewport(0, 0, canvas.width, canvas.height); + } + + pause () { + this.paused = true; + } + + play () { + this.paused = false; + requestAnimationFrame(() => { this.render(); }); + } + + isPlaying () { + return !this.paused; + } + + setAnimation (animationName: string) { + if (!this.loaded) throw new Error("Widget isn't loaded yet"); + this.skeleton.setToSetupPose(); + this.state.setAnimation(0, animationName, this.config.loop); + } + + + static loadWidgets() { + let widgets = document.getElementsByClassName("spine-widget"); + for (var i = 0; i < widgets.length; i++) { + SpineWidget.loadWidget(widgets[i]); + } + } + + static loadWidget(widget: HTMLElement) { + let config = new SpineWidgetConfig(); + config.atlas = widget.getAttribute("data-atlas"); + config.json = widget.getAttribute("data-json"); + config.animation = widget.getAttribute("data-animation"); + if (widget.getAttribute("data-images-path")) config.imagesPath = widget.getAttribute("data-images-path"); + if (widget.getAttribute("data-skin")) config.skin = widget.getAttribute("data-skin"); + if (widget.getAttribute("data-loop")) config.loop = widget.getAttribute("data-loop") === "true"; + if (widget.getAttribute("data-scale")) config.scale = parseFloat(widget.getAttribute("data-scale")); + if (widget.getAttribute("data-x")) config.x = parseFloat(widget.getAttribute("data-x")); + if (widget.getAttribute("data-y")) config.y = parseFloat(widget.getAttribute("data-y")); + if (widget.getAttribute("data-fit-to-canvas")) config.fitToCanvas = widget.getAttribute("data-fit-to-canvas") === "true"; + if (widget.getAttribute("data-background-color")) config.backgroundColor = widget.getAttribute("data-background-color"); + if (widget.getAttribute("data-premultiplied-alpha")) config.premultipliedAlpha = widget.getAttribute("data-premultiplied-alpha") === "true"; + if (widget.getAttribute("data-debug")) config.debug = widget.getAttribute("data-debug") === "true"; + + new spine.SpineWidget(widget, config); + } + + static pageLoaded = false; + private static ready () { + if (SpineWidget.pageLoaded) return; + SpineWidget.pageLoaded = true; + SpineWidget.loadWidgets(); + } + + static setupDOMListener() { + if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", SpineWidget.ready, false); + window.addEventListener("load", SpineWidget.ready, false); + } else { + (document).attachEvent("onreadystatechange", function readyStateChange() { + if (document.readyState === "complete" ) SpineWidget.ready(); + }); + (window).attachEvent("onload", SpineWidget.ready); + } + } + } + + export class SpineWidgetConfig { + json: string; + atlas: string; + animation: string; + imagesPath: string; + skin = "default"; + loop = true; + scale = 1.0; + x = 0; + y = 0; + fitToCanvas = true; + backgroundColor = "#555555"; + premultipliedAlpha = false; + debug = false; + success: (widget: SpineWidget) => void; + error: (widget: SpineWidget, msg: string) => void; + } +} +spine.SpineWidget.setupDOMListener(); diff --git a/spine-unity/Assets/Examples/Getting Started/Scripts/Raptor.cs b/spine-unity/Assets/Examples/Getting Started/Scripts/Raptor.cs index 21041674f7..684365efde 100644 --- a/spine-unity/Assets/Examples/Getting Started/Scripts/Raptor.cs +++ b/spine-unity/Assets/Examples/Getting Started/Scripts/Raptor.cs @@ -1,86 +1,85 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEngine; -using System.Collections; -using Spine.Unity; - -public class Raptor : MonoBehaviour { - - #region Inspector - [SpineAnimation] - public string walk = "walk"; - - [SpineAnimation] - public string gungrab = "gungrab"; - - [SpineAnimation] - public string gunkeep = "gunkeep"; - - [SpineEvent] - public string footstepEvent = "footstep"; - - public AudioSource footstepAudioSource; - #endregion - - SkeletonAnimation skeletonAnimation; - - void Start () { - skeletonAnimation = GetComponent(); - skeletonAnimation.state.Event += HandleEvent; - StartCoroutine(GunGrabRoutine()); - } - - void HandleEvent (Spine.AnimationState state, int trackIndex, Spine.Event e) { - if (e.Data.Name == footstepEvent) { - footstepAudioSource.pitch = 0.5f + Random.Range(-0.2f, 0.2f); - footstepAudioSource.Play(); - } - } - - IEnumerator GunGrabRoutine () { - // Play the walk animation on track 0. - skeletonAnimation.state.SetAnimation(0, walk, true); - - // Repeatedly play the gungrab and gunkeep animation on track 1. - while (true) { - - yield return new WaitForSeconds(Random.Range(0.5f, 3f)); - skeletonAnimation.state.SetAnimation(1, gungrab, false); - - yield return new WaitForSeconds(Random.Range(0.5f, 3f)); - skeletonAnimation.state.SetAnimation(1, gunkeep, false); - - } - - } - +using UnityEngine; +using System.Collections; +using Spine.Unity; + +public class Raptor : MonoBehaviour { + + #region Inspector + [SpineAnimation] + public string walk = "walk"; + + [SpineAnimation] + public string gungrab = "gungrab"; + + [SpineAnimation] + public string gunkeep = "gunkeep"; + + [SpineEvent] + public string footstepEvent = "footstep"; + + public AudioSource footstepAudioSource; + #endregion + + SkeletonAnimation skeletonAnimation; + + void Start () { + skeletonAnimation = GetComponent(); + skeletonAnimation.state.Event += HandleEvent; + StartCoroutine(GunGrabRoutine()); + } + + void HandleEvent (Spine.AnimationState state, int trackIndex, Spine.Event e) { + if (e.Data.Name == footstepEvent) { + footstepAudioSource.pitch = 0.5f + Random.Range(-0.2f, 0.2f); + footstepAudioSource.Play(); + } + } + + IEnumerator GunGrabRoutine () { + // Play the walk animation on track 0. + skeletonAnimation.state.SetAnimation(0, walk, true); + + // Repeatedly play the gungrab and gunkeep animation on track 1. + while (true) { + + yield return new WaitForSeconds(Random.Range(0.5f, 3f)); + skeletonAnimation.state.SetAnimation(1, gungrab, false); + + yield return new WaitForSeconds(Random.Range(0.5f, 3f)); + skeletonAnimation.state.SetAnimation(1, gunkeep, false); + + } + + } + } diff --git a/spine-unity/Assets/Examples/Getting Started/Scripts/SpineBeginnerTwo.cs b/spine-unity/Assets/Examples/Getting Started/Scripts/SpineBeginnerTwo.cs index b3f407e71c..a15af373a5 100644 --- a/spine-unity/Assets/Examples/Getting Started/Scripts/SpineBeginnerTwo.cs +++ b/spine-unity/Assets/Examples/Getting Started/Scripts/SpineBeginnerTwo.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ using UnityEngine; diff --git a/spine-unity/Assets/Examples/Getting Started/Scripts/SpineBlinkPlayer.cs b/spine-unity/Assets/Examples/Getting Started/Scripts/SpineBlinkPlayer.cs index 381fda7c38..b73aa620c2 100644 --- a/spine-unity/Assets/Examples/Getting Started/Scripts/SpineBlinkPlayer.cs +++ b/spine-unity/Assets/Examples/Getting Started/Scripts/SpineBlinkPlayer.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ using UnityEngine; diff --git a/spine-unity/Assets/Examples/Getting Started/Scripts/SpineboyBeginnerInput.cs b/spine-unity/Assets/Examples/Getting Started/Scripts/SpineboyBeginnerInput.cs index ef177ecfec..d3c07c1966 100644 --- a/spine-unity/Assets/Examples/Getting Started/Scripts/SpineboyBeginnerInput.cs +++ b/spine-unity/Assets/Examples/Getting Started/Scripts/SpineboyBeginnerInput.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ using UnityEngine; diff --git a/spine-unity/Assets/Examples/Getting Started/Scripts/SpineboyBeginnerModel.cs b/spine-unity/Assets/Examples/Getting Started/Scripts/SpineboyBeginnerModel.cs index fc25e23f4d..b2eccd2233 100644 --- a/spine-unity/Assets/Examples/Getting Started/Scripts/SpineboyBeginnerModel.cs +++ b/spine-unity/Assets/Examples/Getting Started/Scripts/SpineboyBeginnerModel.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ using UnityEngine; diff --git a/spine-unity/Assets/Examples/Getting Started/Scripts/SpineboyBeginnerView.cs b/spine-unity/Assets/Examples/Getting Started/Scripts/SpineboyBeginnerView.cs index a149dd6e8f..b7be4ffffe 100644 --- a/spine-unity/Assets/Examples/Getting Started/Scripts/SpineboyBeginnerView.cs +++ b/spine-unity/Assets/Examples/Getting Started/Scripts/SpineboyBeginnerView.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ using UnityEngine; diff --git a/spine-unity/Assets/Examples/Scripts/Goblins.cs b/spine-unity/Assets/Examples/Scripts/Goblins.cs index fd299b6aa6..b17261df7c 100644 --- a/spine-unity/Assets/Examples/Scripts/Goblins.cs +++ b/spine-unity/Assets/Examples/Scripts/Goblins.cs @@ -1,65 +1,64 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEngine; -using System.Collections; -using Spine; -using Spine.Unity; - -public class Goblins : MonoBehaviour { - private bool girlSkin; - private SkeletonAnimation skeletonAnimation; - private Bone headBone; - - public void Start () { - skeletonAnimation = GetComponent(); - headBone = skeletonAnimation.skeleton.FindBone("head"); - skeletonAnimation.UpdateLocal += UpdateLocal; - } - - // This is called after the animation is applied to the skeleton and can be used to adjust the bones dynamically. - public void UpdateLocal (ISkeletonAnimation skeletonRenderer) { - headBone.Rotation += 15; - } - - public void OnMouseDown () { - skeletonAnimation.skeleton.SetSkin(girlSkin ? "goblin" : "goblingirl"); - skeletonAnimation.skeleton.SetSlotsToSetupPose(); - - girlSkin = !girlSkin; - - if (girlSkin) { - skeletonAnimation.skeleton.SetAttachment("right hand item", null); - skeletonAnimation.skeleton.SetAttachment("left hand item", "spear"); - } else - skeletonAnimation.skeleton.SetAttachment("left hand item", "dagger"); - } +using UnityEngine; +using System.Collections; +using Spine; +using Spine.Unity; + +public class Goblins : MonoBehaviour { + private bool girlSkin; + private SkeletonAnimation skeletonAnimation; + private Bone headBone; + + public void Start () { + skeletonAnimation = GetComponent(); + headBone = skeletonAnimation.skeleton.FindBone("head"); + skeletonAnimation.UpdateLocal += UpdateLocal; + } + + // This is called after the animation is applied to the skeleton and can be used to adjust the bones dynamically. + public void UpdateLocal (ISkeletonAnimation skeletonRenderer) { + headBone.Rotation += 15; + } + + public void OnMouseDown () { + skeletonAnimation.skeleton.SetSkin(girlSkin ? "goblin" : "goblingirl"); + skeletonAnimation.skeleton.SetSlotsToSetupPose(); + + girlSkin = !girlSkin; + + if (girlSkin) { + skeletonAnimation.skeleton.SetAttachment("right hand item", null); + skeletonAnimation.skeleton.SetAttachment("left hand item", "spear"); + } else + skeletonAnimation.skeleton.SetAttachment("left hand item", "dagger"); + } } diff --git a/spine-unity/Assets/Examples/Scripts/RaggedySpineboy.cs b/spine-unity/Assets/Examples/Scripts/RaggedySpineboy.cs index 42048696d9..01ef90ee06 100644 --- a/spine-unity/Assets/Examples/Scripts/RaggedySpineboy.cs +++ b/spine-unity/Assets/Examples/Scripts/RaggedySpineboy.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ using UnityEngine; diff --git a/spine-unity/Assets/Examples/Scripts/SpineGauge.cs b/spine-unity/Assets/Examples/Scripts/SpineGauge.cs index b0721630ba..b650558fb7 100644 --- a/spine-unity/Assets/Examples/Scripts/SpineGauge.cs +++ b/spine-unity/Assets/Examples/Scripts/SpineGauge.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ using UnityEngine; diff --git a/spine-unity/Assets/Examples/Scripts/Spineboy.cs b/spine-unity/Assets/Examples/Scripts/Spineboy.cs index 3e72f4417f..9a340d2e61 100644 --- a/spine-unity/Assets/Examples/Scripts/Spineboy.cs +++ b/spine-unity/Assets/Examples/Scripts/Spineboy.cs @@ -1,66 +1,65 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEngine; -using System.Collections; -using Spine; -using System; -using Spine.Unity; - -public class Spineboy : MonoBehaviour { - SkeletonAnimation skeletonAnimation; - - public void Start () { - // Get the SkeletonAnimation component for the GameObject this script is attached to. - skeletonAnimation = GetComponent(); - // Call our method any time an animation fires an event. - skeletonAnimation.state.Event += Event; - // A lambda can be used for the callback instead of a method. - skeletonAnimation.state.End += (state, trackIndex) => { - Debug.Log("start: " + state.GetCurrent(trackIndex)); - }; - // Queue jump to be played on track 0 two seconds after the starting animation. - skeletonAnimation.state.AddAnimation(0, "jump", false, 2); - // Queue walk to be looped on track 0 after the jump animation. - skeletonAnimation.state.AddAnimation(0, "run", true, 0); - } - - public void Event (Spine.AnimationState state, int trackIndex, Spine.Event e) { - Debug.Log(trackIndex + " " + state.GetCurrent(trackIndex) + ": event " + e + ", " + e.Int); - } - - public void OnMouseDown () { - // Set jump to be played on track 0 immediately. - skeletonAnimation.state.SetAnimation(0, "jump", false); - // Queue walk to be looped on track 0 after the jump animation. - skeletonAnimation.state.AddAnimation(0, "run", true, 0); - } +using UnityEngine; +using System.Collections; +using Spine; +using System; +using Spine.Unity; + +public class Spineboy : MonoBehaviour { + SkeletonAnimation skeletonAnimation; + + public void Start () { + // Get the SkeletonAnimation component for the GameObject this script is attached to. + skeletonAnimation = GetComponent(); + // Call our method any time an animation fires an event. + skeletonAnimation.state.Event += Event; + // A lambda can be used for the callback instead of a method. + skeletonAnimation.state.End += (state, trackIndex) => { + Debug.Log("start: " + state.GetCurrent(trackIndex)); + }; + // Queue jump to be played on track 0 two seconds after the starting animation. + skeletonAnimation.state.AddAnimation(0, "jump", false, 2); + // Queue walk to be looped on track 0 after the jump animation. + skeletonAnimation.state.AddAnimation(0, "run", true, 0); + } + + public void Event (Spine.AnimationState state, int trackIndex, Spine.Event e) { + Debug.Log(trackIndex + " " + state.GetCurrent(trackIndex) + ": event " + e + ", " + e.Int); + } + + public void OnMouseDown () { + // Set jump to be played on track 0 immediately. + skeletonAnimation.state.SetAnimation(0, "jump", false); + // Queue walk to be looped on track 0 after the jump animation. + skeletonAnimation.state.AddAnimation(0, "run", true, 0); + } } diff --git a/spine-unity/Assets/Examples/Scripts/SpineboyPole.cs b/spine-unity/Assets/Examples/Scripts/SpineboyPole.cs index f4fd6c85a6..2631bd52c9 100644 --- a/spine-unity/Assets/Examples/Scripts/SpineboyPole.cs +++ b/spine-unity/Assets/Examples/Scripts/SpineboyPole.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ using UnityEngine; diff --git a/spine-unity/Assets/spine-unity/Asset Types/AtlasAsset.cs b/spine-unity/Assets/spine-unity/Asset Types/AtlasAsset.cs index 44b178fb94..7f2b6eb77d 100644 --- a/spine-unity/Assets/spine-unity/Asset Types/AtlasAsset.cs +++ b/spine-unity/Assets/spine-unity/Asset Types/AtlasAsset.cs @@ -1,183 +1,182 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using System.IO; -using UnityEngine; -using Spine; - -namespace Spine.Unity { - ///

Loads and stores a Spine atlas and list of materials. - public class AtlasAsset : ScriptableObject { - public TextAsset atlasFile; - public Material[] materials; - private Atlas atlas; - - public void Reset () { - atlas = null; - } - - /// The atlas or null if it could not be loaded. - public Atlas GetAtlas () { - if (atlasFile == null) { - Debug.LogError("Atlas file not set for atlas asset: " + name, this); - Reset(); - return null; - } - - if (materials == null || materials.Length == 0) { - Debug.LogError("Materials not set for atlas asset: " + name, this); - Reset(); - return null; - } - - if (atlas != null) - return atlas; - - try { - atlas = new Atlas(new StringReader(atlasFile.text), "", new MaterialsTextureLoader(this)); - atlas.FlipV(); - return atlas; - } catch (Exception ex) { - Debug.LogError("Error reading atlas file for atlas asset: " + name + "\n" + ex.Message + "\n" + ex.StackTrace, this); - return null; - } - } - - public Sprite GenerateSprite (string name, out Material material) { - AtlasRegion region = atlas.FindRegion(name); - - Sprite sprite = null; - material = null; - - if (region != null) { - //sprite.rect - } - - return sprite; - } - - public Mesh GenerateMesh (string name, Mesh mesh, out Material material, float scale = 0.01f) { - AtlasRegion region = atlas.FindRegion(name); - material = null; - if (region != null) { - if (mesh == null) { - mesh = new Mesh(); - mesh.name = name; - } - - Vector3[] verts = new Vector3[4]; - Vector2[] uvs = new Vector2[4]; - Color[] colors = new Color[4] { Color.white, Color.white, Color.white, Color.white }; - int[] triangles = new int[6] { 0, 1, 2, 2, 3, 0 }; - - float left, right, top, bottom; - left = region.width / -2f; - right = left * -1f; - top = region.height / 2f; - bottom = top * -1; - - verts[0] = new Vector3(left, bottom, 0) * scale; - verts[1] = new Vector3(left, top, 0) * scale; - verts[2] = new Vector3(right, top, 0) * scale; - verts[3] = new Vector3(right, bottom, 0) * scale; - float u, v, u2, v2; - u = region.u; - v = region.v; - u2 = region.u2; - v2 = region.v2; - - if (!region.rotate) { - uvs[0] = new Vector2(u, v2); - uvs[1] = new Vector2(u, v); - uvs[2] = new Vector2(u2, v); - uvs[3] = new Vector2(u2, v2); - } else { - uvs[0] = new Vector2(u2, v2); - uvs[1] = new Vector2(u, v2); - uvs[2] = new Vector2(u, v); - uvs[3] = new Vector2(u2, v); - } - - mesh.triangles = new int[0]; - mesh.vertices = verts; - mesh.uv = uvs; - mesh.colors = colors; - mesh.triangles = triangles; - mesh.RecalculateNormals(); - mesh.RecalculateBounds(); - - material = (Material)region.page.rendererObject; - } else { - mesh = null; - } - - return mesh; - } - } - - public class MaterialsTextureLoader : TextureLoader { - AtlasAsset atlasAsset; - - public MaterialsTextureLoader (AtlasAsset atlasAsset) { - this.atlasAsset = atlasAsset; - } - - public void Load (AtlasPage page, String path) { - String name = Path.GetFileNameWithoutExtension(path); - Material material = null; - foreach (Material other in atlasAsset.materials) { - if (other.mainTexture == null) { - Debug.LogError("Material is missing texture: " + other.name, other); - return; - } - if (other.mainTexture.name == name) { - material = other; - break; - } - } - if (material == null) { - Debug.LogError("Material with texture name \"" + name + "\" not found for atlas asset: " + atlasAsset.name, atlasAsset); - return; - } - page.rendererObject = material; - - // Very old atlas files expected the texture's actual size to be used at runtime. - if (page.width == 0 || page.height == 0) { - page.width = material.mainTexture.width; - page.height = material.mainTexture.height; - } - } - - public void Unload (object texture) { - } - } +using System; +using System.IO; +using UnityEngine; +using Spine; + +namespace Spine.Unity { + /// Loads and stores a Spine atlas and list of materials. + public class AtlasAsset : ScriptableObject { + public TextAsset atlasFile; + public Material[] materials; + private Atlas atlas; + + public void Reset () { + atlas = null; + } + + /// The atlas or null if it could not be loaded. + public Atlas GetAtlas () { + if (atlasFile == null) { + Debug.LogError("Atlas file not set for atlas asset: " + name, this); + Reset(); + return null; + } + + if (materials == null || materials.Length == 0) { + Debug.LogError("Materials not set for atlas asset: " + name, this); + Reset(); + return null; + } + + if (atlas != null) + return atlas; + + try { + atlas = new Atlas(new StringReader(atlasFile.text), "", new MaterialsTextureLoader(this)); + atlas.FlipV(); + return atlas; + } catch (Exception ex) { + Debug.LogError("Error reading atlas file for atlas asset: " + name + "\n" + ex.Message + "\n" + ex.StackTrace, this); + return null; + } + } + + public Sprite GenerateSprite (string name, out Material material) { + AtlasRegion region = atlas.FindRegion(name); + + Sprite sprite = null; + material = null; + + if (region != null) { + //sprite.rect + } + + return sprite; + } + + public Mesh GenerateMesh (string name, Mesh mesh, out Material material, float scale = 0.01f) { + AtlasRegion region = atlas.FindRegion(name); + material = null; + if (region != null) { + if (mesh == null) { + mesh = new Mesh(); + mesh.name = name; + } + + Vector3[] verts = new Vector3[4]; + Vector2[] uvs = new Vector2[4]; + Color[] colors = new Color[4] { Color.white, Color.white, Color.white, Color.white }; + int[] triangles = new int[6] { 0, 1, 2, 2, 3, 0 }; + + float left, right, top, bottom; + left = region.width / -2f; + right = left * -1f; + top = region.height / 2f; + bottom = top * -1; + + verts[0] = new Vector3(left, bottom, 0) * scale; + verts[1] = new Vector3(left, top, 0) * scale; + verts[2] = new Vector3(right, top, 0) * scale; + verts[3] = new Vector3(right, bottom, 0) * scale; + float u, v, u2, v2; + u = region.u; + v = region.v; + u2 = region.u2; + v2 = region.v2; + + if (!region.rotate) { + uvs[0] = new Vector2(u, v2); + uvs[1] = new Vector2(u, v); + uvs[2] = new Vector2(u2, v); + uvs[3] = new Vector2(u2, v2); + } else { + uvs[0] = new Vector2(u2, v2); + uvs[1] = new Vector2(u, v2); + uvs[2] = new Vector2(u, v); + uvs[3] = new Vector2(u2, v); + } + + mesh.triangles = new int[0]; + mesh.vertices = verts; + mesh.uv = uvs; + mesh.colors = colors; + mesh.triangles = triangles; + mesh.RecalculateNormals(); + mesh.RecalculateBounds(); + + material = (Material)region.page.rendererObject; + } else { + mesh = null; + } + + return mesh; + } + } + + public class MaterialsTextureLoader : TextureLoader { + AtlasAsset atlasAsset; + + public MaterialsTextureLoader (AtlasAsset atlasAsset) { + this.atlasAsset = atlasAsset; + } + + public void Load (AtlasPage page, String path) { + String name = Path.GetFileNameWithoutExtension(path); + Material material = null; + foreach (Material other in atlasAsset.materials) { + if (other.mainTexture == null) { + Debug.LogError("Material is missing texture: " + other.name, other); + return; + } + if (other.mainTexture.name == name) { + material = other; + break; + } + } + if (material == null) { + Debug.LogError("Material with texture name \"" + name + "\" not found for atlas asset: " + atlasAsset.name, atlasAsset); + return; + } + page.rendererObject = material; + + // Very old atlas files expected the texture's actual size to be used at runtime. + if (page.width == 0 || page.height == 0) { + page.width = material.mainTexture.width; + page.height = material.mainTexture.height; + } + } + + public void Unload (object texture) { + } + } } diff --git a/spine-unity/Assets/spine-unity/Asset Types/Editor/AtlasAssetInspector.cs b/spine-unity/Assets/spine-unity/Asset Types/Editor/AtlasAssetInspector.cs index 3660f2e489..45464fee51 100644 --- a/spine-unity/Assets/spine-unity/Asset Types/Editor/AtlasAssetInspector.cs +++ b/spine-unity/Assets/spine-unity/Asset Types/Editor/AtlasAssetInspector.cs @@ -1,342 +1,342 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -//#define BAKE_ALL_BUTTON -//#define REGION_BAKING_MESH - -using System; -using System.Collections.Generic; -using System.Reflection; -using System.IO; -using UnityEditor; -using UnityEngine; -using Spine; - -namespace Spine.Unity.Editor { - - [CustomEditor(typeof(AtlasAsset))] - public class AtlasAssetInspector : UnityEditor.Editor { - private SerializedProperty atlasFile, materials; - private AtlasAsset atlasAsset; - - static List GetRegions (Atlas atlas) { - FieldInfo regionsField = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.NonPublic); - return (List)regionsField.GetValue(atlas); - } - - void OnEnable () { - SpineEditorUtilities.ConfirmInitialization(); - atlasFile = serializedObject.FindProperty("atlasFile"); - materials = serializedObject.FindProperty("materials"); - materials.isExpanded = true; - atlasAsset = (AtlasAsset)target; - #if REGION_BAKING_MESH - UpdateBakedList(); - #endif - } - - #if REGION_BAKING_MESH - private List baked; - private List bakedObjects; - - void UpdateBakedList () { - AtlasAsset asset = (AtlasAsset)target; - baked = new List(); - bakedObjects = new List(); - if (atlasFile.objectReferenceValue != null) { - List regions = this.Regions; - string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); - string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); - string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); - for (int i = 0; i < regions.Count; i++) { - AtlasRegion region = regions[i]; - string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(region) + ".prefab").Replace("\\", "/"); - GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(GameObject)); - baked.Add(prefab != null); - bakedObjects.Add(prefab); - } - } - } - #endif - - static public void UpdateSpriteSlices (Texture texture, Atlas atlas) { - string texturePath = AssetDatabase.GetAssetPath(texture.GetInstanceID()); - var t = (TextureImporter)TextureImporter.GetAtPath(texturePath); - t.spriteImportMode = SpriteImportMode.Multiple; - var spriteSheet = t.spritesheet; - var sprites = new List(spriteSheet); - - var regions = AtlasAssetInspector.GetRegions(atlas); - int textureHeight = texture.height; - char[] FilenameDelimiter = {'.'}; - int updatedCount = 0; - int addedCount = 0; - - foreach (var r in regions) { - int width, height; - if (r.rotate) { - width = r.height; - height = r.width; - } else { - width = r.width; - height = r.height; - } - - int x = r.x; - int y = textureHeight - height - r.y; - - string pageName = r.page.name.Split(FilenameDelimiter, StringSplitOptions.RemoveEmptyEntries)[0]; - string textureName = texture.name; - bool pageMatch = string.Equals(pageName, textureName,StringComparison.Ordinal); - int spriteIndex = pageMatch ? sprites.FindIndex( - (s) => string.Equals(s.name, r.name, StringComparison.Ordinal) - ) : -1; - bool matchFound = spriteIndex >= 0; - - if (matchFound) { - var s = sprites[spriteIndex]; - s.rect = new Rect(x, y, width, height); - sprites[spriteIndex] = s; - updatedCount++; - } else { - if (pageMatch) { - sprites.Add(new SpriteMetaData { - name = r.name, - pivot = new Vector2(0.5f, 0.5f), - rect = new Rect(x, y, width, height) - }); - addedCount++; - } - } - } - - t.spritesheet = sprites.ToArray(); - EditorUtility.SetDirty(t); - AssetDatabase.ImportAsset(texturePath, ImportAssetOptions.ForceUpdate); - EditorGUIUtility.PingObject(texture); - Debug.Log(string.Format("Applied sprite slices to {2}. {0} added. {1} updated.", addedCount, updatedCount, texture.name)); - } - - override public void OnInspectorGUI () { - serializedObject.Update(); - atlasAsset = atlasAsset ?? (AtlasAsset)target; - EditorGUI.BeginChangeCheck(); - EditorGUILayout.PropertyField(atlasFile); - - EditorGUILayout.PropertyField(materials, true); - if (EditorGUI.EndChangeCheck()) - serializedObject.ApplyModifiedProperties(); - - if (materials.arraySize == 0) { - EditorGUILayout.LabelField(new GUIContent("Error: Missing materials", SpineEditorUtilities.Icons.warning)); - return; - } - - for (int i = 0; i < materials.arraySize; i++) { - SerializedProperty prop = materials.GetArrayElementAtIndex(i); - Material mat = (Material)prop.objectReferenceValue; - if (mat == null) { - EditorGUILayout.LabelField(new GUIContent("Error: Materials cannot be null", SpineEditorUtilities.Icons.warning)); - return; - } - } - - EditorGUILayout.Space(); - if (atlasFile.objectReferenceValue != null) { - using (new EditorGUILayout.HorizontalScope()) { - EditorGUILayout.Space(); - if (GUILayout.Button( - new GUIContent( - "Apply Regions as Texture Sprite Slices", - SpineEditorUtilities.Icons.unityIcon, - "Adds Sprite slices to atlas texture(s). " + - "Updates existing slices if ones with matching names exist. \n\n" + - "If your atlas was exported with Premultiply Alpha, " + - "your SpriteRenderer should use the generated Spine _Material asset (or any Material with a PMA shader) instead of Sprites-Default.") - , GUILayout.Height(30f))) { - var atlas = atlasAsset.GetAtlas(); - foreach (var m in atlasAsset.materials) - UpdateSpriteSlices(m.mainTexture, atlas); - } - EditorGUILayout.Space(); - } - } - EditorGUILayout.Space(); - - #if REGION_BAKING_MESH - if (atlasFile.objectReferenceValue != null) { - Atlas atlas = asset.GetAtlas(); - FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic); - List regions = (List)field.GetValue(atlas); - EditorGUILayout.LabelField(new GUIContent("Region Baking", SpineEditorUtilities.Icons.unityIcon)); - EditorGUI.indentLevel++; - AtlasPage lastPage = null; - for (int i = 0; i < regions.Count; i++) { - if (lastPage != regions[i].page) { - if (lastPage != null) { - EditorGUILayout.Separator(); - EditorGUILayout.Separator(); - } - lastPage = regions[i].page; - Material mat = ((Material)lastPage.rendererObject); - if (mat != null) { - GUILayout.BeginHorizontal(); - { - EditorGUI.BeginDisabledGroup(true); - EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250)); - EditorGUI.EndDisabledGroup(); - } - GUILayout.EndHorizontal(); - - } else { - EditorGUILayout.LabelField(new GUIContent("Page missing material!", SpineEditorUtilities.Icons.warning)); - } - } - GUILayout.BeginHorizontal(); - { - //EditorGUILayout.ToggleLeft(baked[i] ? "" : regions[i].name, baked[i]); - bool result = baked[i] ? EditorGUILayout.ToggleLeft("", baked[i], GUILayout.Width(24)) : EditorGUILayout.ToggleLeft(" " + regions[i].name, baked[i]); - if(baked[i]){ - EditorGUILayout.ObjectField(bakedObjects[i], typeof(GameObject), false, GUILayout.Width(250)); - } - if (result && !baked[i]) { - //bake - baked[i] = true; - bakedObjects[i] = SpineEditorUtilities.BakeRegion(atlasAsset, regions[i]); - EditorGUIUtility.PingObject(bakedObjects[i]); - } else if (!result && baked[i]) { - //unbake - bool unbakeResult = EditorUtility.DisplayDialog("Delete Baked Region", "Do you want to delete the prefab for " + regions[i].name, "Yes", "Cancel"); - switch (unbakeResult) { - case true: - //delete - string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); - string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); - string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); - string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(regions[i]) + ".prefab").Replace("\\", "/"); - AssetDatabase.DeleteAsset(bakedPrefabPath); - baked[i] = false; - break; - case false: - //do nothing - break; - } - } - } - GUILayout.EndHorizontal(); - } - EditorGUI.indentLevel--; - - #if BAKE_ALL_BUTTON - // Check state - bool allBaked = true; - bool allUnbaked = true; - for (int i = 0; i < regions.Count; i++) { - allBaked &= baked[i]; - allUnbaked &= !baked[i]; - } - - if (!allBaked && GUILayout.Button("Bake All")) { - for (int i = 0; i < regions.Count; i++) { - if (!baked[i]) { - baked[i] = true; - bakedObjects[i] = SpineEditorUtilities.BakeRegion(atlasAsset, regions[i]); - } - } - - } else if (!allUnbaked && GUILayout.Button("Unbake All")) { - bool unbakeResult = EditorUtility.DisplayDialog("Delete All Baked Regions", "Are you sure you want to unbake all region prefabs? This cannot be undone.", "Yes", "Cancel"); - switch (unbakeResult) { - case true: - //delete - for (int i = 0; i < regions.Count; i++) { - if (baked[i]) { - string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); - string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); - string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); - string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(regions[i]) + ".prefab").Replace("\\", "/"); - AssetDatabase.DeleteAsset(bakedPrefabPath); - baked[i] = false; - } - } - break; - case false: - //do nothing - break; - } - - } - #endif - - } - #else - if (atlasFile.objectReferenceValue != null) { - EditorGUILayout.LabelField("Atlas Regions", EditorStyles.boldLabel); - - var regions = AtlasAssetInspector.GetRegions(atlasAsset.GetAtlas()); - AtlasPage lastPage = null; - for (int i = 0; i < regions.Count; i++) { - if (lastPage != regions[i].page) { - if (lastPage != null) { - EditorGUILayout.Separator(); - EditorGUILayout.Separator(); - } - lastPage = regions[i].page; - Material mat = ((Material)lastPage.rendererObject); - if (mat != null) { - - GUILayout.BeginHorizontal(); - { - EditorGUI.BeginDisabledGroup(true); - EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250)); - EditorGUI.EndDisabledGroup(); - EditorGUI.indentLevel++; - } - GUILayout.EndHorizontal(); - - } else { - EditorGUILayout.LabelField(new GUIContent("Page missing material!", SpineEditorUtilities.Icons.warning)); - } - } - EditorGUILayout.LabelField(new GUIContent(regions[i].name, SpineEditorUtilities.Icons.image)); - } - EditorGUI.indentLevel--; - } - #endif - - if (serializedObject.ApplyModifiedProperties() || - (UnityEngine.Event.current.type == EventType.ValidateCommand && UnityEngine.Event.current.commandName == "UndoRedoPerformed") - ) { - atlasAsset.Reset(); - } - } - } +//#define BAKE_ALL_BUTTON +//#define REGION_BAKING_MESH + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.IO; +using UnityEditor; +using UnityEngine; +using Spine; + +namespace Spine.Unity.Editor { + + [CustomEditor(typeof(AtlasAsset))] + public class AtlasAssetInspector : UnityEditor.Editor { + private SerializedProperty atlasFile, materials; + private AtlasAsset atlasAsset; + + static List GetRegions (Atlas atlas) { + FieldInfo regionsField = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.NonPublic); + return (List)regionsField.GetValue(atlas); + } + + void OnEnable () { + SpineEditorUtilities.ConfirmInitialization(); + atlasFile = serializedObject.FindProperty("atlasFile"); + materials = serializedObject.FindProperty("materials"); + materials.isExpanded = true; + atlasAsset = (AtlasAsset)target; + #if REGION_BAKING_MESH + UpdateBakedList(); + #endif + } + + #if REGION_BAKING_MESH + private List baked; + private List bakedObjects; + + void UpdateBakedList () { + AtlasAsset asset = (AtlasAsset)target; + baked = new List(); + bakedObjects = new List(); + if (atlasFile.objectReferenceValue != null) { + List regions = this.Regions; + string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); + string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); + string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); + for (int i = 0; i < regions.Count; i++) { + AtlasRegion region = regions[i]; + string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(region) + ".prefab").Replace("\\", "/"); + GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(GameObject)); + baked.Add(prefab != null); + bakedObjects.Add(prefab); + } + } + } + #endif + + static public void UpdateSpriteSlices (Texture texture, Atlas atlas) { + string texturePath = AssetDatabase.GetAssetPath(texture.GetInstanceID()); + var t = (TextureImporter)TextureImporter.GetAtPath(texturePath); + t.spriteImportMode = SpriteImportMode.Multiple; + var spriteSheet = t.spritesheet; + var sprites = new List(spriteSheet); + + var regions = AtlasAssetInspector.GetRegions(atlas); + int textureHeight = texture.height; + char[] FilenameDelimiter = {'.'}; + int updatedCount = 0; + int addedCount = 0; + + foreach (var r in regions) { + int width, height; + if (r.rotate) { + width = r.height; + height = r.width; + } else { + width = r.width; + height = r.height; + } + + int x = r.x; + int y = textureHeight - height - r.y; + + string pageName = r.page.name.Split(FilenameDelimiter, StringSplitOptions.RemoveEmptyEntries)[0]; + string textureName = texture.name; + bool pageMatch = string.Equals(pageName, textureName,StringComparison.Ordinal); + int spriteIndex = pageMatch ? sprites.FindIndex( + (s) => string.Equals(s.name, r.name, StringComparison.Ordinal) + ) : -1; + bool matchFound = spriteIndex >= 0; + + if (matchFound) { + var s = sprites[spriteIndex]; + s.rect = new Rect(x, y, width, height); + sprites[spriteIndex] = s; + updatedCount++; + } else { + if (pageMatch) { + sprites.Add(new SpriteMetaData { + name = r.name, + pivot = new Vector2(0.5f, 0.5f), + rect = new Rect(x, y, width, height) + }); + addedCount++; + } + } + } + + t.spritesheet = sprites.ToArray(); + EditorUtility.SetDirty(t); + AssetDatabase.ImportAsset(texturePath, ImportAssetOptions.ForceUpdate); + EditorGUIUtility.PingObject(texture); + Debug.Log(string.Format("Applied sprite slices to {2}. {0} added. {1} updated.", addedCount, updatedCount, texture.name)); + } + + override public void OnInspectorGUI () { + serializedObject.Update(); + atlasAsset = atlasAsset ?? (AtlasAsset)target; + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(atlasFile); + + EditorGUILayout.PropertyField(materials, true); + if (EditorGUI.EndChangeCheck()) + serializedObject.ApplyModifiedProperties(); + + if (materials.arraySize == 0) { + EditorGUILayout.LabelField(new GUIContent("Error: Missing materials", SpineEditorUtilities.Icons.warning)); + return; + } + + for (int i = 0; i < materials.arraySize; i++) { + SerializedProperty prop = materials.GetArrayElementAtIndex(i); + Material mat = (Material)prop.objectReferenceValue; + if (mat == null) { + EditorGUILayout.LabelField(new GUIContent("Error: Materials cannot be null", SpineEditorUtilities.Icons.warning)); + return; + } + } + + EditorGUILayout.Space(); + if (atlasFile.objectReferenceValue != null) { + using (new EditorGUILayout.HorizontalScope()) { + EditorGUILayout.Space(); + if (GUILayout.Button( + new GUIContent( + "Apply Regions as Texture Sprite Slices", + SpineEditorUtilities.Icons.unityIcon, + "Adds Sprite slices to atlas texture(s). " + + "Updates existing slices if ones with matching names exist. \n\n" + + "If your atlas was exported with Premultiply Alpha, " + + "your SpriteRenderer should use the generated Spine _Material asset (or any Material with a PMA shader) instead of Sprites-Default.") + , GUILayout.Height(30f))) { + var atlas = atlasAsset.GetAtlas(); + foreach (var m in atlasAsset.materials) + UpdateSpriteSlices(m.mainTexture, atlas); + } + EditorGUILayout.Space(); + } + } + EditorGUILayout.Space(); + + #if REGION_BAKING_MESH + if (atlasFile.objectReferenceValue != null) { + Atlas atlas = asset.GetAtlas(); + FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic); + List regions = (List)field.GetValue(atlas); + EditorGUILayout.LabelField(new GUIContent("Region Baking", SpineEditorUtilities.Icons.unityIcon)); + EditorGUI.indentLevel++; + AtlasPage lastPage = null; + for (int i = 0; i < regions.Count; i++) { + if (lastPage != regions[i].page) { + if (lastPage != null) { + EditorGUILayout.Separator(); + EditorGUILayout.Separator(); + } + lastPage = regions[i].page; + Material mat = ((Material)lastPage.rendererObject); + if (mat != null) { + GUILayout.BeginHorizontal(); + { + EditorGUI.BeginDisabledGroup(true); + EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250)); + EditorGUI.EndDisabledGroup(); + } + GUILayout.EndHorizontal(); + + } else { + EditorGUILayout.LabelField(new GUIContent("Page missing material!", SpineEditorUtilities.Icons.warning)); + } + } + GUILayout.BeginHorizontal(); + { + //EditorGUILayout.ToggleLeft(baked[i] ? "" : regions[i].name, baked[i]); + bool result = baked[i] ? EditorGUILayout.ToggleLeft("", baked[i], GUILayout.Width(24)) : EditorGUILayout.ToggleLeft(" " + regions[i].name, baked[i]); + if(baked[i]){ + EditorGUILayout.ObjectField(bakedObjects[i], typeof(GameObject), false, GUILayout.Width(250)); + } + if (result && !baked[i]) { + //bake + baked[i] = true; + bakedObjects[i] = SpineEditorUtilities.BakeRegion(atlasAsset, regions[i]); + EditorGUIUtility.PingObject(bakedObjects[i]); + } else if (!result && baked[i]) { + //unbake + bool unbakeResult = EditorUtility.DisplayDialog("Delete Baked Region", "Do you want to delete the prefab for " + regions[i].name, "Yes", "Cancel"); + switch (unbakeResult) { + case true: + //delete + string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); + string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); + string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); + string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(regions[i]) + ".prefab").Replace("\\", "/"); + AssetDatabase.DeleteAsset(bakedPrefabPath); + baked[i] = false; + break; + case false: + //do nothing + break; + } + } + } + GUILayout.EndHorizontal(); + } + EditorGUI.indentLevel--; + + #if BAKE_ALL_BUTTON + // Check state + bool allBaked = true; + bool allUnbaked = true; + for (int i = 0; i < regions.Count; i++) { + allBaked &= baked[i]; + allUnbaked &= !baked[i]; + } + + if (!allBaked && GUILayout.Button("Bake All")) { + for (int i = 0; i < regions.Count; i++) { + if (!baked[i]) { + baked[i] = true; + bakedObjects[i] = SpineEditorUtilities.BakeRegion(atlasAsset, regions[i]); + } + } + + } else if (!allUnbaked && GUILayout.Button("Unbake All")) { + bool unbakeResult = EditorUtility.DisplayDialog("Delete All Baked Regions", "Are you sure you want to unbake all region prefabs? This cannot be undone.", "Yes", "Cancel"); + switch (unbakeResult) { + case true: + //delete + for (int i = 0; i < regions.Count; i++) { + if (baked[i]) { + string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); + string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); + string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); + string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(regions[i]) + ".prefab").Replace("\\", "/"); + AssetDatabase.DeleteAsset(bakedPrefabPath); + baked[i] = false; + } + } + break; + case false: + //do nothing + break; + } + + } + #endif + + } + #else + if (atlasFile.objectReferenceValue != null) { + EditorGUILayout.LabelField("Atlas Regions", EditorStyles.boldLabel); + + var regions = AtlasAssetInspector.GetRegions(atlasAsset.GetAtlas()); + AtlasPage lastPage = null; + for (int i = 0; i < regions.Count; i++) { + if (lastPage != regions[i].page) { + if (lastPage != null) { + EditorGUILayout.Separator(); + EditorGUILayout.Separator(); + } + lastPage = regions[i].page; + Material mat = ((Material)lastPage.rendererObject); + if (mat != null) { + + GUILayout.BeginHorizontal(); + { + EditorGUI.BeginDisabledGroup(true); + EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250)); + EditorGUI.EndDisabledGroup(); + EditorGUI.indentLevel++; + } + GUILayout.EndHorizontal(); + + } else { + EditorGUILayout.LabelField(new GUIContent("Page missing material!", SpineEditorUtilities.Icons.warning)); + } + } + EditorGUILayout.LabelField(new GUIContent(regions[i].name, SpineEditorUtilities.Icons.image)); + } + EditorGUI.indentLevel--; + } + #endif + + if (serializedObject.ApplyModifiedProperties() || + (UnityEngine.Event.current.type == EventType.ValidateCommand && UnityEngine.Event.current.commandName == "UndoRedoPerformed") + ) { + atlasAsset.Reset(); + } + } + } + } diff --git a/spine-unity/Assets/spine-unity/Asset Types/SkeletonDataAsset.cs b/spine-unity/Assets/spine-unity/Asset Types/SkeletonDataAsset.cs index 2a06f8bd50..a8634fbf1b 100644 --- a/spine-unity/Assets/spine-unity/Asset Types/SkeletonDataAsset.cs +++ b/spine-unity/Assets/spine-unity/Asset Types/SkeletonDataAsset.cs @@ -1,184 +1,183 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using System.IO; -using UnityEngine; -using Spine; - -namespace Spine.Unity { - public class SkeletonDataAsset : ScriptableObject { - public AtlasAsset[] atlasAssets; - #if SPINE_TK2D - public tk2dSpriteCollectionData spriteCollection; - public float scale = 1f; - #else - public float scale = 0.01f; - #endif - public TextAsset skeletonJSON; - public String[] fromAnimation; - public String[] toAnimation; - public float[] duration; - public float defaultMix; - public RuntimeAnimatorController controller; - private SkeletonData skeletonData; - private AnimationStateData stateData; - - void OnEnable () { - if (atlasAssets == null) - atlasAssets = new AtlasAsset[0]; - } - - public void Reset () { - skeletonData = null; - stateData = null; - } - - public SkeletonData GetSkeletonData (bool quiet) { - if (atlasAssets == null) { - atlasAssets = new AtlasAsset[0]; - if (!quiet) - Debug.LogError("Atlas not set for SkeletonData asset: " + name, this); - Reset(); - return null; - } - - if (skeletonJSON == null) { - if (!quiet) - Debug.LogError("Skeleton JSON file not set for SkeletonData asset: " + name, this); - Reset(); - return null; - } - - #if !SPINE_TK2D - if (atlasAssets.Length == 0) { - Reset(); - return null; - } - #else - if (atlasAssets.Length == 0 && spriteCollection == null) { - Reset(); - return null; - } - #endif - - Atlas[] atlasArr = new Atlas[atlasAssets.Length]; - for (int i = 0; i < atlasAssets.Length; i++) { - if (atlasAssets[i] == null) { - Reset(); - return null; - } - atlasArr[i] = atlasAssets[i].GetAtlas(); - if (atlasArr[i] == null) { - Reset(); - return null; - } - } - - if (skeletonData != null) - return skeletonData; - - AttachmentLoader attachmentLoader; - float skeletonDataScale; - - #if !SPINE_TK2D - attachmentLoader = new AtlasAttachmentLoader(atlasArr); - skeletonDataScale = scale; - #else - if (spriteCollection != null) { - attachmentLoader = new Spine.Unity.TK2D.SpriteCollectionAttachmentLoader(spriteCollection); - skeletonDataScale = (1.0f / (spriteCollection.invOrthoSize * spriteCollection.halfTargetHeight) * scale); - } else { - if (atlasArr.Length == 0) { - Reset(); - if (!quiet) Debug.LogError("Atlas not set for SkeletonData asset: " + name, this); - return null; - } - attachmentLoader = new AtlasAttachmentLoader(atlasArr); - skeletonDataScale = scale; - } - #endif - - try { - //var stopwatch = new System.Diagnostics.Stopwatch(); - if (skeletonJSON.name.ToLower().Contains(".skel")) { - var input = new MemoryStream(skeletonJSON.bytes); - var binary = new SkeletonBinary(attachmentLoader); - binary.Scale = skeletonDataScale; - //stopwatch.Start(); - skeletonData = binary.ReadSkeletonData(input); - } else { - var input = new StringReader(skeletonJSON.text); - var json = new SkeletonJson(attachmentLoader); - json.Scale = skeletonDataScale; - //stopwatch.Start(); - skeletonData = json.ReadSkeletonData(input); - } - //stopwatch.Stop(); - //Debug.Log(stopwatch.Elapsed); - } catch (Exception ex) { - if (!quiet) - Debug.LogError("Error reading skeleton JSON file for SkeletonData asset: " + name + "\n" + ex.Message + "\n" + ex.StackTrace, this); - return null; - } - - stateData = new AnimationStateData(skeletonData); - FillStateData(); - - return skeletonData; - } - - public void FillStateData () { - if (stateData == null) - return; - - stateData.DefaultMix = defaultMix; - - // For compatibility with runtime-instantiated SkeletonDataAsset. - if (fromAnimation == null || toAnimation == null) - return; - - for (int i = 0, n = fromAnimation.Length; i < n; i++) { - if (fromAnimation[i].Length == 0 || toAnimation[i].Length == 0) - continue; - stateData.SetMix(fromAnimation[i], toAnimation[i], duration[i]); - } - } - - public AnimationStateData GetAnimationStateData () { - if (stateData != null) - return stateData; - GetSkeletonData(false); - return stateData; - } - } - +using System; +using System.IO; +using UnityEngine; +using Spine; + +namespace Spine.Unity { + public class SkeletonDataAsset : ScriptableObject { + public AtlasAsset[] atlasAssets; + #if SPINE_TK2D + public tk2dSpriteCollectionData spriteCollection; + public float scale = 1f; + #else + public float scale = 0.01f; + #endif + public TextAsset skeletonJSON; + public String[] fromAnimation; + public String[] toAnimation; + public float[] duration; + public float defaultMix; + public RuntimeAnimatorController controller; + private SkeletonData skeletonData; + private AnimationStateData stateData; + + void OnEnable () { + if (atlasAssets == null) + atlasAssets = new AtlasAsset[0]; + } + + public void Reset () { + skeletonData = null; + stateData = null; + } + + public SkeletonData GetSkeletonData (bool quiet) { + if (atlasAssets == null) { + atlasAssets = new AtlasAsset[0]; + if (!quiet) + Debug.LogError("Atlas not set for SkeletonData asset: " + name, this); + Reset(); + return null; + } + + if (skeletonJSON == null) { + if (!quiet) + Debug.LogError("Skeleton JSON file not set for SkeletonData asset: " + name, this); + Reset(); + return null; + } + + #if !SPINE_TK2D + if (atlasAssets.Length == 0) { + Reset(); + return null; + } + #else + if (atlasAssets.Length == 0 && spriteCollection == null) { + Reset(); + return null; + } + #endif + + Atlas[] atlasArr = new Atlas[atlasAssets.Length]; + for (int i = 0; i < atlasAssets.Length; i++) { + if (atlasAssets[i] == null) { + Reset(); + return null; + } + atlasArr[i] = atlasAssets[i].GetAtlas(); + if (atlasArr[i] == null) { + Reset(); + return null; + } + } + + if (skeletonData != null) + return skeletonData; + + AttachmentLoader attachmentLoader; + float skeletonDataScale; + + #if !SPINE_TK2D + attachmentLoader = new AtlasAttachmentLoader(atlasArr); + skeletonDataScale = scale; + #else + if (spriteCollection != null) { + attachmentLoader = new Spine.Unity.TK2D.SpriteCollectionAttachmentLoader(spriteCollection); + skeletonDataScale = (1.0f / (spriteCollection.invOrthoSize * spriteCollection.halfTargetHeight) * scale); + } else { + if (atlasArr.Length == 0) { + Reset(); + if (!quiet) Debug.LogError("Atlas not set for SkeletonData asset: " + name, this); + return null; + } + attachmentLoader = new AtlasAttachmentLoader(atlasArr); + skeletonDataScale = scale; + } + #endif + + try { + //var stopwatch = new System.Diagnostics.Stopwatch(); + if (skeletonJSON.name.ToLower().Contains(".skel")) { + var input = new MemoryStream(skeletonJSON.bytes); + var binary = new SkeletonBinary(attachmentLoader); + binary.Scale = skeletonDataScale; + //stopwatch.Start(); + skeletonData = binary.ReadSkeletonData(input); + } else { + var input = new StringReader(skeletonJSON.text); + var json = new SkeletonJson(attachmentLoader); + json.Scale = skeletonDataScale; + //stopwatch.Start(); + skeletonData = json.ReadSkeletonData(input); + } + //stopwatch.Stop(); + //Debug.Log(stopwatch.Elapsed); + } catch (Exception ex) { + if (!quiet) + Debug.LogError("Error reading skeleton JSON file for SkeletonData asset: " + name + "\n" + ex.Message + "\n" + ex.StackTrace, this); + return null; + } + + stateData = new AnimationStateData(skeletonData); + FillStateData(); + + return skeletonData; + } + + public void FillStateData () { + if (stateData == null) + return; + + stateData.DefaultMix = defaultMix; + + // For compatibility with runtime-instantiated SkeletonDataAsset. + if (fromAnimation == null || toAnimation == null) + return; + + for (int i = 0, n = fromAnimation.Length; i < n; i++) { + if (fromAnimation[i].Length == 0 || toAnimation[i].Length == 0) + continue; + stateData.SetMix(fromAnimation[i], toAnimation[i], duration[i]); + } + } + + public AnimationStateData GetAnimationStateData () { + if (stateData != null) + return stateData; + GetSkeletonData(false); + return stateData; + } + } + } diff --git a/spine-unity/Assets/spine-unity/BoneFollower.cs b/spine-unity/Assets/spine-unity/BoneFollower.cs index d59c885500..a8a169b46c 100644 --- a/spine-unity/Assets/spine-unity/BoneFollower.cs +++ b/spine-unity/Assets/spine-unity/BoneFollower.cs @@ -1,137 +1,137 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using UnityEngine; - -namespace Spine.Unity { - /// Sets a GameObject's transform to match a bone on a Spine skeleton. - [ExecuteInEditMode] - [AddComponentMenu("Spine/BoneFollower")] - public class BoneFollower : MonoBehaviour { - - #region Inspector - public SkeletonRenderer skeletonRenderer; - public SkeletonRenderer SkeletonRenderer { - get { return skeletonRenderer; } - set { - skeletonRenderer = value; - Initialize(); - } - } - - /// If a bone isn't set in code, boneName is used to find the bone. - [SpineBone(dataField: "skeletonRenderer")] - public String boneName; - - public bool followZPosition = true; - public bool followBoneRotation = true; - - [Tooltip("Follows the skeleton's flip state by controlling this Transform's local scale.")] - public bool followSkeletonFlip = false; - - [UnityEngine.Serialization.FormerlySerializedAs("resetOnAwake")] - public bool initializeOnAwake = true; - #endregion - - [NonSerialized] public bool valid; - [NonSerialized] public Bone bone; - Transform skeletonTransform; - - public void Awake () { - if (initializeOnAwake) Initialize(); - } - - public void HandleRebuildRenderer (SkeletonRenderer skeletonRenderer) { - Initialize(); - } - - public void Initialize () { - bone = null; - valid = skeletonRenderer != null && skeletonRenderer.valid; - if (!valid) return; - - skeletonTransform = skeletonRenderer.transform; - skeletonRenderer.OnRebuild -= HandleRebuildRenderer; - skeletonRenderer.OnRebuild += HandleRebuildRenderer; - - #if UNITY_EDITOR - if (Application.isEditor) - LateUpdate(); - #endif - } - - void OnDestroy () { - if (skeletonRenderer != null) - skeletonRenderer.OnRebuild -= HandleRebuildRenderer; - } - - public void LateUpdate () { - if (!valid) { - Initialize(); - return; - } - - if (bone == null) { - if (string.IsNullOrEmpty(boneName)) return; - - bone = skeletonRenderer.skeleton.FindBone(boneName); - if (bone == null) { - Debug.LogError("Bone not found: " + boneName, this); - return; - } - } - - Transform thisTransform = this.transform; - if (thisTransform.parent == skeletonTransform) { - // Recommended setup: Use local transform properties if Spine GameObject is the immediate parent - thisTransform.localPosition = new Vector3(bone.worldX, bone.worldY, followZPosition ? 0f : thisTransform.localPosition.z); - if (followBoneRotation) thisTransform.localRotation = Quaternion.Euler(0f, 0f, bone.WorldRotationX); - - } else { - // For special cases: Use transform world properties if transform relationship is complicated - Vector3 targetWorldPosition = skeletonTransform.TransformPoint(new Vector3(bone.worldX, bone.worldY, 0f)); - if (!followZPosition) targetWorldPosition.z = thisTransform.position.z; - thisTransform.position = targetWorldPosition; - - if (followBoneRotation) { - Vector3 worldRotation = skeletonTransform.rotation.eulerAngles; - thisTransform.rotation = Quaternion.Euler(worldRotation.x, worldRotation.y, skeletonTransform.rotation.eulerAngles.z + bone.WorldRotationX); - } - } - - if (followSkeletonFlip) { - float flipScaleY = bone.skeleton.flipX ^ bone.skeleton.flipY ? -1f : 1f; - thisTransform.localScale = new Vector3(1f, flipScaleY, 1f); - } - } - } +using System; +using UnityEngine; + +namespace Spine.Unity { + /// Sets a GameObject's transform to match a bone on a Spine skeleton. + [ExecuteInEditMode] + [AddComponentMenu("Spine/BoneFollower")] + public class BoneFollower : MonoBehaviour { + + #region Inspector + public SkeletonRenderer skeletonRenderer; + public SkeletonRenderer SkeletonRenderer { + get { return skeletonRenderer; } + set { + skeletonRenderer = value; + Initialize(); + } + } + + /// If a bone isn't set in code, boneName is used to find the bone. + [SpineBone(dataField: "skeletonRenderer")] + public String boneName; + + public bool followZPosition = true; + public bool followBoneRotation = true; + + [Tooltip("Follows the skeleton's flip state by controlling this Transform's local scale.")] + public bool followSkeletonFlip = false; + + [UnityEngine.Serialization.FormerlySerializedAs("resetOnAwake")] + public bool initializeOnAwake = true; + #endregion + + [NonSerialized] public bool valid; + [NonSerialized] public Bone bone; + Transform skeletonTransform; + + public void Awake () { + if (initializeOnAwake) Initialize(); + } + + public void HandleRebuildRenderer (SkeletonRenderer skeletonRenderer) { + Initialize(); + } + + public void Initialize () { + bone = null; + valid = skeletonRenderer != null && skeletonRenderer.valid; + if (!valid) return; + + skeletonTransform = skeletonRenderer.transform; + skeletonRenderer.OnRebuild -= HandleRebuildRenderer; + skeletonRenderer.OnRebuild += HandleRebuildRenderer; + + #if UNITY_EDITOR + if (Application.isEditor) + LateUpdate(); + #endif + } + + void OnDestroy () { + if (skeletonRenderer != null) + skeletonRenderer.OnRebuild -= HandleRebuildRenderer; + } + + public void LateUpdate () { + if (!valid) { + Initialize(); + return; + } + + if (bone == null) { + if (string.IsNullOrEmpty(boneName)) return; + + bone = skeletonRenderer.skeleton.FindBone(boneName); + if (bone == null) { + Debug.LogError("Bone not found: " + boneName, this); + return; + } + } + + Transform thisTransform = this.transform; + if (thisTransform.parent == skeletonTransform) { + // Recommended setup: Use local transform properties if Spine GameObject is the immediate parent + thisTransform.localPosition = new Vector3(bone.worldX, bone.worldY, followZPosition ? 0f : thisTransform.localPosition.z); + if (followBoneRotation) thisTransform.localRotation = Quaternion.Euler(0f, 0f, bone.WorldRotationX); + + } else { + // For special cases: Use transform world properties if transform relationship is complicated + Vector3 targetWorldPosition = skeletonTransform.TransformPoint(new Vector3(bone.worldX, bone.worldY, 0f)); + if (!followZPosition) targetWorldPosition.z = thisTransform.position.z; + thisTransform.position = targetWorldPosition; + + if (followBoneRotation) { + Vector3 worldRotation = skeletonTransform.rotation.eulerAngles; + thisTransform.rotation = Quaternion.Euler(worldRotation.x, worldRotation.y, skeletonTransform.rotation.eulerAngles.z + bone.WorldRotationX); + } + } + + if (followSkeletonFlip) { + float flipScaleY = bone.skeleton.flipX ^ bone.skeleton.flipY ? -1f : 1f; + thisTransform.localScale = new Vector3(1f, flipScaleY, 1f); + } + } + } + } diff --git a/spine-unity/Assets/spine-unity/Editor/AssetDatabaseAvailabilityDetector.cs b/spine-unity/Assets/spine-unity/Editor/AssetDatabaseAvailabilityDetector.cs index 7be1caa20d..84fa8f984e 100644 --- a/spine-unity/Assets/spine-unity/Editor/AssetDatabaseAvailabilityDetector.cs +++ b/spine-unity/Assets/spine-unity/Editor/AssetDatabaseAvailabilityDetector.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ using UnityEngine; diff --git a/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs b/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs index e4e3672174..0d462ca3c4 100644 --- a/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs +++ b/spine-unity/Assets/spine-unity/Editor/BoneFollowerInspector.cs @@ -1,128 +1,127 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEditor; -using UnityEngine; - -namespace Spine.Unity.Editor { - [CustomEditor(typeof(BoneFollower))] - public class BoneFollowerInspector : UnityEditor.Editor { - SerializedProperty boneName, skeletonRenderer, followZPosition, followBoneRotation, followSkeletonFlip; - BoneFollower targetBoneFollower; - bool needsReset; - - void OnEnable () { - skeletonRenderer = serializedObject.FindProperty("skeletonRenderer"); - boneName = serializedObject.FindProperty("boneName"); - followBoneRotation = serializedObject.FindProperty("followBoneRotation"); - followZPosition = serializedObject.FindProperty("followZPosition"); - followSkeletonFlip = serializedObject.FindProperty("followSkeletonFlip"); - - targetBoneFollower = (BoneFollower)target; - if (targetBoneFollower.SkeletonRenderer != null) - targetBoneFollower.SkeletonRenderer.Initialize(false); - } - - override public void OnInspectorGUI () { - if (needsReset) { - targetBoneFollower.Initialize(); - targetBoneFollower.LateUpdate(); - needsReset = false; - SceneView.RepaintAll(); - } - serializedObject.Update(); - - // Find Renderer - if (skeletonRenderer.objectReferenceValue == null) { - SkeletonRenderer parentRenderer = BoneFollowerInspector.GetInParent(targetBoneFollower.transform); - if (parentRenderer != null && parentRenderer.gameObject != targetBoneFollower.gameObject) { - skeletonRenderer.objectReferenceValue = parentRenderer; - Debug.Log("Inspector automatically assigned BoneFollower.SkeletonRenderer"); - } - } - - EditorGUILayout.PropertyField(skeletonRenderer); - var skeletonRendererReference = skeletonRenderer.objectReferenceValue as SkeletonRenderer; - if (skeletonRendererReference != null) { - if (skeletonRendererReference.gameObject == targetBoneFollower.gameObject) { - skeletonRenderer.objectReferenceValue = null; - EditorUtility.DisplayDialog("Invalid assignment.", "BoneFollower can only follow a skeleton on a separate GameObject.\n\nCreate a new GameObject for your BoneFollower, or choose a SkeletonRenderer from a different GameObject.", "Ok"); - } - } - - if (targetBoneFollower.valid) { - EditorGUI.BeginChangeCheck(); - EditorGUILayout.PropertyField(boneName); - if (EditorGUI.EndChangeCheck()) { - serializedObject.ApplyModifiedProperties(); - needsReset = true; - serializedObject.Update(); - } - EditorGUILayout.PropertyField(followBoneRotation); - EditorGUILayout.PropertyField(followZPosition); - EditorGUILayout.PropertyField(followSkeletonFlip); - } else { - var boneFollowerSkeletonRenderer = targetBoneFollower.skeletonRenderer; - if (boneFollowerSkeletonRenderer == null) { - EditorGUILayout.HelpBox("SkeletonRenderer is unassigned. Please assign a SkeletonRenderer (SkeletonAnimation or SkeletonAnimator).", MessageType.Warning); - } else { - boneFollowerSkeletonRenderer.Initialize(false); - - if (boneFollowerSkeletonRenderer.skeletonDataAsset == null) - EditorGUILayout.HelpBox("Assigned SkeletonRenderer does not have SkeletonData assigned to it.", MessageType.Warning); - - if (!boneFollowerSkeletonRenderer.valid) - EditorGUILayout.HelpBox("Assigned SkeletonRenderer is invalid. Check target SkeletonRenderer, its SkeletonDataAsset or the console for other errors.", MessageType.Warning); - } - } - - var current = UnityEngine.Event.current; - bool wasUndo = (current.type == EventType.ValidateCommand && current.commandName == "UndoRedoPerformed"); - if (serializedObject.ApplyModifiedProperties() || wasUndo) - targetBoneFollower.Initialize(); - } - - public static T GetInParent (Transform origin) where T : Component { - #if UNITY_4_3 - Transform parent = origin.parent; - while (parent.GetComponent() == null) { - parent = parent.parent; - if(parent == null) - return default(T); - } - return parent.GetComponent(); - #else - return origin.GetComponentInParent(); - #endif - } - } - +using UnityEditor; +using UnityEngine; + +namespace Spine.Unity.Editor { + [CustomEditor(typeof(BoneFollower))] + public class BoneFollowerInspector : UnityEditor.Editor { + SerializedProperty boneName, skeletonRenderer, followZPosition, followBoneRotation, followSkeletonFlip; + BoneFollower targetBoneFollower; + bool needsReset; + + void OnEnable () { + skeletonRenderer = serializedObject.FindProperty("skeletonRenderer"); + boneName = serializedObject.FindProperty("boneName"); + followBoneRotation = serializedObject.FindProperty("followBoneRotation"); + followZPosition = serializedObject.FindProperty("followZPosition"); + followSkeletonFlip = serializedObject.FindProperty("followSkeletonFlip"); + + targetBoneFollower = (BoneFollower)target; + if (targetBoneFollower.SkeletonRenderer != null) + targetBoneFollower.SkeletonRenderer.Initialize(false); + } + + override public void OnInspectorGUI () { + if (needsReset) { + targetBoneFollower.Initialize(); + targetBoneFollower.LateUpdate(); + needsReset = false; + SceneView.RepaintAll(); + } + serializedObject.Update(); + + // Find Renderer + if (skeletonRenderer.objectReferenceValue == null) { + SkeletonRenderer parentRenderer = BoneFollowerInspector.GetInParent(targetBoneFollower.transform); + if (parentRenderer != null && parentRenderer.gameObject != targetBoneFollower.gameObject) { + skeletonRenderer.objectReferenceValue = parentRenderer; + Debug.Log("Inspector automatically assigned BoneFollower.SkeletonRenderer"); + } + } + + EditorGUILayout.PropertyField(skeletonRenderer); + var skeletonRendererReference = skeletonRenderer.objectReferenceValue as SkeletonRenderer; + if (skeletonRendererReference != null) { + if (skeletonRendererReference.gameObject == targetBoneFollower.gameObject) { + skeletonRenderer.objectReferenceValue = null; + EditorUtility.DisplayDialog("Invalid assignment.", "BoneFollower can only follow a skeleton on a separate GameObject.\n\nCreate a new GameObject for your BoneFollower, or choose a SkeletonRenderer from a different GameObject.", "Ok"); + } + } + + if (targetBoneFollower.valid) { + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(boneName); + if (EditorGUI.EndChangeCheck()) { + serializedObject.ApplyModifiedProperties(); + needsReset = true; + serializedObject.Update(); + } + EditorGUILayout.PropertyField(followBoneRotation); + EditorGUILayout.PropertyField(followZPosition); + EditorGUILayout.PropertyField(followSkeletonFlip); + } else { + var boneFollowerSkeletonRenderer = targetBoneFollower.skeletonRenderer; + if (boneFollowerSkeletonRenderer == null) { + EditorGUILayout.HelpBox("SkeletonRenderer is unassigned. Please assign a SkeletonRenderer (SkeletonAnimation or SkeletonAnimator).", MessageType.Warning); + } else { + boneFollowerSkeletonRenderer.Initialize(false); + + if (boneFollowerSkeletonRenderer.skeletonDataAsset == null) + EditorGUILayout.HelpBox("Assigned SkeletonRenderer does not have SkeletonData assigned to it.", MessageType.Warning); + + if (!boneFollowerSkeletonRenderer.valid) + EditorGUILayout.HelpBox("Assigned SkeletonRenderer is invalid. Check target SkeletonRenderer, its SkeletonDataAsset or the console for other errors.", MessageType.Warning); + } + } + + var current = UnityEngine.Event.current; + bool wasUndo = (current.type == EventType.ValidateCommand && current.commandName == "UndoRedoPerformed"); + if (serializedObject.ApplyModifiedProperties() || wasUndo) + targetBoneFollower.Initialize(); + } + + public static T GetInParent (Transform origin) where T : Component { + #if UNITY_4_3 + Transform parent = origin.parent; + while (parent.GetComponent() == null) { + parent = parent.parent; + if(parent == null) + return default(T); + } + return parent.GetComponent(); + #else + return origin.GetComponentInParent(); + #endif + } + } + } diff --git a/spine-unity/Assets/spine-unity/Editor/Menus.cs b/spine-unity/Assets/spine-unity/Editor/Menus.cs index f61aad4fa3..9759285988 100644 --- a/spine-unity/Assets/spine-unity/Editor/Menus.cs +++ b/spine-unity/Assets/spine-unity/Editor/Menus.cs @@ -1,84 +1,84 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using System.IO; -using UnityEditor; -using UnityEngine; -namespace Spine.Unity.Editor { - public static class Menus { - [MenuItem("Assets/Create/Spine Atlas")] - static public void CreateAtlas () { - CreateAsset("New Atlas"); - } - - [MenuItem("Assets/Create/Spine SkeletonData")] - static public void CreateSkeletonData () { - CreateAsset("New SkeletonData"); - } - - static private void CreateAsset (String name) where T : ScriptableObject { - var dir = "Assets/"; - var selected = Selection.activeObject; - if (selected != null) { - var assetDir = AssetDatabase.GetAssetPath(selected.GetInstanceID()); - if (assetDir.Length > 0 && Directory.Exists(assetDir)) - dir = assetDir + "/"; - } - ScriptableObject asset = ScriptableObject.CreateInstance(); - AssetDatabase.CreateAsset(asset, dir + name + ".asset"); - AssetDatabase.SaveAssets(); - EditorUtility.FocusProjectWindow(); - Selection.activeObject = asset; - } - - [MenuItem("GameObject/Spine/SkeletonRenderer", false, 10)] - static public void CreateSkeletonRendererGameObject () { - CreateSpineGameObject("New SkeletonRenderer"); - } - - [MenuItem("GameObject/Spine/SkeletonAnimation", false, 10)] - static public void CreateSkeletonAnimationGameObject () { - CreateSpineGameObject("New SkeletonAnimation"); - } - - static public void CreateSpineGameObject (string name) where T : MonoBehaviour { - var parentGameObject = Selection.activeObject as GameObject; - var parentTransform = parentGameObject == null ? null : parentGameObject.transform; - - var gameObject = new GameObject("New SkeletonRenderer", typeof(T)); - gameObject.transform.SetParent(parentTransform, false); - EditorUtility.FocusProjectWindow(); - Selection.activeObject = gameObject; - EditorGUIUtility.PingObject(Selection.activeObject); - } - } +using System; +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace Spine.Unity.Editor { + public static class Menus { + [MenuItem("Assets/Create/Spine Atlas")] + static public void CreateAtlas () { + CreateAsset("New Atlas"); + } + + [MenuItem("Assets/Create/Spine SkeletonData")] + static public void CreateSkeletonData () { + CreateAsset("New SkeletonData"); + } + + static private void CreateAsset (String name) where T : ScriptableObject { + var dir = "Assets/"; + var selected = Selection.activeObject; + if (selected != null) { + var assetDir = AssetDatabase.GetAssetPath(selected.GetInstanceID()); + if (assetDir.Length > 0 && Directory.Exists(assetDir)) + dir = assetDir + "/"; + } + ScriptableObject asset = ScriptableObject.CreateInstance(); + AssetDatabase.CreateAsset(asset, dir + name + ".asset"); + AssetDatabase.SaveAssets(); + EditorUtility.FocusProjectWindow(); + Selection.activeObject = asset; + } + + [MenuItem("GameObject/Spine/SkeletonRenderer", false, 10)] + static public void CreateSkeletonRendererGameObject () { + CreateSpineGameObject("New SkeletonRenderer"); + } + + [MenuItem("GameObject/Spine/SkeletonAnimation", false, 10)] + static public void CreateSkeletonAnimationGameObject () { + CreateSpineGameObject("New SkeletonAnimation"); + } + + static public void CreateSpineGameObject (string name) where T : MonoBehaviour { + var parentGameObject = Selection.activeObject as GameObject; + var parentTransform = parentGameObject == null ? null : parentGameObject.transform; + + var gameObject = new GameObject("New SkeletonRenderer", typeof(T)); + gameObject.transform.SetParent(parentTransform, false); + EditorUtility.FocusProjectWindow(); + Selection.activeObject = gameObject; + EditorGUIUtility.PingObject(Selection.activeObject); + } + } } diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonAnimationInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonAnimationInspector.cs index f574d2fc0d..bb6a77ffc8 100644 --- a/spine-unity/Assets/spine-unity/Editor/SkeletonAnimationInspector.cs +++ b/spine-unity/Assets/spine-unity/Editor/SkeletonAnimationInspector.cs @@ -1,109 +1,109 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEditor; -using UnityEngine; -using Spine; -namespace Spine.Unity.Editor { - - [CustomEditor(typeof(SkeletonAnimation))] - public class SkeletonAnimationInspector : SkeletonRendererInspector { - protected SerializedProperty animationName, loop, timeScale, autoReset; - protected bool wasAnimationNameChanged; - - protected override void OnEnable () { - base.OnEnable(); - animationName = serializedObject.FindProperty("_animationName"); - loop = serializedObject.FindProperty("loop"); - timeScale = serializedObject.FindProperty("timeScale"); - } - - protected override void DrawInspectorGUI () { - base.DrawInspectorGUI(); - - SkeletonAnimation component = (SkeletonAnimation)target; - if (!component.valid) - return; - - if (!isInspectingPrefab) { - if (wasAnimationNameChanged) { - if (!Application.isPlaying) { - if (component.state != null) component.state.ClearTrack(0); - component.skeleton.SetToSetupPose(); - } - - Spine.Animation animationToUse = component.skeleton.Data.FindAnimation(animationName.stringValue); - - if (!Application.isPlaying) { - if (animationToUse != null) animationToUse.Apply(component.skeleton, 0f, 0f, false, null); - component.Update(); - component.LateUpdate(); - SceneView.RepaintAll(); - } else { - if (animationToUse != null) - component.state.SetAnimation(0, animationToUse, loop.boolValue); - else - component.state.ClearTrack(0); - } - - wasAnimationNameChanged = false; - } - - // Reflect animationName serialized property in the inspector even if SetAnimation API was used. - if (Application.isPlaying) { - TrackEntry current = component.state.GetCurrent(0); - if (current != null) { - if (component.AnimationName != animationName.stringValue) - animationName.stringValue = current.Animation.Name; - } - } - } - - EditorGUILayout.Space(); - EditorGUI.BeginChangeCheck(); - EditorGUILayout.PropertyField(animationName); - wasAnimationNameChanged |= EditorGUI.EndChangeCheck(); // Value used in the next update. - - EditorGUILayout.PropertyField(loop); - EditorGUILayout.PropertyField(timeScale); - component.timeScale = Mathf.Max(component.timeScale, 0); - - EditorGUILayout.Space(); - - if (!isInspectingPrefab) { - if (component.GetComponent() == null) { - if (GUILayout.Button(new GUIContent("Add Skeleton Utility", SpineEditorUtilities.Icons.skeletonUtility), GUILayout.Height(30))) - component.gameObject.AddComponent(); - } - } - } - } +using UnityEditor; +using UnityEngine; +using Spine; + +namespace Spine.Unity.Editor { + + [CustomEditor(typeof(SkeletonAnimation))] + public class SkeletonAnimationInspector : SkeletonRendererInspector { + protected SerializedProperty animationName, loop, timeScale, autoReset; + protected bool wasAnimationNameChanged; + + protected override void OnEnable () { + base.OnEnable(); + animationName = serializedObject.FindProperty("_animationName"); + loop = serializedObject.FindProperty("loop"); + timeScale = serializedObject.FindProperty("timeScale"); + } + + protected override void DrawInspectorGUI () { + base.DrawInspectorGUI(); + + SkeletonAnimation component = (SkeletonAnimation)target; + if (!component.valid) + return; + + if (!isInspectingPrefab) { + if (wasAnimationNameChanged) { + if (!Application.isPlaying) { + if (component.state != null) component.state.ClearTrack(0); + component.skeleton.SetToSetupPose(); + } + + Spine.Animation animationToUse = component.skeleton.Data.FindAnimation(animationName.stringValue); + + if (!Application.isPlaying) { + if (animationToUse != null) animationToUse.Apply(component.skeleton, 0f, 0f, false, null); + component.Update(); + component.LateUpdate(); + SceneView.RepaintAll(); + } else { + if (animationToUse != null) + component.state.SetAnimation(0, animationToUse, loop.boolValue); + else + component.state.ClearTrack(0); + } + + wasAnimationNameChanged = false; + } + + // Reflect animationName serialized property in the inspector even if SetAnimation API was used. + if (Application.isPlaying) { + TrackEntry current = component.state.GetCurrent(0); + if (current != null) { + if (component.AnimationName != animationName.stringValue) + animationName.stringValue = current.Animation.Name; + } + } + } + + EditorGUILayout.Space(); + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(animationName); + wasAnimationNameChanged |= EditorGUI.EndChangeCheck(); // Value used in the next update. + + EditorGUILayout.PropertyField(loop); + EditorGUILayout.PropertyField(timeScale); + component.timeScale = Mathf.Max(component.timeScale, 0); + + EditorGUILayout.Space(); + + if (!isInspectingPrefab) { + if (component.GetComponent() == null) { + if (GUILayout.Button(new GUIContent("Add Skeleton Utility", SpineEditorUtilities.Icons.skeletonUtility), GUILayout.Height(30))) + component.gameObject.AddComponent(); + } + } + } + } } diff --git a/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs index cc975a0802..37e922ab70 100644 --- a/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs +++ b/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs @@ -1,198 +1,198 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#define NO_PREFAB_MESH -using UnityEditor; -using UnityEngine; - -namespace Spine.Unity.Editor { - - [CustomEditor(typeof(SkeletonRenderer))] - public class SkeletonRendererInspector : UnityEditor.Editor { - protected static bool advancedFoldout; - protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes, immutableTriangles, separatorSlotNames, frontFacing, zSpacing, pmaVertexColors; - protected SpineInspectorUtility.SerializedSortingProperties sortingProperties; - protected bool isInspectingPrefab; - protected MeshFilter meshFilter; - - protected virtual void OnEnable () { - isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab); - - SpineEditorUtilities.ConfirmInitialization(); - skeletonDataAsset = serializedObject.FindProperty("skeletonDataAsset"); - initialSkinName = serializedObject.FindProperty("initialSkinName"); - normals = serializedObject.FindProperty("calculateNormals"); - tangents = serializedObject.FindProperty("calculateTangents"); - meshes = serializedObject.FindProperty("renderMeshes"); - immutableTriangles = serializedObject.FindProperty("immutableTriangles"); - pmaVertexColors = serializedObject.FindProperty("pmaVertexColors"); - separatorSlotNames = serializedObject.FindProperty("separatorSlotNames"); - separatorSlotNames.isExpanded = true; - - frontFacing = serializedObject.FindProperty("frontFacing"); - zSpacing = serializedObject.FindProperty("zSpacing"); - - var renderer = ((SkeletonRenderer)target).GetComponent(); - sortingProperties = new SpineInspectorUtility.SerializedSortingProperties(renderer); - } - - public static void ReapplySeparatorSlotNames (SkeletonRenderer skeletonRenderer) { - if (!skeletonRenderer.valid) return; - - var separatorSlots = skeletonRenderer.separatorSlots; - var separatorSlotNames = skeletonRenderer.separatorSlotNames; - var skeleton = skeletonRenderer.skeleton; - - separatorSlots.Clear(); - for (int i = 0, n = separatorSlotNames.Length; i < n; i++) { - var slot = skeleton.FindSlot(separatorSlotNames[i]); - if (slot != null) { - separatorSlots.Add(slot); - //Debug.Log(slot + " added as separator."); - } else { - Debug.LogWarning(separatorSlotNames[i] + " is not a slot in " + skeletonRenderer.skeletonDataAsset.skeletonJSON.name); - } - } - - //Debug.Log("Reapplied Separator Slot Names. Count is now: " + separatorSlots.Count); - } - - protected virtual void DrawInspectorGUI () { - // JOHN: todo: support multiediting. - SkeletonRenderer component = (SkeletonRenderer)target; - - using (new EditorGUILayout.HorizontalScope()) { - EditorGUILayout.PropertyField(skeletonDataAsset); - const string ReloadButtonLabel = "Reload"; - float reloadWidth = GUI.skin.label.CalcSize(new GUIContent(ReloadButtonLabel)).x + 20; - if (GUILayout.Button(ReloadButtonLabel, GUILayout.Width(reloadWidth))) { - if (component.skeletonDataAsset != null) { - foreach (AtlasAsset aa in component.skeletonDataAsset.atlasAssets) { - if (aa != null) - aa.Reset(); - } - component.skeletonDataAsset.Reset(); - } - component.Initialize(true); - } - } - - if (!component.valid) { - component.Initialize(true); - component.LateUpdate(); - if (!component.valid) - return; - } - - #if NO_PREFAB_MESH - if (meshFilter == null) - meshFilter = component.GetComponent(); - - if (isInspectingPrefab) - meshFilter.sharedMesh = null; - #endif - - // Initial skin name. - { - string[] skins = new string[component.skeleton.Data.Skins.Count]; - int skinIndex = 0; - for (int i = 0; i < skins.Length; i++) { - string skinNameString = component.skeleton.Data.Skins.Items[i].Name; - skins[i] = skinNameString; - if (skinNameString == initialSkinName.stringValue) - skinIndex = i; - } - skinIndex = EditorGUILayout.Popup("Initial Skin", skinIndex, skins); - initialSkinName.stringValue = skins[skinIndex]; - } - - EditorGUILayout.Space(); - - // Sorting Layers - SpineInspectorUtility.SortingPropertyFields(sortingProperties, applyModifiedProperties: true); - - // More Render Options... - using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) { - EditorGUI.indentLevel++; - advancedFoldout = EditorGUILayout.Foldout(advancedFoldout, "Advanced"); - if (advancedFoldout) { - EditorGUI.indentLevel++; - SeparatorsField(separatorSlotNames); - EditorGUILayout.Space(); - - // Optimization options - SpineInspectorUtility.PropertyFieldWideLabel(meshes, - new GUIContent("Render MeshAttachments", "Disable to optimize rendering for skeletons that don't use Mesh Attachments")); - SpineInspectorUtility.PropertyFieldWideLabel(immutableTriangles, - new GUIContent("Immutable Triangles", "Enable to optimize rendering for skeletons that never change attachment visbility")); - EditorGUILayout.Space(); - - // Render options - const float MinZSpacing = -0.1f; - const float MaxZSpacing = 0f; - EditorGUILayout.Slider(zSpacing, MinZSpacing, MaxZSpacing); - EditorGUILayout.Space(); - SpineInspectorUtility.PropertyFieldWideLabel(pmaVertexColors, - new GUIContent("PMA Vertex Colors", "Use this if you are using the default Spine/Skeleton shader or any premultiply-alpha shader.")); - - // Optional fields. May be disabled in SkeletonRenderer. - if (normals != null) SpineInspectorUtility.PropertyFieldWideLabel(normals, new GUIContent("Add Normals")); - if (tangents != null) SpineInspectorUtility.PropertyFieldWideLabel(tangents, new GUIContent("Solve Tangents")); - if (frontFacing != null) SpineInspectorUtility.PropertyFieldWideLabel(frontFacing); - - EditorGUI.indentLevel--; - } - EditorGUI.indentLevel--; - } - } - - public static void SeparatorsField (SerializedProperty separatorSlotNames) { - using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) { - if (separatorSlotNames.isExpanded) - EditorGUILayout.PropertyField(separatorSlotNames, includeChildren: true); - else - EditorGUILayout.PropertyField(separatorSlotNames, new GUIContent(separatorSlotNames.displayName + string.Format(" [{0}]", separatorSlotNames.arraySize)), includeChildren: true); - } - } - - override public void OnInspectorGUI () { - //serializedObject.Update(); - DrawInspectorGUI(); - if (serializedObject.ApplyModifiedProperties() || - (UnityEngine.Event.current.type == EventType.ValidateCommand && UnityEngine.Event.current.commandName == "UndoRedoPerformed") - ) { - if (!Application.isPlaying) - ((SkeletonRenderer)target).Initialize(true); - } - } - - } -} \ No newline at end of file +#define NO_PREFAB_MESH + +using UnityEditor; +using UnityEngine; + +namespace Spine.Unity.Editor { + + [CustomEditor(typeof(SkeletonRenderer))] + public class SkeletonRendererInspector : UnityEditor.Editor { + protected static bool advancedFoldout; + protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes, immutableTriangles, separatorSlotNames, frontFacing, zSpacing, pmaVertexColors; + protected SpineInspectorUtility.SerializedSortingProperties sortingProperties; + protected bool isInspectingPrefab; + protected MeshFilter meshFilter; + + protected virtual void OnEnable () { + isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab); + + SpineEditorUtilities.ConfirmInitialization(); + skeletonDataAsset = serializedObject.FindProperty("skeletonDataAsset"); + initialSkinName = serializedObject.FindProperty("initialSkinName"); + normals = serializedObject.FindProperty("calculateNormals"); + tangents = serializedObject.FindProperty("calculateTangents"); + meshes = serializedObject.FindProperty("renderMeshes"); + immutableTriangles = serializedObject.FindProperty("immutableTriangles"); + pmaVertexColors = serializedObject.FindProperty("pmaVertexColors"); + separatorSlotNames = serializedObject.FindProperty("separatorSlotNames"); + separatorSlotNames.isExpanded = true; + + frontFacing = serializedObject.FindProperty("frontFacing"); + zSpacing = serializedObject.FindProperty("zSpacing"); + + var renderer = ((SkeletonRenderer)target).GetComponent(); + sortingProperties = new SpineInspectorUtility.SerializedSortingProperties(renderer); + } + + public static void ReapplySeparatorSlotNames (SkeletonRenderer skeletonRenderer) { + if (!skeletonRenderer.valid) return; + + var separatorSlots = skeletonRenderer.separatorSlots; + var separatorSlotNames = skeletonRenderer.separatorSlotNames; + var skeleton = skeletonRenderer.skeleton; + + separatorSlots.Clear(); + for (int i = 0, n = separatorSlotNames.Length; i < n; i++) { + var slot = skeleton.FindSlot(separatorSlotNames[i]); + if (slot != null) { + separatorSlots.Add(slot); + //Debug.Log(slot + " added as separator."); + } else { + Debug.LogWarning(separatorSlotNames[i] + " is not a slot in " + skeletonRenderer.skeletonDataAsset.skeletonJSON.name); + } + } + + //Debug.Log("Reapplied Separator Slot Names. Count is now: " + separatorSlots.Count); + } + + protected virtual void DrawInspectorGUI () { + // JOHN: todo: support multiediting. + SkeletonRenderer component = (SkeletonRenderer)target; + + using (new EditorGUILayout.HorizontalScope()) { + EditorGUILayout.PropertyField(skeletonDataAsset); + const string ReloadButtonLabel = "Reload"; + float reloadWidth = GUI.skin.label.CalcSize(new GUIContent(ReloadButtonLabel)).x + 20; + if (GUILayout.Button(ReloadButtonLabel, GUILayout.Width(reloadWidth))) { + if (component.skeletonDataAsset != null) { + foreach (AtlasAsset aa in component.skeletonDataAsset.atlasAssets) { + if (aa != null) + aa.Reset(); + } + component.skeletonDataAsset.Reset(); + } + component.Initialize(true); + } + } + + if (!component.valid) { + component.Initialize(true); + component.LateUpdate(); + if (!component.valid) + return; + } + + #if NO_PREFAB_MESH + if (meshFilter == null) + meshFilter = component.GetComponent(); + + if (isInspectingPrefab) + meshFilter.sharedMesh = null; + #endif + + // Initial skin name. + { + string[] skins = new string[component.skeleton.Data.Skins.Count]; + int skinIndex = 0; + for (int i = 0; i < skins.Length; i++) { + string skinNameString = component.skeleton.Data.Skins.Items[i].Name; + skins[i] = skinNameString; + if (skinNameString == initialSkinName.stringValue) + skinIndex = i; + } + skinIndex = EditorGUILayout.Popup("Initial Skin", skinIndex, skins); + initialSkinName.stringValue = skins[skinIndex]; + } + + EditorGUILayout.Space(); + + // Sorting Layers + SpineInspectorUtility.SortingPropertyFields(sortingProperties, applyModifiedProperties: true); + + // More Render Options... + using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) { + EditorGUI.indentLevel++; + advancedFoldout = EditorGUILayout.Foldout(advancedFoldout, "Advanced"); + if (advancedFoldout) { + EditorGUI.indentLevel++; + SeparatorsField(separatorSlotNames); + EditorGUILayout.Space(); + + // Optimization options + SpineInspectorUtility.PropertyFieldWideLabel(meshes, + new GUIContent("Render MeshAttachments", "Disable to optimize rendering for skeletons that don't use Mesh Attachments")); + SpineInspectorUtility.PropertyFieldWideLabel(immutableTriangles, + new GUIContent("Immutable Triangles", "Enable to optimize rendering for skeletons that never change attachment visbility")); + EditorGUILayout.Space(); + + // Render options + const float MinZSpacing = -0.1f; + const float MaxZSpacing = 0f; + EditorGUILayout.Slider(zSpacing, MinZSpacing, MaxZSpacing); + EditorGUILayout.Space(); + SpineInspectorUtility.PropertyFieldWideLabel(pmaVertexColors, + new GUIContent("PMA Vertex Colors", "Use this if you are using the default Spine/Skeleton shader or any premultiply-alpha shader.")); + + // Optional fields. May be disabled in SkeletonRenderer. + if (normals != null) SpineInspectorUtility.PropertyFieldWideLabel(normals, new GUIContent("Add Normals")); + if (tangents != null) SpineInspectorUtility.PropertyFieldWideLabel(tangents, new GUIContent("Solve Tangents")); + if (frontFacing != null) SpineInspectorUtility.PropertyFieldWideLabel(frontFacing); + + EditorGUI.indentLevel--; + } + EditorGUI.indentLevel--; + } + } + + public static void SeparatorsField (SerializedProperty separatorSlotNames) { + using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) { + if (separatorSlotNames.isExpanded) + EditorGUILayout.PropertyField(separatorSlotNames, includeChildren: true); + else + EditorGUILayout.PropertyField(separatorSlotNames, new GUIContent(separatorSlotNames.displayName + string.Format(" [{0}]", separatorSlotNames.arraySize)), includeChildren: true); + } + } + + override public void OnInspectorGUI () { + //serializedObject.Update(); + DrawInspectorGUI(); + if (serializedObject.ApplyModifiedProperties() || + (UnityEngine.Event.current.type == EventType.ValidateCommand && UnityEngine.Event.current.commandName == "UndoRedoPerformed") + ) { + if (!Application.isPlaying) + ((SkeletonRenderer)target).Initialize(true); + } + } + + } +} diff --git a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs index 2f12902bfe..8e0939ee00 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,12 +21,13 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + #pragma warning disable 0219 /***************************************************************************** @@ -1503,5 +1503,4 @@ public class AtlasRequirementLoader : AttachmentLoader { } } -} - +} diff --git a/spine-unity/Assets/spine-unity/Editor/SpineInspectorUtility.cs b/spine-unity/Assets/spine-unity/Editor/SpineInspectorUtility.cs index 86a7d9f1db..eeee6bc2dd 100644 --- a/spine-unity/Assets/spine-unity/Editor/SpineInspectorUtility.cs +++ b/spine-unity/Assets/spine-unity/Editor/SpineInspectorUtility.cs @@ -1,109 +1,108 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEngine; -using UnityEditor; -using System.Reflection; - -namespace Spine.Unity.Editor { - public static class SpineInspectorUtility { - - public static string Pluralize (int n, string singular, string plural) { - return n + " " + (n == 1 ? singular : plural); - } - - public static string PluralThenS (int n) { - return n == 1 ? "" : "s"; - } - - public static void PropertyFieldWideLabel (SerializedProperty property, GUIContent label = null, float minimumLabelWidth = 150) { - using (new EditorGUILayout.HorizontalScope()) { - GUILayout.Label(label ?? new GUIContent(property.displayName, property.tooltip), GUILayout.MinWidth(minimumLabelWidth)); - //GUILayout.FlexibleSpace(); - EditorGUILayout.PropertyField(property, GUIContent.none, true, GUILayout.MinWidth(100)); - } - } - - #region Sorting Layer Field Helpers - static readonly GUIContent SortingLayerLabel = new GUIContent("Sorting Layer"); - static readonly GUIContent OrderInLayerLabel = new GUIContent("Order in Layer"); - - static MethodInfo m_SortingLayerFieldMethod; - static MethodInfo SortingLayerFieldMethod { - get { - if (m_SortingLayerFieldMethod == null) - m_SortingLayerFieldMethod = typeof(EditorGUILayout).GetMethod("SortingLayerField", BindingFlags.Static | BindingFlags.NonPublic, null, new [] { typeof(GUIContent), typeof(SerializedProperty), typeof(GUIStyle) }, null); - - return m_SortingLayerFieldMethod; - } - } - - public struct SerializedSortingProperties { - public SerializedObject renderer; - public SerializedProperty sortingLayerID; - public SerializedProperty sortingOrder; - - public SerializedSortingProperties (Renderer r) { - renderer = new SerializedObject(r); - sortingLayerID = renderer.FindProperty("m_SortingLayerID"); - sortingOrder = renderer.FindProperty("m_SortingOrder"); - } - - public void ApplyModifiedProperties () { - renderer.ApplyModifiedProperties(); - } - } - - public static void SortingPropertyFields (SerializedSortingProperties prop, bool applyModifiedProperties) { - if (applyModifiedProperties) { - EditorGUI.BeginChangeCheck(); - SortingPropertyFields(prop.sortingLayerID, prop.sortingOrder); - if(EditorGUI.EndChangeCheck()) { - prop.ApplyModifiedProperties(); - EditorUtility.SetDirty(prop.renderer.targetObject); - } - } else { - SortingPropertyFields(prop.sortingLayerID, prop.sortingOrder); - } - } - - public static void SortingPropertyFields (SerializedProperty m_SortingLayerID, SerializedProperty m_SortingOrder) { - if (SpineInspectorUtility.SortingLayerFieldMethod != null && m_SortingLayerID != null) { - SpineInspectorUtility.SortingLayerFieldMethod.Invoke(null, new object[] { SortingLayerLabel, m_SortingLayerID, EditorStyles.popup } ); - } else { - EditorGUILayout.PropertyField(m_SortingLayerID); - } - - EditorGUILayout.PropertyField(m_SortingOrder, OrderInLayerLabel); - } - #endregion - } +using UnityEngine; +using UnityEditor; +using System.Reflection; + +namespace Spine.Unity.Editor { + public static class SpineInspectorUtility { + + public static string Pluralize (int n, string singular, string plural) { + return n + " " + (n == 1 ? singular : plural); + } + + public static string PluralThenS (int n) { + return n == 1 ? "" : "s"; + } + + public static void PropertyFieldWideLabel (SerializedProperty property, GUIContent label = null, float minimumLabelWidth = 150) { + using (new EditorGUILayout.HorizontalScope()) { + GUILayout.Label(label ?? new GUIContent(property.displayName, property.tooltip), GUILayout.MinWidth(minimumLabelWidth)); + //GUILayout.FlexibleSpace(); + EditorGUILayout.PropertyField(property, GUIContent.none, true, GUILayout.MinWidth(100)); + } + } + + #region Sorting Layer Field Helpers + static readonly GUIContent SortingLayerLabel = new GUIContent("Sorting Layer"); + static readonly GUIContent OrderInLayerLabel = new GUIContent("Order in Layer"); + + static MethodInfo m_SortingLayerFieldMethod; + static MethodInfo SortingLayerFieldMethod { + get { + if (m_SortingLayerFieldMethod == null) + m_SortingLayerFieldMethod = typeof(EditorGUILayout).GetMethod("SortingLayerField", BindingFlags.Static | BindingFlags.NonPublic, null, new [] { typeof(GUIContent), typeof(SerializedProperty), typeof(GUIStyle) }, null); + + return m_SortingLayerFieldMethod; + } + } + + public struct SerializedSortingProperties { + public SerializedObject renderer; + public SerializedProperty sortingLayerID; + public SerializedProperty sortingOrder; + + public SerializedSortingProperties (Renderer r) { + renderer = new SerializedObject(r); + sortingLayerID = renderer.FindProperty("m_SortingLayerID"); + sortingOrder = renderer.FindProperty("m_SortingOrder"); + } + + public void ApplyModifiedProperties () { + renderer.ApplyModifiedProperties(); + } + } + + public static void SortingPropertyFields (SerializedSortingProperties prop, bool applyModifiedProperties) { + if (applyModifiedProperties) { + EditorGUI.BeginChangeCheck(); + SortingPropertyFields(prop.sortingLayerID, prop.sortingOrder); + if(EditorGUI.EndChangeCheck()) { + prop.ApplyModifiedProperties(); + EditorUtility.SetDirty(prop.renderer.targetObject); + } + } else { + SortingPropertyFields(prop.sortingLayerID, prop.sortingOrder); + } + } + + public static void SortingPropertyFields (SerializedProperty m_SortingLayerID, SerializedProperty m_SortingOrder) { + if (SpineInspectorUtility.SortingLayerFieldMethod != null && m_SortingLayerID != null) { + SpineInspectorUtility.SortingLayerFieldMethod.Invoke(null, new object[] { SortingLayerLabel, m_SortingLayerID, EditorStyles.popup } ); + } else { + EditorGUILayout.PropertyField(m_SortingLayerID); + } + + EditorGUILayout.PropertyField(m_SortingOrder, OrderInLayerLabel); + } + #endregion + } } diff --git a/spine-unity/Assets/spine-unity/ISkeletonAnimation.cs b/spine-unity/Assets/spine-unity/ISkeletonAnimation.cs index 44d664708e..f1fc51e0b7 100644 --- a/spine-unity/Assets/spine-unity/ISkeletonAnimation.cs +++ b/spine-unity/Assets/spine-unity/ISkeletonAnimation.cs @@ -1,60 +1,60 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEngine; -namespace Spine.Unity { - public delegate void UpdateBonesDelegate (ISkeletonAnimation animatedSkeletonComponent); - - /// A Spine-Unity Component that animates a Skeleton but not necessarily with a Spine.AnimationState. - public interface ISkeletonAnimation { - event UpdateBonesDelegate UpdateLocal; - event UpdateBonesDelegate UpdateWorld; - event UpdateBonesDelegate UpdateComplete; - - void LateUpdate (); - Skeleton Skeleton { get; } - } - - /// A Spine-Unity Component that manages a Spine.Skeleton instance, instantiated from a SkeletonDataAsset. - public interface ISkeletonComponent { - /// Gets the SkeletonDataAsset of the Spine Component. - SkeletonDataAsset SkeletonDataAsset { get; } - - /// Gets the Spine.Skeleton instance of the Spine Component. This is equivalent to SkeletonRenderer's .skeleton. - Skeleton Skeleton { get; } - } - - /// A Spine-Unity Component that uses a Spine.AnimationState to animate its skeleton. - public interface IAnimationStateComponent { - /// Gets the Spine.AnimationState of the animated Spine Component. This is equivalent to SkeletonAnimation.state. - AnimationState AnimationState { get; } - } +using UnityEngine; + +namespace Spine.Unity { + public delegate void UpdateBonesDelegate (ISkeletonAnimation animatedSkeletonComponent); + + /// A Spine-Unity Component that animates a Skeleton but not necessarily with a Spine.AnimationState. + public interface ISkeletonAnimation { + event UpdateBonesDelegate UpdateLocal; + event UpdateBonesDelegate UpdateWorld; + event UpdateBonesDelegate UpdateComplete; + + void LateUpdate (); + Skeleton Skeleton { get; } + } + + /// A Spine-Unity Component that manages a Spine.Skeleton instance, instantiated from a SkeletonDataAsset. + public interface ISkeletonComponent { + /// Gets the SkeletonDataAsset of the Spine Component. + SkeletonDataAsset SkeletonDataAsset { get; } + + /// Gets the Spine.Skeleton instance of the Spine Component. This is equivalent to SkeletonRenderer's .skeleton. + Skeleton Skeleton { get; } + } + + /// A Spine-Unity Component that uses a Spine.AnimationState to animate its skeleton. + public interface IAnimationStateComponent { + /// Gets the Spine.AnimationState of the animated Spine Component. This is equivalent to SkeletonAnimation.state. + AnimationState AnimationState { get; } + } } diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysMeshGenerator.cs index 42bb85965e..5800fcb89e 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysMeshGenerator.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysMeshGenerator.cs @@ -1,438 +1,437 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#define SPINE_OPTIONAL_NORMALS -using UnityEngine; -namespace Spine.Unity.MeshGeneration { - public class ArraysMeshGenerator { - #region Settings - public bool PremultiplyVertexColors { get; set; } - protected bool addNormals; - public bool AddNormals { get { return addNormals; } set { addNormals = value; } } - protected bool addTangents; - public bool AddTangents { get { return addTangents; } set { addTangents = value; } } - #endregion - - protected float[] attachmentVertexBuffer = new float[8]; - protected Vector3[] meshVertices; - protected Color32[] meshColors32; - protected Vector2[] meshUVs; - - #if SPINE_OPTIONAL_NORMALS - protected Vector3[] meshNormals; - #endif - protected Vector4[] meshTangents; - protected Vector2[] tempTanBuffer; - - public void TryAddNormalsTo (Mesh mesh, int targetVertexCount) { - #if SPINE_OPTIONAL_NORMALS - if (addNormals) { - bool verticesWasResized = this.meshNormals == null || meshNormals.Length < targetVertexCount; - if (verticesWasResized) { - this.meshNormals = new Vector3[targetVertexCount]; - Vector3 fixedNormal = new Vector3(0, 0, -1f); - Vector3[] normals = this.meshNormals; - for (int i = 0; i < targetVertexCount; i++) - normals[i] = fixedNormal; - } - - mesh.normals = this.meshNormals; - } - #endif - } - - /// Ensures the sizes of the passed array references. If they are not the correct size, a new array will be assigned to the references. - /// true, if a resize occurred, false otherwise. - public static bool EnsureSize (int targetVertexCount, ref Vector3[] vertices, ref Vector2[] uvs, ref Color32[] colors) { - Vector3[] verts = vertices; - bool verticesWasResized = verts == null || targetVertexCount > verts.Length; - if (verticesWasResized) { - // Not enough space, increase size. - vertices = new Vector3[targetVertexCount]; - colors = new Color32[targetVertexCount]; - uvs = new Vector2[targetVertexCount]; - } else { - // Too many vertices, zero the extra. - Vector3 zero = Vector3.zero; - for (int i = targetVertexCount, n = verts.Length; i < n; i++) - verts[i] = zero; - } - return verticesWasResized; - } - - public static bool EnsureTriangleBuffersSize (ExposedList submeshBuffers, int targetSubmeshCount, SubmeshInstruction[] instructionItems) { - bool submeshBuffersWasResized = submeshBuffers.Count < targetSubmeshCount; - if (submeshBuffersWasResized) { - submeshBuffers.GrowIfNeeded(targetSubmeshCount - submeshBuffers.Count); - for (int i = submeshBuffers.Count; submeshBuffers.Count < targetSubmeshCount; i++) - submeshBuffers.Add(new SubmeshTriangleBuffer(instructionItems[i].triangleCount)); - } - return submeshBuffersWasResized; - } - - /// Fills Unity vertex data buffers with verts from the Spine Skeleton. - /// Spine.Skeleton source of the drawOrder array - /// Slot index of the first slot. - /// The index bounding the slot list. [endSlot - 1] is the last slot to be added. - /// Spacing along the z-axis between attachments. - /// If set to true, vertex colors will be premultiplied. This will also enable additive. - /// Vertex positions array. - /// Vertex UV array. - /// Vertex color array (Color32). - /// A reference to the running vertex index. This is used when more than one submesh is to be added. - /// A temporary vertex position buffer for attachment position values. - /// Reference to the running calculated minimum bounds. - /// Reference to the running calculated maximum bounds. - /// Include MeshAttachments. If false, it will ignore MeshAttachments. - public static void FillVerts (Skeleton skeleton, int startSlot, int endSlot, float zSpacing, bool pmaColors, Vector3[] verts, Vector2[] uvs, Color32[] colors, ref int vertexIndex, ref float[] tempVertBuffer, ref Vector3 boundsMin, ref Vector3 boundsMax, bool renderMeshes = true) { - Color32 color; - var skeletonDrawOrderItems = skeleton.DrawOrder.Items; - float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b; - - int vi = vertexIndex; - var tempVerts = tempVertBuffer; - Vector3 bmin = boundsMin; - Vector3 bmax = boundsMax; - - // drawOrder[endSlot] is excluded - for (int slotIndex = startSlot; slotIndex < endSlot; slotIndex++) { - var slot = skeletonDrawOrderItems[slotIndex]; - var attachment = slot.attachment; - float z = slotIndex * zSpacing; - - var regionAttachment = attachment as RegionAttachment; - if (regionAttachment != null) { - regionAttachment.ComputeWorldVertices(slot.bone, tempVerts); - - float x1 = tempVerts[RegionAttachment.X1], y1 = tempVerts[RegionAttachment.Y1]; - float x2 = tempVerts[RegionAttachment.X2], y2 = tempVerts[RegionAttachment.Y2]; - float x3 = tempVerts[RegionAttachment.X3], y3 = tempVerts[RegionAttachment.Y3]; - float x4 = tempVerts[RegionAttachment.X4], y4 = tempVerts[RegionAttachment.Y4]; - verts[vi].x = x1; verts[vi].y = y1; verts[vi].z = z; - verts[vi + 1].x = x4; verts[vi + 1].y = y4; verts[vi + 1].z = z; - verts[vi + 2].x = x2; verts[vi + 2].y = y2; verts[vi + 2].z = z; - verts[vi + 3].x = x3; verts[vi + 3].y = y3; verts[vi + 3].z = z; - - if (pmaColors) { - color.a = (byte)(a * slot.a * regionAttachment.a); - color.r = (byte)(r * slot.r * regionAttachment.r * color.a); - color.g = (byte)(g * slot.g * regionAttachment.g * color.a); - color.b = (byte)(b * slot.b * regionAttachment.b * color.a); - if (slot.data.blendMode == BlendMode.additive) color.a = 0; - } else { - color.a = (byte)(a * slot.a * regionAttachment.a); - color.r = (byte)(r * slot.r * regionAttachment.r * 255); - color.g = (byte)(g * slot.g * regionAttachment.g * 255); - color.b = (byte)(b * slot.b * regionAttachment.b * 255); - } - - colors[vi] = color; colors[vi + 1] = color; colors[vi + 2] = color; colors[vi + 3] = color; - - float[] regionUVs = regionAttachment.uvs; - uvs[vi].x = regionUVs[RegionAttachment.X1]; uvs[vi].y = regionUVs[RegionAttachment.Y1]; - uvs[vi + 1].x = regionUVs[RegionAttachment.X4]; uvs[vi + 1].y = regionUVs[RegionAttachment.Y4]; - uvs[vi + 2].x = regionUVs[RegionAttachment.X2]; uvs[vi + 2].y = regionUVs[RegionAttachment.Y2]; - uvs[vi + 3].x = regionUVs[RegionAttachment.X3]; uvs[vi + 3].y = regionUVs[RegionAttachment.Y3]; - - if (x1 < bmin.x) bmin.x = x1; // Potential first attachment bounds initialization. Initial min should not block initial max. Same for Y below. - if (x1 > bmax.x) bmax.x = x1; - if (x2 < bmin.x) bmin.x = x2; - else if (x2 > bmax.x) bmax.x = x2; - if (x3 < bmin.x) bmin.x = x3; - else if (x3 > bmax.x) bmax.x = x3; - if (x4 < bmin.x) bmin.x = x4; - else if (x4 > bmax.x) bmax.x = x4; - - if (y1 < bmin.y) bmin.y = y1; - if (y1 > bmax.y) bmax.y = y1; - if (y2 < bmin.y) bmin.y = y2; - else if (y2 > bmax.y) bmax.y = y2; - if (y3 < bmin.y) bmin.y = y3; - else if (y3 > bmax.y) bmax.y = y3; - if (y4 < bmin.y) bmin.y = y4; - else if (y4 > bmax.y) bmax.y = y4; - - vi += 4; - } else if (renderMeshes) { - var meshAttachment = attachment as MeshAttachment; - if (meshAttachment != null) { - int meshVertexCount = meshAttachment.worldVerticesLength; - if (tempVerts.Length < meshVertexCount) tempVerts = new float[meshVertexCount]; - meshAttachment.ComputeWorldVertices(slot, tempVerts); - - if (pmaColors) { - color.a = (byte)(a * slot.a * meshAttachment.a); - color.r = (byte)(r * slot.r * meshAttachment.r * color.a); - color.g = (byte)(g * slot.g * meshAttachment.g * color.a); - color.b = (byte)(b * slot.b * meshAttachment.b * color.a); - if (slot.data.blendMode == BlendMode.additive) color.a = 0; - } else { - color.a = (byte)(a * slot.a * meshAttachment.a); - color.r = (byte)(r * slot.r * meshAttachment.r * 255); - color.g = (byte)(g * slot.g * meshAttachment.g * 255); - color.b = (byte)(b * slot.b * meshAttachment.b * 255); - } - - float[] attachmentUVs = meshAttachment.uvs; - - // Potential first attachment bounds initialization. See conditions in RegionAttachment logic. - if (vi == vertexIndex) { - // Initial min should not block initial max. - // vi == vertexIndex does not always mean the bounds are fresh. It could be a submesh. Do not nuke old values by omitting the check. - // Should know that this is the first attachment in the submesh. slotIndex == startSlot could be an empty slot. - float fx = tempVerts[0], fy = tempVerts[1]; - if (fx < bmin.x) bmin.x = fx; - if (fx > bmax.x) bmax.x = fx; - if (fy < bmin.y) bmin.y = fy; - if (fy > bmax.y) bmax.y = fy; - } - - for (int iii = 0; iii < meshVertexCount; iii += 2) { - float x = tempVerts[iii], y = tempVerts[iii + 1]; - verts[vi].x = x; verts[vi].y = y; verts[vi].z = z; - colors[vi] = color; uvs[vi].x = attachmentUVs[iii]; uvs[vi].y = attachmentUVs[iii + 1]; - - if (x < bmin.x) bmin.x = x; - else if (x > bmax.x) bmax.x = x; - - if (y < bmin.y) bmin.y = y; - else if (y > bmax.y) bmax.y = y; - - vi++; - } - } - } - } - - // ref return values - vertexIndex = vi; - tempVertBuffer = tempVerts; - boundsMin = bmin; - boundsMax = bmax; - } - - - /// Fills a submesh triangle buffer array. - /// Spine.Skeleton source of draw order slots. - /// The target triangle count. - /// First vertex of this submesh. - /// Start slot. - /// End slot. - /// The triangle buffer array to be filled. This reference will be replaced in case the triangle values don't fit. - /// If set to true, the triangle buffer is allowed to be larger than needed. - public static void FillTriangles (ref int[] triangleBuffer, Skeleton skeleton, int triangleCount, int firstVertex, int startSlot, int endSlot, bool isLastSubmesh) { - int trianglesCapacity = triangleBuffer.Length; - int[] tris = triangleBuffer; - - if (isLastSubmesh) { - if (trianglesCapacity > triangleCount) { - for (int i = triangleCount; i < trianglesCapacity; i++) - tris[i] = 0; - } else if (trianglesCapacity < triangleCount) { - triangleBuffer = tris = new int[triangleCount]; - } - } else if (trianglesCapacity != triangleCount) { - triangleBuffer = tris = new int[triangleCount]; - } - - var skeletonDrawOrderItems = skeleton.drawOrder.Items; - for (int i = startSlot, n = endSlot, ti = 0, afv = firstVertex; i < n; i++) { - var attachment = skeletonDrawOrderItems[i].attachment; - - // RegionAttachment - if (attachment is RegionAttachment) { - tris[ti] = afv; - tris[ti + 1] = afv + 2; - tris[ti + 2] = afv + 1; - tris[ti + 3] = afv + 2; - tris[ti + 4] = afv + 3; - tris[ti + 5] = afv + 1; - ti += 6; - afv += 4; - continue; - } - - // MeshAttachment - var meshAttachment = attachment as MeshAttachment; - if (meshAttachment != null) { - int[] attachmentTriangles = meshAttachment.triangles; - for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, ti++) - tris[ti] = afv + attachmentTriangles[ii]; - - afv += meshAttachment.worldVerticesLength >> 1; // length/2; - } - - } - } - - public static void FillTrianglesQuads (ref int[] triangleBuffer, ref int storedTriangleCount, ref int storedFirstVertex, int instructionsFirstVertex, int instructionTriangleCount, bool isLastSubmesh) { - int trianglesCapacity = triangleBuffer.Length; - - if (isLastSubmesh && trianglesCapacity > instructionTriangleCount) { - for (int i = instructionTriangleCount; i < trianglesCapacity; i++) - triangleBuffer[i] = 0; - storedTriangleCount = instructionTriangleCount; - } else if (trianglesCapacity != instructionTriangleCount) { - triangleBuffer = new int[instructionTriangleCount]; - storedTriangleCount = 0; - } - - // Use stored quad triangles if possible. - int[] tris = triangleBuffer; - if (storedFirstVertex != instructionsFirstVertex || storedTriangleCount < instructionTriangleCount) { //|| storedTriangleCount == 0 - storedTriangleCount = instructionTriangleCount; - storedFirstVertex = instructionsFirstVertex; - int afv = instructionsFirstVertex; // attachment first vertex - for (int ti = 0; ti < instructionTriangleCount; ti += 6, afv += 4) { - tris[ti] = afv; - tris[ti + 1] = afv + 2; - tris[ti + 2] = afv + 1; - tris[ti + 3] = afv + 2; - tris[ti + 4] = afv + 3; - tris[ti + 5] = afv + 1; - } - } - } - - /// Creates a UnityEngine.Bounds struct from minimum and maximum value vectors. - public static Bounds ToBounds (Vector3 boundsMin, Vector3 boundsMax) { - Vector3 size = (boundsMax - boundsMin); - return new Bounds((boundsMin + (size * 0.5f)), size); - } - - #region TangentSolver2D - // Thanks to contributions from forum user ToddRivers - - /// Step 1 of solving tangents. Ensure you have buffers of the correct size. - /// Eventual Vector4[] tangent buffer to assign to Mesh.tangents. - /// Temporary Vector2 buffer for calculating directions. - /// Number of vertices that require tangents (or the size of the vertex array) - public static void SolveTangents2DEnsureSize (ref Vector4[] tangentBuffer, ref Vector2[] tempTanBuffer, int vertexCount) { - if (tangentBuffer == null || tangentBuffer.Length < vertexCount) - tangentBuffer = new Vector4[vertexCount]; - - if (tempTanBuffer == null || tempTanBuffer.Length < vertexCount * 2) - tempTanBuffer = new Vector2[vertexCount * 2]; // two arrays in one. - } - - /// Step 2 of solving tangents. Fills (part of) a temporary tangent-solution buffer based on the vertices and uvs defined by a submesh's triangle buffer. Only needs to be called once for single-submesh meshes. - /// A temporary Vector3[] for calculating tangents. - /// The mesh's current vertex position buffer. - /// The mesh's current triangles buffer. - /// The mesh's current uvs buffer. - /// Number of vertices that require tangents (or the size of the vertex array) - /// The number of triangle indexes in the triangle array to be used. - public static void SolveTangents2DTriangles (Vector2[] tempTanBuffer, int[] triangles, int triangleCount, Vector3[] vertices, Vector2[] uvs, int vertexCount) { - Vector2 sdir; - Vector2 tdir; - for (int t = 0; t < triangleCount; t += 3) { - int i1 = triangles[t + 0]; - int i2 = triangles[t + 1]; - int i3 = triangles[t + 2]; - - Vector3 v1 = vertices[i1]; - Vector3 v2 = vertices[i2]; - Vector3 v3 = vertices[i3]; - - Vector2 w1 = uvs[i1]; - Vector2 w2 = uvs[i2]; - Vector2 w3 = uvs[i3]; - - float x1 = v2.x - v1.x; - float x2 = v3.x - v1.x; - float y1 = v2.y - v1.y; - float y2 = v3.y - v1.y; - - float s1 = w2.x - w1.x; - float s2 = w3.x - w1.x; - float t1 = w2.y - w1.y; - float t2 = w3.y - w1.y; - - float div = s1 * t2 - s2 * t1; - float r = (div == 0f) ? 0f : 1f / div; - - sdir.x = (t2 * x1 - t1 * x2) * r; - sdir.y = (t2 * y1 - t1 * y2) * r; - tempTanBuffer[i1] = tempTanBuffer[i2] = tempTanBuffer[i3] = sdir; - - tdir.x = (s1 * x2 - s2 * x1) * r; - tdir.y = (s1 * y2 - s2 * y1) * r; - tempTanBuffer[vertexCount + i1] = tempTanBuffer[vertexCount + i2] = tempTanBuffer[vertexCount + i3] = tdir; - } - } - - /// Step 3 of solving tangents. Fills a Vector4[] tangents array according to values calculated in step 2. - /// A Vector4[] that will eventually be used to set Mesh.tangents - /// A temporary Vector3[] for calculating tangents. - /// Number of vertices that require tangents (or the size of the vertex array) - public static void SolveTangents2DBuffer (Vector4[] tangents, Vector2[] tempTanBuffer, int vertexCount) { - - Vector4 tangent; - tangent.z = 0; - for (int i = 0; i < vertexCount; ++i) { - Vector2 t = tempTanBuffer[i]; - - // t.Normalize() (aggressively inlined). Even better if offloaded to GPU via vertex shader. - float magnitude = Mathf.Sqrt(t.x * t.x + t.y * t.y); - if (magnitude > 1E-05) { - float reciprocalMagnitude = 1f/magnitude; - t.x *= reciprocalMagnitude; - t.y *= reciprocalMagnitude; - } - - Vector2 t2 = tempTanBuffer[vertexCount + i]; - tangent.x = t.x; - tangent.y = t.y; - //tangent.z = 0; - tangent.w = (t.y * t2.x > t.x * t2.y) ? 1 : -1; // 2D direction calculation. Used for binormals. - tangents[i] = tangent; - } - - } - #endregion - - #region SubmeshTriangleBuffer - public class SubmeshTriangleBuffer { - public int[] triangles; - public int triangleCount; // for last/single submeshes with potentially zeroed triangles. - public int firstVertex = -1; // for !renderMeshes. - - public SubmeshTriangleBuffer () { } - - public SubmeshTriangleBuffer (int triangleCount) { - triangles = new int[triangleCount]; - } - } - #endregion - - } +#define SPINE_OPTIONAL_NORMALS +using UnityEngine; + +namespace Spine.Unity.MeshGeneration { + public class ArraysMeshGenerator { + #region Settings + public bool PremultiplyVertexColors { get; set; } + protected bool addNormals; + public bool AddNormals { get { return addNormals; } set { addNormals = value; } } + protected bool addTangents; + public bool AddTangents { get { return addTangents; } set { addTangents = value; } } + #endregion + + protected float[] attachmentVertexBuffer = new float[8]; + protected Vector3[] meshVertices; + protected Color32[] meshColors32; + protected Vector2[] meshUVs; + + #if SPINE_OPTIONAL_NORMALS + protected Vector3[] meshNormals; + #endif + protected Vector4[] meshTangents; + protected Vector2[] tempTanBuffer; + + public void TryAddNormalsTo (Mesh mesh, int targetVertexCount) { + #if SPINE_OPTIONAL_NORMALS + if (addNormals) { + bool verticesWasResized = this.meshNormals == null || meshNormals.Length < targetVertexCount; + if (verticesWasResized) { + this.meshNormals = new Vector3[targetVertexCount]; + Vector3 fixedNormal = new Vector3(0, 0, -1f); + Vector3[] normals = this.meshNormals; + for (int i = 0; i < targetVertexCount; i++) + normals[i] = fixedNormal; + } + + mesh.normals = this.meshNormals; + } + #endif + } + + /// Ensures the sizes of the passed array references. If they are not the correct size, a new array will be assigned to the references. + /// true, if a resize occurred, false otherwise. + public static bool EnsureSize (int targetVertexCount, ref Vector3[] vertices, ref Vector2[] uvs, ref Color32[] colors) { + Vector3[] verts = vertices; + bool verticesWasResized = verts == null || targetVertexCount > verts.Length; + if (verticesWasResized) { + // Not enough space, increase size. + vertices = new Vector3[targetVertexCount]; + colors = new Color32[targetVertexCount]; + uvs = new Vector2[targetVertexCount]; + } else { + // Too many vertices, zero the extra. + Vector3 zero = Vector3.zero; + for (int i = targetVertexCount, n = verts.Length; i < n; i++) + verts[i] = zero; + } + return verticesWasResized; + } + + public static bool EnsureTriangleBuffersSize (ExposedList submeshBuffers, int targetSubmeshCount, SubmeshInstruction[] instructionItems) { + bool submeshBuffersWasResized = submeshBuffers.Count < targetSubmeshCount; + if (submeshBuffersWasResized) { + submeshBuffers.GrowIfNeeded(targetSubmeshCount - submeshBuffers.Count); + for (int i = submeshBuffers.Count; submeshBuffers.Count < targetSubmeshCount; i++) + submeshBuffers.Add(new SubmeshTriangleBuffer(instructionItems[i].triangleCount)); + } + return submeshBuffersWasResized; + } + + /// Fills Unity vertex data buffers with verts from the Spine Skeleton. + /// Spine.Skeleton source of the drawOrder array + /// Slot index of the first slot. + /// The index bounding the slot list. [endSlot - 1] is the last slot to be added. + /// Spacing along the z-axis between attachments. + /// If set to true, vertex colors will be premultiplied. This will also enable additive. + /// Vertex positions array. + /// Vertex UV array. + /// Vertex color array (Color32). + /// A reference to the running vertex index. This is used when more than one submesh is to be added. + /// A temporary vertex position buffer for attachment position values. + /// Reference to the running calculated minimum bounds. + /// Reference to the running calculated maximum bounds. + /// Include MeshAttachments. If false, it will ignore MeshAttachments. + public static void FillVerts (Skeleton skeleton, int startSlot, int endSlot, float zSpacing, bool pmaColors, Vector3[] verts, Vector2[] uvs, Color32[] colors, ref int vertexIndex, ref float[] tempVertBuffer, ref Vector3 boundsMin, ref Vector3 boundsMax, bool renderMeshes = true) { + Color32 color; + var skeletonDrawOrderItems = skeleton.DrawOrder.Items; + float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b; + + int vi = vertexIndex; + var tempVerts = tempVertBuffer; + Vector3 bmin = boundsMin; + Vector3 bmax = boundsMax; + + // drawOrder[endSlot] is excluded + for (int slotIndex = startSlot; slotIndex < endSlot; slotIndex++) { + var slot = skeletonDrawOrderItems[slotIndex]; + var attachment = slot.attachment; + float z = slotIndex * zSpacing; + + var regionAttachment = attachment as RegionAttachment; + if (regionAttachment != null) { + regionAttachment.ComputeWorldVertices(slot.bone, tempVerts); + + float x1 = tempVerts[RegionAttachment.X1], y1 = tempVerts[RegionAttachment.Y1]; + float x2 = tempVerts[RegionAttachment.X2], y2 = tempVerts[RegionAttachment.Y2]; + float x3 = tempVerts[RegionAttachment.X3], y3 = tempVerts[RegionAttachment.Y3]; + float x4 = tempVerts[RegionAttachment.X4], y4 = tempVerts[RegionAttachment.Y4]; + verts[vi].x = x1; verts[vi].y = y1; verts[vi].z = z; + verts[vi + 1].x = x4; verts[vi + 1].y = y4; verts[vi + 1].z = z; + verts[vi + 2].x = x2; verts[vi + 2].y = y2; verts[vi + 2].z = z; + verts[vi + 3].x = x3; verts[vi + 3].y = y3; verts[vi + 3].z = z; + + if (pmaColors) { + color.a = (byte)(a * slot.a * regionAttachment.a); + color.r = (byte)(r * slot.r * regionAttachment.r * color.a); + color.g = (byte)(g * slot.g * regionAttachment.g * color.a); + color.b = (byte)(b * slot.b * regionAttachment.b * color.a); + if (slot.data.blendMode == BlendMode.additive) color.a = 0; + } else { + color.a = (byte)(a * slot.a * regionAttachment.a); + color.r = (byte)(r * slot.r * regionAttachment.r * 255); + color.g = (byte)(g * slot.g * regionAttachment.g * 255); + color.b = (byte)(b * slot.b * regionAttachment.b * 255); + } + + colors[vi] = color; colors[vi + 1] = color; colors[vi + 2] = color; colors[vi + 3] = color; + + float[] regionUVs = regionAttachment.uvs; + uvs[vi].x = regionUVs[RegionAttachment.X1]; uvs[vi].y = regionUVs[RegionAttachment.Y1]; + uvs[vi + 1].x = regionUVs[RegionAttachment.X4]; uvs[vi + 1].y = regionUVs[RegionAttachment.Y4]; + uvs[vi + 2].x = regionUVs[RegionAttachment.X2]; uvs[vi + 2].y = regionUVs[RegionAttachment.Y2]; + uvs[vi + 3].x = regionUVs[RegionAttachment.X3]; uvs[vi + 3].y = regionUVs[RegionAttachment.Y3]; + + if (x1 < bmin.x) bmin.x = x1; // Potential first attachment bounds initialization. Initial min should not block initial max. Same for Y below. + if (x1 > bmax.x) bmax.x = x1; + if (x2 < bmin.x) bmin.x = x2; + else if (x2 > bmax.x) bmax.x = x2; + if (x3 < bmin.x) bmin.x = x3; + else if (x3 > bmax.x) bmax.x = x3; + if (x4 < bmin.x) bmin.x = x4; + else if (x4 > bmax.x) bmax.x = x4; + + if (y1 < bmin.y) bmin.y = y1; + if (y1 > bmax.y) bmax.y = y1; + if (y2 < bmin.y) bmin.y = y2; + else if (y2 > bmax.y) bmax.y = y2; + if (y3 < bmin.y) bmin.y = y3; + else if (y3 > bmax.y) bmax.y = y3; + if (y4 < bmin.y) bmin.y = y4; + else if (y4 > bmax.y) bmax.y = y4; + + vi += 4; + } else if (renderMeshes) { + var meshAttachment = attachment as MeshAttachment; + if (meshAttachment != null) { + int meshVertexCount = meshAttachment.worldVerticesLength; + if (tempVerts.Length < meshVertexCount) tempVerts = new float[meshVertexCount]; + meshAttachment.ComputeWorldVertices(slot, tempVerts); + + if (pmaColors) { + color.a = (byte)(a * slot.a * meshAttachment.a); + color.r = (byte)(r * slot.r * meshAttachment.r * color.a); + color.g = (byte)(g * slot.g * meshAttachment.g * color.a); + color.b = (byte)(b * slot.b * meshAttachment.b * color.a); + if (slot.data.blendMode == BlendMode.additive) color.a = 0; + } else { + color.a = (byte)(a * slot.a * meshAttachment.a); + color.r = (byte)(r * slot.r * meshAttachment.r * 255); + color.g = (byte)(g * slot.g * meshAttachment.g * 255); + color.b = (byte)(b * slot.b * meshAttachment.b * 255); + } + + float[] attachmentUVs = meshAttachment.uvs; + + // Potential first attachment bounds initialization. See conditions in RegionAttachment logic. + if (vi == vertexIndex) { + // Initial min should not block initial max. + // vi == vertexIndex does not always mean the bounds are fresh. It could be a submesh. Do not nuke old values by omitting the check. + // Should know that this is the first attachment in the submesh. slotIndex == startSlot could be an empty slot. + float fx = tempVerts[0], fy = tempVerts[1]; + if (fx < bmin.x) bmin.x = fx; + if (fx > bmax.x) bmax.x = fx; + if (fy < bmin.y) bmin.y = fy; + if (fy > bmax.y) bmax.y = fy; + } + + for (int iii = 0; iii < meshVertexCount; iii += 2) { + float x = tempVerts[iii], y = tempVerts[iii + 1]; + verts[vi].x = x; verts[vi].y = y; verts[vi].z = z; + colors[vi] = color; uvs[vi].x = attachmentUVs[iii]; uvs[vi].y = attachmentUVs[iii + 1]; + + if (x < bmin.x) bmin.x = x; + else if (x > bmax.x) bmax.x = x; + + if (y < bmin.y) bmin.y = y; + else if (y > bmax.y) bmax.y = y; + + vi++; + } + } + } + } + + // ref return values + vertexIndex = vi; + tempVertBuffer = tempVerts; + boundsMin = bmin; + boundsMax = bmax; + } + + + /// Fills a submesh triangle buffer array. + /// Spine.Skeleton source of draw order slots. + /// The target triangle count. + /// First vertex of this submesh. + /// Start slot. + /// End slot. + /// The triangle buffer array to be filled. This reference will be replaced in case the triangle values don't fit. + /// If set to true, the triangle buffer is allowed to be larger than needed. + public static void FillTriangles (ref int[] triangleBuffer, Skeleton skeleton, int triangleCount, int firstVertex, int startSlot, int endSlot, bool isLastSubmesh) { + int trianglesCapacity = triangleBuffer.Length; + int[] tris = triangleBuffer; + + if (isLastSubmesh) { + if (trianglesCapacity > triangleCount) { + for (int i = triangleCount; i < trianglesCapacity; i++) + tris[i] = 0; + } else if (trianglesCapacity < triangleCount) { + triangleBuffer = tris = new int[triangleCount]; + } + } else if (trianglesCapacity != triangleCount) { + triangleBuffer = tris = new int[triangleCount]; + } + + var skeletonDrawOrderItems = skeleton.drawOrder.Items; + for (int i = startSlot, n = endSlot, ti = 0, afv = firstVertex; i < n; i++) { + var attachment = skeletonDrawOrderItems[i].attachment; + + // RegionAttachment + if (attachment is RegionAttachment) { + tris[ti] = afv; + tris[ti + 1] = afv + 2; + tris[ti + 2] = afv + 1; + tris[ti + 3] = afv + 2; + tris[ti + 4] = afv + 3; + tris[ti + 5] = afv + 1; + ti += 6; + afv += 4; + continue; + } + + // MeshAttachment + var meshAttachment = attachment as MeshAttachment; + if (meshAttachment != null) { + int[] attachmentTriangles = meshAttachment.triangles; + for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, ti++) + tris[ti] = afv + attachmentTriangles[ii]; + + afv += meshAttachment.worldVerticesLength >> 1; // length/2; + } + + } + } + + public static void FillTrianglesQuads (ref int[] triangleBuffer, ref int storedTriangleCount, ref int storedFirstVertex, int instructionsFirstVertex, int instructionTriangleCount, bool isLastSubmesh) { + int trianglesCapacity = triangleBuffer.Length; + + if (isLastSubmesh && trianglesCapacity > instructionTriangleCount) { + for (int i = instructionTriangleCount; i < trianglesCapacity; i++) + triangleBuffer[i] = 0; + storedTriangleCount = instructionTriangleCount; + } else if (trianglesCapacity != instructionTriangleCount) { + triangleBuffer = new int[instructionTriangleCount]; + storedTriangleCount = 0; + } + + // Use stored quad triangles if possible. + int[] tris = triangleBuffer; + if (storedFirstVertex != instructionsFirstVertex || storedTriangleCount < instructionTriangleCount) { //|| storedTriangleCount == 0 + storedTriangleCount = instructionTriangleCount; + storedFirstVertex = instructionsFirstVertex; + int afv = instructionsFirstVertex; // attachment first vertex + for (int ti = 0; ti < instructionTriangleCount; ti += 6, afv += 4) { + tris[ti] = afv; + tris[ti + 1] = afv + 2; + tris[ti + 2] = afv + 1; + tris[ti + 3] = afv + 2; + tris[ti + 4] = afv + 3; + tris[ti + 5] = afv + 1; + } + } + } + + /// Creates a UnityEngine.Bounds struct from minimum and maximum value vectors. + public static Bounds ToBounds (Vector3 boundsMin, Vector3 boundsMax) { + Vector3 size = (boundsMax - boundsMin); + return new Bounds((boundsMin + (size * 0.5f)), size); + } + + #region TangentSolver2D + // Thanks to contributions from forum user ToddRivers + + /// Step 1 of solving tangents. Ensure you have buffers of the correct size. + /// Eventual Vector4[] tangent buffer to assign to Mesh.tangents. + /// Temporary Vector2 buffer for calculating directions. + /// Number of vertices that require tangents (or the size of the vertex array) + public static void SolveTangents2DEnsureSize (ref Vector4[] tangentBuffer, ref Vector2[] tempTanBuffer, int vertexCount) { + if (tangentBuffer == null || tangentBuffer.Length < vertexCount) + tangentBuffer = new Vector4[vertexCount]; + + if (tempTanBuffer == null || tempTanBuffer.Length < vertexCount * 2) + tempTanBuffer = new Vector2[vertexCount * 2]; // two arrays in one. + } + + /// Step 2 of solving tangents. Fills (part of) a temporary tangent-solution buffer based on the vertices and uvs defined by a submesh's triangle buffer. Only needs to be called once for single-submesh meshes. + /// A temporary Vector3[] for calculating tangents. + /// The mesh's current vertex position buffer. + /// The mesh's current triangles buffer. + /// The mesh's current uvs buffer. + /// Number of vertices that require tangents (or the size of the vertex array) + /// The number of triangle indexes in the triangle array to be used. + public static void SolveTangents2DTriangles (Vector2[] tempTanBuffer, int[] triangles, int triangleCount, Vector3[] vertices, Vector2[] uvs, int vertexCount) { + Vector2 sdir; + Vector2 tdir; + for (int t = 0; t < triangleCount; t += 3) { + int i1 = triangles[t + 0]; + int i2 = triangles[t + 1]; + int i3 = triangles[t + 2]; + + Vector3 v1 = vertices[i1]; + Vector3 v2 = vertices[i2]; + Vector3 v3 = vertices[i3]; + + Vector2 w1 = uvs[i1]; + Vector2 w2 = uvs[i2]; + Vector2 w3 = uvs[i3]; + + float x1 = v2.x - v1.x; + float x2 = v3.x - v1.x; + float y1 = v2.y - v1.y; + float y2 = v3.y - v1.y; + + float s1 = w2.x - w1.x; + float s2 = w3.x - w1.x; + float t1 = w2.y - w1.y; + float t2 = w3.y - w1.y; + + float div = s1 * t2 - s2 * t1; + float r = (div == 0f) ? 0f : 1f / div; + + sdir.x = (t2 * x1 - t1 * x2) * r; + sdir.y = (t2 * y1 - t1 * y2) * r; + tempTanBuffer[i1] = tempTanBuffer[i2] = tempTanBuffer[i3] = sdir; + + tdir.x = (s1 * x2 - s2 * x1) * r; + tdir.y = (s1 * y2 - s2 * y1) * r; + tempTanBuffer[vertexCount + i1] = tempTanBuffer[vertexCount + i2] = tempTanBuffer[vertexCount + i3] = tdir; + } + } + + /// Step 3 of solving tangents. Fills a Vector4[] tangents array according to values calculated in step 2. + /// A Vector4[] that will eventually be used to set Mesh.tangents + /// A temporary Vector3[] for calculating tangents. + /// Number of vertices that require tangents (or the size of the vertex array) + public static void SolveTangents2DBuffer (Vector4[] tangents, Vector2[] tempTanBuffer, int vertexCount) { + + Vector4 tangent; + tangent.z = 0; + for (int i = 0; i < vertexCount; ++i) { + Vector2 t = tempTanBuffer[i]; + + // t.Normalize() (aggressively inlined). Even better if offloaded to GPU via vertex shader. + float magnitude = Mathf.Sqrt(t.x * t.x + t.y * t.y); + if (magnitude > 1E-05) { + float reciprocalMagnitude = 1f/magnitude; + t.x *= reciprocalMagnitude; + t.y *= reciprocalMagnitude; + } + + Vector2 t2 = tempTanBuffer[vertexCount + i]; + tangent.x = t.x; + tangent.y = t.y; + //tangent.z = 0; + tangent.w = (t.y * t2.x > t.x * t2.y) ? 1 : -1; // 2D direction calculation. Used for binormals. + tangents[i] = tangent; + } + + } + #endregion + + #region SubmeshTriangleBuffer + public class SubmeshTriangleBuffer { + public int[] triangles; + public int triangleCount; // for last/single submeshes with potentially zeroed triangles. + public int firstVertex = -1; // for !renderMeshes. + + public SubmeshTriangleBuffer () { } + + public SubmeshTriangleBuffer (int triangleCount) { + triangles = new int[triangleCount]; + } + } + #endregion + + } } - diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs index 0bbc87a88b..aa6105360f 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,43 +21,13 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ + using UnityEngine; namespace Spine.Unity.MeshGeneration { @@ -161,4 +130,4 @@ public class ArraysSimpleMeshGenerator : ArraysMeshGenerator, ISimpleMeshGenerat } -} +} diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs index 19dc3ed737..fcd2bce014 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,43 +21,13 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ + using UnityEngine; namespace Spine.Unity.MeshGeneration { @@ -237,4 +206,4 @@ class SmartMesh { #endregion } -} +} diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs index af52601fd2..d590d3b346 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,42 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ using UnityEngine; @@ -318,4 +286,4 @@ class SmartMesh { #endregion } -} +} diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/DoubleBuffered.cs b/spine-unity/Assets/spine-unity/Mesh Generation/DoubleBuffered.cs index 5dfcbe452b..ade519d768 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/DoubleBuffered.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/DoubleBuffered.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ using UnityEngine; diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/DoubleBufferedMesh.cs b/spine-unity/Assets/spine-unity/Mesh Generation/DoubleBufferedMesh.cs index f386a355ba..79cc630a79 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/DoubleBufferedMesh.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/DoubleBufferedMesh.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ using UnityEngine; diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/ISimpleMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/ISimpleMeshGenerator.cs index 70760f2dfc..6a20113ae4 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/ISimpleMeshGenerator.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/ISimpleMeshGenerator.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ namespace Spine.Unity.MeshGeneration { diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/ISubmeshedMeshGenerator.cs b/spine-unity/Assets/spine-unity/Mesh Generation/ISubmeshedMeshGenerator.cs index e879f19ec8..8f95ae4e6b 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/ISubmeshedMeshGenerator.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/ISubmeshedMeshGenerator.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ using UnityEngine; diff --git a/spine-unity/Assets/spine-unity/Mesh Generation/SpineMesh.cs b/spine-unity/Assets/spine-unity/Mesh Generation/SpineMesh.cs index f033f0f641..8b28980077 100644 --- a/spine-unity/Assets/spine-unity/Mesh Generation/SpineMesh.cs +++ b/spine-unity/Assets/spine-unity/Mesh Generation/SpineMesh.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ using UnityEngine; diff --git a/spine-unity/Assets/spine-unity/Modules/AtlasRegionAttacher.cs b/spine-unity/Assets/spine-unity/Modules/AtlasRegionAttacher.cs index 3b28660949..e281b80e5c 100644 --- a/spine-unity/Assets/spine-unity/Modules/AtlasRegionAttacher.cs +++ b/spine-unity/Assets/spine-unity/Modules/AtlasRegionAttacher.cs @@ -1,80 +1,80 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEngine; -using System.Collections; -using Spine; -namespace Spine.Unity.Modules { - public class AtlasRegionAttacher : MonoBehaviour { - - [System.Serializable] - public class SlotRegionPair { - [SpineSlot] - public string slot; - - [SpineAtlasRegion] - public string region; - } - - public AtlasAsset atlasAsset; - public SlotRegionPair[] attachments; - - Atlas atlas; - - void Awake () { - GetComponent().OnRebuild += Apply; - } - - - void Apply (SkeletonRenderer skeletonRenderer) { - atlas = atlasAsset.GetAtlas(); - - AtlasAttachmentLoader loader = new AtlasAttachmentLoader(atlas); - - float scaleMultiplier = skeletonRenderer.skeletonDataAsset.scale; - - var enumerator = attachments.GetEnumerator(); - while (enumerator.MoveNext()) { - var entry = (SlotRegionPair)enumerator.Current; - var regionAttachment = loader.NewRegionAttachment(null, entry.region, entry.region); - regionAttachment.Width = regionAttachment.RegionOriginalWidth * scaleMultiplier; - regionAttachment.Height = regionAttachment.RegionOriginalHeight * scaleMultiplier; - - regionAttachment.SetColor(new Color(1, 1, 1, 1)); - regionAttachment.UpdateOffset(); - - var slot = skeletonRenderer.skeleton.FindSlot(entry.slot); - slot.Attachment = regionAttachment; - } - } - - } +using UnityEngine; +using System.Collections; +using Spine; + +namespace Spine.Unity.Modules { + public class AtlasRegionAttacher : MonoBehaviour { + + [System.Serializable] + public class SlotRegionPair { + [SpineSlot] + public string slot; + + [SpineAtlasRegion] + public string region; + } + + public AtlasAsset atlasAsset; + public SlotRegionPair[] attachments; + + Atlas atlas; + + void Awake () { + GetComponent().OnRebuild += Apply; + } + + + void Apply (SkeletonRenderer skeletonRenderer) { + atlas = atlasAsset.GetAtlas(); + + AtlasAttachmentLoader loader = new AtlasAttachmentLoader(atlas); + + float scaleMultiplier = skeletonRenderer.skeletonDataAsset.scale; + + var enumerator = attachments.GetEnumerator(); + while (enumerator.MoveNext()) { + var entry = (SlotRegionPair)enumerator.Current; + var regionAttachment = loader.NewRegionAttachment(null, entry.region, entry.region); + regionAttachment.Width = regionAttachment.RegionOriginalWidth * scaleMultiplier; + regionAttachment.Height = regionAttachment.RegionOriginalHeight * scaleMultiplier; + + regionAttachment.SetColor(new Color(1, 1, 1, 1)); + regionAttachment.UpdateOffset(); + + var slot = skeletonRenderer.skeleton.FindSlot(entry.slot); + slot.Attachment = regionAttachment; + } + } + + } } diff --git a/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/BoundingBoxFollower.cs b/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/BoundingBoxFollower.cs index 4efb3f985e..27d5e87f46 100644 --- a/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/BoundingBoxFollower.cs +++ b/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/BoundingBoxFollower.cs @@ -1,197 +1,197 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEngine; -using System.Collections.Generic; - -namespace Spine.Unity { - - [ExecuteInEditMode] - public class BoundingBoxFollower : MonoBehaviour { - #region Inspector - public SkeletonRenderer skeletonRenderer; - [SpineSlot(dataField: "skeletonRenderer", containsBoundingBoxes: true)] - public string slotName; - public bool isTrigger; - #endregion - - Slot slot; - BoundingBoxAttachment currentAttachment; - string currentAttachmentName; - PolygonCollider2D currentCollider; - - bool hasReset; - - public readonly Dictionary colliderTable = new Dictionary(); - public readonly Dictionary attachmentNameTable = new Dictionary(); - - public Slot Slot { get { return slot; } } - public BoundingBoxAttachment CurrentAttachment { get { return currentAttachment; } } - public string CurrentAttachmentName { get { return currentAttachmentName; } } - public PolygonCollider2D CurrentCollider { get { return currentCollider; } } - public bool IsTrigger { get { return isTrigger; } } - - void OnEnable () { - ClearColliders(); - - if (skeletonRenderer == null) - skeletonRenderer = GetComponentInParent(); - - if (skeletonRenderer != null) { - skeletonRenderer.OnRebuild -= HandleRebuild; - skeletonRenderer.OnRebuild += HandleRebuild; - - if (hasReset) - HandleRebuild(skeletonRenderer); - } - } - - void OnDisable () { - skeletonRenderer.OnRebuild -= HandleRebuild; - } - - void Start () { - if (!hasReset && skeletonRenderer != null) - HandleRebuild(skeletonRenderer); - } - - public void HandleRebuild (SkeletonRenderer renderer) { - if (string.IsNullOrEmpty(slotName)) - return; - - hasReset = true; - ClearColliders(); - colliderTable.Clear(); - - if (skeletonRenderer.skeleton == null) { - skeletonRenderer.OnRebuild -= HandleRebuild; - skeletonRenderer.Initialize(false); - skeletonRenderer.OnRebuild += HandleRebuild; - } - - var skeleton = skeletonRenderer.skeleton; - slot = skeleton.FindSlot(slotName); - int slotIndex = skeleton.FindSlotIndex(slotName); - - if (this.gameObject.activeInHierarchy) { - foreach (var skin in skeleton.Data.Skins) { - var attachmentNames = new List(); - skin.FindNamesForSlot(slotIndex, attachmentNames); - - foreach (var attachmentName in attachmentNames) { - var attachment = skin.GetAttachment(slotIndex, attachmentName); - var boundingBoxAttachment = attachment as BoundingBoxAttachment; - -#if UNITY_EDITOR - if (attachment != null && boundingBoxAttachment == null) - Debug.Log("BoundingBoxFollower tried to follow a slot that contains non-boundingbox attachments: " + slotName); -#endif - - if (boundingBoxAttachment != null) { - var bbCollider = SkeletonUtility.AddBoundingBoxAsComponent(boundingBoxAttachment, gameObject, true); - bbCollider.enabled = false; - bbCollider.hideFlags = HideFlags.NotEditable; - bbCollider.isTrigger = IsTrigger; - colliderTable.Add(boundingBoxAttachment, bbCollider); - attachmentNameTable.Add(boundingBoxAttachment, attachmentName); - } - } - } - } - -#if UNITY_EDITOR - bool valid = colliderTable.Count != 0; - if (!valid) { - if (this.gameObject.activeInHierarchy) - Debug.LogWarning("Bounding Box Follower not valid! Slot [" + slotName + "] does not contain any Bounding Box Attachments!"); - else - Debug.LogWarning("Bounding Box Follower tried to rebuild as a prefab."); - } -#endif - } - - void ClearColliders () { - var colliders = GetComponents(); - if (colliders.Length == 0) return; - -#if UNITY_EDITOR - if (Application.isPlaying) { - foreach (var c in colliders) { - if (c != null) - Destroy(c); - } - } else { - foreach (var c in colliders) - DestroyImmediate(c); - } -#else - foreach (var c in colliders) - if (c != null) - Destroy(c); -#endif - - colliderTable.Clear(); - attachmentNameTable.Clear(); - } - - void LateUpdate () { - if (!skeletonRenderer.valid) - return; - - if (slot != null && slot.Attachment != currentAttachment) - MatchAttachment(slot.Attachment); - } - - /// Sets the current collider to match attachment. - /// If the attachment is not a bounding box, it will be treated as null. - void MatchAttachment (Attachment attachment) { - var bbAttachment = attachment as BoundingBoxAttachment; - -#if UNITY_EDITOR - if (attachment != null && bbAttachment == null) - Debug.LogWarning("BoundingBoxFollower tried to match a non-boundingbox attachment. It will treat it as null."); -#endif - - if (currentCollider != null) - currentCollider.enabled = false; - - if (bbAttachment == null) { - currentCollider = null; - } else { - currentCollider = colliderTable[bbAttachment]; - currentCollider.enabled = true; - } - - currentAttachment = bbAttachment; - currentAttachmentName = currentAttachment == null ? null : attachmentNameTable[bbAttachment]; - } - } +using UnityEngine; +using System.Collections.Generic; + +namespace Spine.Unity { + + [ExecuteInEditMode] + public class BoundingBoxFollower : MonoBehaviour { + #region Inspector + public SkeletonRenderer skeletonRenderer; + [SpineSlot(dataField: "skeletonRenderer", containsBoundingBoxes: true)] + public string slotName; + public bool isTrigger; + #endregion + + Slot slot; + BoundingBoxAttachment currentAttachment; + string currentAttachmentName; + PolygonCollider2D currentCollider; + + bool hasReset; + + public readonly Dictionary colliderTable = new Dictionary(); + public readonly Dictionary attachmentNameTable = new Dictionary(); + + public Slot Slot { get { return slot; } } + public BoundingBoxAttachment CurrentAttachment { get { return currentAttachment; } } + public string CurrentAttachmentName { get { return currentAttachmentName; } } + public PolygonCollider2D CurrentCollider { get { return currentCollider; } } + public bool IsTrigger { get { return isTrigger; } } + + void OnEnable () { + ClearColliders(); + + if (skeletonRenderer == null) + skeletonRenderer = GetComponentInParent(); + + if (skeletonRenderer != null) { + skeletonRenderer.OnRebuild -= HandleRebuild; + skeletonRenderer.OnRebuild += HandleRebuild; + + if (hasReset) + HandleRebuild(skeletonRenderer); + } + } + + void OnDisable () { + skeletonRenderer.OnRebuild -= HandleRebuild; + } + + void Start () { + if (!hasReset && skeletonRenderer != null) + HandleRebuild(skeletonRenderer); + } + + public void HandleRebuild (SkeletonRenderer renderer) { + if (string.IsNullOrEmpty(slotName)) + return; + + hasReset = true; + ClearColliders(); + colliderTable.Clear(); + + if (skeletonRenderer.skeleton == null) { + skeletonRenderer.OnRebuild -= HandleRebuild; + skeletonRenderer.Initialize(false); + skeletonRenderer.OnRebuild += HandleRebuild; + } + + var skeleton = skeletonRenderer.skeleton; + slot = skeleton.FindSlot(slotName); + int slotIndex = skeleton.FindSlotIndex(slotName); + + if (this.gameObject.activeInHierarchy) { + foreach (var skin in skeleton.Data.Skins) { + var attachmentNames = new List(); + skin.FindNamesForSlot(slotIndex, attachmentNames); + + foreach (var attachmentName in attachmentNames) { + var attachment = skin.GetAttachment(slotIndex, attachmentName); + var boundingBoxAttachment = attachment as BoundingBoxAttachment; + +#if UNITY_EDITOR + if (attachment != null && boundingBoxAttachment == null) + Debug.Log("BoundingBoxFollower tried to follow a slot that contains non-boundingbox attachments: " + slotName); +#endif + + if (boundingBoxAttachment != null) { + var bbCollider = SkeletonUtility.AddBoundingBoxAsComponent(boundingBoxAttachment, gameObject, true); + bbCollider.enabled = false; + bbCollider.hideFlags = HideFlags.NotEditable; + bbCollider.isTrigger = IsTrigger; + colliderTable.Add(boundingBoxAttachment, bbCollider); + attachmentNameTable.Add(boundingBoxAttachment, attachmentName); + } + } + } + } + +#if UNITY_EDITOR + bool valid = colliderTable.Count != 0; + if (!valid) { + if (this.gameObject.activeInHierarchy) + Debug.LogWarning("Bounding Box Follower not valid! Slot [" + slotName + "] does not contain any Bounding Box Attachments!"); + else + Debug.LogWarning("Bounding Box Follower tried to rebuild as a prefab."); + } +#endif + } + + void ClearColliders () { + var colliders = GetComponents(); + if (colliders.Length == 0) return; + +#if UNITY_EDITOR + if (Application.isPlaying) { + foreach (var c in colliders) { + if (c != null) + Destroy(c); + } + } else { + foreach (var c in colliders) + DestroyImmediate(c); + } +#else + foreach (var c in colliders) + if (c != null) + Destroy(c); +#endif + + colliderTable.Clear(); + attachmentNameTable.Clear(); + } + + void LateUpdate () { + if (!skeletonRenderer.valid) + return; + + if (slot != null && slot.Attachment != currentAttachment) + MatchAttachment(slot.Attachment); + } + + /// Sets the current collider to match attachment. + /// If the attachment is not a bounding box, it will be treated as null. + void MatchAttachment (Attachment attachment) { + var bbAttachment = attachment as BoundingBoxAttachment; + +#if UNITY_EDITOR + if (attachment != null && bbAttachment == null) + Debug.LogWarning("BoundingBoxFollower tried to match a non-boundingbox attachment. It will treat it as null."); +#endif + + if (currentCollider != null) + currentCollider.enabled = false; + + if (bbAttachment == null) { + currentCollider = null; + } else { + currentCollider = colliderTable[bbAttachment]; + currentCollider.enabled = true; + } + + currentAttachment = bbAttachment; + currentAttachmentName = currentAttachment == null ? null : attachmentNameTable[bbAttachment]; + } + } + } diff --git a/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/Editor/BoundingBoxFollowerInspector.cs b/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/Editor/BoundingBoxFollowerInspector.cs index d592672483..0fc325912f 100644 --- a/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/Editor/BoundingBoxFollowerInspector.cs +++ b/spine-unity/Assets/spine-unity/Modules/BoundingBoxFollower/Editor/BoundingBoxFollowerInspector.cs @@ -1,113 +1,112 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEngine; -using UnityEditor; - -namespace Spine.Unity.Editor { - - [CustomEditor(typeof(BoundingBoxFollower))] - public class BoundingBoxFollowerInspector : UnityEditor.Editor { - SerializedProperty skeletonRenderer, slotName, isTrigger; - BoundingBoxFollower follower; - bool rebuildRequired = false; - bool addBoneFollower = false; - - void OnEnable () { - skeletonRenderer = serializedObject.FindProperty("skeletonRenderer"); - slotName = serializedObject.FindProperty("slotName"); - isTrigger = serializedObject.FindProperty("isTrigger"); - follower = (BoundingBoxFollower)target; - } - - public override void OnInspectorGUI () { - bool isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab); - bool repaintEvent = UnityEngine.Event.current.type == EventType.Repaint; - - if (rebuildRequired) { - follower.HandleRebuild(null); - rebuildRequired = false; - } - - EditorGUI.BeginChangeCheck(); - EditorGUILayout.PropertyField(skeletonRenderer); - EditorGUILayout.PropertyField(slotName, new GUIContent("Slot")); - EditorGUILayout.PropertyField(isTrigger); - - if (EditorGUI.EndChangeCheck()) { - serializedObject.ApplyModifiedProperties(); - if (!isInspectingPrefab) - rebuildRequired = true; - } - - bool hasBoneFollower = follower.GetComponent() != null; - using (new EditorGUI.DisabledGroupScope(hasBoneFollower || follower.Slot == null)) { - if (GUILayout.Button(new GUIContent("Add Bone Follower", SpineEditorUtilities.Icons.bone))) { - addBoneFollower = true; - } - } - - if (isInspectingPrefab) { - follower.colliderTable.Clear(); - follower.attachmentNameTable.Clear(); - EditorGUILayout.HelpBox("BoundingBoxAttachments cannot be previewed in prefabs.", MessageType.Info); - - // How do you prevent components from being saved into the prefab? No such HideFlag. DontSaveInEditor | DontSaveInBuild does not work. DestroyImmediate does not work. - var collider = follower.GetComponent(); - if (collider != null) Debug.LogWarning("Found BoundingBoxFollower collider components in prefab. These are disposed and regenerated at runtime."); - - } else { - EditorGUILayout.LabelField(string.Format("Attachment Names ({0} PolygonCollider2D)", follower.colliderTable.Count), EditorStyles.boldLabel); - EditorGUI.BeginChangeCheck(); - foreach (var kp in follower.attachmentNameTable) { - string attachmentName = kp.Value; - var collider = follower.colliderTable[kp.Key]; - bool isPlaceholder = attachmentName != kp.Key.Name; - collider.enabled = EditorGUILayout.ToggleLeft(new GUIContent(!isPlaceholder ? attachmentName : attachmentName + " [" + kp.Key.Name + "]", isPlaceholder ? SpineEditorUtilities.Icons.skinPlaceholder : SpineEditorUtilities.Icons.boundingBox), collider.enabled); - } - if (EditorGUI.EndChangeCheck()) { - SceneView.RepaintAll(); - } - - if (!Application.isPlaying) - EditorGUILayout.HelpBox("\nAt runtime, BoundingBoxFollower enables and disables PolygonCollider2Ds based on the currently active attachment in the slot.\n\nCheckboxes in Edit Mode are only for preview. Checkbox states are not saved.\n", MessageType.Info); - } - - if (addBoneFollower && repaintEvent) { - var boneFollower = follower.gameObject.AddComponent(); - boneFollower.boneName = follower.Slot.Data.BoneData.Name; - addBoneFollower = false; - } - } - - } - +using UnityEngine; +using UnityEditor; + +namespace Spine.Unity.Editor { + + [CustomEditor(typeof(BoundingBoxFollower))] + public class BoundingBoxFollowerInspector : UnityEditor.Editor { + SerializedProperty skeletonRenderer, slotName, isTrigger; + BoundingBoxFollower follower; + bool rebuildRequired = false; + bool addBoneFollower = false; + + void OnEnable () { + skeletonRenderer = serializedObject.FindProperty("skeletonRenderer"); + slotName = serializedObject.FindProperty("slotName"); + isTrigger = serializedObject.FindProperty("isTrigger"); + follower = (BoundingBoxFollower)target; + } + + public override void OnInspectorGUI () { + bool isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab); + bool repaintEvent = UnityEngine.Event.current.type == EventType.Repaint; + + if (rebuildRequired) { + follower.HandleRebuild(null); + rebuildRequired = false; + } + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(skeletonRenderer); + EditorGUILayout.PropertyField(slotName, new GUIContent("Slot")); + EditorGUILayout.PropertyField(isTrigger); + + if (EditorGUI.EndChangeCheck()) { + serializedObject.ApplyModifiedProperties(); + if (!isInspectingPrefab) + rebuildRequired = true; + } + + bool hasBoneFollower = follower.GetComponent() != null; + using (new EditorGUI.DisabledGroupScope(hasBoneFollower || follower.Slot == null)) { + if (GUILayout.Button(new GUIContent("Add Bone Follower", SpineEditorUtilities.Icons.bone))) { + addBoneFollower = true; + } + } + + if (isInspectingPrefab) { + follower.colliderTable.Clear(); + follower.attachmentNameTable.Clear(); + EditorGUILayout.HelpBox("BoundingBoxAttachments cannot be previewed in prefabs.", MessageType.Info); + + // How do you prevent components from being saved into the prefab? No such HideFlag. DontSaveInEditor | DontSaveInBuild does not work. DestroyImmediate does not work. + var collider = follower.GetComponent(); + if (collider != null) Debug.LogWarning("Found BoundingBoxFollower collider components in prefab. These are disposed and regenerated at runtime."); + + } else { + EditorGUILayout.LabelField(string.Format("Attachment Names ({0} PolygonCollider2D)", follower.colliderTable.Count), EditorStyles.boldLabel); + EditorGUI.BeginChangeCheck(); + foreach (var kp in follower.attachmentNameTable) { + string attachmentName = kp.Value; + var collider = follower.colliderTable[kp.Key]; + bool isPlaceholder = attachmentName != kp.Key.Name; + collider.enabled = EditorGUILayout.ToggleLeft(new GUIContent(!isPlaceholder ? attachmentName : attachmentName + " [" + kp.Key.Name + "]", isPlaceholder ? SpineEditorUtilities.Icons.skinPlaceholder : SpineEditorUtilities.Icons.boundingBox), collider.enabled); + } + if (EditorGUI.EndChangeCheck()) { + SceneView.RepaintAll(); + } + + if (!Application.isPlaying) + EditorGUILayout.HelpBox("\nAt runtime, BoundingBoxFollower enables and disables PolygonCollider2Ds based on the currently active attachment in the slot.\n\nCheckboxes in Edit Mode are only for preview. Checkbox states are not saved.\n", MessageType.Info); + } + + if (addBoneFollower && repaintEvent) { + var boneFollower = follower.gameObject.AddComponent(); + boneFollower.boneName = follower.Slot.Data.BoneData.Name; + addBoneFollower = false; + } + } + + } + } diff --git a/spine-unity/Assets/spine-unity/Modules/CustomMaterials/Editor/SkeletonRendererCustomMaterialsInspector.cs b/spine-unity/Assets/spine-unity/Modules/CustomMaterials/Editor/SkeletonRendererCustomMaterialsInspector.cs index 07b806c9cc..bd6a137e57 100644 --- a/spine-unity/Assets/spine-unity/Modules/CustomMaterials/Editor/SkeletonRendererCustomMaterialsInspector.cs +++ b/spine-unity/Assets/spine-unity/Modules/CustomMaterials/Editor/SkeletonRendererCustomMaterialsInspector.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ /***************************************************************************** diff --git a/spine-unity/Assets/spine-unity/Modules/CustomMaterials/SkeletonRendererCustomMaterials.cs b/spine-unity/Assets/spine-unity/Modules/CustomMaterials/SkeletonRendererCustomMaterials.cs index 775b25022e..5ddad0f897 100644 --- a/spine-unity/Assets/spine-unity/Modules/CustomMaterials/SkeletonRendererCustomMaterials.cs +++ b/spine-unity/Assets/spine-unity/Modules/CustomMaterials/SkeletonRendererCustomMaterials.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ /***************************************************************************** diff --git a/spine-unity/Assets/spine-unity/Modules/CustomSkin.cs b/spine-unity/Assets/spine-unity/Modules/CustomSkin.cs index 70f514def6..45967e028a 100644 --- a/spine-unity/Assets/spine-unity/Modules/CustomSkin.cs +++ b/spine-unity/Assets/spine-unity/Modules/CustomSkin.cs @@ -1,83 +1,83 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEngine; -using Spine; -using Spine.Unity; - -namespace Spine.Unity.Modules { - public class CustomSkin : MonoBehaviour { - - [System.Serializable] - public class SkinPair { - /// SpineAttachment attachment path to help find the attachment. - /// This use of SpineAttachment generates an attachment path string that can only be used by SpineAttachment.GetAttachment. - [SpineAttachment(currentSkinOnly: false, returnAttachmentPath: true, dataField: "skinSource")] - [UnityEngine.Serialization.FormerlySerializedAs("sourceAttachment")] - public string sourceAttachmentPath; - - [SpineSlot] - public string targetSlot; - - /// The name of the skin placeholder/skin dictionary entry this attachment should be associated with. - /// This name is used by the skin dictionary, used in the method Skin.AddAttachment as well as setting a slot attachment - [SpineAttachment(currentSkinOnly: true, placeholdersOnly: true)] - public string targetAttachment; - } - - #region Inspector - public SkeletonDataAsset skinSource; - - [UnityEngine.Serialization.FormerlySerializedAs("skinning")] - public SkinPair[] skinItems; - - public Skin customSkin; - #endregion - - SkeletonRenderer skeletonRenderer; - - void Start () { - skeletonRenderer = GetComponent(); - Skeleton skeleton = skeletonRenderer.skeleton; - - customSkin = new Skin("CustomSkin"); - - foreach (var pair in skinItems) { - var attachment = SpineAttachment.GetAttachment(pair.sourceAttachmentPath, skinSource); - customSkin.AddAttachment(skeleton.FindSlotIndex(pair.targetSlot), pair.targetAttachment, attachment); - } - - // The custom skin does not need to be added to the skeleton data for it to work. - // But it's useful for your script to keep a reference to it. - skeleton.SetSkin(customSkin); - } - } +using UnityEngine; +using Spine; +using Spine.Unity; + +namespace Spine.Unity.Modules { + public class CustomSkin : MonoBehaviour { + + [System.Serializable] + public class SkinPair { + /// SpineAttachment attachment path to help find the attachment. + /// This use of SpineAttachment generates an attachment path string that can only be used by SpineAttachment.GetAttachment. + [SpineAttachment(currentSkinOnly: false, returnAttachmentPath: true, dataField: "skinSource")] + [UnityEngine.Serialization.FormerlySerializedAs("sourceAttachment")] + public string sourceAttachmentPath; + + [SpineSlot] + public string targetSlot; + + /// The name of the skin placeholder/skin dictionary entry this attachment should be associated with. + /// This name is used by the skin dictionary, used in the method Skin.AddAttachment as well as setting a slot attachment + [SpineAttachment(currentSkinOnly: true, placeholdersOnly: true)] + public string targetAttachment; + } + + #region Inspector + public SkeletonDataAsset skinSource; + + [UnityEngine.Serialization.FormerlySerializedAs("skinning")] + public SkinPair[] skinItems; + + public Skin customSkin; + #endregion + + SkeletonRenderer skeletonRenderer; + + void Start () { + skeletonRenderer = GetComponent(); + Skeleton skeleton = skeletonRenderer.skeleton; + + customSkin = new Skin("CustomSkin"); + + foreach (var pair in skinItems) { + var attachment = SpineAttachment.GetAttachment(pair.sourceAttachmentPath, skinSource); + customSkin.AddAttachment(skeleton.FindSlotIndex(pair.targetSlot), pair.targetAttachment, attachment); + } + + // The custom skin does not need to be added to the skeleton data for it to work. + // But it's useful for your script to keep a reference to it. + skeleton.SetSkin(customSkin); + } + } + } diff --git a/spine-unity/Assets/spine-unity/Modules/Ghost/SkeletonGhost.cs b/spine-unity/Assets/spine-unity/Modules/Ghost/SkeletonGhost.cs index 8511e97bf7..686bfc2c45 100644 --- a/spine-unity/Assets/spine-unity/Modules/Ghost/SkeletonGhost.cs +++ b/spine-unity/Assets/spine-unity/Modules/Ghost/SkeletonGhost.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ /***************************************************************************** diff --git a/spine-unity/Assets/spine-unity/Modules/Ragdoll/Editor/SkeletonRagdoll2DInspector.cs b/spine-unity/Assets/spine-unity/Modules/Ragdoll/Editor/SkeletonRagdoll2DInspector.cs index 1af3af6bf7..1a54abcf30 100644 --- a/spine-unity/Assets/spine-unity/Modules/Ragdoll/Editor/SkeletonRagdoll2DInspector.cs +++ b/spine-unity/Assets/spine-unity/Modules/Ragdoll/Editor/SkeletonRagdoll2DInspector.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ /***************************************************************************** diff --git a/spine-unity/Assets/spine-unity/Modules/Ragdoll/Editor/SkeletonRagdollInspector.cs b/spine-unity/Assets/spine-unity/Modules/Ragdoll/Editor/SkeletonRagdollInspector.cs index 590c7385e9..8844529e5b 100644 --- a/spine-unity/Assets/spine-unity/Modules/Ragdoll/Editor/SkeletonRagdollInspector.cs +++ b/spine-unity/Assets/spine-unity/Modules/Ragdoll/Editor/SkeletonRagdollInspector.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ /***************************************************************************** diff --git a/spine-unity/Assets/spine-unity/Modules/Ragdoll/SkeletonRagdoll.cs b/spine-unity/Assets/spine-unity/Modules/Ragdoll/SkeletonRagdoll.cs index 636d139468..8039620274 100644 --- a/spine-unity/Assets/spine-unity/Modules/Ragdoll/SkeletonRagdoll.cs +++ b/spine-unity/Assets/spine-unity/Modules/Ragdoll/SkeletonRagdoll.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ /***************************************************************************** diff --git a/spine-unity/Assets/spine-unity/Modules/Ragdoll/SkeletonRagdoll2D.cs b/spine-unity/Assets/spine-unity/Modules/Ragdoll/SkeletonRagdoll2D.cs index bc6479db73..c2dfefa77b 100644 --- a/spine-unity/Assets/spine-unity/Modules/Ragdoll/SkeletonRagdoll2D.cs +++ b/spine-unity/Assets/spine-unity/Modules/Ragdoll/SkeletonRagdoll2D.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ /***************************************************************************** diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs index 46bff28a66..0b2ee73061 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,43 +21,13 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ + #if (UNITY_5_0 || UNITY_5_1 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7) #define PREUNITY_5_2 #endif @@ -260,4 +229,4 @@ public class SkeletonGraphicInspector : UnityEditor.Editor { #endif } -} +} diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs index 273c034fde..63a64d09c7 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ /****************************************************************************** diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonPartsRendererInspector.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonPartsRendererInspector.cs index 17b0648002..1a347081e4 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonPartsRendererInspector.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonPartsRendererInspector.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ /****************************************************************************** diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderSeparatorInspector.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderSeparatorInspector.cs index 1c236a36d0..8c0f21c847 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderSeparatorInspector.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/Editor/SkeletonRenderSeparatorInspector.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,43 +21,13 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ + using UnityEngine; using UnityEditor; @@ -311,4 +280,4 @@ public class SkeletonRenderSeparatorInspector : UnityEditor.Editor { #endregion } -} +} diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonPartsRenderer.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonPartsRenderer.cs index d35e57aaa9..babd4b06c9 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonPartsRenderer.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonPartsRenderer.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,43 +21,13 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ + using UnityEngine; using Spine.Unity.MeshGeneration; @@ -124,4 +93,4 @@ public class SkeletonPartsRenderer : MonoBehaviour { return returnComponent; } } -} +} diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderSeparator.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderSeparator.cs index c758bd9915..c5fd91b918 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderSeparator.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderSeparator.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,43 +21,13 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ + using UnityEngine; using System.Collections.Generic; using Spine.Unity; @@ -202,4 +171,4 @@ public class SkeletonRenderSeparator : MonoBehaviour { } } -} +} diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityEyeConstraint.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityEyeConstraint.cs index f7c2714c53..65bbcd92d5 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityEyeConstraint.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityEyeConstraint.cs @@ -1,88 +1,87 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEngine; -using System.Collections; - -namespace Spine.Unity.Modules { - public class SkeletonUtilityEyeConstraint : SkeletonUtilityConstraint { - public Transform[] eyes; - public float radius = 0.5f; - public Transform target; - public Vector3 targetPosition; - public float speed = 10; - Vector3[] origins; - Vector3 centerPoint; - - protected override void OnEnable () { - if (!Application.isPlaying) - return; - - base.OnEnable(); - - Bounds centerBounds = new Bounds(eyes[0].localPosition, Vector3.zero); - origins = new Vector3[eyes.Length]; - for (int i = 0; i < eyes.Length; i++) { - origins[i] = eyes[i].localPosition; - centerBounds.Encapsulate(origins[i]); - } - - centerPoint = centerBounds.center; - } - - protected override void OnDisable () { - if (!Application.isPlaying) - return; - - base.OnDisable(); - } - - public override void DoUpdate () { - - if (target != null) - targetPosition = target.position; - - Vector3 goal = targetPosition; - - Vector3 center = transform.TransformPoint(centerPoint); - Vector3 dir = goal - center; - - if (dir.magnitude > 1) - dir.Normalize(); - - for (int i = 0; i < eyes.Length; i++) { - center = transform.TransformPoint(origins[i]); - eyes[i].position = Vector3.MoveTowards(eyes[i].position, center + (dir * radius), speed * Time.deltaTime); - } - - } - } +using UnityEngine; +using System.Collections; + +namespace Spine.Unity.Modules { + public class SkeletonUtilityEyeConstraint : SkeletonUtilityConstraint { + public Transform[] eyes; + public float radius = 0.5f; + public Transform target; + public Vector3 targetPosition; + public float speed = 10; + Vector3[] origins; + Vector3 centerPoint; + + protected override void OnEnable () { + if (!Application.isPlaying) + return; + + base.OnEnable(); + + Bounds centerBounds = new Bounds(eyes[0].localPosition, Vector3.zero); + origins = new Vector3[eyes.Length]; + for (int i = 0; i < eyes.Length; i++) { + origins[i] = eyes[i].localPosition; + centerBounds.Encapsulate(origins[i]); + } + + centerPoint = centerBounds.center; + } + + protected override void OnDisable () { + if (!Application.isPlaying) + return; + + base.OnDisable(); + } + + public override void DoUpdate () { + + if (target != null) + targetPosition = target.position; + + Vector3 goal = targetPosition; + + Vector3 center = transform.TransformPoint(centerPoint); + Vector3 dir = goal - center; + + if (dir.magnitude > 1) + dir.Normalize(); + + for (int i = 0; i < eyes.Length; i++) { + center = transform.TransformPoint(origins[i]); + eyes[i].position = Vector3.MoveTowards(eyes[i].position, center + (dir * radius), speed * Time.deltaTime); + } + + } + } } diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityGroundConstraint.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityGroundConstraint.cs index a60182e3fc..310c426a2b 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityGroundConstraint.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityGroundConstraint.cs @@ -1,155 +1,154 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEngine; -using System.Collections; - -namespace Spine.Unity.Modules { - [RequireComponent(typeof(SkeletonUtilityBone)), ExecuteInEditMode] - public class SkeletonUtilityGroundConstraint : SkeletonUtilityConstraint { - - #if UNITY_4_3 - public LayerMask groundMask; - public bool use2D = false; - public bool useRadius = false; - public float castRadius = 0.1f; - public float castDistance = 5f; - public float castOffset = 0; - public float groundOffset = 0; - public float adjustSpeed = 5; - #else - [Tooltip("LayerMask for what objects to raycast against")] - public LayerMask groundMask; - [Tooltip("The 2D")] - public bool use2D = false; - [Tooltip("Uses SphereCast for 3D mode and CircleCast for 2D mode")] - public bool useRadius = false; - [Tooltip("The Radius")] - public float castRadius = 0.1f; - [Tooltip("How high above the target bone to begin casting from")] - public float castDistance = 5f; - [Tooltip("X-Axis adjustment")] - public float castOffset = 0; - [Tooltip("Y-Axis adjustment")] - public float groundOffset = 0; - [Tooltip("How fast the target IK position adjusts to the ground. Use smaller values to prevent snapping")] - public float adjustSpeed = 5; - #endif - - - Vector3 rayOrigin; - Vector3 rayDir = new Vector3(0, -1, 0); - float hitY; - float lastHitY; - - protected override void OnEnable () { - base.OnEnable(); - lastHitY = transform.position.y; - } - - protected override void OnDisable () { - base.OnDisable(); - } - - public override void DoUpdate () { - rayOrigin = transform.position + new Vector3(castOffset, castDistance, 0); - - hitY = float.MinValue; - if (use2D) { - RaycastHit2D hit; - - if (useRadius) { - #if UNITY_4_3 - //NOTE: Unity 4.3.x does not have CircleCast - hit = Physics2D.Raycast(rayOrigin , rayDir, castDistance + groundOffset, groundMask); - #else - hit = Physics2D.CircleCast(rayOrigin, castRadius, rayDir, castDistance + groundOffset, groundMask); - #endif - } else { - hit = Physics2D.Raycast(rayOrigin, rayDir, castDistance + groundOffset, groundMask); - } - - if (hit.collider != null) { - hitY = hit.point.y + groundOffset; - if (Application.isPlaying) { - hitY = Mathf.MoveTowards(lastHitY, hitY, adjustSpeed * Time.deltaTime); - } - } else { - if (Application.isPlaying) - hitY = Mathf.MoveTowards(lastHitY, transform.position.y, adjustSpeed * Time.deltaTime); - } - } else { - RaycastHit hit; - bool validHit = false; - - if (useRadius) { - validHit = Physics.SphereCast(rayOrigin, castRadius, rayDir, out hit, castDistance + groundOffset, groundMask); - } else { - validHit = Physics.Raycast(rayOrigin, rayDir, out hit, castDistance + groundOffset, groundMask); - } - - if (validHit) { - hitY = hit.point.y + groundOffset; - if (Application.isPlaying) { - hitY = Mathf.MoveTowards(lastHitY, hitY, adjustSpeed * Time.deltaTime); - } - } else { - if (Application.isPlaying) - hitY = Mathf.MoveTowards(lastHitY, transform.position.y, adjustSpeed * Time.deltaTime); - } - } - - Vector3 v = transform.position; - v.y = Mathf.Clamp(v.y, Mathf.Min(lastHitY, hitY), float.MaxValue); - transform.position = v; - - utilBone.bone.X = transform.localPosition.x; - utilBone.bone.Y = transform.localPosition.y; - - lastHitY = hitY; - } - - void OnDrawGizmos () { - Vector3 hitEnd = rayOrigin + (rayDir * Mathf.Min(castDistance, rayOrigin.y - hitY)); - Vector3 clearEnd = rayOrigin + (rayDir * castDistance); - Gizmos.DrawLine(rayOrigin, hitEnd); - - if (useRadius) { - Gizmos.DrawLine(new Vector3(hitEnd.x - castRadius, hitEnd.y - groundOffset, hitEnd.z), new Vector3(hitEnd.x + castRadius, hitEnd.y - groundOffset, hitEnd.z)); - Gizmos.DrawLine(new Vector3(clearEnd.x - castRadius, clearEnd.y, clearEnd.z), new Vector3(clearEnd.x + castRadius, clearEnd.y, clearEnd.z)); - } - - Gizmos.color = Color.red; - Gizmos.DrawLine(hitEnd, clearEnd); - } - } - +using UnityEngine; +using System.Collections; + +namespace Spine.Unity.Modules { + [RequireComponent(typeof(SkeletonUtilityBone)), ExecuteInEditMode] + public class SkeletonUtilityGroundConstraint : SkeletonUtilityConstraint { + + #if UNITY_4_3 + public LayerMask groundMask; + public bool use2D = false; + public bool useRadius = false; + public float castRadius = 0.1f; + public float castDistance = 5f; + public float castOffset = 0; + public float groundOffset = 0; + public float adjustSpeed = 5; + #else + [Tooltip("LayerMask for what objects to raycast against")] + public LayerMask groundMask; + [Tooltip("The 2D")] + public bool use2D = false; + [Tooltip("Uses SphereCast for 3D mode and CircleCast for 2D mode")] + public bool useRadius = false; + [Tooltip("The Radius")] + public float castRadius = 0.1f; + [Tooltip("How high above the target bone to begin casting from")] + public float castDistance = 5f; + [Tooltip("X-Axis adjustment")] + public float castOffset = 0; + [Tooltip("Y-Axis adjustment")] + public float groundOffset = 0; + [Tooltip("How fast the target IK position adjusts to the ground. Use smaller values to prevent snapping")] + public float adjustSpeed = 5; + #endif + + + Vector3 rayOrigin; + Vector3 rayDir = new Vector3(0, -1, 0); + float hitY; + float lastHitY; + + protected override void OnEnable () { + base.OnEnable(); + lastHitY = transform.position.y; + } + + protected override void OnDisable () { + base.OnDisable(); + } + + public override void DoUpdate () { + rayOrigin = transform.position + new Vector3(castOffset, castDistance, 0); + + hitY = float.MinValue; + if (use2D) { + RaycastHit2D hit; + + if (useRadius) { + #if UNITY_4_3 + //NOTE: Unity 4.3.x does not have CircleCast + hit = Physics2D.Raycast(rayOrigin , rayDir, castDistance + groundOffset, groundMask); + #else + hit = Physics2D.CircleCast(rayOrigin, castRadius, rayDir, castDistance + groundOffset, groundMask); + #endif + } else { + hit = Physics2D.Raycast(rayOrigin, rayDir, castDistance + groundOffset, groundMask); + } + + if (hit.collider != null) { + hitY = hit.point.y + groundOffset; + if (Application.isPlaying) { + hitY = Mathf.MoveTowards(lastHitY, hitY, adjustSpeed * Time.deltaTime); + } + } else { + if (Application.isPlaying) + hitY = Mathf.MoveTowards(lastHitY, transform.position.y, adjustSpeed * Time.deltaTime); + } + } else { + RaycastHit hit; + bool validHit = false; + + if (useRadius) { + validHit = Physics.SphereCast(rayOrigin, castRadius, rayDir, out hit, castDistance + groundOffset, groundMask); + } else { + validHit = Physics.Raycast(rayOrigin, rayDir, out hit, castDistance + groundOffset, groundMask); + } + + if (validHit) { + hitY = hit.point.y + groundOffset; + if (Application.isPlaying) { + hitY = Mathf.MoveTowards(lastHitY, hitY, adjustSpeed * Time.deltaTime); + } + } else { + if (Application.isPlaying) + hitY = Mathf.MoveTowards(lastHitY, transform.position.y, adjustSpeed * Time.deltaTime); + } + } + + Vector3 v = transform.position; + v.y = Mathf.Clamp(v.y, Mathf.Min(lastHitY, hitY), float.MaxValue); + transform.position = v; + + utilBone.bone.X = transform.localPosition.x; + utilBone.bone.Y = transform.localPosition.y; + + lastHitY = hitY; + } + + void OnDrawGizmos () { + Vector3 hitEnd = rayOrigin + (rayDir * Mathf.Min(castDistance, rayOrigin.y - hitY)); + Vector3 clearEnd = rayOrigin + (rayDir * castDistance); + Gizmos.DrawLine(rayOrigin, hitEnd); + + if (useRadius) { + Gizmos.DrawLine(new Vector3(hitEnd.x - castRadius, hitEnd.y - groundOffset, hitEnd.z), new Vector3(hitEnd.x + castRadius, hitEnd.y - groundOffset, hitEnd.z)); + Gizmos.DrawLine(new Vector3(clearEnd.x - castRadius, clearEnd.y, clearEnd.z), new Vector3(clearEnd.x + castRadius, clearEnd.y, clearEnd.z)); + } + + Gizmos.color = Color.red; + Gizmos.DrawLine(hitEnd, clearEnd); + } + } + } diff --git a/spine-unity/Assets/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityKinematicShadow.cs b/spine-unity/Assets/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityKinematicShadow.cs index 72d30a18ec..7330aa1ae1 100644 --- a/spine-unity/Assets/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityKinematicShadow.cs +++ b/spine-unity/Assets/spine-unity/Modules/SkeletonUtility Modules/SkeletonUtilityKinematicShadow.cs @@ -1,126 +1,125 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEngine; -using System.Collections.Generic; - -namespace Spine.Unity.Modules { - - // SkeletonUtilityKinematicShadow allows hinge chains to inherit a velocity interpreted from changes in parent transform position or from unrelated rigidbodies. - // Note: Uncheck "useRootTransformIfNull - public class SkeletonUtilityKinematicShadow : MonoBehaviour { - #region Inspector - [Tooltip("If checked, the hinge chain can inherit your root transform's velocity or position/rotation changes.")] - public bool detachedShadow = false; - public Transform parent; - public bool hideShadow = true; - #endregion - - GameObject shadowRoot; - readonly List shadowTable = new List(); - struct TransformPair { - public Transform dest, src; - } - - void Start () { - // Duplicate this gameObject as the "shadow" with a different parent. - shadowRoot = Instantiate(this.gameObject); - Destroy(shadowRoot.GetComponent()); - - // Prepare shadow gameObject's properties. - var shadowRootTransform = shadowRoot.transform; - shadowRootTransform.position = transform.position; - shadowRootTransform.rotation = transform.rotation; - - Vector3 scaleRef = transform.TransformPoint(Vector3.right); - float scale = Vector3.Distance(transform.position, scaleRef); - shadowRootTransform.localScale = Vector3.one; - - if (!detachedShadow) { - // Do not change to null coalescing operator (??). Unity overloads null checks for UnityEngine.Objects but not the ?? operator. - if (parent == null) - shadowRootTransform.parent = transform.root; - else - shadowRootTransform.parent = parent; - } - - if (hideShadow) - shadowRoot.hideFlags = HideFlags.HideInHierarchy; - - var shadowJoints = shadowRoot.GetComponentsInChildren(); - foreach (Joint j in shadowJoints) - j.connectedAnchor *= scale; - - // Build list of bone pairs (matches shadow transforms with bone transforms) - var bones = GetComponentsInChildren(); - var shadowBones = shadowRoot.GetComponentsInChildren(); - foreach (var b in bones) { - if (b.gameObject == this.gameObject) - continue; - - foreach (var sb in shadowBones) { - if (sb.GetComponent() != null && sb.boneName == b.boneName) { - shadowTable.Add(new TransformPair { - dest = b.transform, - src = sb.transform - }); - break; - } - } - - } - - // Destroy conflicting and unneeded components - DestroyComponents(shadowBones); - - DestroyComponents(GetComponentsInChildren()); - DestroyComponents(GetComponentsInChildren()); - DestroyComponents(GetComponentsInChildren()); - } - - static void DestroyComponents (Component[] components) { - for (int i = 0, n = components.Length; i < n; i++) - Destroy(components[i]); - } - - void FixedUpdate () { - var shadowRootRigidbody = shadowRoot.GetComponent(); - shadowRootRigidbody.MovePosition(transform.position); - shadowRootRigidbody.MoveRotation(transform.rotation); - - for (int i = 0, n = shadowTable.Count; i < n; i++) { - var pair = shadowTable[i]; - pair.dest.localPosition = pair.src.localPosition; - pair.dest.localRotation = pair.src.localRotation; - } - } - } +using UnityEngine; +using System.Collections.Generic; + +namespace Spine.Unity.Modules { + + // SkeletonUtilityKinematicShadow allows hinge chains to inherit a velocity interpreted from changes in parent transform position or from unrelated rigidbodies. + // Note: Uncheck "useRootTransformIfNull + public class SkeletonUtilityKinematicShadow : MonoBehaviour { + #region Inspector + [Tooltip("If checked, the hinge chain can inherit your root transform's velocity or position/rotation changes.")] + public bool detachedShadow = false; + public Transform parent; + public bool hideShadow = true; + #endregion + + GameObject shadowRoot; + readonly List shadowTable = new List(); + struct TransformPair { + public Transform dest, src; + } + + void Start () { + // Duplicate this gameObject as the "shadow" with a different parent. + shadowRoot = Instantiate(this.gameObject); + Destroy(shadowRoot.GetComponent()); + + // Prepare shadow gameObject's properties. + var shadowRootTransform = shadowRoot.transform; + shadowRootTransform.position = transform.position; + shadowRootTransform.rotation = transform.rotation; + + Vector3 scaleRef = transform.TransformPoint(Vector3.right); + float scale = Vector3.Distance(transform.position, scaleRef); + shadowRootTransform.localScale = Vector3.one; + + if (!detachedShadow) { + // Do not change to null coalescing operator (??). Unity overloads null checks for UnityEngine.Objects but not the ?? operator. + if (parent == null) + shadowRootTransform.parent = transform.root; + else + shadowRootTransform.parent = parent; + } + + if (hideShadow) + shadowRoot.hideFlags = HideFlags.HideInHierarchy; + + var shadowJoints = shadowRoot.GetComponentsInChildren(); + foreach (Joint j in shadowJoints) + j.connectedAnchor *= scale; + + // Build list of bone pairs (matches shadow transforms with bone transforms) + var bones = GetComponentsInChildren(); + var shadowBones = shadowRoot.GetComponentsInChildren(); + foreach (var b in bones) { + if (b.gameObject == this.gameObject) + continue; + + foreach (var sb in shadowBones) { + if (sb.GetComponent() != null && sb.boneName == b.boneName) { + shadowTable.Add(new TransformPair { + dest = b.transform, + src = sb.transform + }); + break; + } + } + + } + + // Destroy conflicting and unneeded components + DestroyComponents(shadowBones); + + DestroyComponents(GetComponentsInChildren()); + DestroyComponents(GetComponentsInChildren()); + DestroyComponents(GetComponentsInChildren()); + } + + static void DestroyComponents (Component[] components) { + for (int i = 0, n = components.Length; i < n; i++) + Destroy(components[i]); + } + + void FixedUpdate () { + var shadowRootRigidbody = shadowRoot.GetComponent(); + shadowRootRigidbody.MovePosition(transform.position); + shadowRootRigidbody.MoveRotation(transform.rotation); + + for (int i = 0, n = shadowTable.Count; i < n; i++) { + var pair = shadowTable[i]; + pair.dest.localPosition = pair.src.localPosition; + pair.dest.localRotation = pair.src.localRotation; + } + } + } } diff --git a/spine-unity/Assets/spine-unity/Modules/SpriteAttacher.cs b/spine-unity/Assets/spine-unity/Modules/SpriteAttacher.cs index 811215d567..317cba75ea 100644 --- a/spine-unity/Assets/spine-unity/Modules/SpriteAttacher.cs +++ b/spine-unity/Assets/spine-unity/Modules/SpriteAttacher.cs @@ -1,261 +1,259 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEngine; -using System.Collections.Generic; -using Spine; - -namespace Spine.Unity.Modules { - public class SpriteAttacher : MonoBehaviour { - const string DefaultPMAShader = "Spine/Skeleton"; - const string DefaultStraightAlphaShader = "Sprites/Default"; - - #region Inspector - public bool attachOnStart = true; - public bool keepLoaderInMemory = true; - public Sprite sprite; - - [SpineSlot] - public string slot; - #endregion - - private SpriteAttachmentLoader loader; - private RegionAttachment attachment; - private bool applyPMA; - - void Start () { - if (attachOnStart) - Attach(); - } - - public void Attach () { - var skeletonComponent = GetComponent(); - - var skeletonRenderer = skeletonComponent as SkeletonRenderer; - if (skeletonRenderer != null) - this.applyPMA = skeletonRenderer.pmaVertexColors; - else { - var skeletonGraphic = skeletonComponent as SkeletonGraphic; - if (skeletonGraphic != null) - this.applyPMA = skeletonGraphic.SpineMeshGenerator.PremultiplyVertexColors; - } - - Shader attachmentShader = applyPMA ? Shader.Find(DefaultPMAShader) : Shader.Find(DefaultStraightAlphaShader); - - loader = loader ?? new SpriteAttachmentLoader(sprite, attachmentShader, applyPMA); - - if (attachment == null) - attachment = loader.NewRegionAttachment(null, sprite.name, ""); - - skeletonComponent.Skeleton.FindSlot(slot).Attachment = attachment; - - if (!keepLoaderInMemory) - loader = null; - } - } - - public class SpriteAttachmentLoader : AttachmentLoader { - //IMPORTANT: Make sure you clear this when you don't need it anymore. Goodluck. - static public Dictionary atlasTable = new Dictionary(); - - static public List premultipliedAtlasIds = new List(); - - Sprite sprite; - Shader shader; - //bool applyPMA; - - public SpriteAttachmentLoader (Sprite sprite, Shader shader, bool applyPMA) { - if (sprite.packed && sprite.packingMode == SpritePackingMode.Tight) { - Debug.LogError("Tight Packer Policy not supported yet!"); - return; - } - - this.sprite = sprite; - this.shader = shader; - //this.applyPMA = applyPMA; - - if (applyPMA) { - try { - Texture2D texture = sprite.texture; - int instanceId = texture.GetInstanceID(); - if (!premultipliedAtlasIds.Contains(instanceId)) { - var colors = texture.GetPixels(); - Color c; - float a; - for (int i = 0; i < colors.Length; i++) { - c = colors[i]; - a = c.a; - c.r *= a; - c.g *= a; - c.b *= a; - colors[i] = c; - } - texture.SetPixels(colors); - texture.Apply(); - - premultipliedAtlasIds.Add(instanceId); - } - } catch { - if (Application.isEditor) - Debug.LogWarning("Texture was not readable! Could not apply premultiply alpha. Rendering may be incorrect. Please check your texture import settings and make sure Read/Write is enabled."); - } - } - #if UNITY_EDITOR - else { - Texture2D texture = sprite.texture; - int instanceId = texture.GetInstanceID(); - if (premultipliedAtlasIds.Contains(instanceId)) - Debug.LogWarning("The same texture was used by both premultiply and straight alpha shaders. Rendering may be incorrect."); - } - #endif - - } - - public RegionAttachment NewRegionAttachment (Skin skin, string name, string path) { - RegionAttachment attachment = new RegionAttachment(name); - - Texture2D tex = sprite.texture; - int instanceId = tex.GetInstanceID(); - AtlasRegion atlasRegion; - bool cachedMaterialExists = atlasTable.TryGetValue(instanceId, out atlasRegion); - - if (!cachedMaterialExists) { - // Setup new material. - var material = new Material(shader); - if (sprite.packed) - material.name = "Unity Packed Sprite Material"; - else - material.name = sprite.name + " Sprite Material"; - material.mainTexture = tex; - - // Create faux-region to play nice with SkeletonRenderer. - atlasRegion = new AtlasRegion(); - var page = new AtlasPage(); - page.rendererObject = material; - atlasRegion.page = page; - - // Cache it. - atlasTable[instanceId] = atlasRegion; - } - - Rect texRect = sprite.textureRect; - - // Normalize rect to UV space of packed atlas - texRect.x = Mathf.InverseLerp(0, tex.width, texRect.x); - texRect.y = Mathf.InverseLerp(0, tex.height, texRect.y); - texRect.width = Mathf.InverseLerp(0, tex.width, texRect.width); - texRect.height = Mathf.InverseLerp(0, tex.height, texRect.height); - - Bounds bounds = sprite.bounds; - Vector2 boundsMin = bounds.min, boundsMax = bounds.max; - Vector2 size = bounds.size; - float spriteUnitsPerPixel = 1f / sprite.pixelsPerUnit; - - bool rotated = false; - if (sprite.packed) - rotated = sprite.packingRotation == SpritePackingRotation.Any; - - attachment.SetUVs(texRect.xMin, texRect.yMax, texRect.xMax, texRect.yMin, rotated); - attachment.RendererObject = atlasRegion; - attachment.SetColor(Color.white); - attachment.ScaleX = 1; - attachment.ScaleY = 1; - attachment.RegionOffsetX = sprite.rect.width * (0.5f - InverseLerp(boundsMin.x, boundsMax.x, 0)) * spriteUnitsPerPixel; - attachment.RegionOffsetY = sprite.rect.height * (0.5f - InverseLerp(boundsMin.y, boundsMax.y, 0)) * spriteUnitsPerPixel; - attachment.Width = size.x; - attachment.Height = size.y; - attachment.RegionWidth = size.x; - attachment.RegionHeight = size.y; - attachment.RegionOriginalWidth = size.x; - attachment.RegionOriginalHeight = size.y; - attachment.UpdateOffset(); - - return attachment; - } - - public MeshAttachment NewMeshAttachment (Skin skin, string name, string path) { - return null; - } - - public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, string name) { - return null; - } - - public PathAttachment NewPathAttachment (Skin skin, string name) { - return null; - } - - static float InverseLerp (float a, float b, float value) { - return (value - a) / (b - a); - } - } - - public static class SpriteAttachmentExtensions { - public static Attachment AttachUnitySprite (this Skeleton skeleton, string slotName, Sprite sprite, string shaderName = "Spine/Skeleton", bool applyPMA = true) { - return skeleton.AttachUnitySprite(slotName, sprite, Shader.Find(shaderName), applyPMA); - } - - public static Attachment AddUnitySprite (this SkeletonData skeletonData, string slotName, Sprite sprite, string skinName = "", string shaderName = "Spine/Skeleton", bool applyPMA = true) { - return skeletonData.AddUnitySprite(slotName, sprite, skinName, Shader.Find(shaderName), applyPMA); - } - - public static RegionAttachment ToRegionAttachment (this Sprite sprite, string shaderName = "Spine/Skeleton", bool applyPMA = true) { - return sprite.ToRegionAttachment(Shader.Find(shaderName), applyPMA); - } - - public static Attachment AttachUnitySprite (this Skeleton skeleton, string slotName, Sprite sprite, Shader shader, bool applyPMA) { - var att = sprite.ToRegionAttachment(shader, applyPMA); - skeleton.FindSlot(slotName).Attachment = att; - return att; - } - - public static Attachment AddUnitySprite (this SkeletonData skeletonData, string slotName, Sprite sprite, string skinName, Shader shader, bool applyPMA) { - var att = sprite.ToRegionAttachment(shader, applyPMA); - - var slotIndex = skeletonData.FindSlotIndex(slotName); - Skin skin = skeletonData.defaultSkin; - if (skinName != "") - skin = skeletonData.FindSkin(skinName); - - skin.AddAttachment(slotIndex, att.Name, att); - - return att; - } - - public static RegionAttachment ToRegionAttachment (this Sprite sprite, Shader shader, bool applyPMA) { - var loader = new SpriteAttachmentLoader(sprite, shader, applyPMA); - var att = loader.NewRegionAttachment(null, sprite.name, ""); - loader = null; - return att; - } - } +using UnityEngine; +using System.Collections.Generic; +using Spine; + +namespace Spine.Unity.Modules { + public class SpriteAttacher : MonoBehaviour { + const string DefaultPMAShader = "Spine/Skeleton"; + const string DefaultStraightAlphaShader = "Sprites/Default"; + + #region Inspector + public bool attachOnStart = true; + public bool keepLoaderInMemory = true; + public Sprite sprite; + + [SpineSlot] + public string slot; + #endregion + + private SpriteAttachmentLoader loader; + private RegionAttachment attachment; + private bool applyPMA; + + void Start () { + if (attachOnStart) + Attach(); + } + + public void Attach () { + var skeletonComponent = GetComponent(); + + var skeletonRenderer = skeletonComponent as SkeletonRenderer; + if (skeletonRenderer != null) + this.applyPMA = skeletonRenderer.pmaVertexColors; + else { + var skeletonGraphic = skeletonComponent as SkeletonGraphic; + if (skeletonGraphic != null) + this.applyPMA = skeletonGraphic.SpineMeshGenerator.PremultiplyVertexColors; + } + + Shader attachmentShader = applyPMA ? Shader.Find(DefaultPMAShader) : Shader.Find(DefaultStraightAlphaShader); + + loader = loader ?? new SpriteAttachmentLoader(sprite, attachmentShader, applyPMA); + + if (attachment == null) + attachment = loader.NewRegionAttachment(null, sprite.name, ""); + + skeletonComponent.Skeleton.FindSlot(slot).Attachment = attachment; + + if (!keepLoaderInMemory) + loader = null; + } + } + + public class SpriteAttachmentLoader : AttachmentLoader { + //IMPORTANT: Make sure you clear this when you don't need it anymore. Goodluck. + static public Dictionary atlasTable = new Dictionary(); + + static public List premultipliedAtlasIds = new List(); + + Sprite sprite; + Shader shader; + //bool applyPMA; + + public SpriteAttachmentLoader (Sprite sprite, Shader shader, bool applyPMA) { + if (sprite.packed && sprite.packingMode == SpritePackingMode.Tight) { + Debug.LogError("Tight Packer Policy not supported yet!"); + return; + } + + this.sprite = sprite; + this.shader = shader; + //this.applyPMA = applyPMA; + + if (applyPMA) { + try { + Texture2D texture = sprite.texture; + int instanceId = texture.GetInstanceID(); + if (!premultipliedAtlasIds.Contains(instanceId)) { + var colors = texture.GetPixels(); + Color c; + float a; + for (int i = 0; i < colors.Length; i++) { + c = colors[i]; + a = c.a; + c.r *= a; + c.g *= a; + c.b *= a; + colors[i] = c; + } + texture.SetPixels(colors); + texture.Apply(); + + premultipliedAtlasIds.Add(instanceId); + } + } catch { + if (Application.isEditor) + Debug.LogWarning("Texture was not readable! Could not apply premultiply alpha. Rendering may be incorrect. Please check your texture import settings and make sure Read/Write is enabled."); + } + } + #if UNITY_EDITOR + else { + Texture2D texture = sprite.texture; + int instanceId = texture.GetInstanceID(); + if (premultipliedAtlasIds.Contains(instanceId)) + Debug.LogWarning("The same texture was used by both premultiply and straight alpha shaders. Rendering may be incorrect."); + } + #endif + + } + + public RegionAttachment NewRegionAttachment (Skin skin, string name, string path) { + RegionAttachment attachment = new RegionAttachment(name); + + Texture2D tex = sprite.texture; + int instanceId = tex.GetInstanceID(); + AtlasRegion atlasRegion; + bool cachedMaterialExists = atlasTable.TryGetValue(instanceId, out atlasRegion); + + if (!cachedMaterialExists) { + // Setup new material. + var material = new Material(shader); + if (sprite.packed) + material.name = "Unity Packed Sprite Material"; + else + material.name = sprite.name + " Sprite Material"; + material.mainTexture = tex; + + // Create faux-region to play nice with SkeletonRenderer. + atlasRegion = new AtlasRegion(); + var page = new AtlasPage(); + page.rendererObject = material; + atlasRegion.page = page; + + // Cache it. + atlasTable[instanceId] = atlasRegion; + } + + Rect texRect = sprite.textureRect; + + // Normalize rect to UV space of packed atlas + texRect.x = Mathf.InverseLerp(0, tex.width, texRect.x); + texRect.y = Mathf.InverseLerp(0, tex.height, texRect.y); + texRect.width = Mathf.InverseLerp(0, tex.width, texRect.width); + texRect.height = Mathf.InverseLerp(0, tex.height, texRect.height); + + Bounds bounds = sprite.bounds; + Vector2 boundsMin = bounds.min, boundsMax = bounds.max; + Vector2 size = bounds.size; + float spriteUnitsPerPixel = 1f / sprite.pixelsPerUnit; + + bool rotated = false; + if (sprite.packed) + rotated = sprite.packingRotation == SpritePackingRotation.Any; + + attachment.SetUVs(texRect.xMin, texRect.yMax, texRect.xMax, texRect.yMin, rotated); + attachment.RendererObject = atlasRegion; + attachment.SetColor(Color.white); + attachment.ScaleX = 1; + attachment.ScaleY = 1; + attachment.RegionOffsetX = sprite.rect.width * (0.5f - InverseLerp(boundsMin.x, boundsMax.x, 0)) * spriteUnitsPerPixel; + attachment.RegionOffsetY = sprite.rect.height * (0.5f - InverseLerp(boundsMin.y, boundsMax.y, 0)) * spriteUnitsPerPixel; + attachment.Width = size.x; + attachment.Height = size.y; + attachment.RegionWidth = size.x; + attachment.RegionHeight = size.y; + attachment.RegionOriginalWidth = size.x; + attachment.RegionOriginalHeight = size.y; + attachment.UpdateOffset(); + + return attachment; + } + + public MeshAttachment NewMeshAttachment (Skin skin, string name, string path) { + return null; + } + + public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, string name) { + return null; + } + + public PathAttachment NewPathAttachment (Skin skin, string name) { + return null; + } + + static float InverseLerp (float a, float b, float value) { + return (value - a) / (b - a); + } + } + + public static class SpriteAttachmentExtensions { + public static Attachment AttachUnitySprite (this Skeleton skeleton, string slotName, Sprite sprite, string shaderName = "Spine/Skeleton", bool applyPMA = true) { + return skeleton.AttachUnitySprite(slotName, sprite, Shader.Find(shaderName), applyPMA); + } + + public static Attachment AddUnitySprite (this SkeletonData skeletonData, string slotName, Sprite sprite, string skinName = "", string shaderName = "Spine/Skeleton", bool applyPMA = true) { + return skeletonData.AddUnitySprite(slotName, sprite, skinName, Shader.Find(shaderName), applyPMA); + } + + public static RegionAttachment ToRegionAttachment (this Sprite sprite, string shaderName = "Spine/Skeleton", bool applyPMA = true) { + return sprite.ToRegionAttachment(Shader.Find(shaderName), applyPMA); + } + + public static Attachment AttachUnitySprite (this Skeleton skeleton, string slotName, Sprite sprite, Shader shader, bool applyPMA) { + var att = sprite.ToRegionAttachment(shader, applyPMA); + skeleton.FindSlot(slotName).Attachment = att; + return att; + } + + public static Attachment AddUnitySprite (this SkeletonData skeletonData, string slotName, Sprite sprite, string skinName, Shader shader, bool applyPMA) { + var att = sprite.ToRegionAttachment(shader, applyPMA); + + var slotIndex = skeletonData.FindSlotIndex(slotName); + Skin skin = skeletonData.defaultSkin; + if (skinName != "") + skin = skeletonData.FindSkin(skinName); + + skin.AddAttachment(slotIndex, att.Name, att); + + return att; + } + + public static RegionAttachment ToRegionAttachment (this Sprite sprite, Shader shader, bool applyPMA) { + var loader = new SpriteAttachmentLoader(sprite, shader, applyPMA); + var att = loader.NewRegionAttachment(null, sprite.name, ""); + loader = null; + return att; + } + } } - diff --git a/spine-unity/Assets/spine-unity/Modules/TK2D/SpriteCollectionAttachmentLoader.cs b/spine-unity/Assets/spine-unity/Modules/TK2D/SpriteCollectionAttachmentLoader.cs index 0f3b559cff..a99f8f603b 100644 --- a/spine-unity/Assets/spine-unity/Modules/TK2D/SpriteCollectionAttachmentLoader.cs +++ b/spine-unity/Assets/spine-unity/Modules/TK2D/SpriteCollectionAttachmentLoader.cs @@ -1,150 +1,149 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#if SPINE_TK2D -using System; -using UnityEngine; -using Spine; - -// TODO: handle TPackerCW flip mode (probably not swap uv horizontaly) -namespace Spine.Unity.TK2D { - public class SpriteCollectionAttachmentLoader : AttachmentLoader { - private tk2dSpriteCollectionData sprites; - private float u, v, u2, v2; - private bool regionRotated; - private float regionOriginalWidth, regionOriginalHeight; - private float regionWidth, regionHeight; - private float regionOffsetX, regionOffsetY; - private Material material; - - public SpriteCollectionAttachmentLoader (tk2dSpriteCollectionData sprites) { - if (sprites == null) - throw new ArgumentNullException("sprites cannot be null."); - this.sprites = sprites; - } - - private void ProcessSpriteDefinition (String name) { - // Strip folder names. - int index = name.LastIndexOfAny(new char[] {'/', '\\'}); - if (index != -1) - name = name.Substring(index + 1); - - tk2dSpriteDefinition def = sprites.inst.GetSpriteDefinition(name); - - if (def == null) { - Debug.Log("Sprite not found in atlas: " + name, sprites); - throw new Exception("Sprite not found in atlas: " + name); - } - if (def.complexGeometry) - throw new NotImplementedException("Complex geometry is not supported: " + name); - if (def.flipped == tk2dSpriteDefinition.FlipMode.TPackerCW) - throw new NotImplementedException("Only 2D Toolkit atlases are supported: " + name); - - Vector2 minTexCoords = Vector2.one, maxTexCoords = Vector2.zero; - for (int i = 0; i < def.uvs.Length; ++i) { - Vector2 uv = def.uvs[i]; - minTexCoords = Vector2.Min(minTexCoords, uv); - maxTexCoords = Vector2.Max(maxTexCoords, uv); - } - regionRotated = def.flipped == tk2dSpriteDefinition.FlipMode.Tk2d; - if (regionRotated) { - float temp = minTexCoords.x; - minTexCoords.x = maxTexCoords.x; - maxTexCoords.x = temp; - } - u = minTexCoords.x; - v = maxTexCoords.y; - u2 = maxTexCoords.x; - v2 = minTexCoords.y; - - regionOriginalWidth = (int)(def.untrimmedBoundsData[1].x / def.texelSize.x); - regionOriginalHeight = (int)(def.untrimmedBoundsData[1].y / def.texelSize.y); - - regionWidth = (int)(def.boundsData[1].x / def.texelSize.x); - regionHeight = (int)(def.boundsData[1].y / def.texelSize.y); - - float x0 = def.untrimmedBoundsData[0].x - def.untrimmedBoundsData[1].x / 2; - float x1 = def.boundsData[0].x - def.boundsData[1].x / 2; - regionOffsetX = (int)((x1 - x0) / def.texelSize.x); - - float y0 = def.untrimmedBoundsData[0].y - def.untrimmedBoundsData[1].y / 2; - float y1 = def.boundsData[0].y - def.boundsData[1].y / 2; - regionOffsetY = (int)((y1 - y0) / def.texelSize.y); - - material = def.materialInst; - } - - public RegionAttachment NewRegionAttachment (Skin skin, String name, String path) { - ProcessSpriteDefinition(path); - - RegionAttachment region = new RegionAttachment(name); - region.Path = path; - region.RendererObject = material; - region.SetUVs(u, v, u2, v2, regionRotated); - region.RegionOriginalWidth = regionOriginalWidth; - region.RegionOriginalHeight = regionOriginalHeight; - region.RegionWidth = regionWidth; - region.RegionHeight = regionHeight; - region.RegionOffsetX = regionOffsetX; - region.RegionOffsetY = regionOffsetY; - return region; - } - - public MeshAttachment NewMeshAttachment (Skin skin, String name, String path) { - ProcessSpriteDefinition(path); - - MeshAttachment mesh = new MeshAttachment(name); - mesh.Path = path; - mesh.RendererObject = material; - mesh.RegionU = u; - mesh.RegionV = v; - mesh.RegionU2 = u2; - mesh.RegionV2 = v2; - mesh.RegionRotate = regionRotated; - mesh.RegionOriginalWidth = regionOriginalWidth; - mesh.RegionOriginalHeight = regionOriginalHeight; - mesh.RegionWidth = regionWidth; - mesh.RegionHeight = regionHeight; - mesh.RegionOffsetX = regionOffsetX; - mesh.RegionOffsetY = regionOffsetY; - return mesh; - } - - public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name) { - return new BoundingBoxAttachment(name); - } - - public PathAttachment NewPathAttachment (Skin skin, string name) { - return new PathAttachment(name); - } - } -} +#if SPINE_TK2D +using System; +using UnityEngine; +using Spine; + +// TODO: handle TPackerCW flip mode (probably not swap uv horizontaly) +namespace Spine.Unity.TK2D { + public class SpriteCollectionAttachmentLoader : AttachmentLoader { + private tk2dSpriteCollectionData sprites; + private float u, v, u2, v2; + private bool regionRotated; + private float regionOriginalWidth, regionOriginalHeight; + private float regionWidth, regionHeight; + private float regionOffsetX, regionOffsetY; + private Material material; + + public SpriteCollectionAttachmentLoader (tk2dSpriteCollectionData sprites) { + if (sprites == null) + throw new ArgumentNullException("sprites cannot be null."); + this.sprites = sprites; + } + + private void ProcessSpriteDefinition (String name) { + // Strip folder names. + int index = name.LastIndexOfAny(new char[] {'/', '\\'}); + if (index != -1) + name = name.Substring(index + 1); + + tk2dSpriteDefinition def = sprites.inst.GetSpriteDefinition(name); + + if (def == null) { + Debug.Log("Sprite not found in atlas: " + name, sprites); + throw new Exception("Sprite not found in atlas: " + name); + } + if (def.complexGeometry) + throw new NotImplementedException("Complex geometry is not supported: " + name); + if (def.flipped == tk2dSpriteDefinition.FlipMode.TPackerCW) + throw new NotImplementedException("Only 2D Toolkit atlases are supported: " + name); + + Vector2 minTexCoords = Vector2.one, maxTexCoords = Vector2.zero; + for (int i = 0; i < def.uvs.Length; ++i) { + Vector2 uv = def.uvs[i]; + minTexCoords = Vector2.Min(minTexCoords, uv); + maxTexCoords = Vector2.Max(maxTexCoords, uv); + } + regionRotated = def.flipped == tk2dSpriteDefinition.FlipMode.Tk2d; + if (regionRotated) { + float temp = minTexCoords.x; + minTexCoords.x = maxTexCoords.x; + maxTexCoords.x = temp; + } + u = minTexCoords.x; + v = maxTexCoords.y; + u2 = maxTexCoords.x; + v2 = minTexCoords.y; + + regionOriginalWidth = (int)(def.untrimmedBoundsData[1].x / def.texelSize.x); + regionOriginalHeight = (int)(def.untrimmedBoundsData[1].y / def.texelSize.y); + + regionWidth = (int)(def.boundsData[1].x / def.texelSize.x); + regionHeight = (int)(def.boundsData[1].y / def.texelSize.y); + + float x0 = def.untrimmedBoundsData[0].x - def.untrimmedBoundsData[1].x / 2; + float x1 = def.boundsData[0].x - def.boundsData[1].x / 2; + regionOffsetX = (int)((x1 - x0) / def.texelSize.x); + + float y0 = def.untrimmedBoundsData[0].y - def.untrimmedBoundsData[1].y / 2; + float y1 = def.boundsData[0].y - def.boundsData[1].y / 2; + regionOffsetY = (int)((y1 - y0) / def.texelSize.y); + + material = def.materialInst; + } + + public RegionAttachment NewRegionAttachment (Skin skin, String name, String path) { + ProcessSpriteDefinition(path); + + RegionAttachment region = new RegionAttachment(name); + region.Path = path; + region.RendererObject = material; + region.SetUVs(u, v, u2, v2, regionRotated); + region.RegionOriginalWidth = regionOriginalWidth; + region.RegionOriginalHeight = regionOriginalHeight; + region.RegionWidth = regionWidth; + region.RegionHeight = regionHeight; + region.RegionOffsetX = regionOffsetX; + region.RegionOffsetY = regionOffsetY; + return region; + } + + public MeshAttachment NewMeshAttachment (Skin skin, String name, String path) { + ProcessSpriteDefinition(path); + + MeshAttachment mesh = new MeshAttachment(name); + mesh.Path = path; + mesh.RendererObject = material; + mesh.RegionU = u; + mesh.RegionV = v; + mesh.RegionU2 = u2; + mesh.RegionV2 = v2; + mesh.RegionRotate = regionRotated; + mesh.RegionOriginalWidth = regionOriginalWidth; + mesh.RegionOriginalHeight = regionOriginalHeight; + mesh.RegionWidth = regionWidth; + mesh.RegionHeight = regionHeight; + mesh.RegionOffsetX = regionOffsetX; + mesh.RegionOffsetY = regionOffsetY; + return mesh; + } + + public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name) { + return new BoundingBoxAttachment(name); + } + + public PathAttachment NewPathAttachment (Skin skin, string name) { + return new PathAttachment(name); + } + } +} #endif diff --git a/spine-unity/Assets/spine-unity/Modules/YieldInstructions/WaitForSpineAnimationComplete.cs b/spine-unity/Assets/spine-unity/Modules/YieldInstructions/WaitForSpineAnimationComplete.cs index 54f01bb086..042fefce0c 100644 --- a/spine-unity/Assets/spine-unity/Modules/YieldInstructions/WaitForSpineAnimationComplete.cs +++ b/spine-unity/Assets/spine-unity/Modules/YieldInstructions/WaitForSpineAnimationComplete.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,42 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ #if (UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7) @@ -124,4 +92,4 @@ public class WaitForSpineAnimationComplete : IEnumerator { } -} +} diff --git a/spine-unity/Assets/spine-unity/Modules/YieldInstructions/WaitForSpineEvent.cs b/spine-unity/Assets/spine-unity/Modules/YieldInstructions/WaitForSpineEvent.cs index 206102e384..98442ac589 100644 --- a/spine-unity/Assets/spine-unity/Modules/YieldInstructions/WaitForSpineEvent.cs +++ b/spine-unity/Assets/spine-unity/Modules/YieldInstructions/WaitForSpineEvent.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,42 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ #if (UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7) @@ -207,4 +175,4 @@ public class WaitForSpineEvent : IEnumerator { } -} +} diff --git a/spine-unity/Assets/spine-unity/SkeletonAnimation.cs b/spine-unity/Assets/spine-unity/SkeletonAnimation.cs index 623b3c1060..429406925e 100644 --- a/spine-unity/Assets/spine-unity/SkeletonAnimation.cs +++ b/spine-unity/Assets/spine-unity/SkeletonAnimation.cs @@ -1,196 +1,195 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using UnityEngine; - -namespace Spine.Unity { - - [ExecuteInEditMode] - [AddComponentMenu("Spine/SkeletonAnimation")] - [HelpURL("http://esotericsoftware.com/spine-unity-documentation#Controlling-Animation")] - public class SkeletonAnimation : SkeletonRenderer, ISkeletonAnimation, Spine.Unity.IAnimationStateComponent { - - /// - /// This is the Spine.AnimationState object of this SkeletonAnimation. You can control animations through it. - /// Note that this object, like .skeleton, is not guaranteed to exist in Awake. Do all accesses and caching to it in Start - public Spine.AnimationState state; - public Spine.AnimationState AnimationState { get { return this.state; } } - - /// - /// Occurs after the animations are applied and before world space values are resolved. - /// Use this callback when you want to set bone local values. - /// - public event UpdateBonesDelegate UpdateLocal { - add { _UpdateLocal += value; } - remove { _UpdateLocal -= value; } - } - - /// - /// Occurs after the Skeleton's bone world space values are resolved (including all constraints). - /// Using this callback will cause the world space values to be solved an extra time. - /// Use this callback if want to use bone world space values, and also set bone local values. - /// - public event UpdateBonesDelegate UpdateWorld { - add { _UpdateWorld += value; } - remove { _UpdateWorld -= value; } - } - - /// - /// Occurs after the Skeleton's bone world space values are resolved (including all constraints). - /// Use this callback if you want to use bone world space values, but don't intend to modify bone local values. - /// This callback can also be used when setting world position and the bone matrix. - /// - public event UpdateBonesDelegate UpdateComplete { - add { _UpdateComplete += value; } - remove { _UpdateComplete -= value; } - } - - protected event UpdateBonesDelegate _UpdateLocal; - protected event UpdateBonesDelegate _UpdateWorld; - protected event UpdateBonesDelegate _UpdateComplete; - - [SerializeField] - [SpineAnimation] - private String _animationName; - public String AnimationName { - get { - if (!valid) { - Debug.LogWarning("You tried access AnimationName but the SkeletonAnimation was not valid. Try checking your Skeleton Data for errors."); - return null; - } - - TrackEntry entry = state.GetCurrent(0); - return entry == null ? null : entry.Animation.Name; - } - set { - if (_animationName == value) - return; - _animationName = value; - - if (!valid) { - Debug.LogWarning("You tried to change AnimationName but the SkeletonAnimation was not valid. Try checking your Skeleton Data for errors."); - return; - } - - if (string.IsNullOrEmpty(value)) - state.ClearTrack(0); - else - state.SetAnimation(0, value, loop); - } - } - - /// Whether or not an animation should loop. This only applies to the initial animation specified in the inspector, or any subsequent Animations played through .AnimationName. Animations set through state.SetAnimation are unaffected. - [Tooltip("Whether or not an animation should loop. This only applies to the initial animation specified in the inspector, or any subsequent Animations played through .AnimationName. Animations set through state.SetAnimation are unaffected.")] - public bool loop; - - /// - /// The rate at which animations progress over time. 1 means 100%. 0.5 means 50%. - /// AnimationState and TrackEntry also have their own timeScale. These are combined multiplicatively. - [Tooltip("The rate at which animations progress over time. 1 means 100%. 0.5 means 50%.")] - public float timeScale = 1; - - #region Runtime Instantiation - /// Adds and prepares a SkeletonAnimation component to a GameObject at runtime. - /// The newly instantiated SkeletonAnimation - public static SkeletonAnimation AddToGameObject (GameObject gameObject, SkeletonDataAsset skeletonDataAsset) { - return SkeletonRenderer.AddSpineComponent(gameObject, skeletonDataAsset); - } - - /// Instantiates a new UnityEngine.GameObject and adds a prepared SkeletonAnimation component to it. - /// The newly instantiated SkeletonAnimation component. - public static SkeletonAnimation NewSkeletonAnimationGameObject (SkeletonDataAsset skeletonDataAsset) { - return SkeletonRenderer.NewSpineGameObject(skeletonDataAsset); - } - #endregion - - public override void Initialize (bool overwrite) { - if (valid && !overwrite) - return; - - base.Initialize(overwrite); - - if (!valid) - return; - - state = new Spine.AnimationState(skeletonDataAsset.GetAnimationStateData()); - - #if UNITY_EDITOR - if (!string.IsNullOrEmpty(_animationName)) { - if (Application.isPlaying) { - state.SetAnimation(0, _animationName, loop); - } else { - // Assume SkeletonAnimation is valid for skeletonData and skeleton. Checked above. - var animationObject = skeletonDataAsset.GetSkeletonData(false).FindAnimation(_animationName); - if (animationObject != null) - animationObject.Apply(skeleton, 0f, 0f, false, null); - } - Update(0); - } - #else - if (!string.IsNullOrEmpty(_animationName)) { - state.SetAnimation(0, _animationName, loop); - Update(0); - } - #endif - } - - public virtual void Update () { - Update(Time.deltaTime); - } - - public virtual void Update (float deltaTime) { - if (!valid) - return; - - deltaTime *= timeScale; - skeleton.Update(deltaTime); - state.Update(deltaTime); - state.Apply(skeleton); - - if (_UpdateLocal != null) - _UpdateLocal(this); - - skeleton.UpdateWorldTransform(); - - if (_UpdateWorld != null) { - _UpdateWorld(this); - skeleton.UpdateWorldTransform(); - } - - if (_UpdateComplete != null) { - _UpdateComplete(this); - } - } - - } - +using System; +using UnityEngine; + +namespace Spine.Unity { + + [ExecuteInEditMode] + [AddComponentMenu("Spine/SkeletonAnimation")] + [HelpURL("http://esotericsoftware.com/spine-unity-documentation#Controlling-Animation")] + public class SkeletonAnimation : SkeletonRenderer, ISkeletonAnimation, Spine.Unity.IAnimationStateComponent { + + /// + /// This is the Spine.AnimationState object of this SkeletonAnimation. You can control animations through it. + /// Note that this object, like .skeleton, is not guaranteed to exist in Awake. Do all accesses and caching to it in Start + public Spine.AnimationState state; + public Spine.AnimationState AnimationState { get { return this.state; } } + + /// + /// Occurs after the animations are applied and before world space values are resolved. + /// Use this callback when you want to set bone local values. + /// + public event UpdateBonesDelegate UpdateLocal { + add { _UpdateLocal += value; } + remove { _UpdateLocal -= value; } + } + + /// + /// Occurs after the Skeleton's bone world space values are resolved (including all constraints). + /// Using this callback will cause the world space values to be solved an extra time. + /// Use this callback if want to use bone world space values, and also set bone local values. + /// + public event UpdateBonesDelegate UpdateWorld { + add { _UpdateWorld += value; } + remove { _UpdateWorld -= value; } + } + + /// + /// Occurs after the Skeleton's bone world space values are resolved (including all constraints). + /// Use this callback if you want to use bone world space values, but don't intend to modify bone local values. + /// This callback can also be used when setting world position and the bone matrix. + /// + public event UpdateBonesDelegate UpdateComplete { + add { _UpdateComplete += value; } + remove { _UpdateComplete -= value; } + } + + protected event UpdateBonesDelegate _UpdateLocal; + protected event UpdateBonesDelegate _UpdateWorld; + protected event UpdateBonesDelegate _UpdateComplete; + + [SerializeField] + [SpineAnimation] + private String _animationName; + public String AnimationName { + get { + if (!valid) { + Debug.LogWarning("You tried access AnimationName but the SkeletonAnimation was not valid. Try checking your Skeleton Data for errors."); + return null; + } + + TrackEntry entry = state.GetCurrent(0); + return entry == null ? null : entry.Animation.Name; + } + set { + if (_animationName == value) + return; + _animationName = value; + + if (!valid) { + Debug.LogWarning("You tried to change AnimationName but the SkeletonAnimation was not valid. Try checking your Skeleton Data for errors."); + return; + } + + if (string.IsNullOrEmpty(value)) + state.ClearTrack(0); + else + state.SetAnimation(0, value, loop); + } + } + + /// Whether or not an animation should loop. This only applies to the initial animation specified in the inspector, or any subsequent Animations played through .AnimationName. Animations set through state.SetAnimation are unaffected. + [Tooltip("Whether or not an animation should loop. This only applies to the initial animation specified in the inspector, or any subsequent Animations played through .AnimationName. Animations set through state.SetAnimation are unaffected.")] + public bool loop; + + /// + /// The rate at which animations progress over time. 1 means 100%. 0.5 means 50%. + /// AnimationState and TrackEntry also have their own timeScale. These are combined multiplicatively. + [Tooltip("The rate at which animations progress over time. 1 means 100%. 0.5 means 50%.")] + public float timeScale = 1; + + #region Runtime Instantiation + /// Adds and prepares a SkeletonAnimation component to a GameObject at runtime. + /// The newly instantiated SkeletonAnimation + public static SkeletonAnimation AddToGameObject (GameObject gameObject, SkeletonDataAsset skeletonDataAsset) { + return SkeletonRenderer.AddSpineComponent(gameObject, skeletonDataAsset); + } + + /// Instantiates a new UnityEngine.GameObject and adds a prepared SkeletonAnimation component to it. + /// The newly instantiated SkeletonAnimation component. + public static SkeletonAnimation NewSkeletonAnimationGameObject (SkeletonDataAsset skeletonDataAsset) { + return SkeletonRenderer.NewSpineGameObject(skeletonDataAsset); + } + #endregion + + public override void Initialize (bool overwrite) { + if (valid && !overwrite) + return; + + base.Initialize(overwrite); + + if (!valid) + return; + + state = new Spine.AnimationState(skeletonDataAsset.GetAnimationStateData()); + + #if UNITY_EDITOR + if (!string.IsNullOrEmpty(_animationName)) { + if (Application.isPlaying) { + state.SetAnimation(0, _animationName, loop); + } else { + // Assume SkeletonAnimation is valid for skeletonData and skeleton. Checked above. + var animationObject = skeletonDataAsset.GetSkeletonData(false).FindAnimation(_animationName); + if (animationObject != null) + animationObject.Apply(skeleton, 0f, 0f, false, null); + } + Update(0); + } + #else + if (!string.IsNullOrEmpty(_animationName)) { + state.SetAnimation(0, _animationName, loop); + Update(0); + } + #endif + } + + public virtual void Update () { + Update(Time.deltaTime); + } + + public virtual void Update (float deltaTime) { + if (!valid) + return; + + deltaTime *= timeScale; + skeleton.Update(deltaTime); + state.Update(deltaTime); + state.Apply(skeleton); + + if (_UpdateLocal != null) + _UpdateLocal(this); + + skeleton.UpdateWorldTransform(); + + if (_UpdateWorld != null) { + _UpdateWorld(this); + skeleton.UpdateWorldTransform(); + } + + if (_UpdateComplete != null) { + _UpdateComplete(this); + } + } + + } + } diff --git a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs index 18ff0965c9..23baee3f74 100644 --- a/spine-unity/Assets/spine-unity/SkeletonRenderer.cs +++ b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs @@ -1,776 +1,775 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#define SPINE_OPTIONAL_RENDEROVERRIDE -#define SPINE_OPTIONAL_MATERIALOVERRIDE -#define SPINE_OPTIONAL_NORMALS -#define SPINE_OPTIONAL_SOLVETANGENTS - -//#define SPINE_OPTIONAL_FRONTFACING -//#define SPINE_OPTIONAL_SUBMESHRENDERER // Deprecated - -using System; -using System.Collections.Generic; -using UnityEngine; -using Spine.Unity.MeshGeneration; - -namespace Spine.Unity { - /// Renders a skeleton. - [ExecuteInEditMode, RequireComponent(typeof(MeshFilter), typeof(MeshRenderer)), DisallowMultipleComponent] - [HelpURL("http://esotericsoftware.com/spine-unity-documentation#Rendering")] - public class SkeletonRenderer : MonoBehaviour, ISkeletonComponent { - - public delegate void SkeletonRendererDelegate (SkeletonRenderer skeletonRenderer); - public SkeletonRendererDelegate OnRebuild; - - public SkeletonDataAsset skeletonDataAsset; - public SkeletonDataAsset SkeletonDataAsset { get { return skeletonDataAsset; } } - public String initialSkinName; - - #region Advanced - // Submesh Separation - [UnityEngine.Serialization.FormerlySerializedAs("submeshSeparators")] - [SpineSlot] - public string[] separatorSlotNames = new string[0]; - [System.NonSerialized] - public readonly List separatorSlots = new List(); - - public float zSpacing; - public bool renderMeshes = true, immutableTriangles; - public bool pmaVertexColors = true; - - #if SPINE_OPTIONAL_NORMALS - public bool calculateNormals; - #endif - #if SPINE_OPTIONAL_SOLVETANGENTS - public bool calculateTangents; - #endif - #if SPINE_OPTIONAL_FRONTFACING - public bool frontFacing; - #endif - - public bool logErrors = false; - - #if SPINE_OPTIONAL_RENDEROVERRIDE - public bool disableRenderingOnOverride = true; - public delegate void InstructionDelegate (SkeletonRenderer.SmartMesh.Instruction instruction); - event InstructionDelegate generateMeshOverride; - public event InstructionDelegate GenerateMeshOverride { - add { - generateMeshOverride += value; - if (disableRenderingOnOverride && generateMeshOverride != null) { - Initialize(false); - meshRenderer.enabled = false; - } - } - remove { - generateMeshOverride -= value; - if (disableRenderingOnOverride && generateMeshOverride == null) { - Initialize(false); - meshRenderer.enabled = true; - } - } - } - #endif - - #if SPINE_OPTIONAL_SUBMESHRENDERER - private Spine.Unity.Modules.SkeletonUtilitySubmeshRenderer[] submeshRenderers; - #endif - - #if SPINE_OPTIONAL_MATERIALOVERRIDE - [System.NonSerialized] readonly Dictionary customMaterialOverride = new Dictionary(); - public Dictionary CustomMaterialOverride { get { return customMaterialOverride; } } - #endif - - // Custom Slot Material - [System.NonSerialized] readonly Dictionary customSlotMaterials = new Dictionary(); - public Dictionary CustomSlotMaterials { get { return customSlotMaterials; } } - #endregion - - MeshRenderer meshRenderer; - MeshFilter meshFilter; - - [System.NonSerialized] public bool valid; - [System.NonSerialized] public Skeleton skeleton; - public Skeleton Skeleton { - get { - Initialize(false); - return skeleton; - } - } - - Spine.Unity.DoubleBuffered doubleBufferedMesh; - readonly SmartMesh.Instruction currentInstructions = new SmartMesh.Instruction(); - readonly ExposedList submeshes = new ExposedList(); - readonly ExposedList submeshMaterials = new ExposedList(); - Material[] sharedMaterials = new Material[0]; - float[] tempVertices = new float[8]; - Vector3[] vertices; - Color32[] colors; - Vector2[] uvs; - #if SPINE_OPTIONAL_NORMALS - Vector3[] normals; - #endif - #if SPINE_OPTIONAL_SOLVETANGENTS - Vector4[] tangents; - Vector2[] tempTanBuffer; - #endif - - #region Runtime Instantiation - public static T NewSpineGameObject (SkeletonDataAsset skeletonDataAsset) where T : SkeletonRenderer { - return SkeletonRenderer.AddSpineComponent(new GameObject("New Spine GameObject"), skeletonDataAsset); - } - - /// Add and prepare a Spine component that derives from SkeletonRenderer to a GameObject at runtime. - /// T should be SkeletonRenderer or any of its derived classes. - public static T AddSpineComponent (GameObject gameObject, SkeletonDataAsset skeletonDataAsset) where T : SkeletonRenderer { - var c = gameObject.AddComponent(); - if (skeletonDataAsset != null) { - c.skeletonDataAsset = skeletonDataAsset; - c.Initialize(false); - } - return c; - } - #endregion - - public virtual void Awake () { - Initialize(false); - } - - public virtual void Initialize (bool overwrite) { - if (valid && !overwrite) - return; - - // Clear - { - if (meshFilter != null) - meshFilter.sharedMesh = null; - - meshRenderer = GetComponent(); - if (meshRenderer != null) meshRenderer.sharedMaterial = null; - - currentInstructions.Clear(); - vertices = null; - colors = null; - uvs = null; - sharedMaterials = new Material[0]; - submeshMaterials.Clear(); - submeshes.Clear(); - skeleton = null; - - valid = false; - } - - if (!skeletonDataAsset) { - if (logErrors) - Debug.LogError("Missing SkeletonData asset.", this); - - return; - } - SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(false); - if (skeletonData == null) - return; - valid = true; - - meshFilter = GetComponent(); - meshRenderer = GetComponent(); - doubleBufferedMesh = new DoubleBuffered(); - vertices = new Vector3[0]; - - skeleton = new Skeleton(skeletonData); - if (!string.IsNullOrEmpty(initialSkinName) && initialSkinName != "default") - skeleton.SetSkin(initialSkinName); - - separatorSlots.Clear(); - for (int i = 0; i < separatorSlotNames.Length; i++) - separatorSlots.Add(skeleton.FindSlot(separatorSlotNames[i])); - - #if SPINE_OPTIONAL_SUBMESHRENDERER - submeshRenderers = GetComponentsInChildren(); - #endif - - LateUpdate(); - - if (OnRebuild != null) - OnRebuild(this); - } - - public virtual void LateUpdate () { - if (!valid) - return; - - if ( - (!meshRenderer.enabled) - #if SPINE_OPTIONAL_RENDEROVERRIDE - && this.generateMeshOverride == null - #endif - #if SPINE_OPTIONAL_SUBMESHRENDERER - && submeshRenderers.Length > 0 - #endif - ) - return; - - - // STEP 1. Determine a SmartMesh.Instruction. Split up instructions into submeshes. ============================================================ - ExposedList drawOrder = skeleton.drawOrder; - var drawOrderItems = drawOrder.Items; - int drawOrderCount = drawOrder.Count; - bool renderMeshes = this.renderMeshes; - - // Clear last state of attachments and submeshes - var workingInstruction = this.currentInstructions; - var workingAttachments = workingInstruction.attachments; - workingAttachments.Clear(false); - workingAttachments.GrowIfNeeded(drawOrderCount); - workingAttachments.Count = drawOrderCount; - var workingAttachmentsItems = workingInstruction.attachments.Items; - - #if SPINE_OPTIONAL_FRONTFACING - var workingFlips = workingInstruction.attachmentFlips; - workingFlips.Clear(false); - workingFlips.GrowIfNeeded(drawOrderCount); - workingFlips.Count = drawOrderCount; - var workingFlipsItems = workingFlips.Items; - #endif - - var workingSubmeshInstructions = workingInstruction.submeshInstructions; // Items array should not be cached. There is dynamic writing to this list. - workingSubmeshInstructions.Clear(false); - - #if !SPINE_TK2D - bool isCustomSlotMaterialsPopulated = customSlotMaterials.Count > 0; - #endif - - int vertexCount = 0; - int submeshVertexCount = 0; - int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0; - Material lastMaterial = null; - for (int i = 0; i < drawOrderCount; i++) { - Slot slot = drawOrderItems[i]; - Attachment attachment = slot.attachment; - workingAttachmentsItems[i] = attachment; - - #if SPINE_OPTIONAL_FRONTFACING - bool flip = frontFacing && (slot.bone.WorldSignX != slot.bone.WorldSignY); - workingFlipsItems[i] = flip; - #endif - - object rendererObject; // An AtlasRegion in plain Spine-Unity. Spine-TK2D hooks into TK2D's system. eventual source of Material object. - int attachmentVertexCount, attachmentTriangleCount; - - var regionAttachment = attachment as RegionAttachment; - if (regionAttachment != null) { - rendererObject = regionAttachment.RendererObject; - attachmentVertexCount = 4; - attachmentTriangleCount = 6; - } else { - if (!renderMeshes) - continue; - var meshAttachment = attachment as MeshAttachment; - if (meshAttachment != null) { - rendererObject = meshAttachment.RendererObject; - attachmentVertexCount = meshAttachment.worldVerticesLength >> 1; - attachmentTriangleCount = meshAttachment.triangles.Length; - } else { - continue; - } - } - - #if !SPINE_TK2D - Material material; //= (Material)((AtlasRegion)rendererObject).page.rendererObject; // For no customSlotMaterials - if (isCustomSlotMaterialsPopulated) { - if (!customSlotMaterials.TryGetValue(slot, out material)) { - material = (Material)((AtlasRegion)rendererObject).page.rendererObject; - } - } else { - material = (Material)((AtlasRegion)rendererObject).page.rendererObject; - } - #else - Material material = (rendererObject.GetType() == typeof(Material)) ? (Material)rendererObject : (Material)((AtlasRegion)rendererObject).page.rendererObject; - #endif - - // Create a new SubmeshInstruction when material changes. (or when forced to separate by a submeshSeparator) - bool forceSeparate = (separatorSlots.Count > 0 && separatorSlots.Contains(slot)); - if (vertexCount > 0 && (lastMaterial.GetInstanceID() != material.GetInstanceID() || forceSeparate)) { - workingSubmeshInstructions.Add( - new Spine.Unity.MeshGeneration.SubmeshInstruction { - skeleton = this.skeleton, - material = lastMaterial, - startSlot = submeshStartSlotIndex, - endSlot = i, - triangleCount = submeshTriangleCount, - firstVertexIndex = submeshFirstVertex, - vertexCount = submeshVertexCount, - forceSeparate = forceSeparate - } - ); - submeshTriangleCount = 0; - submeshVertexCount = 0; - submeshFirstVertex = vertexCount; - submeshStartSlotIndex = i; - } - // Update state for the next iteration. - lastMaterial = material; - submeshTriangleCount += attachmentTriangleCount; - vertexCount += attachmentVertexCount; - submeshVertexCount += attachmentVertexCount; - } - - if (submeshVertexCount != 0) { - workingSubmeshInstructions.Add( - new Spine.Unity.MeshGeneration.SubmeshInstruction { - skeleton = this.skeleton, - material = lastMaterial, - startSlot = submeshStartSlotIndex, - endSlot = drawOrderCount, - triangleCount = submeshTriangleCount, - firstVertexIndex = submeshFirstVertex, - vertexCount = submeshVertexCount, - forceSeparate = false - } - ); - } - - workingInstruction.vertexCount = vertexCount; - workingInstruction.immutableTriangles = this.immutableTriangles; - #if SPINE_OPTIONAL_FRONTFACING - workingInstruction.frontFacing = this.frontFacing; - #endif - - - // STEP 1.9. Post-process workingInstructions. ============================================================ - - #if SPINE_OPTIONAL_MATERIALOVERRIDE - // Material overrides are done here so they can be applied per submesh instead of per slot - // but they will still be passed through the GenerateMeshOverride delegate, - // and will still go through the normal material match check step in STEP 3. - if (customMaterialOverride.Count > 0) { // isCustomMaterialOverridePopulated - var workingSubmeshInstructionsItems = workingSubmeshInstructions.Items; - for (int i = 0; i < workingSubmeshInstructions.Count; i++) { - var m = workingSubmeshInstructionsItems[i].material; - Material mo; - if (customMaterialOverride.TryGetValue(m, out mo)) { - workingSubmeshInstructionsItems[i].material = mo; - } - } - } - #endif - #if SPINE_OPTIONAL_RENDEROVERRIDE - if (this.generateMeshOverride != null) { - this.generateMeshOverride(workingInstruction); - if (disableRenderingOnOverride) return; - } - #endif - - - // STEP 2. Update vertex buffer based on verts from the attachments. ============================================================ - // Uses values that were also stored in workingInstruction. - bool vertexCountIncreased = ArraysMeshGenerator.EnsureSize(vertexCount, ref this.vertices, ref this.uvs, ref this.colors); - #if SPINE_OPTIONAL_NORMALS - if (vertexCountIncreased && calculateNormals) { - Vector3[] localNormals = this.normals = new Vector3[vertexCount]; - Vector3 normal = new Vector3(0, 0, -1); - for (int i = 0; i < vertexCount; i++) - localNormals[i] = normal; - } - #endif - - Vector3 meshBoundsMin; - Vector3 meshBoundsMax; - if (vertexCount <= 0) { - meshBoundsMin = new Vector3(0, 0, 0); - meshBoundsMax = new Vector3(0, 0, 0); - } else { - meshBoundsMin.x = int.MaxValue; - meshBoundsMin.y = int.MaxValue; - meshBoundsMax.x = int.MinValue; - meshBoundsMax.y = int.MinValue; - - if (zSpacing > 0f) { - meshBoundsMin.z = 0f; - meshBoundsMax.z = zSpacing * (drawOrderCount - 1); - } else { - meshBoundsMin.z = zSpacing * (drawOrderCount - 1); - meshBoundsMax.z = 0f; - } - } - int vertexIndex = 0; - ArraysMeshGenerator.FillVerts(skeleton, 0, drawOrderCount, this.zSpacing, pmaVertexColors, this.vertices, this.uvs, this.colors, ref vertexIndex, ref tempVertices, ref meshBoundsMin, ref meshBoundsMax, renderMeshes); - - - // Step 3. Move the mesh data into a UnityEngine.Mesh ============================================================ - var currentSmartMesh = doubleBufferedMesh.GetNext(); // Double-buffer for performance. - var currentMesh = currentSmartMesh.mesh; - currentMesh.vertices = this.vertices; - currentMesh.colors32 = colors; - currentMesh.uv = uvs; - currentMesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax); - - var currentSmartMeshInstructionUsed = currentSmartMesh.instructionUsed; - #if SPINE_OPTIONAL_NORMALS - if (calculateNormals && currentSmartMeshInstructionUsed.vertexCount < vertexCount) - currentMesh.normals = normals; - #endif - - // Check if the triangles should also be updated. - // This thorough structure check is cheaper than updating triangles every frame. - bool mustUpdateMeshStructure = CheckIfMustUpdateMeshStructure(workingInstruction, currentSmartMeshInstructionUsed); - int submeshCount = workingSubmeshInstructions.Count; - if (mustUpdateMeshStructure) { - var thisSubmeshMaterials = this.submeshMaterials; - thisSubmeshMaterials.Clear(false); - - int oldSubmeshCount = submeshes.Count; - - if (submeshes.Capacity < submeshCount) - submeshes.Capacity = submeshCount; - for (int i = oldSubmeshCount; i < submeshCount; i++) - submeshes.Items[i] = new ArraysMeshGenerator.SubmeshTriangleBuffer(workingSubmeshInstructions.Items[i].triangleCount); - submeshes.Count = submeshCount; - - var mutableTriangles = !workingInstruction.immutableTriangles; - for (int i = 0, last = submeshCount - 1; i < submeshCount; i++) { - var submeshInstruction = workingSubmeshInstructions.Items[i]; - - if (mutableTriangles || i >= oldSubmeshCount) { - - #if !SPINE_OPTIONAL_FRONTFACING - var currentSubmesh = submeshes.Items[i]; - int instructionTriangleCount = submeshInstruction.triangleCount; - if (renderMeshes) { - ArraysMeshGenerator.FillTriangles(ref currentSubmesh.triangles, skeleton, instructionTriangleCount, submeshInstruction.firstVertexIndex, submeshInstruction.startSlot, submeshInstruction.endSlot, (i == last)); - currentSubmesh.triangleCount = instructionTriangleCount; - } else { - ArraysMeshGenerator.FillTrianglesQuads(ref currentSubmesh.triangles, ref currentSubmesh.triangleCount, ref currentSubmesh.firstVertex, submeshInstruction.firstVertexIndex, instructionTriangleCount, (i == last)); - } - #else - SetSubmesh(i, submeshInstruction, currentInstructions.attachmentFlips, i == last); - #endif - - } - - thisSubmeshMaterials.Add(submeshInstruction.material); - } - - currentMesh.subMeshCount = submeshCount; - - for (int i = 0; i < submeshCount; ++i) - currentMesh.SetTriangles(submeshes.Items[i].triangles, i); - } - - #if SPINE_OPTIONAL_SOLVETANGENTS - if (calculateTangents) { - ArraysMeshGenerator.SolveTangents2DEnsureSize(ref this.tangents, ref this.tempTanBuffer, vertices.Length); - for (int i = 0; i < submeshCount; i++) { - var submesh = submeshes.Items[i]; - ArraysMeshGenerator.SolveTangents2DTriangles(this.tempTanBuffer, submesh.triangles, submesh.triangleCount, this.vertices, this.uvs, vertexCount); - } - ArraysMeshGenerator.SolveTangents2DBuffer(this.tangents, this.tempTanBuffer, vertexCount); - currentMesh.tangents = this.tangents; - } - #endif - - // CheckIfMustUpdateMaterialArray (last pushed materials vs currently parsed materials) - // Needs to check against the Working Submesh Instructions Materials instead of the cached submeshMaterials. - { - var lastPushedMaterials = this.sharedMaterials; - bool mustUpdateRendererMaterials = mustUpdateMeshStructure || - (lastPushedMaterials.Length != submeshCount); - - if (!mustUpdateRendererMaterials) { - var workingSubmeshInstructionsItems = workingSubmeshInstructions.Items; - for (int i = 0, n = lastPushedMaterials.Length; i < n; i++) { - if (lastPushedMaterials[i].GetInstanceID() != workingSubmeshInstructionsItems[i].material.GetInstanceID()) { // Bounds check is implied above. - mustUpdateRendererMaterials = true; - break; - } - } - } - - if (mustUpdateRendererMaterials) { - if (submeshMaterials.Count == sharedMaterials.Length) - submeshMaterials.CopyTo(sharedMaterials); - else - sharedMaterials = submeshMaterials.ToArray(); - - meshRenderer.sharedMaterials = sharedMaterials; - } - } - - - // Step 4. The UnityEngine.Mesh is ready. Set it as the MeshFilter's mesh. Store the instructions used for that mesh. ============================================================ - meshFilter.sharedMesh = currentMesh; - currentSmartMesh.instructionUsed.Set(workingInstruction); - - - #if SPINE_OPTIONAL_SUBMESHRENDERER - if (submeshRenderers.Length > 0) { - for (int i = 0; i < submeshRenderers.Length; i++) { - var submeshRenderer = submeshRenderers[i]; - if (submeshRenderer.submeshIndex < sharedMaterials.Length) - submeshRenderer.SetMesh(meshRenderer, currentMesh, sharedMaterials[submeshRenderer.submeshIndex]); - else - submeshRenderer.GetComponent().enabled = false; - } - } - #endif - } - - static bool CheckIfMustUpdateMeshStructure (SmartMesh.Instruction a, SmartMesh.Instruction b) { - - #if UNITY_EDITOR - if (!Application.isPlaying) - return true; - #endif - - if (a.vertexCount != b.vertexCount) - return true; - - if (a.immutableTriangles != b.immutableTriangles) - return true; - - int attachmentCountB = b.attachments.Count; - if (a.attachments.Count != attachmentCountB) // Bounds check for the looped storedAttachments count below. - return true; - - var attachmentsA = a.attachments.Items; - var attachmentsB = b.attachments.Items; - for (int i = 0; i < attachmentCountB; i++) { - if (attachmentsA[i] != attachmentsB[i]) - return true; - } - - #if SPINE_OPTIONAL_FRONTFACING - if (a.frontFacing != b.frontFacing) { // if settings changed - return true; - } else if (a.frontFacing) { // if settings matched, only need to check one. - var flipsA = a.attachmentFlips.Items; - var flipsB = b.attachmentFlips.Items; - for (int i = 0; i < attachmentCountB; i++) { - if (flipsA[i] != flipsB[i]) - return true; - } - } - #endif - - // Submesh count changed - int submeshCountA = a.submeshInstructions.Count; - int submeshCountB = b.submeshInstructions.Count; - if (submeshCountA != submeshCountB) - return true; - - // Submesh Instruction mismatch - var submeshInstructionsItemsA = a.submeshInstructions.Items; - var submeshInstructionsItemsB = b.submeshInstructions.Items; - for (int i = 0; i < submeshCountB; i++) { - var submeshA = submeshInstructionsItemsA[i]; - var submeshB = submeshInstructionsItemsB[i]; - - if (!( - submeshA.vertexCount == submeshB.vertexCount && - submeshA.startSlot == submeshB.startSlot && - submeshA.endSlot == submeshB.endSlot && - submeshA.triangleCount == submeshB.triangleCount && - submeshA.firstVertexIndex == submeshB.firstVertexIndex - )) - return true; - } - - return false; - } - - #if SPINE_OPTIONAL_FRONTFACING - void SetSubmesh (int submeshIndex, Spine.Unity.MeshGeneration.SubmeshInstruction submeshInstructions, ExposedList flipStates, bool isLastSubmesh) { - var currentSubmesh = submeshes.Items[submeshIndex]; - int[] triangles = currentSubmesh.triangles; - - int triangleCount = submeshInstructions.triangleCount; - int firstVertex = submeshInstructions.firstVertexIndex; - - int trianglesCapacity = triangles.Length; - if (isLastSubmesh && trianglesCapacity > triangleCount) { - // Last submesh may have more triangles than required, so zero triangles to the end. - for (int i = triangleCount; i < trianglesCapacity; i++) - triangles[i] = 0; - - currentSubmesh.triangleCount = triangleCount; - - } else if (trianglesCapacity != triangleCount) { - // Reallocate triangles when not the exact size needed. - currentSubmesh.triangles = triangles = new int[triangleCount]; - currentSubmesh.triangleCount = 0; - } - - if (!this.renderMeshes && !this.frontFacing) { - // Use stored triangles if possible. - if (currentSubmesh.firstVertex != firstVertex || currentSubmesh.triangleCount < triangleCount) { //|| currentSubmesh.triangleCount == 0 - currentSubmesh.triangleCount = triangleCount; - currentSubmesh.firstVertex = firstVertex; - - for (int i = 0; i < triangleCount; i += 6, firstVertex += 4) { - triangles[i] = firstVertex; - triangles[i + 1] = firstVertex + 2; - triangles[i + 2] = firstVertex + 1; - triangles[i + 3] = firstVertex + 2; - triangles[i + 4] = firstVertex + 3; - triangles[i + 5] = firstVertex + 1; - } - } - return; - } - - var flipStatesItems = flipStates.Items; - - // Iterate through all slots and store their triangles. - var drawOrderItems = skeleton.DrawOrder.Items; - int triangleIndex = 0; // Modified by loop - for (int i = submeshInstructions.startSlot, n = submeshInstructions.endSlot; i < n; i++) { - Attachment attachment = drawOrderItems[i].attachment; - bool flip = frontFacing && flipStatesItems[i]; - - // Add RegionAttachment triangles - if (attachment is RegionAttachment) { - if (!flip) { - triangles[triangleIndex] = firstVertex; - triangles[triangleIndex + 1] = firstVertex + 2; - triangles[triangleIndex + 2] = firstVertex + 1; - triangles[triangleIndex + 3] = firstVertex + 2; - triangles[triangleIndex + 4] = firstVertex + 3; - triangles[triangleIndex + 5] = firstVertex + 1; - } else { - triangles[triangleIndex] = firstVertex + 1; - triangles[triangleIndex + 1] = firstVertex + 2; - triangles[triangleIndex + 2] = firstVertex; - triangles[triangleIndex + 3] = firstVertex + 1; - triangles[triangleIndex + 4] = firstVertex + 3; - triangles[triangleIndex + 5] = firstVertex + 2; - } - - triangleIndex += 6; - firstVertex += 4; - continue; - } - - // Add (Weighted)MeshAttachment triangles - int[] attachmentTriangles; - int attachmentVertexCount; - var meshAttachment = attachment as MeshAttachment; - if (meshAttachment != null) { - attachmentVertexCount = meshAttachment.worldVerticesLength >> 1; // length/2 - attachmentTriangles = meshAttachment.triangles; - } else { - continue; - } - - if (flip) { - for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii += 3, triangleIndex += 3) { - triangles[triangleIndex + 2] = firstVertex + attachmentTriangles[ii]; - triangles[triangleIndex + 1] = firstVertex + attachmentTriangles[ii + 1]; - triangles[triangleIndex] = firstVertex + attachmentTriangles[ii + 2]; - } - } else { - for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleIndex++) { - triangles[triangleIndex] = firstVertex + attachmentTriangles[ii]; - } - } - - firstVertex += attachmentVertexCount; - } - } - #endif - - #if UNITY_EDITOR - void OnDrawGizmos () { - // Make scene view selection easier by drawing a clear gizmo over the skeleton. - meshFilter = GetComponent(); - if (meshFilter == null) return; - - Mesh mesh = meshFilter.sharedMesh; - if (mesh == null) return; - - Bounds meshBounds = mesh.bounds; - Gizmos.color = Color.clear; - Gizmos.matrix = transform.localToWorldMatrix; - Gizmos.DrawCube(meshBounds.center, meshBounds.size); - } - #endif - - ///This is a Mesh that also stores the instructions SkeletonRenderer generated for it. - public class SmartMesh { - public Mesh mesh = Spine.Unity.SpineMesh.NewMesh(); - public SmartMesh.Instruction instructionUsed = new SmartMesh.Instruction(); - - public class Instruction { - public bool immutableTriangles; - public int vertexCount = -1; - public readonly ExposedList attachments = new ExposedList(); - public readonly ExposedList submeshInstructions = new ExposedList(); - - #if SPINE_OPTIONAL_FRONTFACING - public bool frontFacing; - public readonly ExposedList attachmentFlips = new ExposedList(); - #endif - - public void Clear () { - this.attachments.Clear(false); - this.submeshInstructions.Clear(false); - - #if SPINE_OPTIONAL_FRONTFACING - this.attachmentFlips.Clear(false); - #endif - } - - public void Set (Instruction other) { - this.immutableTriangles = other.immutableTriangles; - this.vertexCount = other.vertexCount; - - this.attachments.Clear(false); - this.attachments.GrowIfNeeded(other.attachments.Capacity); - this.attachments.Count = other.attachments.Count; - other.attachments.CopyTo(this.attachments.Items); - - #if SPINE_OPTIONAL_FRONTFACING - this.frontFacing = other.frontFacing; - this.attachmentFlips.Clear(false); - this.attachmentFlips.GrowIfNeeded(other.attachmentFlips.Capacity); - this.attachmentFlips.Count = other.attachmentFlips.Count; - if (this.frontFacing) - other.attachmentFlips.CopyTo(this.attachmentFlips.Items); - #endif - - this.submeshInstructions.Clear(false); - this.submeshInstructions.GrowIfNeeded(other.submeshInstructions.Capacity); - this.submeshInstructions.Count = other.submeshInstructions.Count; - other.submeshInstructions.CopyTo(this.submeshInstructions.Items); - } - } - } - } +#define SPINE_OPTIONAL_RENDEROVERRIDE +#define SPINE_OPTIONAL_MATERIALOVERRIDE +#define SPINE_OPTIONAL_NORMALS +#define SPINE_OPTIONAL_SOLVETANGENTS + +//#define SPINE_OPTIONAL_FRONTFACING +//#define SPINE_OPTIONAL_SUBMESHRENDERER // Deprecated + +using System; +using System.Collections.Generic; +using UnityEngine; +using Spine.Unity.MeshGeneration; + +namespace Spine.Unity { + /// Renders a skeleton. + [ExecuteInEditMode, RequireComponent(typeof(MeshFilter), typeof(MeshRenderer)), DisallowMultipleComponent] + [HelpURL("http://esotericsoftware.com/spine-unity-documentation#Rendering")] + public class SkeletonRenderer : MonoBehaviour, ISkeletonComponent { + + public delegate void SkeletonRendererDelegate (SkeletonRenderer skeletonRenderer); + public SkeletonRendererDelegate OnRebuild; + + public SkeletonDataAsset skeletonDataAsset; + public SkeletonDataAsset SkeletonDataAsset { get { return skeletonDataAsset; } } + public String initialSkinName; + + #region Advanced + // Submesh Separation + [UnityEngine.Serialization.FormerlySerializedAs("submeshSeparators")] + [SpineSlot] + public string[] separatorSlotNames = new string[0]; + [System.NonSerialized] + public readonly List separatorSlots = new List(); + + public float zSpacing; + public bool renderMeshes = true, immutableTriangles; + public bool pmaVertexColors = true; + + #if SPINE_OPTIONAL_NORMALS + public bool calculateNormals; + #endif + #if SPINE_OPTIONAL_SOLVETANGENTS + public bool calculateTangents; + #endif + #if SPINE_OPTIONAL_FRONTFACING + public bool frontFacing; + #endif + + public bool logErrors = false; + + #if SPINE_OPTIONAL_RENDEROVERRIDE + public bool disableRenderingOnOverride = true; + public delegate void InstructionDelegate (SkeletonRenderer.SmartMesh.Instruction instruction); + event InstructionDelegate generateMeshOverride; + public event InstructionDelegate GenerateMeshOverride { + add { + generateMeshOverride += value; + if (disableRenderingOnOverride && generateMeshOverride != null) { + Initialize(false); + meshRenderer.enabled = false; + } + } + remove { + generateMeshOverride -= value; + if (disableRenderingOnOverride && generateMeshOverride == null) { + Initialize(false); + meshRenderer.enabled = true; + } + } + } + #endif + + #if SPINE_OPTIONAL_SUBMESHRENDERER + private Spine.Unity.Modules.SkeletonUtilitySubmeshRenderer[] submeshRenderers; + #endif + + #if SPINE_OPTIONAL_MATERIALOVERRIDE + [System.NonSerialized] readonly Dictionary customMaterialOverride = new Dictionary(); + public Dictionary CustomMaterialOverride { get { return customMaterialOverride; } } + #endif + + // Custom Slot Material + [System.NonSerialized] readonly Dictionary customSlotMaterials = new Dictionary(); + public Dictionary CustomSlotMaterials { get { return customSlotMaterials; } } + #endregion + + MeshRenderer meshRenderer; + MeshFilter meshFilter; + + [System.NonSerialized] public bool valid; + [System.NonSerialized] public Skeleton skeleton; + public Skeleton Skeleton { + get { + Initialize(false); + return skeleton; + } + } + + Spine.Unity.DoubleBuffered doubleBufferedMesh; + readonly SmartMesh.Instruction currentInstructions = new SmartMesh.Instruction(); + readonly ExposedList submeshes = new ExposedList(); + readonly ExposedList submeshMaterials = new ExposedList(); + Material[] sharedMaterials = new Material[0]; + float[] tempVertices = new float[8]; + Vector3[] vertices; + Color32[] colors; + Vector2[] uvs; + #if SPINE_OPTIONAL_NORMALS + Vector3[] normals; + #endif + #if SPINE_OPTIONAL_SOLVETANGENTS + Vector4[] tangents; + Vector2[] tempTanBuffer; + #endif + + #region Runtime Instantiation + public static T NewSpineGameObject (SkeletonDataAsset skeletonDataAsset) where T : SkeletonRenderer { + return SkeletonRenderer.AddSpineComponent(new GameObject("New Spine GameObject"), skeletonDataAsset); + } + + /// Add and prepare a Spine component that derives from SkeletonRenderer to a GameObject at runtime. + /// T should be SkeletonRenderer or any of its derived classes. + public static T AddSpineComponent (GameObject gameObject, SkeletonDataAsset skeletonDataAsset) where T : SkeletonRenderer { + var c = gameObject.AddComponent(); + if (skeletonDataAsset != null) { + c.skeletonDataAsset = skeletonDataAsset; + c.Initialize(false); + } + return c; + } + #endregion + + public virtual void Awake () { + Initialize(false); + } + + public virtual void Initialize (bool overwrite) { + if (valid && !overwrite) + return; + + // Clear + { + if (meshFilter != null) + meshFilter.sharedMesh = null; + + meshRenderer = GetComponent(); + if (meshRenderer != null) meshRenderer.sharedMaterial = null; + + currentInstructions.Clear(); + vertices = null; + colors = null; + uvs = null; + sharedMaterials = new Material[0]; + submeshMaterials.Clear(); + submeshes.Clear(); + skeleton = null; + + valid = false; + } + + if (!skeletonDataAsset) { + if (logErrors) + Debug.LogError("Missing SkeletonData asset.", this); + + return; + } + SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(false); + if (skeletonData == null) + return; + valid = true; + + meshFilter = GetComponent(); + meshRenderer = GetComponent(); + doubleBufferedMesh = new DoubleBuffered(); + vertices = new Vector3[0]; + + skeleton = new Skeleton(skeletonData); + if (!string.IsNullOrEmpty(initialSkinName) && initialSkinName != "default") + skeleton.SetSkin(initialSkinName); + + separatorSlots.Clear(); + for (int i = 0; i < separatorSlotNames.Length; i++) + separatorSlots.Add(skeleton.FindSlot(separatorSlotNames[i])); + + #if SPINE_OPTIONAL_SUBMESHRENDERER + submeshRenderers = GetComponentsInChildren(); + #endif + + LateUpdate(); + + if (OnRebuild != null) + OnRebuild(this); + } + + public virtual void LateUpdate () { + if (!valid) + return; + + if ( + (!meshRenderer.enabled) + #if SPINE_OPTIONAL_RENDEROVERRIDE + && this.generateMeshOverride == null + #endif + #if SPINE_OPTIONAL_SUBMESHRENDERER + && submeshRenderers.Length > 0 + #endif + ) + return; + + + // STEP 1. Determine a SmartMesh.Instruction. Split up instructions into submeshes. ============================================================ + ExposedList drawOrder = skeleton.drawOrder; + var drawOrderItems = drawOrder.Items; + int drawOrderCount = drawOrder.Count; + bool renderMeshes = this.renderMeshes; + + // Clear last state of attachments and submeshes + var workingInstruction = this.currentInstructions; + var workingAttachments = workingInstruction.attachments; + workingAttachments.Clear(false); + workingAttachments.GrowIfNeeded(drawOrderCount); + workingAttachments.Count = drawOrderCount; + var workingAttachmentsItems = workingInstruction.attachments.Items; + + #if SPINE_OPTIONAL_FRONTFACING + var workingFlips = workingInstruction.attachmentFlips; + workingFlips.Clear(false); + workingFlips.GrowIfNeeded(drawOrderCount); + workingFlips.Count = drawOrderCount; + var workingFlipsItems = workingFlips.Items; + #endif + + var workingSubmeshInstructions = workingInstruction.submeshInstructions; // Items array should not be cached. There is dynamic writing to this list. + workingSubmeshInstructions.Clear(false); + + #if !SPINE_TK2D + bool isCustomSlotMaterialsPopulated = customSlotMaterials.Count > 0; + #endif + + int vertexCount = 0; + int submeshVertexCount = 0; + int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0; + Material lastMaterial = null; + for (int i = 0; i < drawOrderCount; i++) { + Slot slot = drawOrderItems[i]; + Attachment attachment = slot.attachment; + workingAttachmentsItems[i] = attachment; + + #if SPINE_OPTIONAL_FRONTFACING + bool flip = frontFacing && (slot.bone.WorldSignX != slot.bone.WorldSignY); + workingFlipsItems[i] = flip; + #endif + + object rendererObject; // An AtlasRegion in plain Spine-Unity. Spine-TK2D hooks into TK2D's system. eventual source of Material object. + int attachmentVertexCount, attachmentTriangleCount; + + var regionAttachment = attachment as RegionAttachment; + if (regionAttachment != null) { + rendererObject = regionAttachment.RendererObject; + attachmentVertexCount = 4; + attachmentTriangleCount = 6; + } else { + if (!renderMeshes) + continue; + var meshAttachment = attachment as MeshAttachment; + if (meshAttachment != null) { + rendererObject = meshAttachment.RendererObject; + attachmentVertexCount = meshAttachment.worldVerticesLength >> 1; + attachmentTriangleCount = meshAttachment.triangles.Length; + } else { + continue; + } + } + + #if !SPINE_TK2D + Material material; //= (Material)((AtlasRegion)rendererObject).page.rendererObject; // For no customSlotMaterials + if (isCustomSlotMaterialsPopulated) { + if (!customSlotMaterials.TryGetValue(slot, out material)) { + material = (Material)((AtlasRegion)rendererObject).page.rendererObject; + } + } else { + material = (Material)((AtlasRegion)rendererObject).page.rendererObject; + } + #else + Material material = (rendererObject.GetType() == typeof(Material)) ? (Material)rendererObject : (Material)((AtlasRegion)rendererObject).page.rendererObject; + #endif + + // Create a new SubmeshInstruction when material changes. (or when forced to separate by a submeshSeparator) + bool forceSeparate = (separatorSlots.Count > 0 && separatorSlots.Contains(slot)); + if (vertexCount > 0 && (lastMaterial.GetInstanceID() != material.GetInstanceID() || forceSeparate)) { + workingSubmeshInstructions.Add( + new Spine.Unity.MeshGeneration.SubmeshInstruction { + skeleton = this.skeleton, + material = lastMaterial, + startSlot = submeshStartSlotIndex, + endSlot = i, + triangleCount = submeshTriangleCount, + firstVertexIndex = submeshFirstVertex, + vertexCount = submeshVertexCount, + forceSeparate = forceSeparate + } + ); + submeshTriangleCount = 0; + submeshVertexCount = 0; + submeshFirstVertex = vertexCount; + submeshStartSlotIndex = i; + } + // Update state for the next iteration. + lastMaterial = material; + submeshTriangleCount += attachmentTriangleCount; + vertexCount += attachmentVertexCount; + submeshVertexCount += attachmentVertexCount; + } + + if (submeshVertexCount != 0) { + workingSubmeshInstructions.Add( + new Spine.Unity.MeshGeneration.SubmeshInstruction { + skeleton = this.skeleton, + material = lastMaterial, + startSlot = submeshStartSlotIndex, + endSlot = drawOrderCount, + triangleCount = submeshTriangleCount, + firstVertexIndex = submeshFirstVertex, + vertexCount = submeshVertexCount, + forceSeparate = false + } + ); + } + + workingInstruction.vertexCount = vertexCount; + workingInstruction.immutableTriangles = this.immutableTriangles; + #if SPINE_OPTIONAL_FRONTFACING + workingInstruction.frontFacing = this.frontFacing; + #endif + + + // STEP 1.9. Post-process workingInstructions. ============================================================ + + #if SPINE_OPTIONAL_MATERIALOVERRIDE + // Material overrides are done here so they can be applied per submesh instead of per slot + // but they will still be passed through the GenerateMeshOverride delegate, + // and will still go through the normal material match check step in STEP 3. + if (customMaterialOverride.Count > 0) { // isCustomMaterialOverridePopulated + var workingSubmeshInstructionsItems = workingSubmeshInstructions.Items; + for (int i = 0; i < workingSubmeshInstructions.Count; i++) { + var m = workingSubmeshInstructionsItems[i].material; + Material mo; + if (customMaterialOverride.TryGetValue(m, out mo)) { + workingSubmeshInstructionsItems[i].material = mo; + } + } + } + #endif + #if SPINE_OPTIONAL_RENDEROVERRIDE + if (this.generateMeshOverride != null) { + this.generateMeshOverride(workingInstruction); + if (disableRenderingOnOverride) return; + } + #endif + + + // STEP 2. Update vertex buffer based on verts from the attachments. ============================================================ + // Uses values that were also stored in workingInstruction. + bool vertexCountIncreased = ArraysMeshGenerator.EnsureSize(vertexCount, ref this.vertices, ref this.uvs, ref this.colors); + #if SPINE_OPTIONAL_NORMALS + if (vertexCountIncreased && calculateNormals) { + Vector3[] localNormals = this.normals = new Vector3[vertexCount]; + Vector3 normal = new Vector3(0, 0, -1); + for (int i = 0; i < vertexCount; i++) + localNormals[i] = normal; + } + #endif + + Vector3 meshBoundsMin; + Vector3 meshBoundsMax; + if (vertexCount <= 0) { + meshBoundsMin = new Vector3(0, 0, 0); + meshBoundsMax = new Vector3(0, 0, 0); + } else { + meshBoundsMin.x = int.MaxValue; + meshBoundsMin.y = int.MaxValue; + meshBoundsMax.x = int.MinValue; + meshBoundsMax.y = int.MinValue; + + if (zSpacing > 0f) { + meshBoundsMin.z = 0f; + meshBoundsMax.z = zSpacing * (drawOrderCount - 1); + } else { + meshBoundsMin.z = zSpacing * (drawOrderCount - 1); + meshBoundsMax.z = 0f; + } + } + int vertexIndex = 0; + ArraysMeshGenerator.FillVerts(skeleton, 0, drawOrderCount, this.zSpacing, pmaVertexColors, this.vertices, this.uvs, this.colors, ref vertexIndex, ref tempVertices, ref meshBoundsMin, ref meshBoundsMax, renderMeshes); + + + // Step 3. Move the mesh data into a UnityEngine.Mesh ============================================================ + var currentSmartMesh = doubleBufferedMesh.GetNext(); // Double-buffer for performance. + var currentMesh = currentSmartMesh.mesh; + currentMesh.vertices = this.vertices; + currentMesh.colors32 = colors; + currentMesh.uv = uvs; + currentMesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax); + + var currentSmartMeshInstructionUsed = currentSmartMesh.instructionUsed; + #if SPINE_OPTIONAL_NORMALS + if (calculateNormals && currentSmartMeshInstructionUsed.vertexCount < vertexCount) + currentMesh.normals = normals; + #endif + + // Check if the triangles should also be updated. + // This thorough structure check is cheaper than updating triangles every frame. + bool mustUpdateMeshStructure = CheckIfMustUpdateMeshStructure(workingInstruction, currentSmartMeshInstructionUsed); + int submeshCount = workingSubmeshInstructions.Count; + if (mustUpdateMeshStructure) { + var thisSubmeshMaterials = this.submeshMaterials; + thisSubmeshMaterials.Clear(false); + + int oldSubmeshCount = submeshes.Count; + + if (submeshes.Capacity < submeshCount) + submeshes.Capacity = submeshCount; + for (int i = oldSubmeshCount; i < submeshCount; i++) + submeshes.Items[i] = new ArraysMeshGenerator.SubmeshTriangleBuffer(workingSubmeshInstructions.Items[i].triangleCount); + submeshes.Count = submeshCount; + + var mutableTriangles = !workingInstruction.immutableTriangles; + for (int i = 0, last = submeshCount - 1; i < submeshCount; i++) { + var submeshInstruction = workingSubmeshInstructions.Items[i]; + + if (mutableTriangles || i >= oldSubmeshCount) { + + #if !SPINE_OPTIONAL_FRONTFACING + var currentSubmesh = submeshes.Items[i]; + int instructionTriangleCount = submeshInstruction.triangleCount; + if (renderMeshes) { + ArraysMeshGenerator.FillTriangles(ref currentSubmesh.triangles, skeleton, instructionTriangleCount, submeshInstruction.firstVertexIndex, submeshInstruction.startSlot, submeshInstruction.endSlot, (i == last)); + currentSubmesh.triangleCount = instructionTriangleCount; + } else { + ArraysMeshGenerator.FillTrianglesQuads(ref currentSubmesh.triangles, ref currentSubmesh.triangleCount, ref currentSubmesh.firstVertex, submeshInstruction.firstVertexIndex, instructionTriangleCount, (i == last)); + } + #else + SetSubmesh(i, submeshInstruction, currentInstructions.attachmentFlips, i == last); + #endif + + } + + thisSubmeshMaterials.Add(submeshInstruction.material); + } + + currentMesh.subMeshCount = submeshCount; + + for (int i = 0; i < submeshCount; ++i) + currentMesh.SetTriangles(submeshes.Items[i].triangles, i); + } + + #if SPINE_OPTIONAL_SOLVETANGENTS + if (calculateTangents) { + ArraysMeshGenerator.SolveTangents2DEnsureSize(ref this.tangents, ref this.tempTanBuffer, vertices.Length); + for (int i = 0; i < submeshCount; i++) { + var submesh = submeshes.Items[i]; + ArraysMeshGenerator.SolveTangents2DTriangles(this.tempTanBuffer, submesh.triangles, submesh.triangleCount, this.vertices, this.uvs, vertexCount); + } + ArraysMeshGenerator.SolveTangents2DBuffer(this.tangents, this.tempTanBuffer, vertexCount); + currentMesh.tangents = this.tangents; + } + #endif + + // CheckIfMustUpdateMaterialArray (last pushed materials vs currently parsed materials) + // Needs to check against the Working Submesh Instructions Materials instead of the cached submeshMaterials. + { + var lastPushedMaterials = this.sharedMaterials; + bool mustUpdateRendererMaterials = mustUpdateMeshStructure || + (lastPushedMaterials.Length != submeshCount); + + if (!mustUpdateRendererMaterials) { + var workingSubmeshInstructionsItems = workingSubmeshInstructions.Items; + for (int i = 0, n = lastPushedMaterials.Length; i < n; i++) { + if (lastPushedMaterials[i].GetInstanceID() != workingSubmeshInstructionsItems[i].material.GetInstanceID()) { // Bounds check is implied above. + mustUpdateRendererMaterials = true; + break; + } + } + } + + if (mustUpdateRendererMaterials) { + if (submeshMaterials.Count == sharedMaterials.Length) + submeshMaterials.CopyTo(sharedMaterials); + else + sharedMaterials = submeshMaterials.ToArray(); + + meshRenderer.sharedMaterials = sharedMaterials; + } + } + + + // Step 4. The UnityEngine.Mesh is ready. Set it as the MeshFilter's mesh. Store the instructions used for that mesh. ============================================================ + meshFilter.sharedMesh = currentMesh; + currentSmartMesh.instructionUsed.Set(workingInstruction); + + + #if SPINE_OPTIONAL_SUBMESHRENDERER + if (submeshRenderers.Length > 0) { + for (int i = 0; i < submeshRenderers.Length; i++) { + var submeshRenderer = submeshRenderers[i]; + if (submeshRenderer.submeshIndex < sharedMaterials.Length) + submeshRenderer.SetMesh(meshRenderer, currentMesh, sharedMaterials[submeshRenderer.submeshIndex]); + else + submeshRenderer.GetComponent().enabled = false; + } + } + #endif + } + + static bool CheckIfMustUpdateMeshStructure (SmartMesh.Instruction a, SmartMesh.Instruction b) { + + #if UNITY_EDITOR + if (!Application.isPlaying) + return true; + #endif + + if (a.vertexCount != b.vertexCount) + return true; + + if (a.immutableTriangles != b.immutableTriangles) + return true; + + int attachmentCountB = b.attachments.Count; + if (a.attachments.Count != attachmentCountB) // Bounds check for the looped storedAttachments count below. + return true; + + var attachmentsA = a.attachments.Items; + var attachmentsB = b.attachments.Items; + for (int i = 0; i < attachmentCountB; i++) { + if (attachmentsA[i] != attachmentsB[i]) + return true; + } + + #if SPINE_OPTIONAL_FRONTFACING + if (a.frontFacing != b.frontFacing) { // if settings changed + return true; + } else if (a.frontFacing) { // if settings matched, only need to check one. + var flipsA = a.attachmentFlips.Items; + var flipsB = b.attachmentFlips.Items; + for (int i = 0; i < attachmentCountB; i++) { + if (flipsA[i] != flipsB[i]) + return true; + } + } + #endif + + // Submesh count changed + int submeshCountA = a.submeshInstructions.Count; + int submeshCountB = b.submeshInstructions.Count; + if (submeshCountA != submeshCountB) + return true; + + // Submesh Instruction mismatch + var submeshInstructionsItemsA = a.submeshInstructions.Items; + var submeshInstructionsItemsB = b.submeshInstructions.Items; + for (int i = 0; i < submeshCountB; i++) { + var submeshA = submeshInstructionsItemsA[i]; + var submeshB = submeshInstructionsItemsB[i]; + + if (!( + submeshA.vertexCount == submeshB.vertexCount && + submeshA.startSlot == submeshB.startSlot && + submeshA.endSlot == submeshB.endSlot && + submeshA.triangleCount == submeshB.triangleCount && + submeshA.firstVertexIndex == submeshB.firstVertexIndex + )) + return true; + } + + return false; + } + + #if SPINE_OPTIONAL_FRONTFACING + void SetSubmesh (int submeshIndex, Spine.Unity.MeshGeneration.SubmeshInstruction submeshInstructions, ExposedList flipStates, bool isLastSubmesh) { + var currentSubmesh = submeshes.Items[submeshIndex]; + int[] triangles = currentSubmesh.triangles; + + int triangleCount = submeshInstructions.triangleCount; + int firstVertex = submeshInstructions.firstVertexIndex; + + int trianglesCapacity = triangles.Length; + if (isLastSubmesh && trianglesCapacity > triangleCount) { + // Last submesh may have more triangles than required, so zero triangles to the end. + for (int i = triangleCount; i < trianglesCapacity; i++) + triangles[i] = 0; + + currentSubmesh.triangleCount = triangleCount; + + } else if (trianglesCapacity != triangleCount) { + // Reallocate triangles when not the exact size needed. + currentSubmesh.triangles = triangles = new int[triangleCount]; + currentSubmesh.triangleCount = 0; + } + + if (!this.renderMeshes && !this.frontFacing) { + // Use stored triangles if possible. + if (currentSubmesh.firstVertex != firstVertex || currentSubmesh.triangleCount < triangleCount) { //|| currentSubmesh.triangleCount == 0 + currentSubmesh.triangleCount = triangleCount; + currentSubmesh.firstVertex = firstVertex; + + for (int i = 0; i < triangleCount; i += 6, firstVertex += 4) { + triangles[i] = firstVertex; + triangles[i + 1] = firstVertex + 2; + triangles[i + 2] = firstVertex + 1; + triangles[i + 3] = firstVertex + 2; + triangles[i + 4] = firstVertex + 3; + triangles[i + 5] = firstVertex + 1; + } + } + return; + } + + var flipStatesItems = flipStates.Items; + + // Iterate through all slots and store their triangles. + var drawOrderItems = skeleton.DrawOrder.Items; + int triangleIndex = 0; // Modified by loop + for (int i = submeshInstructions.startSlot, n = submeshInstructions.endSlot; i < n; i++) { + Attachment attachment = drawOrderItems[i].attachment; + bool flip = frontFacing && flipStatesItems[i]; + + // Add RegionAttachment triangles + if (attachment is RegionAttachment) { + if (!flip) { + triangles[triangleIndex] = firstVertex; + triangles[triangleIndex + 1] = firstVertex + 2; + triangles[triangleIndex + 2] = firstVertex + 1; + triangles[triangleIndex + 3] = firstVertex + 2; + triangles[triangleIndex + 4] = firstVertex + 3; + triangles[triangleIndex + 5] = firstVertex + 1; + } else { + triangles[triangleIndex] = firstVertex + 1; + triangles[triangleIndex + 1] = firstVertex + 2; + triangles[triangleIndex + 2] = firstVertex; + triangles[triangleIndex + 3] = firstVertex + 1; + triangles[triangleIndex + 4] = firstVertex + 3; + triangles[triangleIndex + 5] = firstVertex + 2; + } + + triangleIndex += 6; + firstVertex += 4; + continue; + } + + // Add (Weighted)MeshAttachment triangles + int[] attachmentTriangles; + int attachmentVertexCount; + var meshAttachment = attachment as MeshAttachment; + if (meshAttachment != null) { + attachmentVertexCount = meshAttachment.worldVerticesLength >> 1; // length/2 + attachmentTriangles = meshAttachment.triangles; + } else { + continue; + } + + if (flip) { + for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii += 3, triangleIndex += 3) { + triangles[triangleIndex + 2] = firstVertex + attachmentTriangles[ii]; + triangles[triangleIndex + 1] = firstVertex + attachmentTriangles[ii + 1]; + triangles[triangleIndex] = firstVertex + attachmentTriangles[ii + 2]; + } + } else { + for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleIndex++) { + triangles[triangleIndex] = firstVertex + attachmentTriangles[ii]; + } + } + + firstVertex += attachmentVertexCount; + } + } + #endif + + #if UNITY_EDITOR + void OnDrawGizmos () { + // Make scene view selection easier by drawing a clear gizmo over the skeleton. + meshFilter = GetComponent(); + if (meshFilter == null) return; + + Mesh mesh = meshFilter.sharedMesh; + if (mesh == null) return; + + Bounds meshBounds = mesh.bounds; + Gizmos.color = Color.clear; + Gizmos.matrix = transform.localToWorldMatrix; + Gizmos.DrawCube(meshBounds.center, meshBounds.size); + } + #endif + + ///This is a Mesh that also stores the instructions SkeletonRenderer generated for it. + public class SmartMesh { + public Mesh mesh = Spine.Unity.SpineMesh.NewMesh(); + public SmartMesh.Instruction instructionUsed = new SmartMesh.Instruction(); + + public class Instruction { + public bool immutableTriangles; + public int vertexCount = -1; + public readonly ExposedList attachments = new ExposedList(); + public readonly ExposedList submeshInstructions = new ExposedList(); + + #if SPINE_OPTIONAL_FRONTFACING + public bool frontFacing; + public readonly ExposedList attachmentFlips = new ExposedList(); + #endif + + public void Clear () { + this.attachments.Clear(false); + this.submeshInstructions.Clear(false); + + #if SPINE_OPTIONAL_FRONTFACING + this.attachmentFlips.Clear(false); + #endif + } + + public void Set (Instruction other) { + this.immutableTriangles = other.immutableTriangles; + this.vertexCount = other.vertexCount; + + this.attachments.Clear(false); + this.attachments.GrowIfNeeded(other.attachments.Capacity); + this.attachments.Count = other.attachments.Count; + other.attachments.CopyTo(this.attachments.Items); + + #if SPINE_OPTIONAL_FRONTFACING + this.frontFacing = other.frontFacing; + this.attachmentFlips.Clear(false); + this.attachmentFlips.GrowIfNeeded(other.attachmentFlips.Capacity); + this.attachmentFlips.Count = other.attachmentFlips.Count; + if (this.frontFacing) + other.attachmentFlips.CopyTo(this.attachmentFlips.Items); + #endif + + this.submeshInstructions.Clear(false); + this.submeshInstructions.GrowIfNeeded(other.submeshInstructions.Capacity); + this.submeshInstructions.Count = other.submeshInstructions.Count; + other.submeshInstructions.CopyTo(this.submeshInstructions.Items); + } + } + } + } } diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilitySubmeshRendererInspector.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilitySubmeshRendererInspector.cs index bf47ba50b7..c854bacc47 100644 --- a/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilitySubmeshRendererInspector.cs +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/Editor/SkeletonUtilitySubmeshRendererInspector.cs @@ -1,49 +1,49 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEngine; -using UnityEditor; -using Spine.Unity.Editor; -namespace Spine.Unity.Modules { - [CustomEditor(typeof(SkeletonUtilitySubmeshRenderer))] - public class SkeletonUtilitySubmeshRendererInspector : UnityEditor.Editor { - public SpineInspectorUtility.SerializedSortingProperties sorting; - - void OnEnable () { - sorting = new SpineInspectorUtility.SerializedSortingProperties((target as Component).GetComponent()); - } - - public override void OnInspectorGUI () { - EditorGUILayout.HelpBox("SkeletonUtilitySubmeshRenderer is now obsolete. We recommend using SkeletonRenderSeparator.", MessageType.Info); - SpineInspectorUtility.SortingPropertyFields(sorting, true); - } - } +using UnityEngine; +using UnityEditor; +using Spine.Unity.Editor; + +namespace Spine.Unity.Modules { + [CustomEditor(typeof(SkeletonUtilitySubmeshRenderer))] + public class SkeletonUtilitySubmeshRendererInspector : UnityEditor.Editor { + public SpineInspectorUtility.SerializedSortingProperties sorting; + + void OnEnable () { + sorting = new SpineInspectorUtility.SerializedSortingProperties((target as Component).GetComponent()); + } + + public override void OnInspectorGUI () { + EditorGUILayout.HelpBox("SkeletonUtilitySubmeshRenderer is now obsolete. We recommend using SkeletonRenderSeparator.", MessageType.Info); + SpineInspectorUtility.SortingPropertyFields(sorting, true); + } + } } diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityConstraint.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityConstraint.cs index 1381fc8164..e808a9563b 100644 --- a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityConstraint.cs +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilityConstraint.cs @@ -1,54 +1,53 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEngine; -using System.Collections; - -namespace Spine.Unity { - [RequireComponent(typeof(SkeletonUtilityBone)), ExecuteInEditMode] - public abstract class SkeletonUtilityConstraint : MonoBehaviour { - - protected SkeletonUtilityBone utilBone; - protected SkeletonUtility skeletonUtility; - - protected virtual void OnEnable () { - utilBone = GetComponent(); - skeletonUtility = SkeletonUtility.GetInParent(transform); - skeletonUtility.RegisterConstraint(this); - } - - protected virtual void OnDisable () { - skeletonUtility.UnregisterConstraint(this); - } - - public abstract void DoUpdate (); - } +using UnityEngine; +using System.Collections; + +namespace Spine.Unity { + [RequireComponent(typeof(SkeletonUtilityBone)), ExecuteInEditMode] + public abstract class SkeletonUtilityConstraint : MonoBehaviour { + + protected SkeletonUtilityBone utilBone; + protected SkeletonUtility skeletonUtility; + + protected virtual void OnEnable () { + utilBone = GetComponent(); + skeletonUtility = SkeletonUtility.GetInParent(transform); + skeletonUtility.RegisterConstraint(this); + } + + protected virtual void OnDisable () { + skeletonUtility.UnregisterConstraint(this); + } + + public abstract void DoUpdate (); + } } diff --git a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilitySubmeshRenderer.cs b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilitySubmeshRenderer.cs index 2320f86d8a..d7d9685e81 100644 --- a/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilitySubmeshRenderer.cs +++ b/spine-unity/Assets/spine-unity/SkeletonUtility/SkeletonUtilitySubmeshRenderer.cs @@ -1,71 +1,71 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using UnityEngine; - -namespace Spine.Unity.Modules { - [ExecuteInEditMode] - public class SkeletonUtilitySubmeshRenderer : MonoBehaviour { - [System.NonSerialized] - public Mesh mesh; - public int submeshIndex = 0; - public Material hiddenPassMaterial; - Renderer cachedRenderer; - MeshFilter filter; - Material[] sharedMaterials; - - void Awake () { - cachedRenderer = GetComponent(); - filter = GetComponent(); - sharedMaterials = new Material[0]; - } - - public void SetMesh (Renderer parentRenderer, Mesh mesh, Material mat) { - if (cachedRenderer == null) - return; - - cachedRenderer.enabled = true; - filter.sharedMesh = mesh; - if (cachedRenderer.sharedMaterials.Length != parentRenderer.sharedMaterials.Length) { - sharedMaterials = parentRenderer.sharedMaterials; - } - - for (int i = 0; i < sharedMaterials.Length; i++) { - if (i == submeshIndex) - sharedMaterials[i] = mat; - else - sharedMaterials[i] = hiddenPassMaterial; - } - - cachedRenderer.sharedMaterials = sharedMaterials; - } - } +using UnityEngine; + +namespace Spine.Unity.Modules { + [ExecuteInEditMode] + public class SkeletonUtilitySubmeshRenderer : MonoBehaviour { + [System.NonSerialized] + public Mesh mesh; + public int submeshIndex = 0; + public Material hiddenPassMaterial; + Renderer cachedRenderer; + MeshFilter filter; + Material[] sharedMaterials; + + void Awake () { + cachedRenderer = GetComponent(); + filter = GetComponent(); + sharedMaterials = new Material[0]; + } + + public void SetMesh (Renderer parentRenderer, Mesh mesh, Material mat) { + if (cachedRenderer == null) + return; + + cachedRenderer.enabled = true; + filter.sharedMesh = mesh; + if (cachedRenderer.sharedMaterials.Length != parentRenderer.sharedMaterials.Length) { + sharedMaterials = parentRenderer.sharedMaterials; + } + + for (int i = 0; i < sharedMaterials.Length; i++) { + if (i == submeshIndex) + sharedMaterials[i] = mat; + else + sharedMaterials[i] = hiddenPassMaterial; + } + + cachedRenderer.sharedMaterials = sharedMaterials; + } + } + } diff --git a/spine-xna/example/src/ExampleGame.cs b/spine-xna/example/src/ExampleGame.cs index 2fc21c7d0d..5fa40d91f2 100644 --- a/spine-xna/example/src/ExampleGame.cs +++ b/spine-xna/example/src/ExampleGame.cs @@ -1,207 +1,206 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using System.IO; -using System.Collections.Generic; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Audio; -using Microsoft.Xna.Framework.Content; -using Microsoft.Xna.Framework.Graphics; -using Microsoft.Xna.Framework.Input; -using Microsoft.Xna.Framework.Media; -using Spine; - -namespace Spine { - public class Example : Microsoft.Xna.Framework.Game { - GraphicsDeviceManager graphics; - SkeletonMeshRenderer skeletonRenderer; - Skeleton skeleton; - Slot headSlot; - AnimationState state; - SkeletonBounds bounds = new SkeletonBounds(); - -#if WINDOWS_STOREAPP - private string assetsFolder = @"Assets\"; -#else - private string assetsFolder = "data/"; -#endif - - public Example () { - IsMouseVisible = true; - - graphics = new GraphicsDeviceManager(this); - graphics.IsFullScreen = false; - graphics.PreferredBackBufferWidth = 800; - graphics.PreferredBackBufferHeight = 600; - } - - protected override void Initialize () { - // TODO: Add your initialization logic here - - base.Initialize(); - } - - protected override void LoadContent () { - skeletonRenderer = new SkeletonMeshRenderer(GraphicsDevice); - skeletonRenderer.PremultipliedAlpha = true; - - // String name = "spineboy"; - // String name = "goblins-mesh"; - // String name = "raptor"; - String name = "tank"; - // String name = "star"; - bool binaryData = true; - - Atlas atlas = new Atlas(assetsFolder + name + ".atlas", new XnaTextureLoader(GraphicsDevice)); - - float scale = 1; - if (name == "spineboy") scale = 0.6f; - if (name == "raptor") scale = 0.5f; - if (name == "tank") scale = 0.3f; - - SkeletonData skeletonData; - if (binaryData) { - SkeletonBinary binary = new SkeletonBinary(atlas); - binary.Scale = scale; - skeletonData = binary.ReadSkeletonData(assetsFolder + name + ".skel"); - } else { - SkeletonJson json = new SkeletonJson(atlas); - json.Scale = scale; - skeletonData = json.ReadSkeletonData(assetsFolder + name + ".json"); - } - skeleton = new Skeleton(skeletonData); - if (name == "goblins-mesh") skeleton.SetSkin("goblin"); - - // Define mixing between animations. - AnimationStateData stateData = new AnimationStateData(skeleton.Data); - state = new AnimationState(stateData); - - if (name == "spineboy") { - stateData.SetMix("run", "jump", 0.2f); - stateData.SetMix("jump", "run", 0.4f); - - // Event handling for all animations. - state.Start += Start; - state.End += End; - state.Complete += Complete; - state.Event += Event; - - state.SetAnimation(0, "test", false); - TrackEntry entry = state.AddAnimation(0, "jump", false, 0); - entry.End += End; // Event handling for queued animations. - state.AddAnimation(0, "run", true, 0); - } - else if (name == "raptor") { - state.SetAnimation(0, "walk", true); - state.AddAnimation(1, "gungrab", false, 2); - } - else if (name == "star") { - // no animation in star - } - else if (name == "tank") { - state.SetAnimation(0, "drive", true); - } else { - state.SetAnimation(0, "walk", true); - } - - skeleton.X = 400 + (name == "tank" ? 300: 0); - skeleton.Y = 580; - skeleton.UpdateWorldTransform(); - - headSlot = skeleton.FindSlot("head"); - } - - protected override void UnloadContent () { - // TODO: Unload any non ContentManager content here - } - - protected override void Update (GameTime gameTime) { - // TODO: Add your update logic here -#if (!WINDOWS_STOREAPP || WINDOWS_PHONE81) && !IOS - if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) - this.Exit(); -#endif - base.Update(gameTime); - } - - protected override void Draw (GameTime gameTime) { - GraphicsDevice.Clear(Color.Black); - - state.Update(gameTime.ElapsedGameTime.Milliseconds / 1000f); - state.Apply(skeleton); - skeleton.UpdateWorldTransform(); - skeletonRenderer.Begin(); - skeletonRenderer.Draw(skeleton); - skeletonRenderer.End(); - - bounds.Update(skeleton, true); - MouseState mouse = Mouse.GetState(); - if (headSlot != null) { - headSlot.G = 1; - headSlot.B = 1; - if (bounds.AabbContainsPoint(mouse.X, mouse.Y)) { - BoundingBoxAttachment hit = bounds.ContainsPoint(mouse.X, mouse.Y); - if (hit != null) { - headSlot.G = 0; - headSlot.B = 0; - } - } - } - - base.Draw(gameTime); - } - - public void Start (AnimationState state, int trackIndex) { -#if !WINDOWS_STOREAPP - Console.WriteLine(trackIndex + " " + state.GetCurrent(trackIndex) + ": start"); -#endif - } - - public void End (AnimationState state, int trackIndex) { -#if !WINDOWS_STOREAPP - Console.WriteLine(trackIndex + " " + state.GetCurrent(trackIndex) + ": end"); -#endif - } - - public void Complete (AnimationState state, int trackIndex, int loopCount) { -#if !WINDOWS_STOREAPP - Console.WriteLine(trackIndex + " " + state.GetCurrent(trackIndex) + ": complete " + loopCount); -#endif - } - - public void Event (AnimationState state, int trackIndex, Event e) { -#if !WINDOWS_STOREAPP - Console.WriteLine(trackIndex + " " + state.GetCurrent(trackIndex) + ": event " + e); -#endif - } - } +using System; +using System.IO; +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Audio; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using Microsoft.Xna.Framework.Media; +using Spine; + +namespace Spine { + public class Example : Microsoft.Xna.Framework.Game { + GraphicsDeviceManager graphics; + SkeletonMeshRenderer skeletonRenderer; + Skeleton skeleton; + Slot headSlot; + AnimationState state; + SkeletonBounds bounds = new SkeletonBounds(); + +#if WINDOWS_STOREAPP + private string assetsFolder = @"Assets\"; +#else + private string assetsFolder = "data/"; +#endif + + public Example () { + IsMouseVisible = true; + + graphics = new GraphicsDeviceManager(this); + graphics.IsFullScreen = false; + graphics.PreferredBackBufferWidth = 800; + graphics.PreferredBackBufferHeight = 600; + } + + protected override void Initialize () { + // TODO: Add your initialization logic here + + base.Initialize(); + } + + protected override void LoadContent () { + skeletonRenderer = new SkeletonMeshRenderer(GraphicsDevice); + skeletonRenderer.PremultipliedAlpha = true; + + // String name = "spineboy"; + // String name = "goblins-mesh"; + // String name = "raptor"; + String name = "tank"; + // String name = "star"; + bool binaryData = true; + + Atlas atlas = new Atlas(assetsFolder + name + ".atlas", new XnaTextureLoader(GraphicsDevice)); + + float scale = 1; + if (name == "spineboy") scale = 0.6f; + if (name == "raptor") scale = 0.5f; + if (name == "tank") scale = 0.3f; + + SkeletonData skeletonData; + if (binaryData) { + SkeletonBinary binary = new SkeletonBinary(atlas); + binary.Scale = scale; + skeletonData = binary.ReadSkeletonData(assetsFolder + name + ".skel"); + } else { + SkeletonJson json = new SkeletonJson(atlas); + json.Scale = scale; + skeletonData = json.ReadSkeletonData(assetsFolder + name + ".json"); + } + skeleton = new Skeleton(skeletonData); + if (name == "goblins-mesh") skeleton.SetSkin("goblin"); + + // Define mixing between animations. + AnimationStateData stateData = new AnimationStateData(skeleton.Data); + state = new AnimationState(stateData); + + if (name == "spineboy") { + stateData.SetMix("run", "jump", 0.2f); + stateData.SetMix("jump", "run", 0.4f); + + // Event handling for all animations. + state.Start += Start; + state.End += End; + state.Complete += Complete; + state.Event += Event; + + state.SetAnimation(0, "test", false); + TrackEntry entry = state.AddAnimation(0, "jump", false, 0); + entry.End += End; // Event handling for queued animations. + state.AddAnimation(0, "run", true, 0); + } + else if (name == "raptor") { + state.SetAnimation(0, "walk", true); + state.AddAnimation(1, "gungrab", false, 2); + } + else if (name == "star") { + // no animation in star + } + else if (name == "tank") { + state.SetAnimation(0, "drive", true); + } else { + state.SetAnimation(0, "walk", true); + } + + skeleton.X = 400 + (name == "tank" ? 300: 0); + skeleton.Y = 580; + skeleton.UpdateWorldTransform(); + + headSlot = skeleton.FindSlot("head"); + } + + protected override void UnloadContent () { + // TODO: Unload any non ContentManager content here + } + + protected override void Update (GameTime gameTime) { + // TODO: Add your update logic here +#if (!WINDOWS_STOREAPP || WINDOWS_PHONE81) && !IOS + if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) + this.Exit(); +#endif + base.Update(gameTime); + } + + protected override void Draw (GameTime gameTime) { + GraphicsDevice.Clear(Color.Black); + + state.Update(gameTime.ElapsedGameTime.Milliseconds / 1000f); + state.Apply(skeleton); + skeleton.UpdateWorldTransform(); + skeletonRenderer.Begin(); + skeletonRenderer.Draw(skeleton); + skeletonRenderer.End(); + + bounds.Update(skeleton, true); + MouseState mouse = Mouse.GetState(); + if (headSlot != null) { + headSlot.G = 1; + headSlot.B = 1; + if (bounds.AabbContainsPoint(mouse.X, mouse.Y)) { + BoundingBoxAttachment hit = bounds.ContainsPoint(mouse.X, mouse.Y); + if (hit != null) { + headSlot.G = 0; + headSlot.B = 0; + } + } + } + + base.Draw(gameTime); + } + + public void Start (AnimationState state, int trackIndex) { +#if !WINDOWS_STOREAPP + Console.WriteLine(trackIndex + " " + state.GetCurrent(trackIndex) + ": start"); +#endif + } + + public void End (AnimationState state, int trackIndex) { +#if !WINDOWS_STOREAPP + Console.WriteLine(trackIndex + " " + state.GetCurrent(trackIndex) + ": end"); +#endif + } + + public void Complete (AnimationState state, int trackIndex, int loopCount) { +#if !WINDOWS_STOREAPP + Console.WriteLine(trackIndex + " " + state.GetCurrent(trackIndex) + ": complete " + loopCount); +#endif + } + + public void Event (AnimationState state, int trackIndex, Event e) { +#if !WINDOWS_STOREAPP + Console.WriteLine(trackIndex + " " + state.GetCurrent(trackIndex) + ": event " + e); +#endif + } + } } diff --git a/spine-xna/src/MeshBatcher.cs b/spine-xna/src/MeshBatcher.cs index f2d4cd5920..52c2c2ce11 100644 --- a/spine-xna/src/MeshBatcher.cs +++ b/spine-xna/src/MeshBatcher.cs @@ -1,167 +1,166 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using System.Collections.Generic; -using Microsoft.Xna.Framework.Graphics; -using Microsoft.Xna.Framework; - -namespace Spine { - // #region License - // /* - // Microsoft Public License (Ms-PL) - // MonoGame - Copyright © 2009 The MonoGame Team - // - // All rights reserved. - // - // This license governs use of the accompanying software. If you use the software, you accept this license. If you do not - // accept the license, do not use the software. - // - // 1. Definitions - // The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under - // U.S. copyright law. - // - // A "contribution" is the original software, or any additions or changes to the software. - // A "contributor" is any person that distributes its contribution under this license. - // "Licensed patents" are a contributor's patent claims that read directly on its contribution. - // - // 2. Grant of Rights - // (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, - // each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. - // (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, - // each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. - // - // 3. Conditions and Limitations - // (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. - // (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, - // your patent license from such contributor to the software ends automatically. - // (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution - // notices that are present in the software. - // (D) If you distribute any portion of the software in source code form, you may do so only under this license by including - // a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object - // code form, you may only do so under a license that complies with this license. - // (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees - // or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent - // permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular - // purpose and non-infringement. - // */ - // #endregion License - // - - /// Draws batched meshes. - public class MeshBatcher { - private readonly List items; - private readonly Queue freeItems; - private VertexPositionColorTexture[] vertexArray = { }; - private short[] triangles = { }; - - public MeshBatcher () { - items = new List(256); - freeItems = new Queue(256); - EnsureCapacity(256, 512); - } - - /// Returns a pooled MeshItem. - public MeshItem NextItem (int vertexCount, int triangleCount) { - MeshItem item = freeItems.Count > 0 ? freeItems.Dequeue() : new MeshItem(); - if (item.vertices.Length < vertexCount) item.vertices = new VertexPositionColorTexture[vertexCount]; - if (item.triangles.Length < triangleCount) item.triangles = new int[triangleCount]; - item.vertexCount = vertexCount; - item.triangleCount = triangleCount; - items.Add(item); - return item; - } - - private void EnsureCapacity (int vertexCount, int triangleCount) { - if (vertexArray.Length < vertexCount) vertexArray = new VertexPositionColorTexture[vertexCount]; - if (triangles.Length < triangleCount) triangles = new short[triangleCount]; - } - - public void Draw (GraphicsDevice device) { - if (items.Count == 0) return; - - int itemCount = items.Count; - int vertexCount = 0, triangleCount = 0; - for (int i = 0; i < itemCount; i++) { - MeshItem item = items[i]; - vertexCount += item.vertexCount; - triangleCount += item.triangleCount; - } - EnsureCapacity(vertexCount, triangleCount); - - vertexCount = 0; - triangleCount = 0; - Texture2D lastTexture = null; - for (int i = 0; i < itemCount; i++) { - MeshItem item = items[i]; - int itemVertexCount = item.vertexCount; - - if (item.texture != lastTexture || vertexCount + itemVertexCount > short.MaxValue) { - FlushVertexArray(device, vertexCount, triangleCount); - vertexCount = 0; - triangleCount = 0; - lastTexture = item.texture; - device.Textures[0] = lastTexture; - } - - int[] itemTriangles = item.triangles; - int itemTriangleCount = item.triangleCount; - for (int ii = 0, t = triangleCount; ii < itemTriangleCount; ii++, t++) - triangles[t] = (short)(itemTriangles[ii] + vertexCount); - triangleCount += itemTriangleCount; - - Array.Copy(item.vertices, 0, vertexArray, vertexCount, itemVertexCount); - vertexCount += itemVertexCount; - - item.texture = null; - freeItems.Enqueue(item); - } - FlushVertexArray(device, vertexCount, triangleCount); - items.Clear(); - } - - private void FlushVertexArray (GraphicsDevice device, int vertexCount, int triangleCount) { - if (vertexCount == 0) return; - device.DrawUserIndexedPrimitives( - PrimitiveType.TriangleList, - vertexArray, 0, vertexCount, - triangles, 0, triangleCount / 3, - VertexPositionColorTexture.VertexDeclaration); - } - } - - public class MeshItem { - public Texture2D texture; - public int vertexCount, triangleCount; - public VertexPositionColorTexture[] vertices = { }; - public int[] triangles = { }; - } +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework; + +namespace Spine { + // #region License + // /* + // Microsoft Public License (Ms-PL) + // MonoGame - Copyright � 2009 The MonoGame Team + // + // All rights reserved. + // + // This license governs use of the accompanying software. If you use the software, you accept this license. If you do not + // accept the license, do not use the software. + // + // 1. Definitions + // The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under + // U.S. copyright law. + // + // A "contribution" is the original software, or any additions or changes to the software. + // A "contributor" is any person that distributes its contribution under this license. + // "Licensed patents" are a contributor's patent claims that read directly on its contribution. + // + // 2. Grant of Rights + // (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, + // each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. + // (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, + // each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. + // + // 3. Conditions and Limitations + // (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. + // (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, + // your patent license from such contributor to the software ends automatically. + // (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution + // notices that are present in the software. + // (D) If you distribute any portion of the software in source code form, you may do so only under this license by including + // a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object + // code form, you may only do so under a license that complies with this license. + // (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees + // or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent + // permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular + // purpose and non-infringement. + // */ + // #endregion License + // + + /// Draws batched meshes. + public class MeshBatcher { + private readonly List items; + private readonly Queue freeItems; + private VertexPositionColorTexture[] vertexArray = { }; + private short[] triangles = { }; + + public MeshBatcher () { + items = new List(256); + freeItems = new Queue(256); + EnsureCapacity(256, 512); + } + + /// Returns a pooled MeshItem. + public MeshItem NextItem (int vertexCount, int triangleCount) { + MeshItem item = freeItems.Count > 0 ? freeItems.Dequeue() : new MeshItem(); + if (item.vertices.Length < vertexCount) item.vertices = new VertexPositionColorTexture[vertexCount]; + if (item.triangles.Length < triangleCount) item.triangles = new int[triangleCount]; + item.vertexCount = vertexCount; + item.triangleCount = triangleCount; + items.Add(item); + return item; + } + + private void EnsureCapacity (int vertexCount, int triangleCount) { + if (vertexArray.Length < vertexCount) vertexArray = new VertexPositionColorTexture[vertexCount]; + if (triangles.Length < triangleCount) triangles = new short[triangleCount]; + } + + public void Draw (GraphicsDevice device) { + if (items.Count == 0) return; + + int itemCount = items.Count; + int vertexCount = 0, triangleCount = 0; + for (int i = 0; i < itemCount; i++) { + MeshItem item = items[i]; + vertexCount += item.vertexCount; + triangleCount += item.triangleCount; + } + EnsureCapacity(vertexCount, triangleCount); + + vertexCount = 0; + triangleCount = 0; + Texture2D lastTexture = null; + for (int i = 0; i < itemCount; i++) { + MeshItem item = items[i]; + int itemVertexCount = item.vertexCount; + + if (item.texture != lastTexture || vertexCount + itemVertexCount > short.MaxValue) { + FlushVertexArray(device, vertexCount, triangleCount); + vertexCount = 0; + triangleCount = 0; + lastTexture = item.texture; + device.Textures[0] = lastTexture; + } + + int[] itemTriangles = item.triangles; + int itemTriangleCount = item.triangleCount; + for (int ii = 0, t = triangleCount; ii < itemTriangleCount; ii++, t++) + triangles[t] = (short)(itemTriangles[ii] + vertexCount); + triangleCount += itemTriangleCount; + + Array.Copy(item.vertices, 0, vertexArray, vertexCount, itemVertexCount); + vertexCount += itemVertexCount; + + item.texture = null; + freeItems.Enqueue(item); + } + FlushVertexArray(device, vertexCount, triangleCount); + items.Clear(); + } + + private void FlushVertexArray (GraphicsDevice device, int vertexCount, int triangleCount) { + if (vertexCount == 0) return; + device.DrawUserIndexedPrimitives( + PrimitiveType.TriangleList, + vertexArray, 0, vertexCount, + triangles, 0, triangleCount / 3, + VertexPositionColorTexture.VertexDeclaration); + } + } + + public class MeshItem { + public Texture2D texture; + public int vertexCount, triangleCount; + public VertexPositionColorTexture[] vertices = { }; + public int[] triangles = { }; + } } diff --git a/spine-xna/src/RegionBatcher.cs b/spine-xna/src/RegionBatcher.cs index d05973d71a..649577cf2e 100644 --- a/spine-xna/src/RegionBatcher.cs +++ b/spine-xna/src/RegionBatcher.cs @@ -1,182 +1,181 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using System.Collections.Generic; -using Microsoft.Xna.Framework.Graphics; -using Microsoft.Xna.Framework; - -namespace Spine { - // #region License - // /* - // Microsoft Public License (Ms-PL) - // MonoGame - Copyright © 2009 The MonoGame Team - // - // All rights reserved. - // - // This license governs use of the accompanying software. If you use the software, you accept this license. If you do not - // accept the license, do not use the software. - // - // 1. Definitions - // The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under - // U.S. copyright law. - // - // A "contribution" is the original software, or any additions or changes to the software. - // A "contributor" is any person that distributes its contribution under this license. - // "Licensed patents" are a contributor's patent claims that read directly on its contribution. - // - // 2. Grant of Rights - // (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, - // each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. - // (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, - // each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. - // - // 3. Conditions and Limitations - // (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. - // (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, - // your patent license from such contributor to the software ends automatically. - // (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution - // notices that are present in the software. - // (D) If you distribute any portion of the software in source code form, you may do so only under this license by including - // a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object - // code form, you may only do so under a license that complies with this license. - // (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees - // or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent - // permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular - // purpose and non-infringement. - // */ - // #endregion License - // - - /// Draws batched quads using indices. - public class RegionBatcher { - private const int maxBatchSize = short.MaxValue / 6; // 6 = 4 vertices unique and 2 shared, per quad - private readonly List items; - private readonly Queue freeItems; - private VertexPositionColorTexture[] vertexArray; - private short[] indices; - - public RegionBatcher () { - items = new List(256); - freeItems = new Queue(256); - EnsureArrayCapacity(256); - } - - /// Returns a pooled RegionItem. - public RegionItem NextItem () { - RegionItem item = freeItems.Count > 0 ? freeItems.Dequeue() : new RegionItem(); - items.Add(item); - return item; - } - - /// Resize and recreate the indices and vertex position color buffers. - private void EnsureArrayCapacity (int itemCount) { - if (indices != null && indices.Length >= 6 * itemCount) return; - - short[] newIndices = new short[6 * itemCount]; - int start = 0; - if (indices != null) { - indices.CopyTo(newIndices, 0); - start = indices.Length / 6; - } - for (var i = start; i < itemCount; i++) { - /* TL TR - * 0----1 0,1,2,3 = index offsets for vertex indices - * | | TL,TR,BL,BR are vertex references in RegionItem. - * 2----3 - * BL BR */ - newIndices[i * 6 + 0] = (short)(i * 4); - newIndices[i * 6 + 1] = (short)(i * 4 + 1); - newIndices[i * 6 + 2] = (short)(i * 4 + 2); - newIndices[i * 6 + 3] = (short)(i * 4 + 1); - newIndices[i * 6 + 4] = (short)(i * 4 + 3); - newIndices[i * 6 + 5] = (short)(i * 4 + 2); - } - indices = newIndices; - - vertexArray = new VertexPositionColorTexture[4 * itemCount]; - } - - public void Draw (GraphicsDevice device) { - if (items.Count == 0) return; - - int itemIndex = 0; - int itemCount = items.Count; - while (itemCount > 0) { - int itemsToProcess = Math.Min(itemCount, maxBatchSize); - EnsureArrayCapacity(itemsToProcess); - - var count = 0; - Texture2D texture = null; - for (int i = 0; i < itemsToProcess; i++, itemIndex++) { - RegionItem item = items[itemIndex]; - if (item.texture != texture) { - FlushVertexArray(device, count); - texture = item.texture; - count = 0; - device.Textures[0] = texture; - } - - vertexArray[count++] = item.vertexTL; - vertexArray[count++] = item.vertexTR; - vertexArray[count++] = item.vertexBL; - vertexArray[count++] = item.vertexBR; - - item.texture = null; - freeItems.Enqueue(item); - } - FlushVertexArray(device, count); - itemCount -= itemsToProcess; - } - items.Clear(); - } - - /// Sends the triangle list to the graphics device. - /// Start index of vertices to draw. Not used except to compute the count of vertices to draw. - /// End index of vertices to draw. Not used except to compute the count of vertices to draw. - private void FlushVertexArray (GraphicsDevice device, int count) { - if (count == 0) return; - device.DrawUserIndexedPrimitives( - PrimitiveType.TriangleList, - vertexArray, 0, count, - indices, 0, (count / 4) * 2, - VertexPositionColorTexture.VertexDeclaration); - } - } - - public class RegionItem { - public Texture2D texture; - public VertexPositionColorTexture vertexTL; - public VertexPositionColorTexture vertexTR; - public VertexPositionColorTexture vertexBL; - public VertexPositionColorTexture vertexBR; - } +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework; + +namespace Spine { + // #region License + // /* + // Microsoft Public License (Ms-PL) + // MonoGame - Copyright � 2009 The MonoGame Team + // + // All rights reserved. + // + // This license governs use of the accompanying software. If you use the software, you accept this license. If you do not + // accept the license, do not use the software. + // + // 1. Definitions + // The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under + // U.S. copyright law. + // + // A "contribution" is the original software, or any additions or changes to the software. + // A "contributor" is any person that distributes its contribution under this license. + // "Licensed patents" are a contributor's patent claims that read directly on its contribution. + // + // 2. Grant of Rights + // (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, + // each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. + // (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, + // each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. + // + // 3. Conditions and Limitations + // (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. + // (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, + // your patent license from such contributor to the software ends automatically. + // (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution + // notices that are present in the software. + // (D) If you distribute any portion of the software in source code form, you may do so only under this license by including + // a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object + // code form, you may only do so under a license that complies with this license. + // (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees + // or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent + // permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular + // purpose and non-infringement. + // */ + // #endregion License + // + + /// Draws batched quads using indices. + public class RegionBatcher { + private const int maxBatchSize = short.MaxValue / 6; // 6 = 4 vertices unique and 2 shared, per quad + private readonly List items; + private readonly Queue freeItems; + private VertexPositionColorTexture[] vertexArray; + private short[] indices; + + public RegionBatcher () { + items = new List(256); + freeItems = new Queue(256); + EnsureArrayCapacity(256); + } + + /// Returns a pooled RegionItem. + public RegionItem NextItem () { + RegionItem item = freeItems.Count > 0 ? freeItems.Dequeue() : new RegionItem(); + items.Add(item); + return item; + } + + /// Resize and recreate the indices and vertex position color buffers. + private void EnsureArrayCapacity (int itemCount) { + if (indices != null && indices.Length >= 6 * itemCount) return; + + short[] newIndices = new short[6 * itemCount]; + int start = 0; + if (indices != null) { + indices.CopyTo(newIndices, 0); + start = indices.Length / 6; + } + for (var i = start; i < itemCount; i++) { + /* TL TR + * 0----1 0,1,2,3 = index offsets for vertex indices + * | | TL,TR,BL,BR are vertex references in RegionItem. + * 2----3 + * BL BR */ + newIndices[i * 6 + 0] = (short)(i * 4); + newIndices[i * 6 + 1] = (short)(i * 4 + 1); + newIndices[i * 6 + 2] = (short)(i * 4 + 2); + newIndices[i * 6 + 3] = (short)(i * 4 + 1); + newIndices[i * 6 + 4] = (short)(i * 4 + 3); + newIndices[i * 6 + 5] = (short)(i * 4 + 2); + } + indices = newIndices; + + vertexArray = new VertexPositionColorTexture[4 * itemCount]; + } + + public void Draw (GraphicsDevice device) { + if (items.Count == 0) return; + + int itemIndex = 0; + int itemCount = items.Count; + while (itemCount > 0) { + int itemsToProcess = Math.Min(itemCount, maxBatchSize); + EnsureArrayCapacity(itemsToProcess); + + var count = 0; + Texture2D texture = null; + for (int i = 0; i < itemsToProcess; i++, itemIndex++) { + RegionItem item = items[itemIndex]; + if (item.texture != texture) { + FlushVertexArray(device, count); + texture = item.texture; + count = 0; + device.Textures[0] = texture; + } + + vertexArray[count++] = item.vertexTL; + vertexArray[count++] = item.vertexTR; + vertexArray[count++] = item.vertexBL; + vertexArray[count++] = item.vertexBR; + + item.texture = null; + freeItems.Enqueue(item); + } + FlushVertexArray(device, count); + itemCount -= itemsToProcess; + } + items.Clear(); + } + + /// Sends the triangle list to the graphics device. + /// Start index of vertices to draw. Not used except to compute the count of vertices to draw. + /// End index of vertices to draw. Not used except to compute the count of vertices to draw. + private void FlushVertexArray (GraphicsDevice device, int count) { + if (count == 0) return; + device.DrawUserIndexedPrimitives( + PrimitiveType.TriangleList, + vertexArray, 0, count, + indices, 0, (count / 4) * 2, + VertexPositionColorTexture.VertexDeclaration); + } + } + + public class RegionItem { + public Texture2D texture; + public VertexPositionColorTexture vertexTL; + public VertexPositionColorTexture vertexTR; + public VertexPositionColorTexture vertexBL; + public VertexPositionColorTexture vertexBR; + } } diff --git a/spine-xna/src/SkeletonMeshRenderer.cs b/spine-xna/src/SkeletonMeshRenderer.cs index 1f7a291510..3b00f9b80d 100644 --- a/spine-xna/src/SkeletonMeshRenderer.cs +++ b/spine-xna/src/SkeletonMeshRenderer.cs @@ -1,196 +1,195 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using System.Collections.Generic; -using Microsoft.Xna.Framework.Graphics; -using Microsoft.Xna.Framework; - -namespace Spine { - /// Draws region and mesh attachments. - public class SkeletonMeshRenderer { - private const int TL = 0; - private const int TR = 1; - private const int BL = 2; - private const int BR = 3; - - GraphicsDevice device; - MeshBatcher batcher; - RasterizerState rasterizerState; - float[] vertices = new float[8]; - int[] quadTriangles = { 0, 1, 2, 1, 3, 2 }; - BlendState defaultBlendState; - - BasicEffect effect; - public BasicEffect Effect { get { return effect; } set { effect = value; } } - - private bool premultipliedAlpha; - public bool PremultipliedAlpha { get { return premultipliedAlpha; } set { premultipliedAlpha = value; } } - - public SkeletonMeshRenderer (GraphicsDevice device) { - this.device = device; - - batcher = new MeshBatcher(); - - effect = new BasicEffect(device); - effect.World = Matrix.Identity; - effect.View = Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 1.0f), Vector3.Zero, Vector3.Up); - effect.TextureEnabled = true; - effect.VertexColorEnabled = true; - - rasterizerState = new RasterizerState(); - rasterizerState.CullMode = CullMode.None; - - Bone.yDown = true; - } - - public void Begin () { - defaultBlendState = premultipliedAlpha ? BlendState.AlphaBlend : BlendState.NonPremultiplied; - - device.RasterizerState = rasterizerState; - device.BlendState = defaultBlendState; - - effect.Projection = Matrix.CreateOrthographicOffCenter(0, device.Viewport.Width, device.Viewport.Height, 0, 1, 0); - } - - public void End () { - foreach (EffectPass pass in effect.CurrentTechnique.Passes) { - pass.Apply(); - batcher.Draw(device); - } - } - - public void Draw (Skeleton skeleton) { - float[] vertices = this.vertices; - var drawOrder = skeleton.DrawOrder; - var drawOrderItems = skeleton.DrawOrder.Items; - float skeletonR = skeleton.R, skeletonG = skeleton.G, skeletonB = skeleton.B, skeletonA = skeleton.A; - for (int i = 0, n = drawOrder.Count; i < n; i++) { - Slot slot = drawOrderItems[i]; - Attachment attachment = slot.Attachment; - if (attachment is RegionAttachment) { - RegionAttachment regionAttachment = (RegionAttachment)attachment; - BlendState blend = slot.Data.BlendMode == BlendMode.additive ? BlendState.Additive : defaultBlendState; - if (device.BlendState != blend) { - End(); - device.BlendState = blend; - } - - MeshItem item = batcher.NextItem(4, 6); - item.triangles = quadTriangles; - VertexPositionColorTexture[] itemVertices = item.vertices; - - AtlasRegion region = (AtlasRegion)regionAttachment.RendererObject; - item.texture = (Texture2D)region.page.rendererObject; - - Color color; - float a = skeletonA * slot.A * regionAttachment.A; - if (premultipliedAlpha) { - color = new Color( - skeletonR * slot.R * regionAttachment.R * a, - skeletonG * slot.G * regionAttachment.G * a, - skeletonB * slot.B * regionAttachment.B * a, a); - } else { - color = new Color( - skeletonR * slot.R * regionAttachment.R, - skeletonG * slot.G * regionAttachment.G, - skeletonB * slot.B * regionAttachment.B, a); - } - itemVertices[TL].Color = color; - itemVertices[BL].Color = color; - itemVertices[BR].Color = color; - itemVertices[TR].Color = color; - - regionAttachment.ComputeWorldVertices(slot.Bone, vertices); - itemVertices[TL].Position.X = vertices[RegionAttachment.X1]; - itemVertices[TL].Position.Y = vertices[RegionAttachment.Y1]; - itemVertices[TL].Position.Z = 0; - itemVertices[BL].Position.X = vertices[RegionAttachment.X2]; - itemVertices[BL].Position.Y = vertices[RegionAttachment.Y2]; - itemVertices[BL].Position.Z = 0; - itemVertices[BR].Position.X = vertices[RegionAttachment.X3]; - itemVertices[BR].Position.Y = vertices[RegionAttachment.Y3]; - itemVertices[BR].Position.Z = 0; - itemVertices[TR].Position.X = vertices[RegionAttachment.X4]; - itemVertices[TR].Position.Y = vertices[RegionAttachment.Y4]; - itemVertices[TR].Position.Z = 0; - - float[] uvs = regionAttachment.UVs; - itemVertices[TL].TextureCoordinate.X = uvs[RegionAttachment.X1]; - itemVertices[TL].TextureCoordinate.Y = uvs[RegionAttachment.Y1]; - itemVertices[BL].TextureCoordinate.X = uvs[RegionAttachment.X2]; - itemVertices[BL].TextureCoordinate.Y = uvs[RegionAttachment.Y2]; - itemVertices[BR].TextureCoordinate.X = uvs[RegionAttachment.X3]; - itemVertices[BR].TextureCoordinate.Y = uvs[RegionAttachment.Y3]; - itemVertices[TR].TextureCoordinate.X = uvs[RegionAttachment.X4]; - itemVertices[TR].TextureCoordinate.Y = uvs[RegionAttachment.Y4]; - } else if (attachment is MeshAttachment) { - MeshAttachment mesh = (MeshAttachment)attachment; - int vertexCount = mesh.WorldVerticesLength; - if (vertices.Length < vertexCount) vertices = new float[vertexCount]; - mesh.ComputeWorldVertices(slot, vertices); - - int[] triangles = mesh.Triangles; - MeshItem item = batcher.NextItem(vertexCount, triangles.Length); - item.triangles = triangles; - - AtlasRegion region = (AtlasRegion)mesh.RendererObject; - item.texture = (Texture2D)region.page.rendererObject; - - Color color; - float a = skeletonA * slot.A * mesh.A; - if (premultipliedAlpha) { - color = new Color( - skeletonR * slot.R * mesh.R * a, - skeletonG * slot.G * mesh.G * a, - skeletonB * slot.B * mesh.B * a, a); - } else { - color = new Color( - skeletonR * slot.R * mesh.R, - skeletonG * slot.G * mesh.G, - skeletonB * slot.B * mesh.B, a); - } - - float[] uvs = mesh.UVs; - VertexPositionColorTexture[] itemVertices = item.vertices; - for (int ii = 0, v = 0; v < vertexCount; ii++, v += 2) { - itemVertices[ii].Color = color; - itemVertices[ii].Position.X = vertices[v]; - itemVertices[ii].Position.Y = vertices[v + 1]; - itemVertices[ii].Position.Z = 0; - itemVertices[ii].TextureCoordinate.X = uvs[v]; - itemVertices[ii].TextureCoordinate.Y = uvs[v + 1]; - } - } - } - } - } +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework; + +namespace Spine { + /// Draws region and mesh attachments. + public class SkeletonMeshRenderer { + private const int TL = 0; + private const int TR = 1; + private const int BL = 2; + private const int BR = 3; + + GraphicsDevice device; + MeshBatcher batcher; + RasterizerState rasterizerState; + float[] vertices = new float[8]; + int[] quadTriangles = { 0, 1, 2, 1, 3, 2 }; + BlendState defaultBlendState; + + BasicEffect effect; + public BasicEffect Effect { get { return effect; } set { effect = value; } } + + private bool premultipliedAlpha; + public bool PremultipliedAlpha { get { return premultipliedAlpha; } set { premultipliedAlpha = value; } } + + public SkeletonMeshRenderer (GraphicsDevice device) { + this.device = device; + + batcher = new MeshBatcher(); + + effect = new BasicEffect(device); + effect.World = Matrix.Identity; + effect.View = Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 1.0f), Vector3.Zero, Vector3.Up); + effect.TextureEnabled = true; + effect.VertexColorEnabled = true; + + rasterizerState = new RasterizerState(); + rasterizerState.CullMode = CullMode.None; + + Bone.yDown = true; + } + + public void Begin () { + defaultBlendState = premultipliedAlpha ? BlendState.AlphaBlend : BlendState.NonPremultiplied; + + device.RasterizerState = rasterizerState; + device.BlendState = defaultBlendState; + + effect.Projection = Matrix.CreateOrthographicOffCenter(0, device.Viewport.Width, device.Viewport.Height, 0, 1, 0); + } + + public void End () { + foreach (EffectPass pass in effect.CurrentTechnique.Passes) { + pass.Apply(); + batcher.Draw(device); + } + } + + public void Draw (Skeleton skeleton) { + float[] vertices = this.vertices; + var drawOrder = skeleton.DrawOrder; + var drawOrderItems = skeleton.DrawOrder.Items; + float skeletonR = skeleton.R, skeletonG = skeleton.G, skeletonB = skeleton.B, skeletonA = skeleton.A; + for (int i = 0, n = drawOrder.Count; i < n; i++) { + Slot slot = drawOrderItems[i]; + Attachment attachment = slot.Attachment; + if (attachment is RegionAttachment) { + RegionAttachment regionAttachment = (RegionAttachment)attachment; + BlendState blend = slot.Data.BlendMode == BlendMode.additive ? BlendState.Additive : defaultBlendState; + if (device.BlendState != blend) { + End(); + device.BlendState = blend; + } + + MeshItem item = batcher.NextItem(4, 6); + item.triangles = quadTriangles; + VertexPositionColorTexture[] itemVertices = item.vertices; + + AtlasRegion region = (AtlasRegion)regionAttachment.RendererObject; + item.texture = (Texture2D)region.page.rendererObject; + + Color color; + float a = skeletonA * slot.A * regionAttachment.A; + if (premultipliedAlpha) { + color = new Color( + skeletonR * slot.R * regionAttachment.R * a, + skeletonG * slot.G * regionAttachment.G * a, + skeletonB * slot.B * regionAttachment.B * a, a); + } else { + color = new Color( + skeletonR * slot.R * regionAttachment.R, + skeletonG * slot.G * regionAttachment.G, + skeletonB * slot.B * regionAttachment.B, a); + } + itemVertices[TL].Color = color; + itemVertices[BL].Color = color; + itemVertices[BR].Color = color; + itemVertices[TR].Color = color; + + regionAttachment.ComputeWorldVertices(slot.Bone, vertices); + itemVertices[TL].Position.X = vertices[RegionAttachment.X1]; + itemVertices[TL].Position.Y = vertices[RegionAttachment.Y1]; + itemVertices[TL].Position.Z = 0; + itemVertices[BL].Position.X = vertices[RegionAttachment.X2]; + itemVertices[BL].Position.Y = vertices[RegionAttachment.Y2]; + itemVertices[BL].Position.Z = 0; + itemVertices[BR].Position.X = vertices[RegionAttachment.X3]; + itemVertices[BR].Position.Y = vertices[RegionAttachment.Y3]; + itemVertices[BR].Position.Z = 0; + itemVertices[TR].Position.X = vertices[RegionAttachment.X4]; + itemVertices[TR].Position.Y = vertices[RegionAttachment.Y4]; + itemVertices[TR].Position.Z = 0; + + float[] uvs = regionAttachment.UVs; + itemVertices[TL].TextureCoordinate.X = uvs[RegionAttachment.X1]; + itemVertices[TL].TextureCoordinate.Y = uvs[RegionAttachment.Y1]; + itemVertices[BL].TextureCoordinate.X = uvs[RegionAttachment.X2]; + itemVertices[BL].TextureCoordinate.Y = uvs[RegionAttachment.Y2]; + itemVertices[BR].TextureCoordinate.X = uvs[RegionAttachment.X3]; + itemVertices[BR].TextureCoordinate.Y = uvs[RegionAttachment.Y3]; + itemVertices[TR].TextureCoordinate.X = uvs[RegionAttachment.X4]; + itemVertices[TR].TextureCoordinate.Y = uvs[RegionAttachment.Y4]; + } else if (attachment is MeshAttachment) { + MeshAttachment mesh = (MeshAttachment)attachment; + int vertexCount = mesh.WorldVerticesLength; + if (vertices.Length < vertexCount) vertices = new float[vertexCount]; + mesh.ComputeWorldVertices(slot, vertices); + + int[] triangles = mesh.Triangles; + MeshItem item = batcher.NextItem(vertexCount, triangles.Length); + item.triangles = triangles; + + AtlasRegion region = (AtlasRegion)mesh.RendererObject; + item.texture = (Texture2D)region.page.rendererObject; + + Color color; + float a = skeletonA * slot.A * mesh.A; + if (premultipliedAlpha) { + color = new Color( + skeletonR * slot.R * mesh.R * a, + skeletonG * slot.G * mesh.G * a, + skeletonB * slot.B * mesh.B * a, a); + } else { + color = new Color( + skeletonR * slot.R * mesh.R, + skeletonG * slot.G * mesh.G, + skeletonB * slot.B * mesh.B, a); + } + + float[] uvs = mesh.UVs; + VertexPositionColorTexture[] itemVertices = item.vertices; + for (int ii = 0, v = 0; v < vertexCount; ii++, v += 2) { + itemVertices[ii].Color = color; + itemVertices[ii].Position.X = vertices[v]; + itemVertices[ii].Position.Y = vertices[v + 1]; + itemVertices[ii].Position.Z = 0; + itemVertices[ii].TextureCoordinate.X = uvs[v]; + itemVertices[ii].TextureCoordinate.Y = uvs[v + 1]; + } + } + } + } + } } diff --git a/spine-xna/src/SkeletonRegionRenderer.cs b/spine-xna/src/SkeletonRegionRenderer.cs index c20c6b4100..686a1ab179 100644 --- a/spine-xna/src/SkeletonRegionRenderer.cs +++ b/spine-xna/src/SkeletonRegionRenderer.cs @@ -1,143 +1,142 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using System.Collections.Generic; -using Microsoft.Xna.Framework.Graphics; -using Microsoft.Xna.Framework; - -namespace Spine { - /// Draws region attachments. - public class SkeletonRegionRenderer { - GraphicsDevice device; - RegionBatcher batcher; - RasterizerState rasterizerState; - float[] vertices = new float[8]; - BlendState defaultBlendState; - - BasicEffect effect; - public BasicEffect Effect { get { return effect; } set { effect = value; } } - - private bool premultipliedAlpha; - public bool PremultipliedAlpha { get { return premultipliedAlpha; } set { premultipliedAlpha = value; } } - - public SkeletonRegionRenderer (GraphicsDevice device) { - this.device = device; - - batcher = new RegionBatcher(); - - effect = new BasicEffect(device); - effect.World = Matrix.Identity; - effect.View = Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 1.0f), Vector3.Zero, Vector3.Up); - effect.TextureEnabled = true; - effect.VertexColorEnabled = true; - - rasterizerState = new RasterizerState(); - rasterizerState.CullMode = CullMode.None; - - Bone.yDown = true; - } - - public void Begin () { - defaultBlendState = premultipliedAlpha ? BlendState.AlphaBlend : BlendState.NonPremultiplied; - - device.RasterizerState = rasterizerState; - device.BlendState = defaultBlendState; - - effect.Projection = Matrix.CreateOrthographicOffCenter(0, device.Viewport.Width, device.Viewport.Height, 0, 1, 0); - } - - public void End () { - foreach (EffectPass pass in effect.CurrentTechnique.Passes) { - pass.Apply(); - batcher.Draw(device); - } - } - - public void Draw (Skeleton skeleton) { - var drawOrder = skeleton.DrawOrder; - var drawOrderItems = skeleton.DrawOrder.Items; - float skeletonR = skeleton.R, skeletonG = skeleton.G, skeletonB = skeleton.B, skeletonA = skeleton.A; - for (int i = 0, n = drawOrder.Count; i < n; i++) { - Slot slot = drawOrderItems[i]; - RegionAttachment regionAttachment = slot.Attachment as RegionAttachment; - if (regionAttachment != null) { - BlendState blend = slot.Data.BlendMode == BlendMode.additive ? BlendState.Additive : defaultBlendState; - if (device.BlendState != blend) { - End(); - device.BlendState = blend; - } - - RegionItem item = batcher.NextItem(); - - AtlasRegion region = (AtlasRegion)regionAttachment.RendererObject; - item.texture = (Texture2D)region.page.rendererObject; - - Color color; - float a = skeletonA * slot.A; - if (premultipliedAlpha) - color = new Color(skeletonR * slot.R * a, skeletonG * slot.G * a, skeletonB * slot.B * a, a); - else - color = new Color(skeletonR * slot.R, skeletonG * slot.G, skeletonB * slot.B, a); - item.vertexTL.Color = color; - item.vertexBL.Color = color; - item.vertexBR.Color = color; - item.vertexTR.Color = color; - - float[] vertices = this.vertices; - regionAttachment.ComputeWorldVertices(slot.Bone, vertices); - item.vertexTL.Position.X = vertices[RegionAttachment.X1]; - item.vertexTL.Position.Y = vertices[RegionAttachment.Y1]; - item.vertexTL.Position.Z = 0; - item.vertexBL.Position.X = vertices[RegionAttachment.X2]; - item.vertexBL.Position.Y = vertices[RegionAttachment.Y2]; - item.vertexBL.Position.Z = 0; - item.vertexBR.Position.X = vertices[RegionAttachment.X3]; - item.vertexBR.Position.Y = vertices[RegionAttachment.Y3]; - item.vertexBR.Position.Z = 0; - item.vertexTR.Position.X = vertices[RegionAttachment.X4]; - item.vertexTR.Position.Y = vertices[RegionAttachment.Y4]; - item.vertexTR.Position.Z = 0; - - float[] uvs = regionAttachment.UVs; - item.vertexTL.TextureCoordinate.X = uvs[RegionAttachment.X1]; - item.vertexTL.TextureCoordinate.Y = uvs[RegionAttachment.Y1]; - item.vertexBL.TextureCoordinate.X = uvs[RegionAttachment.X2]; - item.vertexBL.TextureCoordinate.Y = uvs[RegionAttachment.Y2]; - item.vertexBR.TextureCoordinate.X = uvs[RegionAttachment.X3]; - item.vertexBR.TextureCoordinate.Y = uvs[RegionAttachment.Y3]; - item.vertexTR.TextureCoordinate.X = uvs[RegionAttachment.X4]; - item.vertexTR.TextureCoordinate.Y = uvs[RegionAttachment.Y4]; - } - } - } - } +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework; + +namespace Spine { + /// Draws region attachments. + public class SkeletonRegionRenderer { + GraphicsDevice device; + RegionBatcher batcher; + RasterizerState rasterizerState; + float[] vertices = new float[8]; + BlendState defaultBlendState; + + BasicEffect effect; + public BasicEffect Effect { get { return effect; } set { effect = value; } } + + private bool premultipliedAlpha; + public bool PremultipliedAlpha { get { return premultipliedAlpha; } set { premultipliedAlpha = value; } } + + public SkeletonRegionRenderer (GraphicsDevice device) { + this.device = device; + + batcher = new RegionBatcher(); + + effect = new BasicEffect(device); + effect.World = Matrix.Identity; + effect.View = Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 1.0f), Vector3.Zero, Vector3.Up); + effect.TextureEnabled = true; + effect.VertexColorEnabled = true; + + rasterizerState = new RasterizerState(); + rasterizerState.CullMode = CullMode.None; + + Bone.yDown = true; + } + + public void Begin () { + defaultBlendState = premultipliedAlpha ? BlendState.AlphaBlend : BlendState.NonPremultiplied; + + device.RasterizerState = rasterizerState; + device.BlendState = defaultBlendState; + + effect.Projection = Matrix.CreateOrthographicOffCenter(0, device.Viewport.Width, device.Viewport.Height, 0, 1, 0); + } + + public void End () { + foreach (EffectPass pass in effect.CurrentTechnique.Passes) { + pass.Apply(); + batcher.Draw(device); + } + } + + public void Draw (Skeleton skeleton) { + var drawOrder = skeleton.DrawOrder; + var drawOrderItems = skeleton.DrawOrder.Items; + float skeletonR = skeleton.R, skeletonG = skeleton.G, skeletonB = skeleton.B, skeletonA = skeleton.A; + for (int i = 0, n = drawOrder.Count; i < n; i++) { + Slot slot = drawOrderItems[i]; + RegionAttachment regionAttachment = slot.Attachment as RegionAttachment; + if (regionAttachment != null) { + BlendState blend = slot.Data.BlendMode == BlendMode.additive ? BlendState.Additive : defaultBlendState; + if (device.BlendState != blend) { + End(); + device.BlendState = blend; + } + + RegionItem item = batcher.NextItem(); + + AtlasRegion region = (AtlasRegion)regionAttachment.RendererObject; + item.texture = (Texture2D)region.page.rendererObject; + + Color color; + float a = skeletonA * slot.A; + if (premultipliedAlpha) + color = new Color(skeletonR * slot.R * a, skeletonG * slot.G * a, skeletonB * slot.B * a, a); + else + color = new Color(skeletonR * slot.R, skeletonG * slot.G, skeletonB * slot.B, a); + item.vertexTL.Color = color; + item.vertexBL.Color = color; + item.vertexBR.Color = color; + item.vertexTR.Color = color; + + float[] vertices = this.vertices; + regionAttachment.ComputeWorldVertices(slot.Bone, vertices); + item.vertexTL.Position.X = vertices[RegionAttachment.X1]; + item.vertexTL.Position.Y = vertices[RegionAttachment.Y1]; + item.vertexTL.Position.Z = 0; + item.vertexBL.Position.X = vertices[RegionAttachment.X2]; + item.vertexBL.Position.Y = vertices[RegionAttachment.Y2]; + item.vertexBL.Position.Z = 0; + item.vertexBR.Position.X = vertices[RegionAttachment.X3]; + item.vertexBR.Position.Y = vertices[RegionAttachment.Y3]; + item.vertexBR.Position.Z = 0; + item.vertexTR.Position.X = vertices[RegionAttachment.X4]; + item.vertexTR.Position.Y = vertices[RegionAttachment.Y4]; + item.vertexTR.Position.Z = 0; + + float[] uvs = regionAttachment.UVs; + item.vertexTL.TextureCoordinate.X = uvs[RegionAttachment.X1]; + item.vertexTL.TextureCoordinate.Y = uvs[RegionAttachment.Y1]; + item.vertexBL.TextureCoordinate.X = uvs[RegionAttachment.X2]; + item.vertexBL.TextureCoordinate.Y = uvs[RegionAttachment.Y2]; + item.vertexBR.TextureCoordinate.X = uvs[RegionAttachment.X3]; + item.vertexBR.TextureCoordinate.Y = uvs[RegionAttachment.Y3]; + item.vertexTR.TextureCoordinate.X = uvs[RegionAttachment.X4]; + item.vertexTR.TextureCoordinate.Y = uvs[RegionAttachment.Y4]; + } + } + } + } } diff --git a/spine-xna/src/Util.cs b/spine-xna/src/Util.cs index 1df35a44dc..864d0161b0 100644 --- a/spine-xna/src/Util.cs +++ b/spine-xna/src/Util.cs @@ -1,18 +1,17 @@ /****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 + * Spine Runtimes Software License v2.5 * - * Copyright (c) 2013-2015, Esoteric Software + * Copyright (c) 2013-2016, Esoteric Software * All rights reserved. * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, * or other intellectual property or proprietary rights notices on or in the * Software, including any copy thereof. Redistributions in binary or source * form must include this license and terms. @@ -22,11 +21,11 @@ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ using System; diff --git a/spine-xna/src/XnaTextureLoader.cs b/spine-xna/src/XnaTextureLoader.cs index 30359bc93e..c718247afb 100644 --- a/spine-xna/src/XnaTextureLoader.cs +++ b/spine-xna/src/XnaTextureLoader.cs @@ -1,56 +1,55 @@ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.3 - * - * Copyright (c) 2013-2015, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to use, install, execute and perform the Spine - * Runtimes Software (the "Software") and derivative works solely for personal - * or internal use. Without the written permission of Esoteric Software (see - * Section 2 of the Spine Software License Agreement), you may not (a) modify, - * translate, adapt or otherwise create derivative works, improvements of the - * Software or develop new applications using the Software or (b) remove, - * delete, alter or obscure any trademarks or any copyright, trademark, patent - * or other intellectual property or proprietary rights notices on or in the - * Software, including any copy thereof. Redistributions in binary or source - * form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/****************************************************************************** + * Spine Runtimes Software License v2.5 + * + * Copyright (c) 2013-2016, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable, and + * non-transferable license to use, install, execute, and perform the Spine + * Runtimes software and derivative works solely for personal or internal + * use. Without the written permission of Esoteric Software (see Section 2 of + * the Spine Software License Agreement), you may not (a) modify, translate, + * adapt, or develop new applications using the Spine Runtimes or otherwise + * create derivative works or improvements of the Spine Runtimes or (b) remove, + * delete, alter, or obscure any trademarks or any copyright, trademark, patent, + * or other intellectual property or proprietary rights notices on or in the + * Software, including any copy thereof. Redistributions in binary or source + * form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF + * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -using System; -using System.IO; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; - -namespace Spine { - public class XnaTextureLoader : TextureLoader { - GraphicsDevice device; - - public XnaTextureLoader (GraphicsDevice device) { - this.device = device; - } - - public void Load (AtlasPage page, String path) { - Texture2D texture = Util.LoadTexture(device, path); - page.rendererObject = texture; - page.width = texture.Width; - page.height = texture.Height; - } - - public void Unload (Object texture) { - ((Texture2D)texture).Dispose(); - } - } +using System; +using System.IO; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace Spine { + public class XnaTextureLoader : TextureLoader { + GraphicsDevice device; + + public XnaTextureLoader (GraphicsDevice device) { + this.device = device; + } + + public void Load (AtlasPage page, String path) { + Texture2D texture = Util.LoadTexture(device, path); + page.rendererObject = texture; + page.width = texture.Width; + page.height = texture.Height; + } + + public void Unload (Object texture) { + ((Texture2D)texture).Dispose(); + } + } }