Browse Source

Merge remote-tracking branch 'origin/3.6' into 3.6

NathanSweet 8 years ago
parent
commit
e62d8a921c
100 changed files with 2605 additions and 1578 deletions
  1. 3 0
      .gitignore
  2. 12 0
      CHANGELOG.md
  3. 2 2
      spine-as3/README.md
  4. BIN
      spine-as3/spine-as3-example/lib/spine-as3.swc
  5. 8 0
      spine-as3/spine-as3/.settings/org.eclipse.core.resources.prefs
  6. 5 5
      spine-as3/spine-as3/src/spine/Bone.as
  7. 41 0
      spine-as3/spine-as3/src/spine/Interpolation.as
  8. 12 1
      spine-as3/spine-as3/src/spine/MathUtils.as
  9. 3 1
      spine-as3/spine-as3/src/spine/PathConstraint.as
  10. 45 0
      spine-as3/spine-as3/src/spine/Vertex.as
  11. 39 0
      spine-as3/spine-as3/src/spine/VertexEffect.as
  12. 2 6
      spine-as3/spine-as3/src/spine/animation/AnimationState.as
  13. 29 9
      spine-as3/spine-as3/src/spine/animation/DeformTimeline.as
  14. 20 20
      spine-as3/spine-as3/src/spine/attachments/RegionAttachment.as
  15. 46 0
      spine-as3/spine-as3/src/spine/interpolation/Pow.as
  16. 41 0
      spine-as3/spine-as3/src/spine/interpolation/PowOut.as
  17. 57 0
      spine-as3/spine-as3/src/spine/vertexeffects/JitterEffect.as
  18. 84 0
      spine-as3/spine-as3/src/spine/vertexeffects/SwirlEffect.as
  19. 2 2
      spine-c/README.md
  20. 3 3
      spine-c/spine-c-unit-tests/tests/C_InterfaceTestFixture.cpp
  21. 1 1
      spine-c/spine-c-unit-tests/tests/MemoryTestFixture.cpp
  22. 0 2
      spine-c/spine-c/include/spine/Array.h
  23. 4 0
      spine-c/spine-c/include/spine/Color.h
  24. 84 0
      spine-c/spine-c/include/spine/VertexEffect.h
  25. 28 13
      spine-c/spine-c/include/spine/extension.h
  26. 1 0
      spine-c/spine-c/include/spine/spine.h
  27. 18 5
      spine-c/spine-c/src/spine/Animation.c
  28. 1 5
      spine-c/spine-c/src/spine/AnimationState.c
  29. 4 4
      spine-c/spine-c/src/spine/Bone.c
  30. 3 1
      spine-c/spine-c/src/spine/PathConstraint.c
  31. 98 0
      spine-c/spine-c/src/spine/VertexEffect.c
  32. 51 10
      spine-c/spine-c/src/spine/extension.c
  33. 3 2
      spine-cocos2d-objc/README.md
  34. 5 0
      spine-cocos2d-objc/example/RaptorExample.m
  35. 8 4
      spine-cocos2d-objc/spine-cocos2d-objc.xcodeproj/project.pbxproj
  36. 2 0
      spine-cocos2d-objc/src/spine/SkeletonRenderer.h
  37. 64 12
      spine-cocos2d-objc/src/spine/SkeletonRenderer.m
  38. 1 1
      spine-cocos2d-objc/src/spine/spine-cocos2d-objc.m
  39. 4 4
      spine-cocos2dx/README.md
  40. 17 1
      spine-cocos2dx/example/Classes/RaptorExample.cpp
  41. 3 0
      spine-cocos2dx/example/Classes/RaptorExample.h
  42. 1 0
      spine-cocos2dx/example/proj.android/jni/Android.mk
  43. 98 0
      spine-cocos2dx/example/proj.ios_mac/VertexEffect.c
  44. 6 0
      spine-cocos2dx/example/proj.ios_mac/spine-cocos2d-x.xcodeproj/project.pbxproj
  45. 1 0
      spine-cocos2dx/example/proj.win32/spine-cocos2d-x.vcxproj
  46. 167 46
      spine-cocos2dx/src/spine/SkeletonRenderer.cpp
  47. 5 1
      spine-cocos2dx/src/spine/SkeletonRenderer.h
  48. 2 2
      spine-corona/README.md
  49. 16 5
      spine-corona/main.lua
  50. 39 7
      spine-corona/spine-corona/spine.lua
  51. 1 1
      spine-csharp/README.md
  52. 45 43
      spine-csharp/src/AnimationState.cs
  53. 20 6
      spine-csharp/src/Atlas.cs
  54. 5 5
      spine-csharp/src/Bone.cs
  55. 18 3
      spine-csharp/src/ExposedList.cs
  56. 3 1
      spine-csharp/src/PathConstraint.cs
  57. 4 2
      spine-csharp/src/Skeleton.cs
  58. 1 1
      spine-csharp/src/SkeletonBinary.cs
  59. 6 6
      spine-csharp/src/SkeletonClipping.cs
  60. 10 3
      spine-csharp/src/SkeletonJson.cs
  61. 2 2
      spine-csharp/src/Triangulator.cs
  62. 2 2
      spine-libgdx/README.md
  63. 1 0
      spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/VertexEffectTest.java
  64. 5 5
      spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java
  65. 4 2
      spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java
  66. 2 1
      spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonClipping.java
  67. 1 1
      spine-love/README.md
  68. 23 2
      spine-love/main.lua
  69. 57 12
      spine-love/spine-love/spine.lua
  70. 32 10
      spine-lua/Animation.lua
  71. 5 7
      spine-lua/AnimationState.lua
  72. 6 6
      spine-lua/Bone.lua
  73. 48 0
      spine-lua/Interpolation.lua
  74. 1 0
      spine-lua/PathConstraint.lua
  75. 2 2
      spine-lua/README.md
  76. 13 10
      spine-lua/Skin.lua
  77. 1 0
      spine-lua/attachments/MeshAttachment.lua
  78. 14 0
      spine-lua/utils.lua
  79. 64 0
      spine-lua/vertexeffects/JitterEffect.lua
  80. 85 0
      spine-lua/vertexeffects/SwirlEffect.lua
  81. 3 3
      spine-monogame/README.md
  82. 32 48
      spine-monogame/example/ExampleGame.cs
  83. 1 0
      spine-sfml/CMakeLists.txt
  84. 5 5
      spine-sfml/README.md
  85. 12 0
      spine-sfml/example/main.cpp
  86. 61 8
      spine-sfml/src/spine/spine-sfml.cpp
  87. 5 0
      spine-sfml/src/spine/spine-sfml.h
  88. 2 2
      spine-starling/README.md
  89. BIN
      spine-starling/spine-starling-example/lib/spine-as3.swc
  90. BIN
      spine-starling/spine-starling-example/lib/spine-starling.swc
  91. 1 1
      spine-starling/spine-starling-example/src/spine/examples/GoblinsExample.as
  92. 22 1
      spine-starling/spine-starling-example/src/spine/examples/RaptorExample.as
  93. BIN
      spine-starling/spine-starling/lib/spine-as3.swc
  94. 41 7
      spine-starling/spine-starling/src/spine/starling/SkeletonSprite.as
  95. 37 69
      spine-starling/spine-starling/src/spine/starling/StarlingAtlasAttachmentLoader.as
  96. 2 2
      spine-ts/README.md
  97. 300 296
      spine-ts/build/spine-all.d.ts
  98. 167 584
      spine-ts/build/spine-all.js
  99. 0 0
      spine-ts/build/spine-all.js.map
  100. 244 244
      spine-ts/build/spine-canvas.d.ts

+ 3 - 0
.gitignore

@@ -55,6 +55,7 @@ spine-xna/obj
 spine-xna/example/bin
 spine-xna/example/obj
 spine-xna/example-content/obj/
+spine-xna/.vs/
 
 spine-unity/Assets/spine-csharp*
 !spine-unity/Assets/spine-csharp/Place spine-csharp src here.*
@@ -107,3 +108,5 @@ spine-ue4/SpineUE4.VC.opendb
 spine-ue4/SpineUE4.VC.db
 spine-ue4/SpineUE4.sln
 spine-ue4/SpineUE4.VC.db
+spine-ue4/.vs/
+spine-ue4/SpineUE4.VC.VC.opendb

+ 12 - 0
CHANGELOG.md

@@ -17,12 +17,14 @@
   * Added `ClippingAttachment`, additional method `newClippingAttachment` in `AttachmentLoader` interface.
   * `AnimationState#apply` returns boolean indicating if any timeline was applied or not.
   * `Animation#apply` and `Timeline#apply`` now take enums `MixPose` and `MixDirection` instead of booleans
+  * Added `VertexEffect` and implementations `JitterEffect` and `SwirlEffect`. Allows you to modify vertices before they are submitted for drawing. See Starling changes.
 
 ### Starling
  * Fixed renderer to work with 3.6 changes.
  * Added support for two color tinting.
  * Added support for clipping.
  * Added support for rotated regions in texture atlas loaded via StarlingAtlasAttachmentLoader.
+ * Added support for vertex effects. See `RaptorExample.as`
 
 ## C
  * **Breaking changes**
@@ -46,6 +48,8 @@
   * Added `spSkeletonClipper` and `spTriangulator`, used to implement software clipping of attachments.
   * `AnimationState#apply` returns boolean indicating if any timeline was applied or not.
   * `Animation#apply` and `Timeline#apply`` now take enums `MixPose` and `MixDirection` instead of booleans
+  * Added `spVertexEffect` and corresponding implementations `spJitterVertexEffect` and `spSwirlVertexEffect`. Create/dispose through the corresponding `spXXXVertexEffect_create()/dispose()` functions. Set on framework/engine specific renderer. See changes for spine-c based frameworks/engines below.
+  * Functions in `extension.h` are not prefixed with `_sp` instead of just `_` to avoid interference with other libraries.
 
 ### Cocos2d-X
  * Fixed renderer to work with 3.6 changes
@@ -55,6 +59,7 @@
  * Added mesh debug rendering. Enable/Disable via `SkeletonRenderer::setDebugMeshesEnabled()`.
  * Added support for clipping.
  * SkeletonRenderer now combines the displayed color of the Node (cascaded from all parents) with the skeleton color for tinting.
+ * Added support for vertex effects. See `RaptorExample.cpp`.
 
 ### Cocos2d-Objc
  * Fixed renderer to work with 3.6 changes
@@ -64,6 +69,7 @@
 ### SFML
  * Fixed renderer to work with 3.6 changes. Sadly, two color tinting does not work, as the vertex format in SFML is fixed.
  * Added support for clipping.
+ * Added support for vertex effects. See raptor example.
 
 ### Unreal Engine 4
  * Fixed renderer to work with 3.6 changes
@@ -134,6 +140,7 @@
  * Removed `RegionBatcher` and `SkeletonRegionRenderer`, renamed `SkeletonMeshRenderer` to `SkeletonRenderer`
  * Added support for two color tint. For it to work, you need to add the `SpineEffect.fx` file to your content project, then load it via `var effect = Content.Load<Effect>("SpineEffect");`, and set it on the `SkeletonRenderer`. See the example project for code.
  * Added support for any `Effect` to be used by `SkeletonRenderer`
+ * Added `SkeletonDebugRenderer`
 
 ## Java
  * **Breaking changes**
@@ -174,15 +181,18 @@
   * Added `SkeletonClipper` and `Triangulator`, used to implement software clipping of attachments.
   * `AnimationState#apply` returns boolean indicating if any timeline was applied or not.
   * `Animation#apply` and `Timeline#apply`` now take enums `MixPose` and `MixDirection` instead of booleans
+  * Added `JitterEffect` and `SwirlEffect` and support for vertex effects in Corona and Love
 
 ### Love2D
   * Fixed renderer to work with 3.6 changes
   * Added support for two color tinting. Enable it via `SkeletonRenderer.new(true)`.
   * Added clipping support.
+  * Added support for vertex effects. Set an implementation like "JitterEffect" on `Skeleton.vertexEffect`. See `main.lua` for an example.
 
 ### Corona
   * Fixed renderer to work with 3.6 changes. Sadly, two color tinting is not supported, as Corona doesn't let us change the vertex format needed and its doesn't allow to modify shaders in the way needed for two color tinting
   * Added clipping support.
+  * Added support for vertex effects. Set an implementation like "JitterEffect" on `SkeletonRenderer.vertexEffect`. See `main.lua` for an example
 
 ## Typescript/Javascript
  * **Breaking changes**
@@ -216,6 +226,7 @@
  * Improved performance by using `DYNAMIC_DRAW` for vertex buffer objects and fixing bug that copied to much data to the GPU each frame in `PolygonBatcher`/`Mesh`.
  * Added two color tinting support, enabled by default. You can disable it via the constructors of `SceneRenderer`, `SkeletonRenderer`and `PolygonBatcher`. Note that you will need to use a shader created via `Shader.newTwoColoredTexturedShader` shader with `SkeletonRenderer` and `PolygonBatcher` if two color tinting is enabled.
  * Added clipping support
+ * Added `VertexEffect` interface, instances of which can be set on `SkeletonRenderer`. Allows to modify vertices before submitting them to GPU. See `SwirlEffect`, `JitterEffect`, and the example which allows to set effects.
 
 ### Canvas backend
  * Fixed renderer to work for 3.6 changes. Sadly, we can't support two color tinting via the Canvas API.
@@ -225,6 +236,7 @@
 ### Three.js backend
  * Fixed renderer to work with 3.6 changes. Two color tinting is not supported.
  * Added clipping support
+ * Added `VertexEffect` interface, instances of which can be set on `SkeletonMesh`. Allows to modify vertices before submitting them to GPU. See `SwirlEffect`, `JitterEffect`.
 
 ### Widget backend
  * Fixed WebGL context loss (see WebGL backend changes). Enabled automatically.

+ 2 - 2
spine-as3/README.md

@@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
 
 ## Spine version
 
-spine-as3 works with data exported from Spine 3.5.xx.
+spine-as3 works with data exported from Spine 3.6.xx.
 
 spine-as3 supports all Spine features, including meshes. If using the `spine.flash` classes for rendering, meshes are not supported.
 
@@ -18,7 +18,7 @@ spine-as3 does not yet support loading the binary format.
 
 ## Usage
 1. Create a new Flex or Adobe AIR project in your preferred IDE.
-2. Download the Spine Runtimes source using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip)
+2. Download the Spine Runtimes source using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip)
 3. Add the sources from `spine-as3/spine-as3/src/` to your project
 
 ## Example

BIN
spine-as3/spine-as3-example/lib/spine-as3.swc


+ 8 - 0
spine-as3/spine-as3/.settings/org.eclipse.core.resources.prefs

@@ -1,10 +1,18 @@
 eclipse.preferences.version=1
+encoding//src/spine/Interpolation.as=UTF-8
+encoding//src/spine/MathUtils.as=UTF-8
 encoding//src/spine/SkeletonClipping.as=UTF-8
 encoding//src/spine/SkeletonJson.as=UTF-8
 encoding//src/spine/Triangulator.as=UTF-8
+encoding//src/spine/Vertex.as=UTF-8
+encoding//src/spine/VertexEffect.as=UTF-8
 encoding//src/spine/animation/MixDirection.as=UTF-8
 encoding//src/spine/animation/MixPose.as=UTF-8
 encoding//src/spine/animation/TwoColorTimeline.as=UTF-8
 encoding//src/spine/attachments/ClippingAttachment.as=UTF-8
 encoding//src/spine/attachments/PointAttachment.as=UTF-8
+encoding//src/spine/interpolation/Pow.as=UTF-8
+encoding//src/spine/interpolation/PowOut.as=UTF-8
+encoding//src/spine/vertexeffects/JitterEffect.as=UTF-8
+encoding//src/spine/vertexeffects/SwirlEffect.as=UTF-8
 encoding/<project>=UTF-8

+ 5 - 5
spine-as3/spine-as3/src/spine/Bone.as

@@ -188,14 +188,14 @@ package spine {
 					lb = MathUtils.cosDeg(90 + shearY) * scaleY;
 					lc = MathUtils.sinDeg(shearX) * scaleX;
 					ld = MathUtils.sinDeg(90 + shearY) * scaleY;
+					if (this.data.transformMode != TransformMode.noScaleOrReflection ? pa * pd - pb * pc < 0 : this.skeleton.flipX != this.skeleton.flipY) {
+						zb = -zb;
+						zd = -zd;
+					}
 					this.a = za * la + zb * lc;
 					this.b = za * lb + zb * ld;
 					this.c = zc * la + zd * lc;
-					this.d = zc * lb + zd * ld;
-					if (this.data.transformMode != TransformMode.noScaleOrReflection ? pa * pd - pb * pc < 0 : skeleton.flipX != skeleton.flipY) {
-						this.b = -this.b;
-						this.d = -this.d;
-					}
+					this.d = zc * lb + zd * ld;					
 					return;
 				}
 			}

+ 41 - 0
spine-as3/spine-as3/src/spine/Interpolation.as

@@ -0,0 +1,41 @@
+/******************************************************************************
+ * Spine Runtimes Software License v2.5
+ *
+ * Copyright (c) 2013-2016, Esoteric Software
+ * All rights reserved.
+ *
+ * You are granted a perpetual, non-exclusive, non-sublicensable, and
+ * non-transferable license to use, install, execute, and perform the Spine
+ * Runtimes software and derivative works solely for personal or internal
+ * use. Without the written permission of Esoteric Software (see Section 2 of
+ * the Spine Software License Agreement), you may not (a) modify, translate,
+ * adapt, or develop new applications using the Spine Runtimes or otherwise
+ * create derivative works or improvements of the Spine Runtimes or (b) remove,
+ * delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
+ * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (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 Interpolation {		
+		protected function applyInternal (a : Number) : Number {
+			return a;
+		}
+		
+		public function apply (start : Number, end : Number, a : Number) : Number {
+			return start + (end - start) * applyInternal(a);
+		}
+	}
+}

+ 12 - 1
spine-as3/spine-as3/src/spine/MathUtils.as

@@ -27,7 +27,7 @@
  * 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 PI : Number = Math.PI;
@@ -52,5 +52,16 @@ package spine {
 		static public function signum(value : Number) : Number {
 			return value > 0 ? 1 : value < 0 ? -1 : 0;
 		}
+
+		static public function randomTriangular(min : Number, max : Number) : Number {
+			return randomTriangularWith(min, max, (min + max) * 0.5);
+		}
+
+		static public function randomTriangularWith(min : Number, max : Number, mode : Number) : Number {
+			var u : Number = Math.random();
+			var d : Number = max - min;
+			if (u <= (mode - min) / d) return min + Math.sqrt(u * d * (mode - min));
+			return max - Math.sqrt((1 - u) * d * (max - mode));
+		}
 	}
 }

+ 3 - 1
spine-as3/spine-as3/src/spine/PathConstraint.as

@@ -87,7 +87,9 @@ package spine {
 				}
 				for (var i : int = 0, n : int = spacesCount - 1; i < n;) {
 					var bone : Bone = bones[i];
-					var setupLength : Number = bone.data.length, x : Number = setupLength * bone.a, y : Number = setupLength * bone.c;
+					var setupLength : Number = bone.data.length;
+					if (setupLength == 0) setupLength = 0.000000001;
+					var x : Number = setupLength * bone.a, y : Number = setupLength * bone.c;
 					var length : Number = Math.sqrt(x * x + y * y);
 					if (scale) lengths[i] = length;
 					spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;

+ 45 - 0
spine-as3/spine-as3/src/spine/Vertex.as

@@ -0,0 +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.
+ *****************************************************************************/
+
+package spine {
+	/**
+	 * @author badlogic
+	 */
+	public class Vertex {
+		public var x : Number;
+		public var y : Number;
+		public var u : Number;
+		public var v : Number;
+		public var light : Color = new spine.Color(0, 0, 0);
+		public var dark : Color = new spine.Color(0, 0, 0);
+		
+		function Vertex() { }
+	}
+}

+ 39 - 0
spine-as3/spine-as3/src/spine/VertexEffect.as

@@ -0,0 +1,39 @@
+/******************************************************************************
+ * Spine Runtimes Software License v2.5
+ *
+ * Copyright (c) 2013-2016, Esoteric Software
+ * All rights reserved.
+ *
+ * You are granted a perpetual, non-exclusive, non-sublicensable, and
+ * non-transferable license to use, install, execute, and perform the Spine
+ * Runtimes software and derivative works solely for personal or internal
+ * use. Without the written permission of Esoteric Software (see Section 2 of
+ * the Spine Software License Agreement), you may not (a) modify, translate,
+ * adapt, or develop new applications using the Spine Runtimes or otherwise
+ * create derivative works or improvements of the Spine Runtimes or (b) remove,
+ * delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
+ * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (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 VertexEffect {
+		function begin(skeleton : Skeleton) : void;
+
+		function transform(vertex : Vertex) : void;
+		
+		function end() : void;
+	}
+}

+ 2 - 6
spine-as3/spine-as3/src/spine/animation/AnimationState.as

@@ -551,14 +551,10 @@ package spine.animation {
 			animationsChanged = false;
 
 			var propertyIDs : Dictionary = this.propertyIDs = new Dictionary();					
-			var mixingTo : Vector.<TrackEntry> = this.mixingTo;
-			var lastEntry : TrackEntry = null;
+			var mixingTo : Vector.<TrackEntry> = this.mixingTo;			
 			for (var i : int = 0, n : int = tracks.length; i < n; i++) {
 				var entry : TrackEntry = tracks[i];
-				if (entry != null) {
-					entry.setTimelineData(lastEntry, mixingTo, propertyIDs);
-					lastEntry = entry;
-				}
+				if (entry != null) entry.setTimelineData(null, mixingTo, propertyIDs);				
 			}
 		}
 

+ 29 - 9
spine-as3/spine-as3/src/spine/animation/DeformTimeline.as

@@ -36,6 +36,7 @@ package spine.animation {
 	import spine.Slot;
 
 	public class DeformTimeline extends CurveTimeline {
+		private static var zeros : Vector.<Number> = new Vector.<Number>(64);
 		public var slotIndex : int;
 		public var frames : Vector.<Number>;
 		public var frameVertices : Vector.<Vector.<Number>>;
@@ -58,35 +59,54 @@ package spine.animation {
 		}
 
 		override public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, pose : MixPose, direction : MixDirection) : void {
+			var vertexAttachment : VertexAttachment;
+			var setupVertices : Vector.<Number>;
 			var slot : Slot = skeleton.slots[slotIndex];
 			var slotAttachment : Attachment = slot.attachment;
 			if (!(slotAttachment is VertexAttachment) || !(VertexAttachment(slotAttachment)).applyDeform(attachment)) return;
 			
 			var verticesArray : Vector.<Number> = slot.attachmentVertices;
 			var frameVertices : Vector.<Vector.<Number>> = this.frameVertices;
-			var vertexCount : int = frameVertices[0].length;
-			if (verticesArray.length != vertexCount && pose != MixPose.setup) alpha = 1; // Don't mix from uninitialized slot vertices.
+			var vertexCount : int = frameVertices[0].length;			
 			verticesArray.length = vertexCount;
 			var vertices : Vector.<Number> = verticesArray;
 
 			var frames : Vector.<Number> = this.frames;
 			var i : int;			
 			if (time < frames[0]) {
+				vertexAttachment = VertexAttachment(slotAttachment);
 				switch (pose) {
 				case MixPose.setup:
-					verticesArray.length = 0;
+					var zeroVertices : Vector.<Number>;
+					if (vertexAttachment.bones == null) {
+						// Unweighted vertex positions (setup pose).
+						zeroVertices = vertexAttachment.vertices;
+					} else {
+						// Weighted deform offsets (zeros).
+						zeroVertices = zeros;
+						if (zeroVertices.length < vertexCount) zeros = zeroVertices = new Vector.<Number>(vertexCount);
+					}					
+					for (i = 0; i < vertexCount; i++)
+						vertices[i] = zeroVertices[i];
 					return;
 				case MixPose.current:
-					alpha = 1 - alpha;
-					for (i = 0; i < vertexCount; i++)
-						vertices[i] *= alpha;
+					if (alpha == 1) break;
+					if (vertexAttachment.bones == null) {
+						// Unweighted vertex positions.
+						setupVertices = vertexAttachment.vertices;
+						for (i = 0; i < vertexCount; i++)
+							vertices[i] += (setupVertices[i] - vertices[i]) * alpha;
+					} else {
+						// Weighted deform offsets.
+						alpha = 1 - alpha;
+						for (i = 0; i < vertexCount; i++)
+							vertices[i] *= alpha;
+					}
 				}
 				return;
 			}						
 
-			var n : int;
-			var vertexAttachment : VertexAttachment;
-			var setupVertices : Vector.<Number>;
+			var n : int;			
 			var setup : Number, prev : Number;
 			if (time >= frames[frames.length - 1]) { // Time is after last frame.
 				var lastVertices : Vector.<Number> = frameVertices[frames.length - 1];

+ 20 - 20
spine-as3/spine-as3/src/spine/attachments/RegionAttachment.as

@@ -69,29 +69,29 @@ package spine.attachments {
 		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 localX : Number = -width * 0.5 * scaleX + regionOffsetX * regionScaleX;
+			var localY : Number = -height * 0.5 * 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[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;
+			var ulDist : Number = Math.sqrt(localX * localX + localY * localY);
+			var ulAngle : Number = Math.atan2(localY, localX);
+			var urDist : Number = Math.sqrt(localX2 * localX2 + localY * localY);
+			var urAngle : Number = Math.atan2(localY, localX2);
+			var blDist : Number = Math.sqrt(localX * localX + localY2 * localY2);
+			var blAngle : Number = Math.atan2(localY2, localX);
+			var brDist : Number = Math.sqrt(localX2 * localX2 + localY2 * localY2);
+			var brAngle : Number = Math.atan2(localY2, localX2);
+					
+			offset[BLX] = Math.cos(radians - blAngle) * blDist + x;
+			offset[BLY] = Math.sin(radians - blAngle) * blDist + y;
+			offset[ULX] = Math.cos(radians - ulAngle) * ulDist + x;
+			offset[ULY] = Math.sin(radians - ulAngle) * ulDist + y;
+			offset[URX] = Math.cos(radians - urAngle) * urDist + x;
+			offset[URY] = Math.sin(radians - urAngle) * urDist + y;
+			offset[BRX] = Math.cos(radians - brAngle) * brDist + x;
+			offset[BRY] = Math.sin(radians - brAngle) * brDist + y;
 		}
 
 		public function setUVs(u : Number, v : Number, u2 : Number, v2 : Number, rotate : Boolean) : void {

+ 46 - 0
spine-as3/spine-as3/src/spine/interpolation/Pow.as

@@ -0,0 +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.
+ *****************************************************************************/
+
+package spine.interpolation {
+	import spine.Interpolation;
+	
+	public class Pow extends Interpolation {
+		protected var power : Number;
+		
+		public function Pow(power : Number) {
+			this.power = power;
+		}
+		
+		protected override function applyInternal(a : Number) : Number {
+			if (a <= 0.5) return Math.pow(a * 2, power) / 2;
+			return Math.pow((a - 1) * 2, power) / (power % 2 == 0 ? -2 : 2) + 1;
+		}
+	}
+}

+ 41 - 0
spine-as3/spine-as3/src/spine/interpolation/PowOut.as

@@ -0,0 +1,41 @@
+/******************************************************************************
+ * Spine Runtimes Software License v2.5
+ *
+ * Copyright (c) 2013-2016, Esoteric Software
+ * All rights reserved.
+ *
+ * You are granted a perpetual, non-exclusive, non-sublicensable, and
+ * non-transferable license to use, install, execute, and perform the Spine
+ * Runtimes software and derivative works solely for personal or internal
+ * use. Without the written permission of Esoteric Software (see Section 2 of
+ * the Spine Software License Agreement), you may not (a) modify, translate,
+ * adapt, or develop new applications using the Spine Runtimes or otherwise
+ * create derivative works or improvements of the Spine Runtimes or (b) remove,
+ * delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
+ * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (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.interpolation {
+	public class PowOut extends Pow {
+		public function PowOut(power : Number) {
+			super(power);	
+		}
+		
+		protected override function applyInternal(a : Number) : Number {
+			return Math.pow(a - 1, power) * (power % 2 == 0 ? -1 : 1) + 1;
+		}
+	}
+}

+ 57 - 0
spine-as3/spine-as3/src/spine/vertexeffects/JitterEffect.as

@@ -0,0 +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.
+ *****************************************************************************/
+
+package spine.vertexeffects {
+	import spine.MathUtils;
+	import spine.Skeleton;
+	import spine.Vertex;
+	import spine.VertexEffect;
+ 
+ 	public class JitterEffect implements VertexEffect {
+		public var jitterX : Number;
+		public var jitterY : Number;
+		
+		public function JitterEffect(jitterX: Number, jitterY: Number) {
+			this.jitterX = jitterX;
+			this.jitterY = jitterY;
+		}
+		
+		public function begin(skeleton : Skeleton) : void {
+		}
+
+		public function transform(vertex : Vertex) : void {
+			vertex.x += MathUtils.randomTriangular(-jitterX, jitterY);
+			vertex.y += MathUtils.randomTriangular(-jitterX, jitterY);
+		}
+
+		public function end() : void {
+		}
+	}
+}

+ 84 - 0
spine-as3/spine-as3/src/spine/vertexeffects/SwirlEffect.as

@@ -0,0 +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.
+ *****************************************************************************/
+
+package spine.vertexeffects {
+	import spine.interpolation.Pow;
+	import spine.MathUtils;
+	import spine.Interpolation;
+	import spine.Skeleton;
+	import spine.Vertex;
+	import spine.VertexEffect;
+	
+	public class SwirlEffect implements VertexEffect {
+		private var worldX : Number, worldY : Number, _radius : Number = 0, _angle : Number = 0;
+		private var _interpolation : Interpolation;
+		private var _centerX : Number = 0, _centerY : Number = 0;
+		
+		public function SwirlEffect(radius : Number) {
+			this._interpolation = new Pow(2);;
+			this._radius = radius;
+		}
+		
+		public function begin(skeleton : Skeleton) : void {
+			worldX = skeleton.x + _centerX;
+			worldY = skeleton.y + _centerY;			
+		}
+
+		public function transform(vertex : Vertex) : void {
+			var x : Number = vertex.x - worldX;
+			var y : Number = vertex.y - worldY;
+			var dist : Number = Math.sqrt(x * x + y * y);
+			if (dist < radius) {
+				var theta : Number = interpolation.apply(0, angle, (radius - dist) / radius);
+				var cos : Number = Math.cos(theta), sin : Number = Math.sin(theta);
+				vertex.x = cos * x - sin * y + worldX;
+				vertex.y = sin * x + cos * y + worldY;
+			}
+		}
+
+		public function end() : void {
+		}
+		
+		public function get radius () : Number { return _radius; }
+		public function set radius (radius : Number) : void { _radius = radius; }
+		
+		public function get angle () : Number { return _angle; }
+		public function set angle (angle : Number) : void { _angle = angle * MathUtils.degRad; }
+		
+		public function get centerX () : Number { return _centerX; }
+		public function set centerX (centerX : Number) : void { _centerX = centerX; }
+		
+		public function get centerY () : Number { return _centerY; }
+		public function set centerY (centerY : Number) : void { _centerY = centerY; }
+		
+		public function get interpolation () : Interpolation { return _interpolation; }
+		public function set interpolation (interpolation : Interpolation) : void { _interpolation = interpolation; }
+	}
+}

+ 2 - 2
spine-c/README.md

@@ -12,13 +12,13 @@ The Spine Runtimes are developed with the intent to be used with data exported f
 
 ## Spine version
 
-spine-c works with data exported from Spine 3.5.xx.
+spine-c works with data exported from Spine 3.6.xx.
 
 spine-c supports all Spine features.
 
 ## Setup
 
-1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip).
+1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip).
 1. Open the `spine-c.sln` Visual C++ 2010 Express project file. For other IDEs, you will need to create a new project and import the source.
 
 Alternatively, the contents of the `spine-c/spine-c/src` and `spine-c/spine-c/include` directories can be copied into your project. Be sure your header search is configured to find the contents of the `spine-c/spine-c/include` directory. Note that the includes use `spine/Xxx.h`, so the `spine` directory cannot be omitted when copying the files.

+ 3 - 3
spine-c/spine-c-unit-tests/tests/C_InterfaceTestFixture.cpp

@@ -6,13 +6,13 @@
 
 #include "KMemory.h" // last include
 
-#define SPINEBOY_JSON "testdata/spineboy/spineboy.json"
+#define SPINEBOY_JSON "testdata/spineboy/spineboy-ess.json"
 #define SPINEBOY_ATLAS "testdata/spineboy/spineboy.atlas"
 
-#define RAPTOR_JSON "testdata/raptor/raptor.json"
+#define RAPTOR_JSON "testdata/raptor/raptor-pro.json"
 #define RAPTOR_ATLAS "testdata/raptor/raptor.atlas"
 
-#define GOBLINS_JSON "testdata/goblins/goblins.json"
+#define GOBLINS_JSON "testdata/goblins/goblins-pro.json"
 #define GOBLINS_ATLAS "testdata/goblins/goblins.atlas"
 
 #define MAX_RUN_TIME 6000 // equal to about 100 seconds of execution

+ 1 - 1
spine-c/spine-c-unit-tests/tests/MemoryTestFixture.cpp

@@ -6,7 +6,7 @@
 
 #include "KMemory.h" // last include
 
-#define SPINEBOY_JSON "testdata/spineboy/spineboy.json"
+#define SPINEBOY_JSON "testdata/spineboy/spineboy-ess.json"
 #define SPINEBOY_ATLAS "testdata/spineboy/spineboy.atlas"
 
 #define MAX_RUN_TIME 6000 // equal to about 100 seconds of execution

+ 0 - 2
spine-c/spine-c/include/spine/Array.h

@@ -100,7 +100,6 @@ extern "C" {
 	void name##_removeAt(name* self, int index) { \
 		self->size--; \
 		memmove(self->items + index, self->items + index + 1, sizeof(itemType) * (self->size - index)); \
-		self->items[self->size] = 0; \
 	} \
 	int name##_contains(name* self, itemType value) { \
 		itemType* items = self->items; \
@@ -112,7 +111,6 @@ extern "C" {
 	} \
 	itemType name##_pop(name* self) { \
 		itemType item = self->items[--self->size]; \
-		self->items[self->size] = 0; \
 		return item; \
 	} \
 	itemType name##_peek(name* self) { \

+ 4 - 0
spine-c/spine-c/include/spine/Color.h

@@ -42,6 +42,10 @@ typedef struct spColor {
 	spColor() :
 		r(0), g(0), b(0), a(0) {
 	}
+
+	bool operator==(const spColor& rhs) {
+		return r == rhs.r && g == rhs.g && b == rhs.b && a == rhs.a;
+	}
 #endif
 } spColor;
 

+ 84 - 0
spine-c/spine-c/include/spine/VertexEffect.h

@@ -0,0 +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.
+ *****************************************************************************/
+
+#ifndef SPINE_VERTEXEFFECT_H_
+#define SPINE_VERTEXEFFECT_H_
+
+#include <spine/Skeleton.h>
+#include <spine/Color.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct spVertexEffect;
+
+typedef void (*spVertexEffectBegin)(struct spVertexEffect *self, spSkeleton *skeleton);
+
+typedef void (*spVertexEffectTransform)(struct spVertexEffect *self, float *x, float *y, float *u, float *v,
+										spColor *light, spColor *dark);
+
+typedef void (*spVertexEffectEnd)(struct spVertexEffect *self);
+
+typedef struct spVertexEffect {
+	spVertexEffectBegin begin;
+	spVertexEffectTransform transform;
+	spVertexEffectEnd end;
+} spVertexEffect;
+
+typedef struct spJitterVertexEffect {
+	spVertexEffect super;
+	float jitterX;
+	float jitterY;
+} spJitterVertexEffect;
+
+typedef struct spSwirlVertexEffect {
+	spVertexEffect super;
+	float centerX;
+	float centerY;
+	float radius;
+	float angle;
+	float worldX;
+	float worldY;
+} spSwirlVertexEffect;
+
+spJitterVertexEffect *spJitterVertexEffect_create(float jitterX, float jitterY);
+
+void spJitterVertexEffect_dispose(spJitterVertexEffect *effect);
+
+spSwirlVertexEffect *spSwirlVertexEffect_create(float radius);
+
+void spSwirlVertexEffect_dispose(spSwirlVertexEffect *effect);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPINE_VERTEX_EFFECT_H_ */

+ 28 - 13
spine-c/spine-c/include/spine/extension.h

@@ -62,9 +62,9 @@
 #define SPINE_EXTENSION_H_
 
 /* All allocation uses these. */
-#define MALLOC(TYPE,COUNT) ((TYPE*)_malloc(sizeof(TYPE) * (COUNT), __FILE__, __LINE__))
-#define CALLOC(TYPE,COUNT) ((TYPE*)_calloc(COUNT, sizeof(TYPE), __FILE__, __LINE__))
-#define REALLOC(PTR,TYPE,COUNT) ((TYPE*)_realloc(PTR, sizeof(TYPE) * (COUNT)))
+#define MALLOC(TYPE,COUNT) ((TYPE*)_spMalloc(sizeof(TYPE) * (COUNT), __FILE__, __LINE__))
+#define CALLOC(TYPE,COUNT) ((TYPE*)_spCalloc(COUNT, sizeof(TYPE), __FILE__, __LINE__))
+#define REALLOC(PTR,TYPE,COUNT) ((TYPE*)_spRealloc(PTR, sizeof(TYPE) * (COUNT)))
 #define NEW(TYPE) CALLOC(TYPE,1)
 
 /* Gets the direct super class. Type safe. */
@@ -83,7 +83,7 @@
 #define VTABLE(TYPE,VALUE) ((_##TYPE##Vtable*)((TYPE*)VALUE)->vtable)
 
 /* Frees memory. Can be used on const types. */
-#define FREE(VALUE) _free((void*)VALUE)
+#define FREE(VALUE) _spFree((void*)VALUE)
 
 /* Allocates a new char[], assigns it to TO, and copies FROM to it. Can be used on const types. */
 #define MALLOC_STR(TO,FROM) strcpy(CONST_CAST(char*, TO) = (char*)MALLOC(char, strlen(FROM) + 1), FROM)
@@ -103,6 +103,7 @@
 #define COS(A) cosf(A)
 #define SQRT(A) sqrtf(A)
 #define ACOS(A) acosf(A)
+#define POW(A,B) pow(A, B)
 #else
 #define FMOD(A,B) (float)fmod(A, B)
 #define ATAN2(A,B) (float)atan2(A, B)
@@ -110,6 +111,7 @@
 #define SIN(A) (float)sin(A)
 #define SQRT(A) (float)sqrt(A)
 #define ACOS(A) (float)acos(A)
+#define POW(A,B) (float)pow(A, B)
 #endif
 
 #define SIN_DEG(A) SIN((A) * DEG_RAD)
@@ -162,17 +164,30 @@ char* _spUtil_readFile (const char* path, int* length);
  * Internal API available for extension:
  */
 
-void* _malloc (size_t size, const char* file, int line);
-void* _calloc (size_t num, size_t size, const char* file, int line);
-void* _realloc(void* ptr, size_t size);
-void _free (void* ptr);
+void* _spMalloc (size_t size, const char* file, int line);
+void* _spCalloc (size_t num, size_t size, const char* file, int line);
+void* _spRealloc(void* ptr, size_t size);
+void _spFree (void* ptr);
+float _spRandom ();
 
-void _setMalloc (void* (*_malloc) (size_t size));
-void _setDebugMalloc (void* (*_malloc) (size_t size, const char* file, int line));
-void _setRealloc(void* (*_realloc) (void* ptr, size_t size));
-void _setFree (void (*_free) (void* ptr));
+void _spSetMalloc (void* (*_malloc) (size_t size));
+void _spSetDebugMalloc (void* (*_malloc) (size_t size, const char* file, int line));
+void _spSetRealloc(void* (*_realloc) (void* ptr, size_t size));
+void _spSetFree (void (*_free) (void* ptr));
+void _spSetRandom(float (*_random) ());
 
-char* _readFile (const char* path, int* length);
+char* _spReadFile (const char* path, int* length);
+
+
+/*
+ * Math utilities
+ */
+float _spMath_random(float min, float max);
+float _spMath_randomTriangular(float min, float max);
+float _spMath_randomTriangularWith(float min, float max, float mode);
+float _spMath_interpolate(float (*apply) (float a), float start, float end, float a);
+float _spMath_pow2_apply(float a);
+float _spMath_pow2out_apply(float a);
 
 /**/
 

+ 1 - 0
spine-c/spine-c/include/spine/spine.h

@@ -57,5 +57,6 @@
 #include <spine/SkeletonClipping.h>
 #include <spine/Event.h>
 #include <spine/EventData.h>
+#include <spine/VertexEffect.h>
 
 #endif /* SPINE_SPINE_H_ */

+ 18 - 5
spine-c/spine-c/src/spine/Animation.c

@@ -851,22 +851,35 @@ void _spDeformTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton,
 			slot->attachmentVerticesCapacity = vertexCount;
 		}
 	}
-	if (slot->attachmentVerticesCount != vertexCount && pose != SP_MIX_POSE_SETUP) alpha = 1; /* Don't mix from uninitialized slot vertices. */
 	slot->attachmentVerticesCount = vertexCount;
 
 	frameVertices = self->frameVertices;
 	vertices = slot->attachmentVertices;
 
 	if (time < frames[0]) { /* Time is before first frame. */
+		spVertexAttachment* vertexAttachment = SUB_CAST(spVertexAttachment, slot->attachment);
 		switch (pose) {
 			case SP_MIX_POSE_SETUP:
-				slot->attachmentVerticesCount = 0;
+				if (!vertexAttachment->bones) {
+					memcpy(vertices, vertexAttachment->vertices, vertexCount * sizeof(float));
+				} else {
+					for (i = 0; i < vertexCount; i++) vertices[i] = 0;
+				}
 				return;
 			case SP_MIX_POSE_CURRENT:
 			case SP_MIX_POSE_CURRENT_LAYERED: /* to appease compiler */
-				alpha = 1 - alpha;
-				for (i = 0; i < vertexCount; i++)
-					vertices[i] *= alpha;
+				if (alpha == 1) break;
+				if (!vertexAttachment->bones) {
+					float* setupVertices = vertexAttachment->vertices;
+					for (i = 0; i < vertexCount; i++) {
+						vertices[i] += (setupVertices[i] - vertices[i]) * alpha;
+					}
+				} else {
+					alpha = 1 - alpha;
+					for (i = 0; i < vertexCount; i++) {
+						vertices[i] *= alpha;
+					}
+				}
 		}
 		return;
 	}

+ 1 - 5
spine-c/spine-c/src/spine/AnimationState.c

@@ -801,7 +801,6 @@ void _spAnimationState_animationsChanged (spAnimationState* self) {
 	_spAnimationState* internal = SUB_CAST(_spAnimationState, self);
 	int i, n;
 	spTrackEntry* entry;
-	spTrackEntry* lastEntry = 0;
 	spTrackEntryArray* mixingTo;
 	internal->animationsChanged = 0;
 
@@ -812,10 +811,7 @@ void _spAnimationState_animationsChanged (spAnimationState* self) {
 
 	for (;i < n; i++) {
 		entry = self->tracks[i];
-		if (entry != 0) {
-			_spTrackEntry_setTimelineData(entry, lastEntry, mixingTo, self);
-			lastEntry = entry;
-		}
+		if (entry != 0) _spTrackEntry_setTimelineData(entry, 0, mixingTo, self);
 	}
 }
 

+ 4 - 4
spine-c/spine-c/src/spine/Bone.c

@@ -173,14 +173,14 @@ void spBone_updateWorldTransformWith (spBone* self, float x, float y, float rota
 			lb = COS_DEG(90 + shearY) * scaleY;
 			lc = SIN_DEG(shearX) * scaleX;
 			ld = SIN_DEG(90 + shearY) * scaleY;
+			if (self->data->transformMode != SP_TRANSFORMMODE_NOSCALEORREFLECTION ? pa * pd - pb * pc < 0 : self->skeleton->flipX != self->skeleton->flipY) {
+				zb = -zb;
+				zd = -zd;
+			}
 			CONST_CAST(float, self->a) = za * la + zb * lc;
 			CONST_CAST(float, self->b) = za * lb + zb * ld;
 			CONST_CAST(float, self->c) = zc * la + zd * lc;
 			CONST_CAST(float, self->d) = zc * lb + zd * ld;
-			if (self->data->transformMode != SP_TRANSFORMMODE_NOSCALEORREFLECTION ? pa * pd - pb * pc < 0 : self->skeleton->flipX != self->skeleton->flipY) {
-				CONST_CAST(float, self->b) = -self->b;
-				CONST_CAST(float, self->d) = -self->d;
-			}
 			return;
 		}
 	}

+ 3 - 1
spine-c/spine-c/src/spine/PathConstraint.c

@@ -114,7 +114,9 @@ void spPathConstraint_apply (spPathConstraint* self) {
 		}
 		for (i = 0, n = spacesCount - 1; i < n;) {
 			spBone* bone = bones[i];
-			setupLength = bone->data->length, x = setupLength * bone->a, y = setupLength * bone->c;
+			setupLength = bone->data->length;
+			if (setupLength == 0) setupLength = 0.000000001f;
+			x = setupLength * bone->a, y = setupLength * bone->c;
 			length = SQRT(x * x + y * y);
 			if (scale) lengths[i] = length;
 			spaces[++i] =  (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;

+ 98 - 0
spine-c/spine-c/src/spine/VertexEffect.c

@@ -0,0 +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.
+ *****************************************************************************/
+
+#include <spine/VertexEffect.h>
+#include <spine/extension.h>
+
+void _spJitterVertexEffect_begin(spVertexEffect* self, spSkeleton* skeleton) {
+}
+
+void _spJitterVertexEffect_transform(spVertexEffect* self, float* x, float* y, float* u, float* v, spColor* light, spColor* dark) {
+	spJitterVertexEffect* internal = (spJitterVertexEffect*)self;
+	float jitterX = internal->jitterX;
+	float jitterY = internal->jitterY;
+	(*x) += _spMath_randomTriangular(-jitterX, jitterY);
+	(*y) += _spMath_randomTriangular(-jitterX, jitterY);
+}
+
+void _spJitterVertexEffect_end(spVertexEffect* self) {
+}
+
+spJitterVertexEffect* spJitterVertexEffect_create(float jitterX, float jitterY) {
+	spJitterVertexEffect* effect = CALLOC(spJitterVertexEffect, 1);
+	effect->super.begin = _spJitterVertexEffect_begin;
+	effect->super.transform = _spJitterVertexEffect_transform;
+	effect->super.end = _spJitterVertexEffect_end;
+	effect->jitterX = jitterX;
+	effect->jitterY = jitterY;
+	return effect;
+}
+
+void spJitterVertexEffect_dispose(spJitterVertexEffect* effect) {
+	FREE(effect);
+}
+
+void _spSwirlVertexEffect_begin(spVertexEffect* self, spSkeleton* skeleton) {
+	spSwirlVertexEffect* internal = (spSwirlVertexEffect*)self;
+	internal->worldX = skeleton->x + internal->centerX;
+	internal->worldY = skeleton->y + internal->centerY;
+}
+
+void _spSwirlVertexEffect_transform(spVertexEffect* self, float* positionX, float* positionY, float* u, float* v, spColor* light, spColor* dark) {
+	spSwirlVertexEffect* internal = (spSwirlVertexEffect*)self;
+	float radAngle = internal->angle * DEG_RAD;
+	float x = *positionX - internal->worldX;
+	float y = *positionY - internal->worldY;
+	float dist = SQRT(x * x + y * y);
+	if (dist < internal->radius) {
+		float theta = _spMath_interpolate(_spMath_pow2_apply, 0, radAngle, (internal->radius - dist) / internal->radius);
+		float cosine = COS(theta);
+		float sine = SIN(theta);
+		(*positionX) = cosine * x - sine * y + internal->worldX;
+		(*positionY) = sine * x + cosine * y + internal->worldY;
+	}
+}
+
+void _spSwirlVertexEffect_end(spVertexEffect* self) {
+}
+
+spSwirlVertexEffect* spSwirlVertexEffect_create(float radius) {
+	spSwirlVertexEffect* effect = CALLOC(spSwirlVertexEffect, 1);
+	effect->super.begin = _spSwirlVertexEffect_begin;
+	effect->super.transform = _spSwirlVertexEffect_transform;
+	effect->super.end = _spSwirlVertexEffect_end;
+	effect->radius = radius;
+	return effect;
+}
+
+void spSwirlVertexEffect_dispose(spSwirlVertexEffect* effect) {
+	FREE(effect);
+}
+

+ 51 - 10
spine-c/spine-c/src/spine/extension.c

@@ -31,46 +31,59 @@
 #include <spine/extension.h>
 #include <stdio.h>
 
+float _spInternalRandom () {
+	return rand() / (float)RAND_MAX;
+}
+
 static void* (*mallocFunc) (size_t size) = malloc;
 static void* (*reallocFunc) (void* ptr, size_t size) = realloc;
 static void* (*debugMallocFunc) (size_t size, const char* file, int line) = NULL;
 static void (*freeFunc) (void* ptr) = free;
+static float (*randomFunc) () = _spInternalRandom;
 
-void* _malloc (size_t size, const char* file, int line) {
+void* _spMalloc (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);
+void* _spCalloc (size_t num, size_t size, const char* file, int line) {
+	void* ptr = _spMalloc(num * size, file, line);
 	if (ptr) memset(ptr, 0, num * size);
 	return ptr;
 }
-void* _realloc(void* ptr, size_t size) {
+void* _spRealloc(void* ptr, size_t size) {
 	return reallocFunc(ptr, size);
 }
-void _free (void* ptr) {
+void _spFree (void* ptr) {
 	freeFunc(ptr);
 }
 
-void _setDebugMalloc(void* (*malloc) (size_t size, const char* file, int line)) {
+float _spRandom () {
+	return randomFunc();
+}
+
+void _spSetDebugMalloc(void* (*malloc) (size_t size, const char* file, int line)) {
 	debugMallocFunc = malloc;
 }
 
-void _setMalloc (void* (*malloc) (size_t size)) {
+void _spSetMalloc (void* (*malloc) (size_t size)) {
 	mallocFunc = malloc;
 }
 
-void _setRealloc (void* (*realloc) (void* ptr, size_t size)) {
+void _spSetRealloc (void* (*realloc) (void* ptr, size_t size)) {
 	reallocFunc = realloc;
 }
 
-void _setFree (void (*free) (void* ptr)) {
+void _spSetFree (void (*free) (void* ptr)) {
 	freeFunc = free;
 }
 
-char* _readFile (const char* path, int* length) {
+void _spSetRandom (float (*random) ()) {
+	randomFunc = random;
+}
+
+char* _spReadFile (const char* path, int* length) {
 	char *data;
 	FILE *file = fopen(path, "rb");
 	if (!file) return 0;
@@ -85,3 +98,31 @@ char* _readFile (const char* path, int* length) {
 
 	return data;
 }
+
+float _spMath_random(float min, float max) {
+	return min + (max - min) * _spRandom();
+}
+
+float _spMath_randomTriangular(float min, float max) {
+	return _spMath_randomTriangularWith(min, max, (min + max) * 0.5f);
+}
+
+float _spMath_randomTriangularWith(float min, float max, float mode) {
+	float u = _spRandom();
+	float d = max - min;
+	if (u <= (mode - min) / d) return min + SQRT(u * d * (mode - min));
+	return max - SQRT((1 - u) * d * (max - mode));
+}
+
+float _spMath_interpolate(float (*apply) (float a), float start, float end, float a) {
+	return start + (end - start) * apply(a);
+}
+
+float _spMath_pow2_apply(float a) {
+	if (a <= 0.5) return POW(a * 2, 2) / 2;
+	return POW((a - 1) * 2, 2) / -2 + 1;
+}
+
+float _spMath_pow2out_apply(float a) {
+	return POW(a - 1, 2) * -1 + 1;
+}

+ 3 - 2
spine-cocos2d-objc/README.md

@@ -19,9 +19,10 @@ spine-cocos2d-objc does not yet support loading the binary format.
 ## Usage
 
 1. Create a new cocos2d-obj project. See the [cocos2d-objc documentation](http://cocos2d-objc.org/started/) or have a look at the example in this repository.
-2. Download the Spine Runtimes source using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip)
+2. Download the Spine Runtimes source using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip)
 3. Add the sources from `spine-c/spine-c/src/spine` and `spine-cocos2d-objc/src/spine` to your project
 4. Add the folders `spine-c/spine-c/include` and `spine-cocos2d-objc/src` to your header search path. Note that includes are specified as `#inclue <spine/file.h>`, so the `spine` directory cannot be omitted when copying the source files.
+5. If your project uses ARC, you have to exclude the `.m` files in `spine-cocos2d-objc/src` from ARC. See https://stackoverflow.com/questions/6646052/how-can-i-disable-arc-for-a-single-file-in-a-project for more information.
 
 See the [Spine Runtimes documentation](http://esotericsoftware.com/spine-documentation#runtimesTitle) on how to use the APIs or check out the Spine cocos2d-objc example.
 
@@ -36,7 +37,7 @@ The Spine cocos2d-objc example works on iOS simulators and devices.
 1. Install [Xcode](https://developer.apple.com/xcode/)
 2. Install [Homebrew](http://brew.sh/)
 3. Open a terminal and install CMake via `brew install cmake`
-3. Download the Spine Runtimes repository using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip)
+3. Download the Spine Runtimes repository using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip)
 4. Open a terminal, and `cd` into the `spine-runtimes/spine-cocos2d-objc` folder
 5. Type `mkdir build && cd build && cmake ../..`, this will download the cocos2d-objc dependency
 6. Open the Xcode project in `spine-runtimes/spine-cocos2d-objc/spine-cocos2d-objc.xcodeproj/`

+ 5 - 0
spine-cocos2d-objc/example/RaptorExample.m

@@ -31,6 +31,8 @@
 #import "RaptorExample.h"
 #import "TankExample.h"
 
+spJitterVertexEffect* effect = 0;
+
 @implementation RaptorExample
 
 + (CCScene*) scene {
@@ -42,9 +44,12 @@
 -(id) init {
     self = [super init];
     if (!self) return nil;
+	
+	if (!effect) effect = spJitterVertexEffect_create(10, 10);
     
     skeletonNode = [SkeletonAnimation skeletonWithFile:@"raptor-pro.json" atlasFile:@"raptor.atlas" scale:0.3f];
     [skeletonNode setAnimationForTrack:0 name:@"walk" loop:YES];
+	[skeletonNode setEffect:&effect->super];
     
     CGSize windowSize = [[CCDirector sharedDirector] viewSize];
     [skeletonNode setPosition:ccp(windowSize.width / 2, 20)];

+ 8 - 4
spine-cocos2d-objc/spine-cocos2d-objc.xcodeproj/project.pbxproj

@@ -84,6 +84,7 @@
 		76F5BDAD1D2BDFA2005917E5 /* TankExample.m in Sources */ = {isa = PBXBuildFile; fileRef = 76F5BDAC1D2BDFA2005917E5 /* TankExample.m */; };
 		76FAC1961E3FA15E001CCC8C /* Color.c in Sources */ = {isa = PBXBuildFile; fileRef = 76FAC1941E3FA15E001CCC8C /* Color.c */; };
 		76FAC1971E3FA15E001CCC8C /* PointAttachment.c in Sources */ = {isa = PBXBuildFile; fileRef = 76FAC1951E3FA15E001CCC8C /* PointAttachment.c */; };
+		76FB151A1F01413B00C5377F /* VertexEffect.c in Sources */ = {isa = PBXBuildFile; fileRef = 76FB15191F01413B00C5377F /* VertexEffect.c */; };
 		83F1A0EF1986955A001F6B44 /* GLKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83F1A0EE1986955A001F6B44 /* GLKit.framework */; };
 		9A5D2499170A94DA0030D4DD /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A5D2498170A94DA0030D4DD /* QuartzCore.framework */; };
 		9A5D249B170A94DA0030D4DD /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A5D249A170A94DA0030D4DD /* OpenGLES.framework */; };
@@ -137,7 +138,7 @@
 /* Begin PBXFileReference section */
 		43C3282D170B0C19004A9460 /* spine-cocos2d-objc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "spine-cocos2d-objc.m"; path = "src/spine/spine-cocos2d-objc.m"; sourceTree = "<group>"; };
 		43C3282E170B0C19004A9460 /* spine-cocos2d-objc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "spine-cocos2d-objc.h"; path = "src/spine/spine-cocos2d-objc.h"; sourceTree = "<group>"; };
-		43C32868170B0DA6004A9460 /* spineboy-ess.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = spineboy-ess.json; path = Resources/spineboy-ess.json; sourceTree = "<group>"; };
+		43C32868170B0DA6004A9460 /* spineboy-ess.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "spineboy-ess.json"; path = "Resources/spineboy-ess.json"; sourceTree = "<group>"; };
 		43C3286A170B0DA6004A9460 /* spineboy.atlas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = spineboy.atlas; path = Resources/spineboy.atlas; sourceTree = "<group>"; };
 		43C3286B170B0DA6004A9460 /* spineboy.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = spineboy.png; path = Resources/spineboy.png; sourceTree = "<group>"; };
 		43C32871170B0DBE004A9460 /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "[email protected]"; path = "Resources-ios/[email protected]"; sourceTree = "<group>"; };
@@ -175,7 +176,7 @@
 		76EE4E441EB36DE6000254F4 /* SkeletonClipping.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SkeletonClipping.c; path = "../spine-c/spine-c/src/spine/SkeletonClipping.c"; sourceTree = "<group>"; };
 		76EE4E451EB36DE6000254F4 /* Triangulator.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = Triangulator.c; path = "../spine-c/spine-c/src/spine/Triangulator.c"; sourceTree = "<group>"; };
 		76EE4E4E1EB36E53000254F4 /* coin.atlas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = coin.atlas; path = Resources/coin.atlas; sourceTree = "<group>"; };
-		76EE4E4F1EB36E53000254F4 /* coin-pro.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = coin-pro.json; path = Resources/coin-pro.json; sourceTree = "<group>"; };
+		76EE4E4F1EB36E53000254F4 /* coin-pro.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "coin-pro.json"; path = "Resources/coin-pro.json"; sourceTree = "<group>"; };
 		76EE4E501EB36E53000254F4 /* coin.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = coin.png; path = Resources/coin.png; sourceTree = "<group>"; };
 		76EE4E541EB36E94000254F4 /* CoinExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CoinExample.h; path = example/CoinExample.h; sourceTree = "<group>"; };
 		76EE4E551EB36E94000254F4 /* CoinExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CoinExample.m; path = example/CoinExample.m; sourceTree = "<group>"; };
@@ -214,10 +215,10 @@
 		76F28D141DEC810300CDE54D /* TransformConstraintData.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = TransformConstraintData.c; path = "../spine-c/spine-c/src/spine/TransformConstraintData.c"; sourceTree = "<group>"; };
 		76F28D151DEC810300CDE54D /* VertexAttachment.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = VertexAttachment.c; path = "../spine-c/spine-c/src/spine/VertexAttachment.c"; sourceTree = "<group>"; };
 		76F5BD9C1D2BDE1C005917E5 /* raptor.atlas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = raptor.atlas; path = Resources/raptor.atlas; sourceTree = "<group>"; };
-		76F5BD9D1D2BDE1C005917E5 /* raptor-pro.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = raptor-pro.json; path = Resources/raptor-pro.json; sourceTree = "<group>"; };
+		76F5BD9D1D2BDE1C005917E5 /* raptor-pro.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "raptor-pro.json"; path = "Resources/raptor-pro.json"; sourceTree = "<group>"; };
 		76F5BD9E1D2BDE1C005917E5 /* raptor.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = raptor.png; path = Resources/raptor.png; sourceTree = "<group>"; };
 		76F5BD9F1D2BDE1C005917E5 /* tank.atlas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = tank.atlas; path = Resources/tank.atlas; sourceTree = "<group>"; };
-		76F5BDA01D2BDE1C005917E5 /* tank-pro.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = tank-pro.json; path = Resources/tank-pro.json; sourceTree = "<group>"; };
+		76F5BDA01D2BDE1C005917E5 /* tank-pro.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "tank-pro.json"; path = "Resources/tank-pro.json"; sourceTree = "<group>"; };
 		76F5BDA11D2BDE1C005917E5 /* tank.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = tank.png; path = Resources/tank.png; sourceTree = "<group>"; };
 		76F5BDA81D2BDE67005917E5 /* RaptorExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RaptorExample.h; path = example/RaptorExample.h; sourceTree = "<group>"; };
 		76F5BDA91D2BDE67005917E5 /* RaptorExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RaptorExample.m; path = example/RaptorExample.m; sourceTree = "<group>"; };
@@ -225,6 +226,7 @@
 		76F5BDAC1D2BDFA2005917E5 /* TankExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TankExample.m; path = example/TankExample.m; sourceTree = "<group>"; };
 		76FAC1941E3FA15E001CCC8C /* Color.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = Color.c; path = "../spine-c/spine-c/src/spine/Color.c"; sourceTree = "<group>"; };
 		76FAC1951E3FA15E001CCC8C /* PointAttachment.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = PointAttachment.c; path = "../spine-c/spine-c/src/spine/PointAttachment.c"; sourceTree = "<group>"; };
+		76FB15191F01413B00C5377F /* VertexEffect.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = VertexEffect.c; path = "../spine-c/spine-c/src/spine/VertexEffect.c"; sourceTree = "<group>"; };
 		83F1A0EE1986955A001F6B44 /* GLKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLKit.framework; path = System/Library/Frameworks/GLKit.framework; sourceTree = SDKROOT; };
 		9A5D2495170A94DA0030D4DD /* SpineExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SpineExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		9A5D2498170A94DA0030D4DD /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
@@ -299,6 +301,7 @@
 		43C32822170B0BC2004A9460 /* spine-c */ = {
 			isa = PBXGroup;
 			children = (
+				76FB15191F01413B00C5377F /* VertexEffect.c */,
 				76EE4E421EB36DE6000254F4 /* Array.c */,
 				76EE4E431EB36DE6000254F4 /* ClippingAttachment.c */,
 				76EE4E441EB36DE6000254F4 /* SkeletonClipping.c */,
@@ -597,6 +600,7 @@
 				76BF7E071E66ED9C00485998 /* GLUtils.c in Sources */,
 				76EE4E481EB36DE6000254F4 /* SkeletonClipping.c in Sources */,
 				43C3282F170B0C19004A9460 /* spine-cocos2d-objc.m in Sources */,
+				76FB151A1F01413B00C5377F /* VertexEffect.c in Sources */,
 				76F28D1F1DEC810300CDE54D /* BoundingBoxAttachment.c in Sources */,
 				76F28D281DEC810300CDE54D /* PathConstraint.c in Sources */,
 				76F28D2F1DEC810300CDE54D /* SkeletonJson.c in Sources */,

+ 2 - 0
spine-cocos2d-objc/src/spine/SkeletonRenderer.h

@@ -47,6 +47,7 @@
 	float* _worldVertices;
 	CCBlendMode* screenMode;
 	spSkeletonClipping* _clipper;
+	spVertexEffect* _effect;
 }
 
 + (id) skeletonWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData;
@@ -90,5 +91,6 @@
 @property (nonatomic) bool debugBones;
 @property (nonatomic) bool skipVisibilityCheck;
 @property (nonatomic) spBone* rootBone;
+@property (nonatomic) spVertexEffect* effect;
 
 @end

+ 64 - 12
spine-cocos2d-objc/src/spine/SkeletonRenderer.m

@@ -50,6 +50,7 @@ static bool handlerQueued = false;
 @synthesize twoColorTint = _twoColorTint;
 @synthesize debugSlots = _debugSlots;
 @synthesize debugBones = _debugBones;
+@synthesize effect = _effect;
 
 + (id) skeletonWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData {
 	return [[[self alloc] initWithData:skeletonData ownsSkeletonData:ownsSkeletonData] autorelease];
@@ -91,6 +92,7 @@ static bool handlerQueued = false;
 	];
 	
 	_clipper = spSkeletonClipping_create();
+	_effect = 0;
 }
 
 - (id) initWithData:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData {
@@ -173,6 +175,8 @@ static bool handlerQueued = false;
 		handlerQueued = true;
 	}
 	
+	if (_effect) _effect->begin(_effect, _skeleton);
+	
 	CCColor* nodeColor = self.color;
 	_skeleton->color.r = nodeColor.red;
 	_skeleton->color.g = nodeColor.green;
@@ -288,6 +292,20 @@ static bool handlerQueued = false;
 							vertex.position = GLKVector4Make(vertices[i * 2], vertices[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]);
+							if (_effect) {
+								spColor light;
+								spColor dark;
+								light.r = r;
+								light.g = g;
+								light.b = b;
+								light.a = a;
+								dark.r = dark.g = dark.b = dark.a = 0;
+								_effect->transform(_effect, &vertex.position.x, &vertex.position.y, &vertex.texCoord1.s, &vertex.texCoord1.t, &light, &dark);
+								vertex.color.r = light.r;
+								vertex.color.g = light.g;
+								vertex.color.b = light.b;
+								vertex.color.a = light.a;
+							}
 							CCRenderBufferSetVertex(buffer, i, CCVertexApplyTransform(vertex, transform));
 						}
 						for (int j = 0; j * 3 < trianglesCount; ++j) {
@@ -308,18 +326,50 @@ static bool handlerQueued = false;
 						spVertex* verts = &meshPart.mesh->vertices[meshPart.startVertex];
 						unsigned short* indices = &meshPart.mesh->indices[meshPart.startIndex];
 						
-						for (int i = 0; i * 2 < verticesCount; i++, verts++) {
-							CCVertex vertex;
-							vertex.position = GLKVector4Make(vertices[i * 2], vertices[i * 2 + 1], 0.0, 1.0);
-							vertex = CCVertexApplyTransform(vertex, transform);
-							verts->x = vertex.position.x;
-							verts->y = vertex.position.y;
-							verts->z = vertex.position.z;
-							verts->w = vertex.position.w;
-							verts->color = ((unsigned short)(r * 255))| ((unsigned short)(g * 255)) << 8 | ((unsigned short)(b * 255)) <<16 | ((unsigned short)(a * 255)) << 24;
-							verts->color2 = ((unsigned short)(dr * 255)) | ((unsigned short)(dg * 255)) << 8 | ((unsigned short)(db * 255)) << 16 | ((unsigned short)(255)) << 24;
-							verts->u = uvs[i * 2];
-							verts->v = 1 - uvs[i * 2 + 1];
+						if (_effect) {
+							spColor light;
+							light.r = r;
+							light.g = g;
+							light.b = b;
+							light.a = a;
+							spColor dark;
+							dark.r = dr;
+							dark.g = dg;
+							dark.b = db;
+							dark.a = 1;
+							for (int i = 0; i * 2 < verticesCount; i++, verts++) {
+								spColor lightCopy = light;
+								spColor darkCopy = dark;
+								
+								CCVertex vertex;
+								vertex.position = GLKVector4Make(vertices[i * 2], vertices[i * 2 + 1], 0.0, 1.0);
+								verts->u = uvs[i * 2];
+								verts->v = 1 - uvs[i * 2 + 1];
+								_effect->transform(_effect, &vertex.position.x, &vertex.position.y, &verts->u, &verts->v, &lightCopy, &darkCopy);
+								
+								vertex = CCVertexApplyTransform(vertex, transform);
+								verts->x = vertex.position.x;
+								verts->y = vertex.position.y;
+								verts->z = vertex.position.z;
+								verts->w = vertex.position.w;
+								verts->color = ((unsigned short)(lightCopy.r * 255))| ((unsigned short)(lightCopy.g * 255)) << 8 | ((unsigned short)(lightCopy.b * 255)) <<16 | ((unsigned short)(lightCopy.a * 255)) << 24;
+								verts->color2 = ((unsigned short)(darkCopy.r * 255)) | ((unsigned short)(darkCopy.g * 255)) << 8 | ((unsigned short)(darkCopy.b * 255)) << 16 | ((unsigned short)(255)) << 24;
+								
+							}
+						} else {
+							for (int i = 0; i * 2 < verticesCount; i++, verts++) {
+								CCVertex vertex;
+								vertex.position = GLKVector4Make(vertices[i * 2], vertices[i * 2 + 1], 0.0, 1.0);
+								vertex = CCVertexApplyTransform(vertex, transform);
+								verts->x = vertex.position.x;
+								verts->y = vertex.position.y;
+								verts->z = vertex.position.z;
+								verts->w = vertex.position.w;
+								verts->color = ((unsigned short)(r * 255))| ((unsigned short)(g * 255)) << 8 | ((unsigned short)(b * 255)) <<16 | ((unsigned short)(a * 255)) << 24;
+								verts->color2 = ((unsigned short)(dr * 255)) | ((unsigned short)(dg * 255)) << 8 | ((unsigned short)(db * 255)) << 16 | ((unsigned short)(255)) << 24;
+								verts->u = uvs[i * 2];
+								verts->v = 1 - uvs[i * 2 + 1];
+							}
 						}
 						
 						for (int j = 0; j < trianglesCount; j++, indices++) {
@@ -375,6 +425,8 @@ static bool handlerQueued = false;
 			if (i == 0) [_drawNode drawDot:ccp(bone->worldX, bone->worldY) radius:4 color:[CCColor blueColor]];
 		}
 	}
+	
+	if (_effect) _effect->end(_effect);
 }
 
 - (CCTexture*) getTextureForRegion:(spRegionAttachment*)attachment {

+ 1 - 1
spine-cocos2d-objc/src/spine/spine-cocos2d-objc.m

@@ -44,5 +44,5 @@ void _spAtlasPage_disposeTexture (spAtlasPage* self) {
 }
 
 char* _spUtil_readFile (const char* path, int* length) {
-	return _readFile([[[CCFileUtils sharedFileUtils] fullPathForFilename:@(path)] UTF8String], length);
+	return _spReadFile([[[CCFileUtils sharedFileUtils] fullPathForFilename:@(path)] UTF8String], length);
 }

+ 4 - 4
spine-cocos2dx/README.md

@@ -21,7 +21,7 @@ The setup for cocos2d-x differs from most other Spine Runtimes because the cocos
 1. Create a new cocos2d-x project. See [the cocos2d-x documentation](http://www.cocos2d-x.org/docs/static-pages/installation.html)
 2. Delete the folder `cocos2d/cocos/editor-support/spine`. This will remove the outdated Spine cocos2d-x runtime shipped by cocos2d-x.
 3. Open your project in your IDE of choice, then open the cocos2d_libs sub project and delete the `editor-support/spine` group. This will remove the outdated Spine cocos2d-x runtime shipped by cocos2d-x from your build.
-3. Download the Spine Runtimes source using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip)
+3. Download the Spine Runtimes source using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip)
 4. Add the sources from `spine-c/spine-c/src/spine` and `spine-cocos2dx/src/spine` to your project
 4. Add the folders `spine-c/spine-c/include` and `spine-cocos2dx/src` to your header search path. Note that includes are specified as `#inclue <spine/file.h>`, so the `spine` directory cannot be omitted when copying the source files.
 
@@ -31,7 +31,7 @@ The Spine cocos2d-x example works on Windows and Mac OS X.
 ### Windows
 1. Install [Visual Studio 2015 Community](https://www.visualstudio.com/en-us/downloads/download-visual-studio-vs.aspx)
 2. Install CMake via the [Windows installer package](https://cmake.org/download/).
-3. Download the Spine Runtimes repository using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip)
+3. Download the Spine Runtimes repository using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip)
 4. Run CMake GUI from the start menu
 5. Click `Browse Source` and select the directory `spine-runtimes`
 6. Click `Browse Build` and select the `spine-runtimes/spine-cocos2dx/build` directory. You can create the `build` folder directly in the file dialog via `New Folder`.
@@ -47,7 +47,7 @@ The Spine cocos2d-x example works on Windows and Mac OS X.
 1. Install [Xcode](https://developer.apple.com/xcode/)
 2. Install [Homebrew](http://brew.sh/)
 3. Open a terminal and install CMake via `brew install cmake`
-3. Download the Spine Runtimes repository using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip)
+3. Download the Spine Runtimes repository using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip)
 4. Open a terminal, and `cd` into the `spine-runtimes/spine-cocos2dx` folder
 5. Type `mkdir build && cd build && cmake ../..`. This will download the cocos2d-x dependency and wire it up with the example source code in `spine-runtimes/spine-cocos2dx/example`. The download is 400mb, so get yourself a cup of tea.
 6. Open the Xcode project in `spine-runtimes/spine-cocos2dx/example/proj.ios_mac`
@@ -58,7 +58,7 @@ The Spine cocos2d-x example works on Windows and Mac OS X.
 1. Install the prerequisits for [cocos2d-x Android development](http://www.cocos2d-x.org/docs/installation/Android-terminal/)
 2. Install [Homebrew](http://brew.sh/)
 3. Open a terminal and install CMake via `brew install cmake`
-3. Download the Spine Runtimes repository using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip)
+3. Download the Spine Runtimes repository using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip)
 4. Open a terminal, and `cd` into the `spine-runtimes/spine-cocos2dx` folder
 5. Type `mkdir build && cd build && cmake ../..`. This will download the cocos2d-x dependency and wire it up with the example source code in `spine-runtimes/spine-cocos2dx/example`. The download is 400mb, so get yourself a cup of tea.
 6. Delete `spine-runtimes/spine-cocos2dx/example/cocos2d/cocos/editor-support/spine`

+ 17 - 1
spine-cocos2dx/example/Classes/RaptorExample.cpp

@@ -30,10 +30,13 @@
 
 #include "RaptorExample.h"
 #include "TankExample.h"
+#include <spine/extension.h>
 
 USING_NS_CC;
 using namespace spine;
 
+spSwirlVertexEffect* effect = spSwirlVertexEffect_create(400);
+
 Scene* RaptorExample::scene () {
 	Scene *scene = Scene::create();
 	scene->addChild(RaptorExample::create());
@@ -46,7 +49,13 @@ bool RaptorExample::init () {
 	skeletonNode = SkeletonAnimation::createWithJsonFile("raptor-pro.json", "raptor.atlas", 0.5f);
 	skeletonNode->setAnimation(0, "walk", true);
 	skeletonNode->setAnimation(1, "empty", false);
-	skeletonNode->addAnimation(1, "gungrab", false, 2);	
+	skeletonNode->addAnimation(1, "gungrab", false, 2);
+	skeletonNode->setTwoColorTint(true);
+	
+	effect->centerY = 200;
+	swirlTime = 0;
+	
+	skeletonNode->setVertexEffect(&effect->super);
 
 	skeletonNode->setPosition(Vec2(_contentSize.width / 2, 20));
 	addChild(skeletonNode);
@@ -68,3 +77,10 @@ bool RaptorExample::init () {
 
 	return true;
 }
+
+void RaptorExample::update(float fDelta) {
+	swirlTime += fDelta;
+	float percent = fmod(swirlTime, 2);
+	if (percent > 1) percent = 1 - (percent - 1);
+	effect->angle = _spMath_interpolate(_spMath_pow2_apply, -60, 60, percent);
+}

+ 3 - 0
spine-cocos2dx/example/Classes/RaptorExample.h

@@ -41,9 +41,12 @@ public:
 	CREATE_FUNC(RaptorExample);
 
 	virtual bool init ();
+	
+	virtual void update(float fDelta);
 
 private:
 	spine::SkeletonAnimation* skeletonNode;
+	float swirlTime;
 };
 
 #endif // _RAPTOREXAMPLE_H_

+ 1 - 0
spine-cocos2dx/example/proj.android/jni/Android.mk

@@ -59,6 +59,7 @@ LOCAL_SRC_FILES := hellocpp/main.cpp \
 				   ../../../../spine-c/spine-c/src/spine/TransformConstraint.c \
 				   ../../../../spine-c/spine-c/src/spine/TransformConstraintData.c \
 				   ../../../../spine-c/spine-c/src/spine/VertexAttachment.c \
+				   ../../../../spine-c/spine-c/src/spine/VertexEffect.c \
 				   ../../../../spine-c/spine-c/src/spine/extension.c
 
 

+ 98 - 0
spine-cocos2dx/example/proj.ios_mac/VertexEffect.c

@@ -0,0 +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.
+ *****************************************************************************/
+
+#include <spine/VertexEffect.h>
+#include <spine/extension.h>
+
+void _spJitterVertexEffect_begin(spVertexEffect* self, spSkeleton* skeleton) {
+}
+
+void _spJitterVertexEffect_transform(spVertexEffect* self, float* x, float* y, float* u, float* v, spColor* light, spColor* dark) {
+	spJitterVertexEffect* internal = (spJitterVertexEffect*)self;
+	float jitterX = internal->jitterX;
+	float jitterY = internal->jitterY;
+	(*x) += _spMath_randomTriangular(-jitterX, jitterY);
+	(*y) += _spMath_randomTriangular(-jitterX, jitterY);
+}
+
+void _spJitterVertexEffect_end(spVertexEffect* self) {
+}
+
+spJitterVertexEffect* spJitterVertexEffect_create(float jitterX, float jitterY) {
+	spJitterVertexEffect* effect = CALLOC(spJitterVertexEffect, 1);
+	effect->super.begin = _spJitterVertexEffect_begin;
+	effect->super.transform = _spJitterVertexEffect_transform;
+	effect->super.end = _spJitterVertexEffect_end;
+	effect->jitterX = jitterX;
+	effect->jitterY = jitterY;
+	return effect;
+}
+
+void spJitterVertexEffect_dispose(spJitterVertexEffect* effect) {
+	FREE(effect);
+}
+
+void _spSwirlVertexEffect_begin(spVertexEffect* self, spSkeleton* skeleton) {
+	spSwirlVertexEffect* internal = (spSwirlVertexEffect*)self;
+	internal->worldX = skeleton->x + internal->centerX;
+	internal->worldY = skeleton->y + internal->centerY;
+}
+
+void _spSwirlVertexEffect_transform(spVertexEffect* self, float* positionX, float* positionY, float* u, float* v, spColor* light, spColor* dark) {
+	spSwirlVertexEffect* internal = (spSwirlVertexEffect*)self;
+	float radAngle = internal->angle * DEG_RAD;
+	float x = *positionX - internal->worldX;
+	float y = *positionY - internal->worldY;
+	float dist = SQRT(x * x + y * y);
+	if (dist < internal->radius) {
+		float theta = _spMath_interpolate(_spMath_pow2_apply, 0, radAngle, (internal->radius - dist) / internal->radius);
+		float cosine = COS(theta);
+		float sine = SIN(theta);
+		(*positionX) = cosine * x - sine * y + internal->worldX;
+		(*positionY) = sine * x + cosine * y + internal->worldY;
+	}
+}
+
+void _spSwirlVertexEffect_end(spVertexEffect* self) {
+}
+
+spSwirlVertexEffect* spSwirlVertexEffect_create(float radius) {
+	spSwirlVertexEffect* effect = CALLOC(spSwirlVertexEffect, 1);
+	effect->super.begin = _spSwirlVertexEffect_begin;
+	effect->super.transform = _spSwirlVertexEffect_transform;
+	effect->super.end = _spSwirlVertexEffect_end;
+	effect->radius = radius;
+	return effect;
+}
+
+void spSwirlVertexEffect_dispose(spSwirlVertexEffect* effect) {
+	FREE(effect);
+}
+

+ 6 - 0
spine-cocos2dx/example/proj.ios_mac/spine-cocos2d-x.xcodeproj/project.pbxproj

@@ -170,6 +170,8 @@
 		76FAC18D1E3F97D2001CCC8C /* PointAttachment.c in Sources */ = {isa = PBXBuildFile; fileRef = 76FAC18B1E3F97D2001CCC8C /* PointAttachment.c */; };
 		76FAC18F1E3F98A0001CCC8C /* Color.c in Sources */ = {isa = PBXBuildFile; fileRef = 76FAC18A1E3F97D2001CCC8C /* Color.c */; };
 		76FAC1901E3F98A0001CCC8C /* PointAttachment.c in Sources */ = {isa = PBXBuildFile; fileRef = 76FAC18B1E3F97D2001CCC8C /* PointAttachment.c */; };
+		76FB150F1F01377200C5377F /* VertexEffect.c in Sources */ = {isa = PBXBuildFile; fileRef = 76FB150E1F01377200C5377F /* VertexEffect.c */; };
+		76FB15111F0139B400C5377F /* VertexEffect.c in Sources */ = {isa = PBXBuildFile; fileRef = 76FB150E1F01377200C5377F /* VertexEffect.c */; };
 		8262943E1AAF051F00CB7CF7 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8262943D1AAF051F00CB7CF7 /* Security.framework */; };
 		BF171245129291EC00B8313A /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF170DB012928DE900B8313A /* OpenGLES.framework */; };
 		BF1712471292920000B8313A /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BF170DB412928DE900B8313A /* libz.dylib */; };
@@ -335,6 +337,7 @@
 		76F5BD541D2BD7D3005917E5 /* TankExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TankExample.h; sourceTree = "<group>"; };
 		76FAC18A1E3F97D2001CCC8C /* Color.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = Color.c; path = "../../../spine-c/spine-c/src/spine/Color.c"; sourceTree = "<group>"; };
 		76FAC18B1E3F97D2001CCC8C /* PointAttachment.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = PointAttachment.c; path = "../../../spine-c/spine-c/src/spine/PointAttachment.c"; sourceTree = "<group>"; };
+		76FB150E1F01377200C5377F /* VertexEffect.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = VertexEffect.c; sourceTree = "<group>"; };
 		8262943D1AAF051F00CB7CF7 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
 		BF170DB012928DE900B8313A /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };
 		BF170DB412928DE900B8313A /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
@@ -552,6 +555,7 @@
 		76AAA3B21D180F7300C54FCB /* spine */ = {
 			isa = PBXGroup;
 			children = (
+				76FB150E1F01377200C5377F /* VertexEffect.c */,
 				76D520E11EB3625700572471 /* Array.c */,
 				76D520D71EB3611300572471 /* ClippingAttachment.c */,
 				76D520D81EB3611300572471 /* SkeletonClipping.c */,
@@ -803,6 +807,7 @@
 				76F28CB81DEC7EBB00CDE54D /* Bone.c in Sources */,
 				76F28CB61DEC7EBB00CDE54D /* Attachment.c in Sources */,
 				503AE10217EB989F00D1A890 /* RootViewController.mm in Sources */,
+				76FB150F1F01377200C5377F /* VertexEffect.c in Sources */,
 				503AE10117EB989F00D1A890 /* main.m in Sources */,
 				76D520DB1EB3611300572471 /* SkeletonClipping.c in Sources */,
 				76F28CCB1DEC7EBB00CDE54D /* Skin.c in Sources */,
@@ -820,6 +825,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				76FB15111F0139B400C5377F /* VertexEffect.c in Sources */,
 				76D520E71EB3634600572471 /* CoinExample.cpp in Sources */,
 				76D520E31EB3625B00572471 /* Array.c in Sources */,
 				76D520DE1EB3619800572471 /* ClippingAttachment.c in Sources */,

+ 1 - 0
spine-cocos2dx/example/proj.win32/spine-cocos2d-x.vcxproj

@@ -179,6 +179,7 @@ xcopy "$(ProjectDir)..\Resources" "$(OutDir)" /D /E /I /F /Y
     <ClCompile Include="..\..\..\spine-c\spine-c\src\spine\TransformConstraint.c" />
     <ClCompile Include="..\..\..\spine-c\spine-c\src\spine\TransformConstraintData.c" />
     <ClCompile Include="..\..\..\spine-c\spine-c\src\spine\VertexAttachment.c" />
+    <ClCompile Include="..\..\..\spine-c\spine-c\src\spine\VertexEffect.c" />
     <ClCompile Include="..\..\src\spine\AttachmentVertices.cpp" />
     <ClCompile Include="..\..\src\spine\Cocos2dAttachmentLoader.cpp" />
     <ClCompile Include="..\..\src\spine\SkeletonAnimation.cpp" />

+ 167 - 46
spine-cocos2dx/src/spine/SkeletonRenderer.cpp

@@ -77,21 +77,21 @@ void SkeletonRenderer::setSkeletonData (spSkeletonData *skeletonData, bool ownsS
 }
 
 SkeletonRenderer::SkeletonRenderer ()
-	: _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1) {
+	: _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1), _effect(nullptr) {
 }
 
 SkeletonRenderer::SkeletonRenderer (spSkeletonData *skeletonData, bool ownsSkeletonData)
-	: _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1) {
+	: _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1), _effect(nullptr) {
 	initWithData(skeletonData, ownsSkeletonData);
 }
 
 SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, spAtlas* atlas, float scale)
-	: _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1) {
+	: _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1), _effect(nullptr) {
 	initWithJsonFile(skeletonDataFile, atlas, scale);
 }
 
 SkeletonRenderer::SkeletonRenderer (const std::string& skeletonDataFile, const std::string& atlasFile, float scale)
-	: _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1) {
+	: _atlas(nullptr), _attachmentLoader(nullptr), _debugSlots(false), _debugBones(false), _debugMeshes(false), _timeScale(1), _effect(nullptr) {
 	initWithJsonFile(skeletonDataFile, atlasFile, scale);
 }
 
@@ -183,6 +183,8 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t
 	SkeletonBatch* batch = SkeletonBatch::getInstance();
 	SkeletonTwoColorBatch* twoColorBatch = SkeletonTwoColorBatch::getInstance();
 	bool isTwoColorTint = this->isTwoColorTint();
+	
+	if (_effect) _effect->begin(_effect, _skeleton);
 
 	Color4F nodeColor;
 	nodeColor.r = getDisplayedColor().r / (float)255;
@@ -279,6 +281,11 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t
 		}
 		
 		color.a *= nodeColor.a * _skeleton->color.a * slot->color.a * 255;
+		// skip rendering if the color of this attachment is 0
+		if (color.a == 0){
+			spSkeletonClipping_clipEnd(_clipper, slot);
+			continue;
+		}
 		float multiplier = _premultipliedAlpha ? color.a : 255;
 		color.r *= nodeColor.r * _skeleton->color.r * slot->color.r * multiplier;
 		color.g *= nodeColor.g * _skeleton->color.g * slot->color.g * multiplier;
@@ -308,8 +315,10 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t
 				spSkeletonClipping_clipTriangles(_clipper, (float*)&triangles.verts[0].vertices, triangles.vertCount * sizeof(cocos2d::V3F_C4B_T2F) / 4, triangles.indices, triangles.indexCount, (float*)&triangles.verts[0].texCoords, 6);
 				batch->deallocateVertices(triangles.vertCount);
 				
-				if (_clipper->clippedTriangles->size == 0)
+				if (_clipper->clippedTriangles->size == 0){
+					spSkeletonClipping_clipEnd(_clipper, slot);
 					continue;
+				}
 				
 				triangles.vertCount = _clipper->clippedVertices->size >> 1;
 				triangles.verts = batch->allocateVertices(triangles.vertCount);
@@ -321,26 +330,70 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t
 				
 				float* verts = _clipper->clippedVertices->items;
 				float* uvs = _clipper->clippedUVs->items;
-				for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv+=2) {
-					V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
-					vertex->vertices.x = verts[vv];
-					vertex->vertices.y = verts[vv + 1];
-					vertex->texCoords.u = uvs[vv];
-					vertex->texCoords.v = uvs[vv + 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;
+				if (_effect) {
+					spColor light;
+					spColor dark;
+					light.r = color.r / 255.0f;
+					light.g = color.g / 255.0f;
+					light.b = color.b / 255.0f;
+					light.a = color.a / 255.0f;
+					dark.r = dark.g = dark.b = dark.a = 0;
+					for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv+=2) {
+						V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
+						spColor lightCopy = light;
+						spColor darkCopy = dark;
+						vertex->vertices.x = verts[vv];
+						vertex->vertices.y = verts[vv + 1];
+						vertex->texCoords.u = uvs[vv];
+						vertex->texCoords.v = uvs[vv + 1];
+						_effect->transform(_effect, &vertex->vertices.x, &vertex->vertices.y, &vertex->texCoords.u, &vertex->texCoords.v, &lightCopy, &darkCopy);
+						vertex->colors.r = (GLubyte)(lightCopy.r * 255);
+						vertex->colors.g = (GLubyte)(lightCopy.g * 255);
+						vertex->colors.b = (GLubyte)(lightCopy.b * 255);
+						vertex->colors.a = (GLubyte)(lightCopy.a * 255);
+					}
+				} else {
+					for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv+=2) {
+						V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
+						vertex->vertices.x = verts[vv];
+						vertex->vertices.y = verts[vv + 1];
+						vertex->texCoords.u = uvs[vv];
+						vertex->texCoords.v = uvs[vv + 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;
+					}
 				}
 			} else {
 				cocos2d::TrianglesCommand* batchedTriangles = batch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture, _glProgramState, blendFunc, triangles, transform, transformFlags);
 				
-				for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
-					V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
-					vertex->colors.r = (GLubyte)color.r;
-					vertex->colors.g = (GLubyte)color.g;
-					vertex->colors.b = (GLubyte)color.b;
-					vertex->colors.a = (GLubyte)color.a;
+				if (_effect) {
+					spColor light;
+					spColor dark;
+					light.r = color.r / 255.0f;
+					light.g = color.g / 255.0f;
+					light.b = color.b / 255.0f;
+					light.a = color.a / 255.0f;
+					dark.r = dark.g = dark.b = dark.a = 0;
+					for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
+						V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
+						spColor lightCopy = light;
+						spColor darkCopy = dark;
+						_effect->transform(_effect, &vertex->vertices.x, &vertex->vertices.y, &vertex->texCoords.u, &vertex->texCoords.v, &lightCopy, &darkCopy);
+						vertex->colors.r = (GLubyte)(lightCopy.r * 255);
+						vertex->colors.g = (GLubyte)(lightCopy.g * 255);
+						vertex->colors.b = (GLubyte)(lightCopy.b * 255);
+						vertex->colors.a = (GLubyte)(lightCopy.a * 255);
+					}
+				} else {
+					for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
+						V3F_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
+						vertex->colors.r = (GLubyte)color.r;
+						vertex->colors.g = (GLubyte)color.g;
+						vertex->colors.b = (GLubyte)color.b;
+						vertex->colors.a = (GLubyte)color.a;
+					}
 				}
 			}
 		} else {
@@ -348,8 +401,10 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t
 				spSkeletonClipping_clipTriangles(_clipper, (float*)&trianglesTwoColor.verts[0].position, trianglesTwoColor.vertCount * sizeof(V3F_C4B_C4B_T2F) / 4, trianglesTwoColor.indices, trianglesTwoColor.indexCount, (float*)&trianglesTwoColor.verts[0].texCoords, 7);
 				twoColorBatch->deallocateVertices(trianglesTwoColor.vertCount);
 				
-				if (_clipper->clippedTriangles->size == 0)
+				if (_clipper->clippedTriangles->size == 0){
+					spSkeletonClipping_clipEnd(_clipper, slot);
 					continue;
+				}
 				
 				trianglesTwoColor.vertCount = _clipper->clippedVertices->size >> 1;
 				trianglesTwoColor.verts = twoColorBatch->allocateVertices(trianglesTwoColor.vertCount);
@@ -361,34 +416,94 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t
 				
 				float* verts = _clipper->clippedVertices->items;
 				float* uvs = _clipper->clippedUVs->items;
-				for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv += 2) {
-					V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
-					vertex->position.x = verts[vv];
-					vertex->position.y = verts[vv + 1];
-					vertex->texCoords.u = uvs[vv];
-					vertex->texCoords.v = uvs[vv + 1];
-					vertex->color.r = (GLubyte)color.r;
-					vertex->color.g = (GLubyte)color.g;
-					vertex->color.b = (GLubyte)color.b;
-					vertex->color.a = (GLubyte)color.a;
-					vertex->color2.r = (GLubyte)darkColor.r;
-					vertex->color2.g = (GLubyte)darkColor.g;
-					vertex->color2.b = (GLubyte)darkColor.b;
-					vertex->color2.a = 1;
+				
+				if (_effect) {
+					spColor light;
+					spColor dark;
+					light.r = color.r / 255.0f;
+					light.g = color.g / 255.0f;
+					light.b = color.b / 255.0f;
+					light.a = color.a / 255.0f;
+					dark.r = darkColor.r / 255.0f;
+					dark.g = darkColor.g / 255.0f;
+					dark.b = darkColor.b / 255.0f;
+					dark.a = darkColor.a / 255.0f;
+					for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv += 2) {
+						V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
+						spColor lightCopy = light;
+						spColor darkCopy = dark;
+						vertex->position.x = verts[vv];
+						vertex->position.y = verts[vv + 1];
+						vertex->texCoords.u = uvs[vv];
+						vertex->texCoords.v = uvs[vv + 1];
+						_effect->transform(_effect, &vertex->position.x, &vertex->position.y, &vertex->texCoords.u, &vertex->texCoords.v, &lightCopy, &darkCopy);
+						vertex->color.r = (GLubyte)(lightCopy.r * 255);
+						vertex->color.g = (GLubyte)(lightCopy.g * 255);
+						vertex->color.b = (GLubyte)(lightCopy.b * 255);
+						vertex->color.a = (GLubyte)(lightCopy.a * 255);
+						vertex->color2.r = (GLubyte)(darkCopy.r * 255);
+						vertex->color2.g = (GLubyte)(darkCopy.g * 255);
+						vertex->color2.b = (GLubyte)(darkCopy.b * 255);
+						vertex->color2.a = 1;
+					}
+				} else {
+					for (int v = 0, vn = batchedTriangles->getTriangles().vertCount, vv = 0; v < vn; ++v, vv += 2) {
+						V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
+						vertex->position.x = verts[vv];
+						vertex->position.y = verts[vv + 1];
+						vertex->texCoords.u = uvs[vv];
+						vertex->texCoords.v = uvs[vv + 1];
+						vertex->color.r = (GLubyte)color.r;
+						vertex->color.g = (GLubyte)color.g;
+						vertex->color.b = (GLubyte)color.b;
+						vertex->color.a = (GLubyte)color.a;
+						vertex->color2.r = (GLubyte)darkColor.r;
+						vertex->color2.g = (GLubyte)darkColor.g;
+						vertex->color2.b = (GLubyte)darkColor.b;
+						vertex->color2.a = 1;
+					}
 				}
 			} else {
 				TwoColorTrianglesCommand* batchedTriangles = lastTwoColorTrianglesCommand = twoColorBatch->addCommand(renderer, _globalZOrder, attachmentVertices->_texture->getName(), _glProgramState, blendFunc, trianglesTwoColor, transform, transformFlags);
 				
-				for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
-					V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
-					vertex->color.r = (GLubyte)color.r;
-					vertex->color.g = (GLubyte)color.g;
-					vertex->color.b = (GLubyte)color.b;
-					vertex->color.a = (GLubyte)color.a;
-					vertex->color2.r = (GLubyte)darkColor.r;
-					vertex->color2.g = (GLubyte)darkColor.g;
-					vertex->color2.b = (GLubyte)darkColor.b;
-					vertex->color2.a = 1;
+				if (_effect) {
+					spColor light;
+					spColor dark;
+					light.r = color.r / 255.0f;
+					light.g = color.g / 255.0f;
+					light.b = color.b / 255.0f;
+					light.a = color.a / 255.0f;
+					dark.r = darkColor.r / 255.0f;
+					dark.g = darkColor.g / 255.0f;
+					dark.b = darkColor.b / 255.0f;
+					dark.a = darkColor.a / 255.0f;
+					
+					for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
+						V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
+						spColor lightCopy = light;
+						spColor darkCopy = dark;
+						_effect->transform(_effect, &vertex->position.x, &vertex->position.y, &vertex->texCoords.u, &vertex->texCoords.v, &lightCopy, &darkCopy);
+						vertex->color.r = (GLubyte)(lightCopy.r * 255);
+						vertex->color.g = (GLubyte)(lightCopy.g * 255);
+						vertex->color.b = (GLubyte)(lightCopy.b * 255);
+						vertex->color.a = (GLubyte)(lightCopy.a * 255);
+						vertex->color2.r = (GLubyte)(darkCopy.r * 255);
+						vertex->color2.g = (GLubyte)(darkCopy.g * 255);
+						vertex->color2.b = (GLubyte)(darkCopy.b * 255);
+						vertex->color2.a = 1;
+					}
+				} else {
+					for (int v = 0, vn = batchedTriangles->getTriangles().vertCount; v < vn; ++v) {
+						V3F_C4B_C4B_T2F* vertex = batchedTriangles->getTriangles().verts + v;
+						vertex->color.r = (GLubyte)color.r;
+						vertex->color.g = (GLubyte)color.g;
+						vertex->color.b = (GLubyte)color.b;
+						vertex->color.a = (GLubyte)color.a;
+						vertex->color2.r = (GLubyte)darkColor.r;
+						vertex->color2.g = (GLubyte)darkColor.g;
+						vertex->color2.b = (GLubyte)darkColor.b;
+						vertex->color2.a = 1;
+					}
 				}
 			}
 		}
@@ -432,6 +547,8 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t
 			}
 		}
 	}
+	
+	if (_effect) _effect->end(_effect);
 
 	if (_debugSlots || _debugBones || _debugMeshes) {
         drawDebug(renderer, transform, transformFlags);
@@ -595,6 +712,10 @@ void SkeletonRenderer::setTwoColorTint(bool enabled) {
 bool SkeletonRenderer::isTwoColorTint() {
 	return getGLProgramState() == SkeletonTwoColorBatch::getInstance()->getTwoColorTintProgramState();
 }
+	
+void SkeletonRenderer::setVertexEffect(spVertexEffect *effect) {
+	this->_effect = effect;
+}
 
 spSkeleton* SkeletonRenderer::getSkeleton () {
 	return _skeleton;

+ 5 - 1
spine-cocos2dx/src/spine/SkeletonRenderer.h

@@ -99,6 +99,9 @@ public:
 	void setTwoColorTint(bool enabled);
 	/* Whether two color tinting is enabled */
 	bool isTwoColorTint();
+	
+	/* Sets the vertex effect to be used, set to 0 to disable vertex effects */
+	void setVertexEffect(spVertexEffect* effect);
 
     // --- BlendProtocol
     virtual void setBlendFunc (const cocos2d::BlendFunc& blendFunc)override;
@@ -125,7 +128,7 @@ CC_CONSTRUCTOR_ACCESS:
 protected:
 	void setSkeletonData (spSkeletonData* skeletonData, bool ownsSkeletonData);
 	virtual AttachmentVertices* getAttachmentVertices (spRegionAttachment* attachment) const;
-	virtual AttachmentVertices* getAttachmentVertices (spMeshAttachment* attachment) const;
+	virtual AttachmentVertices* getAttachmentVertices (spMeshAttachment* attachment) const;	
 
 	bool _ownsSkeletonData;
 	spAtlas* _atlas;
@@ -140,6 +143,7 @@ protected:
 	bool _debugBones;
 	bool _debugMeshes;
 	spSkeletonClipping* _clipper;
+	spVertexEffect* _effect;
 };
 
 }

+ 2 - 2
spine-corona/README.md

@@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
 
 ## Spine version
 
-spine-corona works with data exported from Spine 3.5.xx.
+spine-corona works with data exported from Spine 3.6.xx.
 
 spine-corona supports all Spine features.
 
@@ -18,7 +18,7 @@ spine-corona does not yet support loading the binary format.
 
 ## Setup
 
-1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip).
+1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip).
 1. Copy the contents of `spine-lua` to `spine-corona/spine-lua`.
 1. Run the `main.lua` file using Corona. Tap/click to switch between skeletons
 

+ 16 - 5
spine-corona/main.lua

@@ -5,6 +5,8 @@ local spine = require "spine-corona.spine"
 local skeletons = {}
 local activeSkeleton = 1
 local lastTime = 0
+local swirl = spine.SwirlEffect.new(400)
+local swirlTime = 0
 
 function loadSkeleton(atlasFile, jsonFile, x, y, scale, animation, skin)
 	-- to load an atlas, we need to define a function that returns
@@ -67,7 +69,11 @@ function loadSkeleton(atlasFile, jsonFile, x, y, scale, animation, skin)
 		animationState:setAnimationByName(0, "walk", true)
 		local jumpEntry = animationState:addAnimationByName(0, "jump", false, 3)
 		animationState:addAnimationByName(0, "run", true, 0)
-  else
+  elseif atlasFile == "raptor.atlas" then
+		--skeleton.vertexEffect = spine.JitterEffect.new(5, 5)
+		skeleton.vertexEffect = swirl
+		animationState:setAnimationByName(0, animation, true)
+	else
     animationState:setAnimationByName(0, animation, true)
   end
 
@@ -77,11 +83,11 @@ end
 
 -- table.insert(skeletons, loadSkeleton("coin.atlas", "coin-pro.json", 240, 300, 0.4, "rotate"))
 -- table.insert(skeletons, loadSkeleton("spineboy.atlas", "spineboy-ess.json", 240, 300, 0.4, "walk"))
--- table.insert(skeletons, loadSkeleton("raptor.atlas", "raptor-pro.json", 200, 300, 0.25, "walk"))
+table.insert(skeletons, loadSkeleton("raptor.atlas", "raptor-pro.json", 200, 300, 0.25, "walk"))
 -- table.insert(skeletons, loadSkeleton("goblins.atlas", "goblins-pro.json", 240, 300, 0.8, "walk", "goblin"))
--- table.insert(skeletons, loadSkeleton("stretchyman.atlas", "stretchyman-pro.json", 40, 300, 0.5, "sneak"))
-table.insert(skeletons, loadSkeleton("tank.atlas", "tank-pro.json", 400, 300, 0.2, "drive"))
--- table.insert(skeletons, loadSkeleton("vine.atlas", "vine-pro.json", 240, 300, 0.3, "grow"))
+table.insert(skeletons, loadSkeleton("stretchyman.atlas", "stretchyman-pro.json", 40, 300, 0.5, "sneak"))
+-- table.insert(skeletons, loadSkeleton("tank.atlas", "tank-pro.json", 400, 300, 0.2, "drive"))
+table.insert(skeletons, loadSkeleton("vine.atlas", "vine-pro.json", 240, 300, 0.3, "grow"))
 
 local triangulator = spine.Triangulator.new()
 local polygon = { 411, 219, 199, 230, 161, 362, 534, 407, 346, 305, 596, 265 }
@@ -109,6 +115,11 @@ Runtime:addEventListener("enterFrame", function (event)
 	local currentTime = event.time / 1000
 	local delta = currentTime - lastTime
 	lastTime = currentTime
+	
+	swirlTime = swirlTime + delta
+	local percent = swirlTime % 2
+	if (percent > 1) then percent = 1 - (percent - 1) end
+	swirl.angle = spine.Interpolation.apply(spine.Interpolation.pow2, -60, 60, percent)
 
 	skeleton = skeletons[activeSkeleton].skeleton
 	skeleton.group.isVisible = true

+ 39 - 7
spine-corona/spine-corona/spine.lua

@@ -65,6 +65,9 @@ spine.AtlasAttachmentLoader = require "spine-lua.AtlasAttachmentLoader"
 spine.Color = require "spine-lua.Color"
 spine.Triangulator = require "spine-lua.Triangulator"
 spine.SkeletonClipping = require "spine-lua.SkeletonClipping"
+spine.JitterEffect = require "spine-lua.vertexeffects.JitterEffect"
+spine.SwirlEffect = require "spine-lua.vertexeffects.SwirlEffect"
+spine.Interpolation = require "spine-lua.Interpolation"
 
 spine.utils.readFile = function (fileName, base)
 	if not base then base = system.ResourceDirectory end
@@ -92,6 +95,14 @@ spine.Skeleton.new = function(skeletonData, group)
 	self.batches = 0
 	self.tempColor = spine.Color.newWith(1, 1, 1, 1)
 	self.tempColor2 = spine.Color.newWith(-1, 1, 1, 1)
+	self.tempVertex = {
+		x = 0,
+		y = 0,
+		u = 0,
+		v = 0,
+		light = spine.Color.newWith(1, 1, 1, 1),
+		dark = spine.Color.newWith(0, 0, 0, 0)
+	}
 	self.clipper = spine.SkeletonClipping.new()
 	return self
 end
@@ -119,6 +130,8 @@ function spine.Skeleton:updateWorldTransform()
 	local premultipliedAlpha = self.premultipliedAlpha
 
 	self.batches = 0
+	
+	if (self.vertexEffect) then self.vertexEffect:beginEffect(self) end
 
 	-- Remove old drawing group, we will start anew
 	if self.drawingGroup then self.drawingGroup:removeSelf() end
@@ -217,6 +230,7 @@ function spine.Skeleton:updateWorldTransform()
 	end
 	
 	self.clipper:clipEnd2()
+	if (self.vertexEffect) then self.vertexEffect:endEffect() end
 end
 
 function spine.Skeleton:flush(groupVertices, groupUvs, groupIndices, texture, color, blendMode, drawingGroup)
@@ -250,13 +264,31 @@ function spine.Skeleton:batch(vertices, uvs, numVertices, indices, groupVertices
 	i = 1
 	local vertexStart = #groupVertices + 1
 	local vertexEnd = vertexStart + numVertices * 2
-	while vertexStart < vertexEnd do
-		groupVertices[vertexStart] = vertices[i]
-		groupVertices[vertexStart+1] = vertices[i+1]
-		groupUvs[vertexStart] = uvs[i]
-		groupUvs[vertexStart+1] = uvs[i+1]
-		vertexStart = vertexStart + 2
-		i = i + 2
+	if (self.vertexEffect) then
+		local effect = self.vertexEffect
+		local vertex = self.tempVertex
+		while vertexStart < vertexEnd do
+			vertex.x = vertices[i]
+			vertex.y = vertices[i+1]
+			vertex.u = uvs[i]
+			vertex.v = uvs[i+1]
+			effect:transform(vertex);
+			groupVertices[vertexStart] = vertex.x
+			groupVertices[vertexStart+1] = vertex.y
+			groupUvs[vertexStart] = vertex.u
+			groupUvs[vertexStart+1] = vertex.v
+			vertexStart = vertexStart + 2
+			i = i + 2
+		end
+	else
+		while vertexStart < vertexEnd do
+			groupVertices[vertexStart] = vertices[i]
+			groupVertices[vertexStart+1] = vertices[i+1]
+			groupUvs[vertexStart] = uvs[i]
+			groupUvs[vertexStart+1] = uvs[i+1]
+			vertexStart = vertexStart + 2
+			i = i + 2
+		end
 	end
 end
 

+ 1 - 1
spine-csharp/README.md

@@ -16,7 +16,7 @@ spine-csharp supports all Spine features.
 
 ## Setup
 
-1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip).
+1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip).
 1. Open the `spine-csharp.sln` Visual Studio 2015 Community project file.
 
 Alternatively, the contents of the `spine-csharp/src` directory can be copied into your project.

+ 45 - 43
spine-csharp/src/AnimationState.cs

@@ -34,21 +34,21 @@ using System.Collections.Generic;
 namespace Spine {
 	public class AnimationState {
 		static readonly Animation EmptyAnimation = new Animation("<empty>", new ExposedList<Timeline>(), 0);
-		internal const int SUBSEQUENT = 0, FIRST = 1, DIP = 2, DIP_MIX = 3;
+		internal const int Subsequent = 0, First = 1, Dip = 2, DipMix = 3;
 
 		private AnimationStateData data;
+
+		Pool<TrackEntry> trackEntryPool = new Pool<TrackEntry>();
 		private readonly ExposedList<TrackEntry> tracks = new ExposedList<TrackEntry>();
-		private readonly HashSet<int> propertyIDs = new HashSet<int>();
 		private readonly ExposedList<Event> events = new ExposedList<Event>();
-		private readonly EventQueue queue;
+		private readonly EventQueue queue; // Initialized by constructor.
 
+		private readonly HashSet<int> propertyIDs = new HashSet<int>();
 		private readonly ExposedList<TrackEntry> mixingTo = new ExposedList<TrackEntry>();
 		private bool animationsChanged;
 
 		private float timeScale = 1;
 
-		Pool<TrackEntry> trackEntryPool = new Pool<TrackEntry>();
-
 		public AnimationStateData Data { get { return data; } }
 		/// <summary>A list of tracks that have animations, which may contain nulls.</summary>
 		public ExposedList<TrackEntry> Tracks { get { return tracks; } }
@@ -63,13 +63,13 @@ namespace Spine {
 		public AnimationState (AnimationStateData data) {
 			if (data == null) throw new ArgumentNullException("data", "data cannot be null.");
 			this.data = data;
-			this.queue = new EventQueue(this, HandleAnimationsChanged, trackEntryPool);
+			this.queue = new EventQueue(
+				this,
+				delegate { this.animationsChanged = true; },
+				trackEntryPool
+			);
 		}
-
-		void HandleAnimationsChanged () {
-			this.animationsChanged = true;
-		}
-
+			
 		/// <summary>
 		/// Increments the track entry times, setting queued animations as current if needed</summary>
 		/// <param name="delta">delta time</param>
@@ -155,7 +155,6 @@ namespace Spine {
 			return false;
 		}
 
-
 		/// <summary>
 		/// Poses the skeleton using the track entry animations. There are no side effects other than invoking listeners, so the 
 		/// animation state can be applied to multiple skeletons to pose them identically.</summary>
@@ -197,7 +196,7 @@ namespace Spine {
 
 					for (int ii = 0; ii < timelineCount; ii++) {
 						Timeline timeline = timelinesItems[ii];
-						MixPose pose = timelineData[ii] >= FIRST ? MixPose.Setup : currentPose;
+						MixPose pose = timelineData[ii] >= AnimationState.First ? MixPose.Setup : currentPose;
 						var rotateTimeline = timeline as RotateTimeline;
 						if (rotateTimeline != null)
 							ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, pose, timelinesRotation, ii << 1, firstFrame);
@@ -246,17 +245,17 @@ namespace Spine {
 			for (int i = 0; i < timelineCount; i++) {
 				Timeline timeline = timelinesItems[i];
 				switch (timelineData[i]) {
-				case SUBSEQUENT:
+				case Subsequent:
 					if (!attachments && timeline is AttachmentTimeline) continue;
 					if (!drawOrder && timeline is DrawOrderTimeline) continue;
 					pose = currentPose;
 					alpha = alphaMix;
 					break;
-				case FIRST:
+				case First:
 					pose = MixPose.Setup;
 					alpha = alphaMix;
 					break;
-				case DIP:
+				case Dip:
 					pose = MixPose.Setup;
 					alpha = alphaDip;
 					break;
@@ -421,6 +420,7 @@ namespace Spine {
 			queue.Drain();
 		}
 
+		/// <summary>Sets the active TrackEntry for a given track number.</summary>
 		private void SetCurrent (int index, TrackEntry current, bool interrupt) {
 			TrackEntry from = ExpandToIndex(index);
 			tracks.Items[index] = current;
@@ -437,12 +437,12 @@ namespace Spine {
 				from.timelinesRotation.Clear(); // Reset rotation for mixing out, in case entry was mixed in.
 			}
 
-			queue.Start(current);
+			queue.Start(current); // triggers AnimationsChanged
 		}
 
 
 		/// <summary>Sets an animation by name. <seealso cref="SetAnimation(int, Animation, bool)" /></summary>
-		public TrackEntry SetAnimation (int trackIndex, String animationName, bool loop) {
+		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);
@@ -480,7 +480,7 @@ namespace Spine {
 
 		/// <summary>Queues an animation by name.</summary>
 		/// <seealso cref="AddAnimation(int, Animation, bool, float)" />
-		public TrackEntry AddAnimation (int trackIndex, String animationName, bool loop, float delay) {
+		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);
@@ -570,6 +570,7 @@ namespace Spine {
 			return null;
 		}
 
+		/// <summary>Object-pooling version of new TrackEntry. Obtain an unused TrackEntry from the pool and clear/initialize its values.</summary>
 		/// <param name="last">May be null.</param>
 		private TrackEntry NewTrackEntry (int trackIndex, Animation animation, bool loop, TrackEntry last) {
 			TrackEntry entry = trackEntryPool.Obtain(); // Pooling
@@ -589,7 +590,7 @@ namespace Spine {
 			entry.delay = 0;
 			entry.trackTime = 0;
 			entry.trackLast = -1;
-			entry.nextTrackLast = -1;
+			entry.nextTrackLast = -1; // nextTrackLast == -1 signifies a TrackEntry that wasn't applied yet.
 			entry.trackEnd = float.MaxValue; // loop ? float.MaxValue : animation.Duration;
 			entry.timeScale = 1;
 
@@ -600,6 +601,7 @@ namespace Spine {
 			return entry;
 		}
 
+		/// <summary>Dispose all track entries queued after the given TrackEntry.</summary>
 		private void DisposeNext (TrackEntry entry) {
 			TrackEntry next = entry.next;
 			while (next != null) {
@@ -628,7 +630,7 @@ namespace Spine {
 			return (trackIndex >= tracks.Count) ? null : tracks.Items[trackIndex];
 		}
 
-		override public String ToString () {
+		override public string ToString () {
 			var buffer = new System.Text.StringBuilder();
 			for (int i = 0, n = tracks.Count; i < n; i++) {
 				TrackEntry entry = tracks.Items[i];
@@ -680,11 +682,12 @@ namespace Spine {
 			Event = null;
 		}
 
+		/// <summary>Sets the timeline data.</summary>
 		/// <param name="to">May be null.</param>
 		internal TrackEntry SetTimelineData (TrackEntry to, ExposedList<TrackEntry> mixingToArray, HashSet<int> propertyIDs) {
 			if (to != null) mixingToArray.Add(to);
 			var lastEntry = mixingFrom != null ? mixingFrom.SetTimelineData(this, mixingToArray, propertyIDs) : this;
-			if (to != null) mixingToArray.RemoveAt(mixingToArray.Count - 1); // mixingToArray.pop();
+			if (to != null) mixingToArray.Pop();
 
 			var mixingTo = mixingToArray.Items;
 			int mixingToLast = mixingToArray.Count - 1;
@@ -698,21 +701,19 @@ namespace Spine {
 			for (int i = 0; i < timelinesCount; i++) {
 				int id = timelines[i].PropertyId;
 				if (!propertyIDs.Add(id)) {
-					timelineDataItems[i] = AnimationState.SUBSEQUENT;
+					timelineDataItems[i] = AnimationState.Subsequent;
 				} else if (to == null || !to.HasTimeline(id)) {
-					timelineDataItems[i] = AnimationState.FIRST;
+					timelineDataItems[i] = AnimationState.First;
 				} else {
 					for (int ii = mixingToLast; ii >= 0; ii--) {
 						var entry = mixingTo[ii];
-						if (!entry.HasTimeline(id)) {
-							if (entry.mixDuration > 0) {
-								timelineDataItems[i] = AnimationState.DIP_MIX;
-								timelineDipMixItems[i] = entry;
-								goto outer; // continue outer;
-							}
+						if (entry.mixDuration > 0 && !entry.HasTimeline(id)) {
+							timelineDataItems[i] = AnimationState.DipMix;
+							timelineDipMixItems[i] = entry;
+							goto outer; // continue outer;
 						}
 					}
-					timelineDataItems[i] = AnimationState.DIP;
+					timelineDataItems[i] = AnimationState.Dip;
 				}
 				outer: {}
 			}
@@ -886,20 +887,20 @@ namespace Spine {
 			timelinesRotation.Clear();
 		}
 
-		override public String ToString () {
+		override public string ToString () {
 			return animation == null ? "<none>" : animation.name;
 		}
 	}
 
 	class EventQueue {
 		private readonly List<EventQueueEntry> eventQueueEntries = new List<EventQueueEntry>();
-		public bool drainDisabled;
+		internal bool drainDisabled;
 
 		private readonly AnimationState state;
 		private readonly Pool<TrackEntry> trackEntryPool;
-		public event Action AnimationsChanged;
+		internal event Action AnimationsChanged;
 
-		public EventQueue (AnimationState state, Action HandleAnimationsChanged, Pool<TrackEntry> trackEntryPool) {
+		internal EventQueue (AnimationState state, Action HandleAnimationsChanged, Pool<TrackEntry> trackEntryPool) {
 			this.state = state;
 			this.AnimationsChanged += HandleAnimationsChanged;
 			this.trackEntryPool = trackEntryPool;
@@ -921,33 +922,34 @@ namespace Spine {
 			Start, Interrupt, End, Dispose, Complete, Event
 		}
 
-		public void Start (TrackEntry entry) {
+		internal void Start (TrackEntry entry) {
 			eventQueueEntries.Add(new EventQueueEntry(EventType.Start, entry));
 			if (AnimationsChanged != null) AnimationsChanged();
 		}
 
-		public void Interrupt (TrackEntry entry) {
+		internal void Interrupt (TrackEntry entry) {
 			eventQueueEntries.Add(new EventQueueEntry(EventType.Interrupt, entry));
 		}
 
-		public void End (TrackEntry entry) {
+		internal void End (TrackEntry entry) {
 			eventQueueEntries.Add(new EventQueueEntry(EventType.End, entry));
 			if (AnimationsChanged != null) AnimationsChanged();
 		}
 
-		public void Dispose (TrackEntry entry) {
+		internal void Dispose (TrackEntry entry) {
 			eventQueueEntries.Add(new EventQueueEntry(EventType.Dispose, entry));
 		}
 
-		public void Complete (TrackEntry entry) {
+		internal void Complete (TrackEntry entry) {
 			eventQueueEntries.Add(new EventQueueEntry(EventType.Complete, entry));
 		}
 
-		public void Event (TrackEntry entry, Event e) {
+		internal void Event (TrackEntry entry, Event e) {
 			eventQueueEntries.Add(new EventQueueEntry(EventType.Event, entry, e));
 		}
 
-		public void Drain () {
+		/// <summary>Raises all events in the queue and drains the queue.</summary>
+		internal void Drain () {
 			if (drainDisabled) return;
 			drainDisabled = true;
 
@@ -992,7 +994,7 @@ namespace Spine {
 			drainDisabled = false;
 		}
 
-		public void Clear () {
+		internal void Clear () {
 			eventQueueEntries.Clear();
 		}
 	}

+ 20 - 6
spine-csharp/src/Atlas.cs

@@ -28,6 +28,10 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
 
+#if (UNITY_5 || UNITY_5_3_OR_NEWER || UNITY_WSA || UNITY_WP8 || UNITY_WP8_1)
+#define IS_UNITY
+#endif
+
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -39,12 +43,22 @@ using Windows.Storage;
 #endif
 
 namespace Spine {
-	public class Atlas {
+	public class Atlas : IEnumerable<AtlasRegion> {
 		readonly List<AtlasPage> pages = new List<AtlasPage>();
 		List<AtlasRegion> regions = new List<AtlasRegion>();
 		TextureLoader textureLoader;
 
-		#if !(UNITY_5 || UNITY_4 || UNITY_WSA || UNITY_WP8 || UNITY_WP8_1) // !UNITY
+		#region IEnumerable implementation
+		public IEnumerator<AtlasRegion> GetEnumerator () {
+			return regions.GetEnumerator();
+		}
+
+		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () {
+			return regions.GetEnumerator();
+		}
+		#endregion
+
+		#if !(IS_UNITY)
 		#if WINDOWS_STOREAPP
 		private async Task ReadFile(string path, TextureLoader textureLoader) {
 			var folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
@@ -82,7 +96,7 @@ namespace Spine {
 		}
 		#endif // WINDOWS_STOREAPP
 
-		#endif // !(UNITY)
+		#endif
 
 		public Atlas (TextReader reader, string dir, TextureLoader textureLoader) {
 			Load(reader, dir, textureLoader);
@@ -95,7 +109,7 @@ namespace Spine {
 		}
 
 		private void Load (TextReader reader, string imagesDir, TextureLoader textureLoader) {
-			if (textureLoader == null) throw new ArgumentNullException("textureLoader cannot be null.");
+			if (textureLoader == null) throw new ArgumentNullException("textureLoader", "textureLoader cannot be null.");
 			this.textureLoader = textureLoader;
 
 			string[] tuple = new string[4];
@@ -164,11 +178,11 @@ namespace Spine {
 					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]),
+						region.splits = new [] {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]),
+							region.pads = new [] {int.Parse(tuple[0]), int.Parse(tuple[1]),
 									int.Parse(tuple[2]), int.Parse(tuple[3])};
 
 							ReadTuple(reader, tuple);

+ 5 - 5
spine-csharp/src/Bone.cs

@@ -246,14 +246,14 @@ namespace Spine {
 					float lb = MathUtils.CosDeg(90 + shearY) * scaleY;
 					float lc = MathUtils.SinDeg(shearX) * scaleX;
 					float ld = MathUtils.SinDeg(90 + shearY) * scaleY;
+					if (data.transformMode != TransformMode.NoScaleOrReflection? pa * pd - pb* pc< 0 : skeleton.flipX != skeleton.flipY) {
+						zb = -zb;
+						zd = -zd;
+					}
 					a = za * la + zb * lc;
 					b = za * lb + zb * ld;
 					c = zc * la + zd * lc;
-					d = zc * lb + zd * ld;
-					if (data.transformMode != TransformMode.NoScaleOrReflection ? pa * pd - pb * pc < 0 : skeleton.flipX != skeleton.flipY) {
-						b = -b;
-						d = -d;
-					}
+					d = zc * lb + zd * ld;					
 					return;
 				}
 			}

+ 18 - 3
spine-csharp/src/ExposedList.cs

@@ -104,14 +104,14 @@ namespace Spine {
 			}
 		}
 
-		private void CheckRange (int idx, int count) {
-			if (idx < 0)
+		private void CheckRange (int index, int count) {
+			if (index < 0)
 				throw new ArgumentOutOfRangeException("index");
 
 			if (count < 0)
 				throw new ArgumentOutOfRangeException("count");
 
-			if ((uint)idx + (uint)count > (uint)Count)
+			if ((uint)index + (uint)count > (uint)Count)
 				throw new ArgumentException("index and count exceed length of list");
 		}
 
@@ -450,6 +450,21 @@ namespace Spine {
 			version++;
 		}
 
+		// Spine Added Method
+		// Based on Stack<T>.Pop(); https://referencesource.microsoft.com/#mscorlib/system/collections/stack.cs
+		/// <summary>Pops the last item of the list. If the list is empty, Pop throws an InvalidOperationException.</summary>
+		public T Pop () {
+			if (Count == 0)
+				throw new InvalidOperationException("List is empty. Nothing to pop.");
+			
+			int i = Count - 1;
+			T item = Items[i];
+			Items[i] = default(T);
+			Count--;
+			version++;
+			return item;
+		}
+
 		public void RemoveRange (int index, int count) {
 			CheckRange(index, count);
 			if (count > 0) {

+ 3 - 1
spine-csharp/src/PathConstraint.cs

@@ -91,7 +91,9 @@ namespace Spine {
 				if (scale) lengths = this.lengths.Resize(boneCount);
 				for (int i = 0, n = spacesCount - 1; i < n;) {
 					Bone bone = bonesItems[i];
-					float setupLength = bone.data.length, x = setupLength * bone.a, y = setupLength * bone.c;
+					float setupLength = bone.data.length;
+					if (setupLength == 0) setupLength = 0.000000001f;
+					float x = setupLength * bone.a, y = setupLength * bone.c;
 					float length = (float)Math.Sqrt(x * x + y * y);
 					if (scale) lengths.Items[i] = setupLength;
 					spaces.Items[++i] = (lengthSpacing ? Math.Max(0, setupLength + spacing) : spacing) * length / setupLength;

+ 4 - 2
spine-csharp/src/Skeleton.cs

@@ -502,14 +502,16 @@ namespace Spine {
 				var regionAttachment = attachment as RegionAttachment;
 				if (regionAttachment != null) {
 					verticesLength = 8;
-					if (temp.Length < 8) temp = new float[8];
+					vertices = temp;
+					if (vertices.Length < 8) vertices = temp = new float[8];
 					regionAttachment.ComputeWorldVertices(slot.bone, temp, 0);
 				} else {
 					var meshAttachment = attachment as MeshAttachment;
 					if (meshAttachment != null) {
 						MeshAttachment mesh = meshAttachment;
 						verticesLength = mesh.WorldVerticesLength;
-						if (temp.Length < verticesLength) temp = new float[verticesLength];
+						vertices = temp;
+						if (vertices.Length < verticesLength) vertices = temp = new float[verticesLength];
 						mesh.ComputeWorldVertices(slot, 0, verticesLength, temp, 0);
 					}
 				}

+ 1 - 1
spine-csharp/src/SkeletonBinary.cs

@@ -28,7 +28,7 @@
  * 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)
+#if (UNITY_5 || UNITY_5_3_OR_NEWER || UNITY_WSA || UNITY_WP8 || UNITY_WP8_1)
 #define IS_UNITY
 #endif
 

+ 6 - 6
spine-csharp/src/SkeletonClipping.cs

@@ -154,7 +154,7 @@ namespace Spine {
 						clippedUVsItems[s + 2] = u2;
 						clippedUVsItems[s + 3] = v2;
 						clippedUVsItems[s + 4] = u3;
-						clippedUVsItems[s + 5] = v3;					
+						clippedUVsItems[s + 5] = v3;
 
 						s = clippedTriangles.Count;
 						int[] clippedTrianglesItems = clippedTriangles.Resize(s + 3).Items;
@@ -180,9 +180,9 @@ namespace Spine {
 			if (clippingArea.Count % 4 >= 2) {
 				input = output;
 				output = scratch;
-			}
-			else
+			} else {
 				input = scratch;
+			}
 
 			input.Clear();
 			input.Add(x1);
@@ -251,14 +251,14 @@ namespace Spine {
 				for (int i = 0, n = output.Count - 2; i < n; i++) {
 					originalOutput.Add(output.Items[i]);
 				}
-			}
-			else
+			} else {
 				originalOutput.Resize(originalOutput.Count - 2);
+			}
 
 			return clipped;
 		}
 
-		static void MakeClockwise (ExposedList<float> polygon) {
+		public static void MakeClockwise (ExposedList<float> polygon) {
 			float[] vertices = polygon.Items;
 			int verticeslength = polygon.Count;
 

+ 10 - 3
spine-csharp/src/SkeletonJson.cs

@@ -420,10 +420,17 @@ namespace Spine {
 					ClippingAttachment clip = attachmentLoader.NewClippingAttachment(skin, name);
 					if (clip == null) return null;
 
-					SlotData slot = skeletonData.FindSlot(GetString(map, "end", null));
-					if (slot == null) throw new Exception("Clipping end slot not found: " + GetString(map, "end", null));
-					clip.endSlot = slot;
+					string end = GetString(map, "end", null);
+					if (end != null) {
+						SlotData slot = skeletonData.FindSlot(end);
+						if (slot == null) throw new Exception("Clipping end slot not found: " + end);
+						clip.EndSlot = slot;
+					}
+
 					ReadVertices(map, clip, GetInt(map, "vertexCount", 0) << 1);
+
+					//string color = GetString(map, "color", null);
+					// if (color != null) clip.color = color;
 					return clip;
 				}
 			}

+ 2 - 2
spine-csharp/src/Triangulator.cs

@@ -31,7 +31,7 @@
 using System;
 
 namespace Spine {
-	internal class Triangulator {
+	public class Triangulator {
 		private readonly ExposedList<ExposedList<float>> convexPolygons = new ExposedList<ExposedList<float>>();
 		private readonly ExposedList<ExposedList<int>> convexPolygonsIndices = new ExposedList<ExposedList<int>>();
 
@@ -84,6 +84,7 @@ namespace Spine {
 						}
 						break;
 					}
+					outer:
 
 					if (next == 0) {
 						do {
@@ -97,7 +98,6 @@ namespace Spine {
 					i = next;
 					next = (next + 1) % vertexCount;
 				}
-				outer:
 
 				// Cut ear tip.
 				triangles.Add(indices[(vertexCount + i - 1) % vertexCount]);

+ 2 - 2
spine-libgdx/README.md

@@ -10,13 +10,13 @@ The Spine Runtimes are developed with the intent to be used with data exported f
 
 ## Spine version
 
-spine-libgdx works with data exported from Spine 3.5.xx.
+spine-libgdx works with data exported from Spine 3.6.xx.
 
 spine-libgdx supports all Spine features and is the reference runtime implementation.
 
 ## Setup
 
-1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip).
+1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip).
 1. Using Eclipse, import the project by choosing File -> Import -> Existing projects. For other IDEs you will need to create a new project and import the source.
 
 Alternatively, the contents of the `spine-libgdx/src` directory can be copied into your project.

+ 1 - 0
spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/VertexEffectTest.java

@@ -39,6 +39,7 @@ import com.badlogic.gdx.graphics.OrthographicCamera;
 import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
 import com.badlogic.gdx.graphics.g2d.TextureAtlas;
 import com.badlogic.gdx.math.Interpolation;
+import com.esotericsoftware.spine.vertexeffects.JitterEffect;
 import com.esotericsoftware.spine.vertexeffects.SwirlEffect;
 
 public class VertexEffectTest extends ApplicationAdapter {

+ 5 - 5
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java

@@ -201,15 +201,15 @@ public class Bone implements Updatable {
 			float la = cosDeg(shearX) * scaleX;
 			float lb = cosDeg(90 + shearY) * scaleY;
 			float lc = sinDeg(shearX) * scaleX;
-			float ld = sinDeg(90 + shearY) * scaleY;
+			float ld = sinDeg(90 + shearY) * scaleY;			
+			if (data.transformMode != TransformMode.noScaleOrReflection ? pa * pd - pb * pc < 0 : skeleton.flipX != skeleton.flipY) {
+			    zb = -zb;
+			    zd = -zd;
+			}			
 			a = za * la + zb * lc;
 			b = za * lb + zb * ld;
 			c = zc * la + zd * lc;
 			d = zc * lb + zd * ld;
-			if (data.transformMode != TransformMode.noScaleOrReflection ? pa * pd - pb * pc < 0 : skeleton.flipX != skeleton.flipY) {
-				b = -b;
-				d = -d;
-			}
 			return;
 		}
 		}

+ 4 - 2
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java

@@ -112,9 +112,11 @@ public class PathConstraint implements Constraint {
 			if (scale) lengths = this.lengths.setSize(boneCount);
 			for (int i = 0, n = spacesCount - 1; i < n;) {
 				Bone bone = (Bone)bones[i];
-				float setupLength = bone.data.length, x = setupLength * bone.a, y = setupLength * bone.c;
+				float setupLength = bone.data.length;
+				if (setupLength == 0) setupLength = 0.000000001f;
+				float x = setupLength * bone.a, y = setupLength * bone.c;
 				float length = (float)Math.sqrt(x * x + y * y);
-				if (scale) lengths[i] = length;
+				if (scale) lengths[i] = length;				
 				spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;
 			}
 		} else {

+ 2 - 1
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonClipping.java

@@ -56,7 +56,8 @@ public class SkeletonClipping {
 		float[] vertices = clippingPolygon.setSize(n);
 		clip.computeWorldVertices(slot, 0, n, vertices, 0, 2);
 		makeClockwise(clippingPolygon);
-		clippingPolygons = triangulator.decompose(clippingPolygon, triangulator.triangulate(clippingPolygon));
+		ShortArray triangles = triangulator.triangulate(clippingPolygon);
+		clippingPolygons = triangulator.decompose(clippingPolygon, triangles);
 		for (FloatArray polygon : clippingPolygons) {
 			makeClockwise(polygon);
 			polygon.add(polygon.items[0]);

+ 1 - 1
spine-love/README.md

@@ -18,7 +18,7 @@ spine-love does not yet support loading the binary format.
 
 ## Setup
 
-1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip).
+1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip).
 1. Copy the contents of `spine-lua` to `spine-love/spine-lua`.
 1. Run the `main.lua` file using LÖVE.
 

+ 23 - 2
spine-love/main.lua

@@ -32,6 +32,8 @@ local spine = require "spine-love.spine"
 
 local skeletons = {}
 local activeSkeleton = 1
+local swirl = spine.SwirlEffect.new(400)
+local swirlTime = 0
 
 function loadSkeleton (jsonFile, atlasFile, animation, skin, scale, x, y)
 	local loader = function (path) return love.graphics.newImage("data/" .. path) end
@@ -53,13 +55,19 @@ function loadSkeleton (jsonFile, atlasFile, animation, skin, scale, x, y)
 	local stateData = spine.AnimationStateData.new(skeletonData)
 	local state = spine.AnimationState.new(stateData)
 	state:setAnimationByName(0, animation, true)
-	if (jsonFile == "spineboy") then
+	if (jsonFile == "spineboy-ess") then
 		stateData:setMix("walk", "jump", 0.5)
 		stateData:setMix("jump", "run", 0.5)
 		state:addAnimationByName(0, "jump", false, 3)
 		state:addAnimationByName(0, "run", true, 0)
 	end
 	
+	if (jsonFile == "raptor-pro") then
+		swirl.centerY = -200
+		skeleton.vertexEffect = swirl
+		-- skeleton.vertexEffect = spine.JitterEffect.new(10, 10)
+	end
+	
 	-- set some event callbacks
 	state.onStart = function (entry)
 		print(entry.trackIndex.." start: "..entry.animation.name)
@@ -88,6 +96,7 @@ end
 
 function love.load(arg)
 	if arg[#arg] == "-debug" then require("mobdebug").start() end
+	skeletonRenderer = spine.SkeletonRenderer.new(true)
 	table.insert(skeletons, loadSkeleton("coin-pro", "coin", "rotate", nil, 0.5, 400, 500))
 	table.insert(skeletons, loadSkeleton("spineboy-ess", "spineboy", "walk", nil, 0.5, 400, 500))
 	table.insert(skeletons, loadSkeleton("raptor-pro", "raptor", "walk", nil, 0.3, 400, 500))
@@ -95,7 +104,6 @@ function love.load(arg)
 	table.insert(skeletons, loadSkeleton("tank-pro", "tank", "drive", nil, 0.2, 600, 500))
 	table.insert(skeletons, loadSkeleton("vine-pro", "vine", "grow", nil, 0.3, 400, 500))
 	table.insert(skeletons, loadSkeleton("stretchyman-pro", "stretchyman", "sneak", nil, 0.3, 200, 500))
-	skeletonRenderer = spine.SkeletonRenderer.new(true)
 end
 
 function love.update (delta)
@@ -105,12 +113,25 @@ function love.update (delta)
 	state:update(delta)
 	state:apply(skeleton)
 	skeleton:updateWorldTransform()
+	
+	if (skeleton.vertexEffect) then
+		skeletonRenderer.vertexEffect = skeleton.vertexEffect
+		if (skeleton.vertexEffect == swirl) then
+			swirlTime = swirlTime + delta
+			local percent = swirlTime % 2
+			if (percent > 1) then percent = 1 - (percent - 1) end
+			swirl.angle = spine.Interpolation.apply(spine.Interpolation.pow2, -60, 60, percent)
+		end
+	else
+		skeletonRenderer.vertexEffect = nil
+	end
 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
 

+ 57 - 12
spine-love/spine-love/spine.lua

@@ -67,6 +67,9 @@ spine.AtlasAttachmentLoader = require "spine-lua.AtlasAttachmentLoader"
 spine.Color = require "spine-lua.Color"
 spine.Triangulator = require "spine-lua.Triangulator"
 spine.SkeletonClipping = require "spine-lua.SkeletonClipping"
+spine.JitterEffect = require "spine-lua.vertexeffects.JitterEffect"
+spine.SwirlEffect = require "spine-lua.vertexeffects.SwirlEffect"
+spine.Interpolation = require "spine-lua.Interpolation"
 
 spine.utils.readFile = function (fileName, base)
 	local path = fileName
@@ -139,7 +142,15 @@ function PolygonBatcher.new(vertexCount, useTwoColorTint)
 		vertex = { 0, 0, 0, 0, 0, 0, 0, 0 },
 		indices = nil,
 		useTwoColorTint = useTwoColorTint,
-		twoColorTintShader = twoColorTintShader
+		twoColorTintShader = twoColorTintShader,
+		tempVertex = {
+			x = 0,
+			y = 0,
+			u = 0,
+			v = 0,
+			light = spine.Color.newWith(1, 1, 1, 1),
+			dark = spine.Color.newWith(0, 0, 0, 0)
+		}
 	}
 
 	local indices = {}
@@ -163,7 +174,7 @@ function PolygonBatcher:begin ()
 	self.drawCalls = 0
 end
 
-function PolygonBatcher:draw (texture, vertices, uvs, numVertices, indices, color, darkColor)
+function PolygonBatcher:draw (texture, vertices, uvs, numVertices, indices, color, darkColor, vertexEffect)
 	local numIndices = #indices
 	local mesh = self.mesh
 
@@ -207,14 +218,44 @@ function PolygonBatcher:draw (texture, vertices, uvs, numVertices, indices, colo
 	end
 	
 	local v = 1
-	while vertexStart < vertexEnd do
-		vertex[1] = vertices[v]
-		vertex[2] = vertices[v + 1]
-		vertex[3] = uvs[v]
-		vertex[4] = uvs[v + 1]
-		mesh:setVertex(vertexStart, vertex)
-		vertexStart = vertexStart + 1
-		v = v + 2
+	if (vertexEffect) then
+		local tempVertex = self.tempVertex
+		while vertexStart < vertexEnd do
+			tempVertex.x = vertices[v]
+			tempVertex.y = vertices[v + 1]
+			tempVertex.u = uvs[v]
+			tempVertex.v = uvs[v + 1]
+			tempVertex.light:setFrom(color)
+			tempVertex.dark:setFrom(darkColor)
+			vertexEffect:transform(tempVertex)
+			vertex[1] = tempVertex.x
+			vertex[2] = tempVertex.y
+			vertex[3] = tempVertex.u
+			vertex[4] = tempVertex.v
+			vertex[5] = tempVertex.light.r * 255
+			vertex[6] = tempVertex.light.g * 255
+			vertex[7] = tempVertex.light.b * 255
+			vertex[8] = tempVertex.light.a * 255
+			if (self.useTwoColorTint) then
+				vertex[9] = tempVertex.dark.r * 255
+				vertex[10] = tempVertex.dark.g * 255
+				vertex[11] = tempVertex.dark.b * 255
+				vertex[12] = tempVertex.dark.a * 255
+			end
+			mesh:setVertex(vertexStart, vertex)
+			vertexStart = vertexStart + 1
+			v = v + 2
+		end
+	else
+		while vertexStart < vertexEnd do
+			vertex[1] = vertices[v]
+			vertex[2] = vertices[v + 1]
+			vertex[3] = uvs[v]
+			vertex[4] = uvs[v + 1]
+			mesh:setVertex(vertexStart, vertex)
+			vertexStart = vertexStart + 1
+			v = v + 2
+		end
 	end
 	self.verticesLength = self.verticesLength + numVertices
 end
@@ -255,7 +296,8 @@ function SkeletonRenderer.new (useTwoColorTint)
 		batcher = PolygonBatcher.new(3 * 500, useTwoColorTint),
 		premultipliedAlpha = false,
 		useTwoColorTint = useTwoColorTint,
-		clipper = spine.SkeletonClipping.new()
+		clipper = spine.SkeletonClipping.new(),
+		vertexEffect = nil
 	}
 
 	setmetatable(self, SkeletonRenderer)
@@ -270,6 +312,8 @@ function SkeletonRenderer:draw (skeleton)
 	local batcher = self.batcher
 	local premultipliedAlpha = self.premultipliedAlpha
 
+	if (self.vertexEffect) then self.vertexEffect:beginEffect(skeleton) end
+
 	local lastLoveBlendMode = love.graphics.getBlendMode()
 	love.graphics.setBlendMode("alpha")
 	local lastBlendMode = spine.BlendMode.normal
@@ -342,7 +386,7 @@ function SkeletonRenderer:draw (skeleton)
 					indices = self.clipper.clippedTriangles
 				end
 				
-				batcher:draw(texture, vertices, uvs, numVertices, indices, color, dark)
+				batcher:draw(texture, vertices, uvs, numVertices, indices, color, dark, self.vertexEffect)
 			end
 			
 			self.clipper:clipEnd(slot)
@@ -352,6 +396,7 @@ function SkeletonRenderer:draw (skeleton)
 	batcher:stop()
 	love.graphics.setBlendMode(lastLoveBlendMode)
 	self.clipper:clipEnd2()
+	if (self.vertexEffect) then self.vertexEffect:endEffect(skeleton) end
 end
 
 spine.PolygonBatcher = PolygonBatcher

+ 32 - 10
spine-lua/Animation.lua

@@ -800,21 +800,43 @@ function Animation.DeformTimeline.new (frameCount)
 
 		local frameVertices = self.frameVertices
 		local vertexCount = #(frameVertices[0])
-
-		if (#verticesArray ~= vertexCount and not setupPose) then alpha = 1 end -- Don't mix from uninitialized slot vertices.
 		local vertices = utils.setArraySize(verticesArray, vertexCount)
 		
 		if time < frames[0] then
+			local vertexAttachment = slotAttachment;
 			if pose == MixPose.setup then
-				verticesArray = {}
-				slot.attachmentVertices = verticesArray
-			elseif pose == MixPose.current then
-				alpha = 1 - alpha
-				local i = 1
-				while i <= vertexCount do
-					vertices[i] = vertices[i] * alpha
-					i = i + 1
+				if (vertexAttachment.bones == nil) then
+					local i = 1
+					local setupVertices = vertexAttachment.vertices
+					while i <= vertexCount do
+						vertices[i] = setupVertices[i]
+						i = i + 1
+					end
+				else
+					local i = 1
+					while i <= vertexCount do
+						vertices[i] = 0
+						i = i + 1
+					end
 				end
+			elseif pose == MixPose.current then
+				if (alpha ~= 1) then
+					if (vertexAttachment.bones == nil) then
+						local setupVertices = vertexAttachment.vertices
+						local i = 1
+						while i <= vertexCount do
+							vertices[i] = vertices[i] + (setupVertices[i] - vertices[i]) * alpha
+							i = i + 1
+						end
+					else
+						alpha = 1 - alpha
+						local i = 1
+						while i <= vertexCount do
+							vertices[i] = vertices[i] * alpha
+							i = i + 1
+						end
+					end
+				end				
 			end
 			return
 		end

+ 5 - 7
spine-lua/AnimationState.lua

@@ -804,17 +804,15 @@ function AnimationState:disposeNext (entry)
 end
 
 function AnimationState:_animationsChanged ()
-  self.animationsChanged = false
+	self.animationsChanged = false
 
-  self.propertyIDs = {}
-  local propertyIDs = self.propertyIDs
+	self.propertyIDs = {}
+	local propertyIDs = self.propertyIDs
 	local mixingTo = self.mixingTo
-	
-  local lastEntry = nil
+	  
 	for i, entry in pairs(self.tracks) do
 		if entry then
-			entry:setTimelineData(lastEntry, mixingTo, propertyIDs)
-			lastEntry = entry
+			entry:setTimelineData(nil, mixingTo, propertyIDs)			
 		end
 	end
 end

+ 6 - 6
spine-lua/Bone.lua

@@ -190,16 +190,16 @@ function Bone:updateWorldTransformWith (x, y, rotation, scaleX, scaleY, shearX,
 		local lb = math_cos(math_rad(90 + shearY)) * scaleY;
 		local lc = math_sin(math_rad(shearX)) * scaleX;
 		local ld = math_sin(90 + shearY) * scaleY;
-		self.a = za * la + zb * lc
-		self.b = za * lb + zb * ld
-		self.c = zc * la + zd * lc
-		self.d = zc * lb + zd * ld
 		local flip = self.skeleton.flipX ~= self.skeleton.flipY
 		if transformMode ~= TransformMode.noScaleOrReflection then flip = pa * pd - pb * pc < 0 end
 		if flip then
-			self.b = -self.b
-			self.d = -self.d
+			zb = -zb
+			zd = -zd
 		end
+		self.a = za * la + zb * lc
+		self.b = za * lb + zb * ld
+		self.c = zc * la + zd * lc
+		self.d = zc * lb + zd * ld		
 		return
 	end
 	

+ 48 - 0
spine-lua/Interpolation.lua

@@ -0,0 +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.
+-------------------------------------------------------------------------------
+
+local interpolation = {}
+
+local math_pow = math.pow
+
+function interpolation.apply (func, start, _end, a)
+	return start + (_end - start) * func(a)
+end
+
+function interpolation.pow2(a)
+	if (a <= 0.5) then return math_pow(a * 2, 2) / 2 end
+	return math_pow((a - 1) * 2, 2) / -2 + 1
+end
+
+function interpolation.pow2out(a)
+	return math_pow(a - 1, 2) * -1 + 1
+end
+
+return interpolation

+ 1 - 0
spine-lua/PathConstraint.lua

@@ -118,6 +118,7 @@ function PathConstraint:update ()
 		while i < n do
 			local bone = bones[i + 1];
 			local setupLength = bone.data.length
+			if setupLength == 0 then setupLength = 0.0000001 end
 			local x = setupLength * bone.a
 			local y = setupLength * bone.c
 			local length = math_sqrt(x * x + y * y)

+ 2 - 2
spine-lua/README.md

@@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
 
 ## Spine version
 
-spine-lua works with data exported from Spine 3.5.xx.
+spine-lua works with data exported from Spine 3.6.xx.
 
 spine-lua supports all Spine features.
 
@@ -18,7 +18,7 @@ spine-lua does not yet support loading the binary format.
 
 ## Setup
 
-1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip).
+1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip).
 1. Copy the contents of the `spine-lua` directory into your project.
 
 ## Runtimes Extending spine-lua

+ 13 - 10
spine-lua/Skin.lua

@@ -63,21 +63,24 @@ function Skin:getAttachment (slotIndex, name)
 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
+		if slotAttachment then
+			local dictionary = oldSkin.attachments[i]
+			if (dictionary) then
+				for key, value in pairs(dictionary) do
+					local skinAttachment = value
+					if slotAttachment == skinAttachment then
+						local attachment = self:getAttachment(i, key)
+						if attachment then
+							print("Set attachment " .. attachment.name .. " on slot " .. slot.data.name)
+							slot:setAttachment(attachment) 
+						end
+						break
+					end
 				end
 			end
 		end
-		slotIndex = slotIndex + 1
 	end
 end
 

+ 1 - 0
spine-lua/attachments/MeshAttachment.lua

@@ -103,6 +103,7 @@ function MeshAttachment:setParentMesh (parentMesh)
 	if parentMesh then
 		self.bones = parentMesh.bones
 		self.vertices = parentMesh.vertices
+		self.worldVerticesLength = parentMesh.worldVerticesLength
 		self.regionUVs = parentMesh.regionUVs
 		self.triangles = parentMesh.triangles
 		self.hullLength = parentMesh.hullLength

+ 14 - 0
spine-lua/utils.lua

@@ -30,6 +30,9 @@
 
 local utils = {}
 
+local math_sqrt = math.sqrt
+local math_random = math.random
+
 utils.degRad = math.pi / 180
 
 function tablePrint (tt, indent, done)
@@ -153,4 +156,15 @@ function utils.mod(a, b)
   end
 end
 
+function utils.randomTriangular(min, max)
+	return utils.randomTriangularWith(min, max, (min + max) * 0.5)
+end
+
+function utils.randomTriangularWith(min, max, mode)
+	local u = math.random()
+	local d = max - min
+	if (u <= (mode - min) / d) then return min + math_sqrt(u * d * (mode - min)) end
+	return max - math_sqrt((1 - u) * d * (max - mode))
+end
+
 return utils

+ 64 - 0
spine-lua/vertexeffects/JitterEffect.lua

@@ -0,0 +1,64 @@
+-------------------------------------------------------------------------------
+-- Spine Runtimes Software License v2.5
+--
+-- Copyright (c) 2013-2016, Esoteric Software
+-- All rights reserved.
+--
+-- You are granted a perpetual, non-exclusive, non-sublicensable, and
+-- non-transferable license to use, install, execute, and perform the Spine
+-- Runtimes software and derivative works solely for personal or internal
+-- use. Without the written permission of Esoteric Software (see Section 2 of
+-- the Spine Software License Agreement), you may not (a) modify, translate,
+-- adapt, or develop new applications using the Spine Runtimes or otherwise
+-- create derivative works or improvements of the Spine Runtimes or (b) remove,
+-- delete, alter, or obscure any trademarks or any copyright, trademark, patent,
+-- or other intellectual property or proprietary rights notices on or in the
+-- Software, including any copy thereof. Redistributions in binary or source
+-- form must include this license and terms.
+--
+-- THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+-- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+-- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+-- EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+-- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
+-- USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+-- IN CONTRACT, STRICT LIABILITY, OR TORT (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 = 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 table_remove = table.remove
+
+local JitterEffect = {}
+JitterEffect.__index = JitterEffect
+
+function JitterEffect.new (jitterX, jitterY)
+	local self = {
+		jitterX = jitterX,
+		jitterY = jitterY
+	}
+	setmetatable(self, JitterEffect)
+
+	return self
+end
+
+function JitterEffect:beginEffect (skeleton)
+end
+
+function JitterEffect:transform (vertex)
+	vertex.x = vertex.x + utils.randomTriangular(-self.jitterX, self.jitterY)
+	vertex.y = vertex.y + utils.randomTriangular(-self.jitterX, self.jitterY)
+end
+
+function JitterEffect:endEffect ()
+end
+
+return JitterEffect

+ 85 - 0
spine-lua/vertexeffects/SwirlEffect.lua

@@ -0,0 +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.
+-------------------------------------------------------------------------------
+
+local utils = require "spine-lua.utils"
+local interpolation = require "spine-lua.Interpolation"
+
+local setmetatable = setmetatable
+local math_min = math.min
+local math_max = math.max
+local ipairs = ipairs
+local table_insert = table.insert
+local table_remove = table.remove
+local utils_deg_rad = utils.degRad
+local math_sqrt = math.sqrt
+local math_sin = math.sin
+local math_cos = math.cos
+
+local SwirlEffect = {}
+SwirlEffect.__index = SwirlEffect
+
+function SwirlEffect.new (radius)
+	local self = {
+		worldX = 0,
+		worldY = 0,
+		centerX = 0,
+		centerY = 0,
+		radius = radius,
+		angle = 0,
+		interpolation = interpolation.pow2
+	}
+	setmetatable(self, SwirlEffect)
+
+	return self
+end
+
+function SwirlEffect:beginEffect (skeleton)
+	self.worldX = skeleton.x + self.centerX
+	self.worldY = skeleton.y + self.centerY
+	self.angleRad = self.angle * utils_deg_rad
+end
+
+function SwirlEffect:transform (vertex)
+	local x = vertex.x - self.worldX
+	local y = vertex.y - self.worldY
+	local dist = math_sqrt(x * x + y * y)
+	if (dist < self.radius) then		
+		local theta = interpolation.apply(self.interpolation, 0, self.angleRad, (self.radius - dist) / self.radius)
+		local cos = math_cos(theta)
+		local sin = math_sin(theta)
+		vertex.x = cos * x - sin * y + self.worldX
+		vertex.y = sin * x + cos * y + self.worldY
+	end
+end
+
+function SwirlEffect:endEffect ()
+end
+
+return SwirlEffect

+ 3 - 3
spine-monogame/README.md

@@ -10,18 +10,18 @@ The Spine Runtimes are developed with the intent to be used with data exported f
 
 ## Spine version
 
-spine-monogame works with data exported from Spine 3.5.xx.
+spine-monogame works with data exported from Spine 3.6.xx.
 
 spine-monogame supports all Spine features.
 
 ## Setup
 
-1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip).
+1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip).
 1. Copy the contents of the `spine-csharp/src` and `spine-xna/src` directories into your project.
 
 ## Example
 
-1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip).
+1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip).
 1. Open the `spine-monogame-example.sln` Solution in either Visual Studio 2015 or Xamarin Studio
 1. Right click the `spine-monogame-example` project in the solution explorer and select `Properties`
 1. Select `Debug` and set the working directory to point to `spine-runtimes/spine-xna/example`

+ 32 - 48
spine-monogame/example/ExampleGame.cs

@@ -29,15 +29,9 @@
  *****************************************************************************/
 
 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 {
@@ -50,7 +44,7 @@ namespace Spine {
 
 		private string assetsFolder = "data/";
 
-		public Example () {
+		public Example() {
 			IsMouseVisible = true;
 
 			graphics = new GraphicsDeviceManager(this);
@@ -59,56 +53,51 @@ namespace Spine {
 			graphics.PreferredBackBufferHeight = 600;
 		}
 
-		protected override void Initialize () {
-			// TODO: Add your initialization logic here
-
-			base.Initialize();
-		}
-
 		protected override void LoadContent() {
-			// Two color tint effect, comment line 76 to disable
+			// Two color tint effect, comment line 80 to disable
 			var spineEffect = Content.Load<Effect>("Content\\SpineEffect");
 			spineEffect.Parameters["World"].SetValue(Matrix.Identity);
 			spineEffect.Parameters["View"].SetValue(Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 1.0f), Vector3.Zero, Vector3.Up));
 
 			skeletonRenderer = new SkeletonRenderer(GraphicsDevice);
-			skeletonRenderer.PremultipliedAlpha = true;
+			skeletonRenderer.PremultipliedAlpha = false;
 			skeletonRenderer.Effect = spineEffect;
 
-			// String name = "spineboy";
-			// String name = "goblins-mesh";
-			// String name = "raptor";
-			// String name = "tank";
-			// String name = "coin";
-			String name = "TwoColorTest";
-			bool binaryData = true;
+			// String name = "spineboy-ess";
+			// String name = "goblins-pro";
+			// String name = "raptor-pro";
+			// String name = "tank-pro";
+			String name = "coin-pro";
+			String atlasName = name.Replace("-pro", "").Replace("-ess", "");
+			bool binaryData = false;
 
-			Atlas atlas = new Atlas(assetsFolder + name + ".atlas", new XnaTextureLoader(GraphicsDevice));
+			Atlas atlas = new Atlas(assetsFolder + atlasName + ".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;
-			if (name == "TwoColorTest") scale = 0.5f;
+			if (name == "spineboy-ess") scale = 0.6f;
+			if (name == "raptor-pro") scale = 0.5f;
+			if (name == "tank-pro") scale = 0.3f;
+			if (name == "coin-pro") scale = 1;
 
 			SkeletonData skeletonData;
 			if (binaryData) {
 				SkeletonBinary binary = new SkeletonBinary(atlas);
 				binary.Scale = scale;
 				skeletonData = binary.ReadSkeletonData(assetsFolder + name + ".skel");
-			} else {
+			}
+			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");
+			if (name == "goblins-pro") skeleton.SetSkin("goblin");
 
 			// Define mixing between animations.
 			AnimationStateData stateData = new AnimationStateData(skeleton.Data);
 			state = new AnimationState(stateData);
 
-			if (name == "spineboy") {
+			if (name == "spineboy-ess") {
 				stateData.SetMix("run", "jump", 0.2f);
 				stateData.SetMix("jump", "run", 0.4f);
 
@@ -123,41 +112,36 @@ namespace Spine {
 				entry.End += End; // Event handling for queued animations.
 				state.AddAnimation(0, "run", true, 0);
 			}
-			else if (name == "raptor") {
+			else if (name == "raptor-pro") {
 				state.SetAnimation(0, "walk", true);
 				state.AddAnimation(1, "gungrab", false, 2);
 			}
-			else if (name == "coin") {
+			else if (name == "coin-pro") {
 				state.SetAnimation(0, "rotate", true);
 			}
-			else if (name == "tank") {
+			else if (name == "tank-pro") {
 				state.SetAnimation(0, "drive", true);
 			}
-			else if (name == "TwoColorTest") {
-				state.SetAnimation(0, "animation", true);
-			} else {
+			else {
 				state.SetAnimation(0, "walk", true);
 			}
 
-			skeleton.X = 400 + (name == "tank" ? 300: 0);
-			skeleton.Y = 580 + (name == "TwoColorTest" ? -300 : 0);
+			skeleton.X = 400 + (name == "tank-pro" ? 300 : 0);
+			skeleton.Y = GraphicsDevice.Viewport.Height;
 			skeleton.UpdateWorldTransform();
 
 			headSlot = skeleton.FindSlot("head");
 		}
 
-		protected override void UnloadContent () {			
-		}
-
-		protected override void Update (GameTime gameTime) {			
+		protected override void Update(GameTime gameTime) {
 			base.Update(gameTime);
 		}
 
-		protected override void Draw (GameTime gameTime) {
+		protected override void Draw(GameTime gameTime) {
 			GraphicsDevice.Clear(Color.Black);
 
 			state.Update(gameTime.ElapsedGameTime.Milliseconds / 1000f);
-			state.Apply(skeleton);			
+			state.Apply(skeleton);
 			skeleton.UpdateWorldTransform();
 			if (skeletonRenderer.Effect is BasicEffect) {
 				((BasicEffect)skeletonRenderer.Effect).Projection = Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 1, 0);
@@ -186,19 +170,19 @@ namespace Spine {
 			base.Draw(gameTime);
 		}
 
-		public void Start (TrackEntry entry) {
+		public void Start(TrackEntry entry) {
 			Console.WriteLine(entry + ": start");
 		}
 
-		public void End (TrackEntry entry) {
+		public void End(TrackEntry entry) {
 			Console.WriteLine(entry + ": end");
 		}
 
-		public void Complete (TrackEntry entry) {
+		public void Complete(TrackEntry entry) {
 			Console.WriteLine(entry + ": complete ");
 		}
 
-		public void Event (TrackEntry entry, Event e) {
+		public void Event(TrackEntry entry, Event e) {
 			Console.WriteLine(entry + ": event " + e);
 		}
 	}

+ 1 - 0
spine-sfml/CMakeLists.txt

@@ -1,3 +1,4 @@
+cmake_minimum_required(VERSION 2.8.9)
 #
 # First download and extract SFML 2.3.2 for the respective OS we are on
 #

+ 5 - 5
spine-sfml/README.md

@@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
 
 ## Spine version
 
-spine-sfml works with data exported from Spine 3.5.xx.
+spine-sfml works with data exported from Spine 3.6.xx.
 
 spine-sfml supports all Spine features.
 
@@ -18,7 +18,7 @@ spine-sfml does not yet support loading the binary format.
 
 ## Usage
 1. Create a new SFML project. See the [SFML documentation](http://www.sfml-dev.org/tutorials/2.1/) or have a look at the example in this repository.
-2. Download the Spine Runtimes source using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip)
+2. Download the Spine Runtimes source using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip)
 3. Add the sources from `spine-c/spine-c/src/spine` and `spine-sfml/src/spine` to your project
 4. Add the folder `spine-c/spine-c/include` to your header search path. Note that includes are specified as `#inclue <spine/file.h>`, so the `spine` directory cannot be omitted when copying the source files.
 
@@ -30,7 +30,7 @@ The Spine SFML example works on Windows, Linux and Mac OS X.
 ### Windows
 1. Install [Visual Studio 2015 Community](https://www.visualstudio.com/en-us/downloads/download-visual-studio-vs.aspx). Make sure you install support for C++ as well as th Windows SDK for XP/7/8.
 2. Install CMake via the [Windows installer package](https://cmake.org/download/).
-3. Download the Spine Runtimes repository using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip)
+3. Download the Spine Runtimes repository using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip)
 4. Run CMake GUI from the start menu
 5. Click `Browse Source` and select the directory `spine-runtimes`
 6. Click `Browse Build` and select the `spine-runtimes/spine-sfml/build` directory. You can create the `build` folder directly in the file dialog via `New Folder`.
@@ -46,7 +46,7 @@ The entire example code is contained in [main.cpp](https://github.com/EsotericSo
 ### Linux
 1. Install the SFML dependencies, e.g. on Ubuntu/Debian via `sudo apt-get install -y libpthread-stubs0-dev libgl1-mesa-dev libx11-dev libxrandr-dev libfreetype6-dev libglew1.5-dev libjpeg8-dev libsndfile1-dev libopenal-dev libudev-dev libxcb-image0-dev libjpeg-dev libflac-dev`
 2. Install CMake, e.g. on Ubuntu/Debian via `sudo apt-get install -y cmake`
-3. Download the Spine Runtimes repository using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip)
+3. Download the Spine Runtimes repository using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip)
 4. Open a terminal, and `cd` into the `spine-runtimes/spine-sfml` folder
 5. Type `mkdir build && cd build && cmake ../..` to generate Make files
 6. Type `make` to compile the example
@@ -56,7 +56,7 @@ The entire example code is contained in [main.cpp](https://github.com/EsotericSo
 1. Install [Xcode](https://developer.apple.com/xcode/)
 2. Install [Homebrew](http://brew.sh/)
 3. Open a terminal and install CMake via `brew install cmake`
-3. Download the Spine Runtimes repository using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip)
+3. Download the Spine Runtimes repository using git (`git clone https://github.com/esotericsoftware/spine-runtimes`) or download it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip)
 4. Open a terminal, and `cd` into the `spine-runtimes/spine-sfml` folder
 5. Type `mkdir build && cd build && cmake -G Xcode ../..` to generate an Xcode project called `spine.xcodeproj`
 6. Open the Xcode project in `spine-runtimes/spine-sfml/build/`

+ 12 - 0
spine-sfml/example/main.cpp

@@ -204,6 +204,10 @@ void raptor (SkeletonData* skeletonData, Atlas* atlas) {
 	SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData);
 	drawable->timeScale = 1;
 
+	spSwirlVertexEffect* effect = spSwirlVertexEffect_create(400);
+	effect->centerY = -200;
+	drawable->vertexEffect = &effect->super;
+
 	Skeleton* skeleton = drawable->skeleton;
 	skeleton->x = 320;
 	skeleton->y = 590;
@@ -216,6 +220,7 @@ void raptor (SkeletonData* skeletonData, Atlas* atlas) {
 	window.setFramerateLimit(60);
 	sf::Event event;
 	sf::Clock deltaClock;
+	float swirlTime = 0;
 	while (window.isOpen()) {
 		while (window.pollEvent(event))
 			if (event.type == sf::Event::Closed) window.close();
@@ -223,12 +228,18 @@ void raptor (SkeletonData* skeletonData, Atlas* atlas) {
 		float delta = deltaClock.getElapsedTime().asSeconds();
 		deltaClock.restart();
 
+		swirlTime += delta;
+		float percent = fmod(swirlTime, 2);
+		if (percent > 1) percent = 1 - (percent - 1);
+		effect->angle = _spMath_interpolate(_spMath_pow2_apply, -60, 60, percent);
+
 		drawable->update(delta);
 
 		window.clear();
 		window.draw(*drawable);
 		window.display();
 	}
+	spSwirlVertexEffect_dispose(effect);
 }
 
 void tank (SkeletonData* skeletonData, Atlas* atlas) {
@@ -338,6 +349,7 @@ void coin (SkeletonData* skeletonData, Atlas* atlas) {
 	window.setFramerateLimit(60);
 	sf::Event event;
 	sf::Clock deltaClock;
+	float swirlTime = 0;
 	while (window.isOpen()) {
 		while (window.pollEvent(event))
 			if (event.type == sf::Event::Closed) window.close();

+ 61 - 8
spine-sfml/src/spine/spine-sfml.cpp

@@ -36,6 +36,8 @@
 
 using namespace sf;
 
+_SP_ARRAY_IMPLEMENT_TYPE(spColorArray, spColor)
+
 void _AtlasPage_createTexture (AtlasPage* self, const char* path){
 	Texture* texture = new Texture();
 	if (!texture->loadFromFile(path)) return;
@@ -54,7 +56,7 @@ void _AtlasPage_disposeTexture (AtlasPage* self){
 }
 
 char* _Util_readFile (const char* path, int* length){
-	return _readFile(path, length);
+	return _spReadFile(path, length);
 }
 
 /**/
@@ -64,10 +66,13 @@ namespace spine {
 SkeletonDrawable::SkeletonDrawable (SkeletonData* skeletonData, AnimationStateData* stateData) :
 		timeScale(1),
 		vertexArray(new VertexArray(Triangles, skeletonData->bonesCount * 4)),
+		vertexEffect(0),
 		worldVertices(0), clipper(0) {
 	Bone_setYDown(true);
 	worldVertices = MALLOC(float, SPINE_MESH_VERTEX_COUNT_MAX);
 	skeleton = Skeleton_create(skeletonData);
+	tempUvs = spFloatArray_create(16);
+	tempColors = spColorArray_create(16);
 
 	ownsAnimationStateData = stateData == 0;
 	if (ownsAnimationStateData) stateData = AnimationStateData_create(skeletonData);
@@ -84,6 +89,8 @@ SkeletonDrawable::~SkeletonDrawable () {
 	AnimationState_dispose(state);
 	Skeleton_dispose(skeleton);
 	spSkeletonClipping_dispose(clipper);
+	spFloatArray_dispose(tempUvs);
+	spColorArray_dispose(tempColors);
 }
 
 void SkeletonDrawable::update (float deltaTime) {
@@ -98,6 +105,8 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const {
 	states.texture = 0;
 	unsigned short quadIndices[6] = { 0, 1, 2, 2, 3, 0 };
 
+	if (vertexEffect != 0) vertexEffect->begin(vertexEffect, skeleton);
+
 	sf::Vertex vertex;
 	Texture* texture = 0;
 	for (int i = 0; i < skeleton->slotsCount; ++i) {
@@ -147,6 +156,12 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const {
 		vertex.color.b = b;
 		vertex.color.a = a;
 
+		spColor light;
+		light.r = r / 255.0f;
+		light.g = g / 255.0f;
+		light.b = b / 255.0f;
+		light.a = a / 255.0f;
+
 		sf::BlendMode blend;
 		switch (slot->data->blendMode) {
 			case BLEND_MODE_ADDITIVE:
@@ -179,19 +194,57 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const {
 		}
 
 		Vector2u size = texture->getSize();
-		for (int i = 0; i < indicesCount; ++i) {
-			int index = indices[i] << 1;
-			vertex.position.x = vertices[index];
-			vertex.position.y = vertices[index + 1];
-			vertex.texCoords.x = uvs[index] * size.x;
-			vertex.texCoords.y = uvs[index + 1] * size.y;
-			vertexArray->append(vertex);
+
+		if (vertexEffect != 0) {
+			spFloatArray_clear(tempUvs);
+			spColorArray_clear(tempColors);
+			for (int i = 0; i < verticesCount; i++) {
+				spColor vertexColor = light;
+				spColor dark;
+				dark.r = dark.g = dark.b = dark.a = 0;
+				int index = i << 1;
+				float x = vertices[index];
+				float y = vertices[index + 1];
+				float u = uvs[index];
+				float v = uvs[index + 1];
+				vertexEffect->transform(vertexEffect, &x, &y, &u, &v, &vertexColor, &dark);
+				vertices[index] = x;
+				vertices[index + 1] = y;
+				spFloatArray_add(tempUvs, u);
+				spFloatArray_add(tempUvs, v);
+				spColorArray_add(tempColors, vertexColor);
+			}
+
+			for (int i = 0; i < indicesCount; ++i) {
+				int index = indices[i] << 1;
+				vertex.position.x = vertices[index];
+				vertex.position.y = vertices[index + 1];
+				vertex.texCoords.x = uvs[index] * size.x;
+				vertex.texCoords.y = uvs[index + 1] * size.y;
+				spColor vertexColor = tempColors->items[index >> 1];
+				vertex.color.r = static_cast<Uint8>(vertexColor.r * 255);
+				vertex.color.g = static_cast<Uint8>(vertexColor.g * 255);
+				vertex.color.b = static_cast<Uint8>(vertexColor.b * 255);
+				vertex.color.a = static_cast<Uint8>(vertexColor.a * 255);
+				vertexArray->append(vertex);
+			}
+		} else {
+			for (int i = 0; i < indicesCount; ++i) {
+				int index = indices[i] << 1;
+				vertex.position.x = vertices[index];
+				vertex.position.y = vertices[index + 1];
+				vertex.texCoords.x = uvs[index] * size.x;
+				vertex.texCoords.y = uvs[index + 1] * size.y;
+				vertexArray->append(vertex);
+			}
 		}
 
 		spSkeletonClipping_clipEnd(clipper, slot);
 	}
 	target.draw(*vertexArray, states);
 	spSkeletonClipping_clipEnd2(clipper);
+
+	if (vertexEffect != 0) vertexEffect->end(vertexEffect);
 }
 
 } /* namespace spine */

+ 5 - 0
spine-sfml/src/spine/spine-sfml.h

@@ -40,6 +40,8 @@
 #include <SFML/Graphics/RenderTarget.hpp>
 #include <SFML/Graphics/RenderStates.hpp>
 
+_SP_ARRAY_DECLARE_TYPE(spColorArray, spColor)
+
 namespace spine {
 
 class SkeletonDrawable: public sf::Drawable {
@@ -48,6 +50,7 @@ public:
 	AnimationState* state;
 	float timeScale;
 	sf::VertexArray* vertexArray;
+	spVertexEffect* vertexEffect;
 
 	SkeletonDrawable (SkeletonData* skeleton, AnimationStateData* stateData = 0);
 	~SkeletonDrawable ();
@@ -58,6 +61,8 @@ public:
 private:
 	bool ownsAnimationStateData;
 	float* worldVertices;
+	spFloatArray* tempUvs;
+	spColorArray* tempColors;
 	spSkeletonClipping* clipper;
 };
 

+ 2 - 2
spine-starling/README.md

@@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
 
 ## Spine version
 
-spine-starling works with data exported from Spine 3.5.xx.
+spine-starling works with data exported from Spine 3.6.xx.
 
 spine-starling supports all Spine features.
 
@@ -18,7 +18,7 @@ spine-starling does not yet support loading the binary format.
 
 # Usage
 1. Create a new Starling 2.0 project as per the [documentation].
-2. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip).
+2. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip).
 3. Copy the sources in `spine-as3/spine-as3/src/` and `spine-starling/spine-starling/src/` into your project's source directory
 
 ## Example

BIN
spine-starling/spine-starling-example/lib/spine-as3.swc


BIN
spine-starling/spine-starling-example/lib/spine-starling.swc


+ 1 - 1
spine-starling/spine-starling-example/src/spine/examples/GoblinsExample.as

@@ -66,7 +66,7 @@ package spine.examples {
 		private var skinChangeCount: Number = 0;
 
 		public function GoblinsExample() {
-			var useStarlingAtlas : Boolean = false;
+			var useStarlingAtlas : Boolean = true;
 
 			var attachmentLoader : AttachmentLoader;
 			if (useStarlingAtlas) {

+ 22 - 1
spine-starling/spine-starling-example/src/spine/examples/RaptorExample.as

@@ -29,6 +29,10 @@
  *****************************************************************************/
 
 package spine.examples {
+	import spine.interpolation.Pow;
+	import starling.animation.IAnimatable;
+	import spine.vertexeffects.SwirlEffect;
+	import spine.vertexeffects.JitterEffect;
 	import starling.display.DisplayObjectContainer;
 	import spine.atlas.Atlas;
 	import spine.*;
@@ -43,7 +47,7 @@ package spine.examples {
 	import starling.events.TouchEvent;
 	import starling.events.TouchPhase;
 
-	public class RaptorExample extends Sprite {
+	public class RaptorExample extends Sprite implements IAnimatable {
 		[Embed(source = "/raptor-pro.json", mimeType = "application/octet-stream")]
 		static public const RaptorJson : Class;
 
@@ -55,6 +59,10 @@ package spine.examples {
 		private var skeleton : SkeletonAnimation;
 		private var gunGrabbed : Boolean;
 		private var gunGrabCount : Number = 0;
+		
+		private var swirl : SwirlEffect;
+		private var swirlTime : Number = 0;
+		private var pow2 : Interpolation = new Pow(2);
 
 		public function RaptorExample() {
 			var attachmentLoader : AttachmentLoader;
@@ -74,9 +82,15 @@ package spine.examples {
 			skeleton.state.apply(skeleton.skeleton);
 			skeleton.skeleton.updateWorldTransform();
 			this.setRequiresRedraw();
+			
+			// skeleton.vertexEffect = new JitterEffect(10, 10);
+			swirl = new SwirlEffect(400);
+			swirl.centerY = -200;	
+			skeleton.vertexEffect = swirl;
 
 			addChild(skeleton);
 			Starling.juggler.add(skeleton);
+			Starling.juggler.add(this);
 
 			addEventListener(TouchEvent.TOUCH, onClick);
 		}
@@ -98,5 +112,12 @@ package spine.examples {
 				}
 			}
 		}
+
+		public function advanceTime(time : Number) : void {
+			swirlTime += time;
+			var percent : Number = swirlTime % 2;
+			if (percent > 1) percent = 1 - (percent - 1);
+			swirl.angle = pow2.apply(-60, 60, percent);
+		}
 	}
 }

BIN
spine-starling/spine-starling/lib/spine-as3.swc


+ 41 - 7
spine-starling/spine-starling/src/spine/starling/SkeletonSprite.as

@@ -39,6 +39,7 @@ package spine.starling {
 	import spine.attachments.Attachment;
 	import spine.attachments.MeshAttachment;
 	import spine.attachments.RegionAttachment;
+	import spine.VertexEffect;
 
 	import starling.display.BlendMode;
 	import starling.display.DisplayObject;
@@ -63,6 +64,11 @@ package spine.starling {
 		private var _smoothing : String = "bilinear";
 		private static var clipper: SkeletonClipping = new SkeletonClipping();
 		private static var QUAD_INDICES : Vector.<uint> = new <uint>[0, 1, 2, 2, 3, 0];
+		
+		public var vertexEffect : VertexEffect;
+		private var tempLight : spine.Color = new spine.Color(0, 0, 0);
+		private var tempDark : spine.Color = new spine.Color(0, 0, 0);
+		private var tempVertex : spine.Vertex = new spine.Vertex();
 
 		public function SkeletonSprite(skeletonData : SkeletonData) {
 			Bone.yDown = true;
@@ -86,6 +92,8 @@ package spine.starling {
 			var verticesLength : int, verticesCount : int, indicesLength : int;
 			var indexData : IndexData, indices : Vector.<uint>, vertexData : VertexData;
 			var uvs : Vector.<Number>;
+			
+			if (vertexEffect != null) vertexEffect.begin(skeleton);
 
 			for (var i : int = 0, n : int = drawOrder.length; i < n; ++i) {
 				var worldVertices : Vector.<Number> = _tempVertices;
@@ -171,13 +179,37 @@ package spine.starling {
 				}
 
 				vertexData = mesh.getVertexData();
-				vertexData.numVertices = verticesCount;				
-				vertexData.colorize("color", rgb, a);
-				vertexData.colorize("color2", dark);
-				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;	
+				if (vertexEffect != null) {
+					tempLight.r = ((rgb >> 16) & 0xff) / 255.0;
+					tempLight.g = ((rgb >> 8) & 0xff) / 255.0;
+					tempLight.b = (rgb & 0xff) / 255.0;
+					tempLight.a = a;
+					tempDark.r = ((dark >> 16) & 0xff) / 255.0;
+					tempDark.g = ((dark >> 8) & 0xff) / 255.0;
+					tempDark.b = (dark & 0xff) / 255.0;
+					tempDark.a = 0;
+					for (ii = 0, iii = 0; ii < verticesCount; ii++, iii += 2) {
+						tempVertex.x = worldVertices[iii];
+						tempVertex.y = worldVertices[iii + 1];
+						tempVertex.u = uvs[iii];
+						tempVertex.v = uvs[iii + 1];
+						tempVertex.light.setFromColor(tempLight);
+						tempVertex.dark.setFromColor(tempDark);
+						vertexEffect.transform(tempVertex);
+						vertexData.colorize("color", Color.rgb(tempVertex.light.r * 255, tempVertex.light.g * 255, tempVertex.light.b * 255), tempVertex.light.a, ii, 1);
+						vertexData.colorize("color2", Color.rgb(tempVertex.dark.r * 255, tempVertex.dark.g * 255, tempVertex.dark.b * 255), a, ii, 1);						
+						mesh.setVertexPosition(ii, tempVertex.x, tempVertex.y);
+						mesh.setTexCoords(ii, tempVertex.u, tempVertex.v);
+					}
+				} else {
+					vertexData.colorize("color", rgb, a);
+					vertexData.colorize("color2", dark);
+					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]);
+					}				
+				}
 				painter.state.blendMode = blendModes[slot.data.blendMode.ordinal];				
 				painter.batchMesh(mesh);
 				
@@ -185,6 +217,8 @@ package spine.starling {
 			}
 			painter.state.blendMode = originalBlendMode;
 			clipper.clipEnd();
+			
+			if (vertexEffect != null) vertexEffect.end();
 		}
 
 		override public function hitTest(localPoint : Point) : DisplayObject {

+ 37 - 69
spine-starling/spine-starling/src/spine/starling/StarlingAtlasAttachmentLoader.as

@@ -27,21 +27,18 @@
  * 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.ClippingAttachment;
-	import spine.attachments.PointAttachment;
-	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.ClippingAttachment;
 	import spine.attachments.MeshAttachment;
+	import spine.attachments.PathAttachment;
+	import spine.attachments.PointAttachment;
 	import spine.attachments.RegionAttachment;
 
+	import starling.display.Image;
 	import starling.textures.SubTexture;
 	import starling.textures.Texture;
 	import starling.textures.TextureAtlas;
@@ -53,16 +50,19 @@ package spine.starling {
 
 		public function StarlingAtlasAttachmentLoader(atlas : TextureAtlas) {
 			this.atlas = atlas;
-
 			Bone.yDown = true;
 		}
 
+		protected function getTexture(path : String) : Texture {
+			return atlas.getTexture(path);
+		}
+
 		public function newRegionAttachment(skin : Skin, name : String, path : String) : RegionAttachment {
-			var texture : Texture = atlas.getTexture(path);			
+			var texture : SubTexture = getTexture(path) as SubTexture;
 			if (texture == null)
 				throw new Error("Region not found in Starling atlas: " + path + " (region attachment: " + name + ")");
 			var attachment : RegionAttachment = new RegionAttachment(name);
-			var rotated : Boolean = atlas.getRotation(path);			
+			var rotated : Boolean = texture.rotated;
 			attachment.rendererObject = new Image(Texture.fromTexture(texture)); // Discard frame.
 			var frame : Rectangle = texture.frame;
 			attachment.regionOffsetX = frame ? -frame.x : 0;
@@ -78,76 +78,44 @@ package spine.starling {
 				tmp = attachment.regionWidth;
 				attachment.regionWidth = attachment.regionHeight;
 				attachment.regionHeight = tmp;
+                attachment["regionU2"] = 0;
+                attachment["regionV2"] = 1;
+                attachment["regionU"] = 1;
+                attachment["regionV"] = 0;
+			}else{
+                attachment["regionU"] = 0;
+                attachment["regionV"] = 0;
+                attachment["regionU2"] = 1;
+                attachment["regionV2"] = 1;
 			}
-			var subTexture : SubTexture = texture as SubTexture;
-			if (subTexture) {
-				var root : Texture = subTexture.root;
-				var rectRegion : Rectangle = atlas.getRegion(path);				
-				if (!rotated) {
-					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;
-				} else {
-					attachment["regionU2"] = rectRegion.x / root.width;
-					attachment["regionV2"] = rectRegion.y / root.height;
-					attachment["regionU"] = (rectRegion.x + subTexture.width) / root.width;
-					attachment["regionV"] = (rectRegion.y + subTexture.height) / root.height;
-				}
-				attachment.setUVs(attachment["regionU"], attachment["regionV"], attachment["regionU2"], attachment["regionV2"], atlas.getRotation(path));
-			} else {
-				if (!rotated) {
-					attachment["regionU"] = 0;
-					attachment["regionV"] = 1;
-					attachment["regionU2"] = 1;
-					attachment["regionV2"] = 0;
-				} else {
-					attachment["regionU2"] = 0;
-					attachment["regionV2"] = 1;
-					attachment["regionU"] = 1;
-					attachment["regionV"] = 0;
-				}
-			}
+			attachment.setUVs(attachment["regionU"], attachment["regionV"], attachment["regionU2"], attachment["regionV2"], rotated);
 			return attachment;
 		}
 
 		public function newMeshAttachment(skin : Skin, name : String, path : String) : MeshAttachment {
-			var texture : Texture = atlas.getTexture(path);
+			var texture : SubTexture = getTexture(path) as SubTexture;
 			if (texture == null)
 				throw new Error("Region not found in Starling atlas: " + path + " (mesh attachment: " + name + ")");
-			var rotated : Boolean = atlas.getRotation(path);
+			var rotated : Boolean = texture.rotated;
 			var attachment : MeshAttachment = new MeshAttachment(name);
 			attachment.regionRotate = rotated;
 			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);
-				if (!rotated) {
-					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;
-				} else {
-					attachment.regionU2 = rectRegion.x / root.width;
-					attachment.regionV2 = rectRegion.y / root.height;
-					attachment.regionU = (rectRegion.x + subTexture.height) / root.width;
-					attachment.regionV = (rectRegion.y + subTexture.width) / root.height;
-				}
-				attachment.rendererObject = new Image(root);
+
+			var root : Texture = texture.root;
+			var rectRegion : Rectangle = atlas.getRegion(path);
+			if (!rotated) {
+				attachment.regionU = rectRegion.x / root.width;
+				attachment.regionV = rectRegion.y / root.height;
+				attachment.regionU2 = (rectRegion.x + texture.width) / root.width;
+				attachment.regionV2 = (rectRegion.y + texture.height) / root.height;
 			} else {
-				if (!rotated) {
-					attachment.regionU = 0;
-					attachment.regionV = 1;
-					attachment.regionU2 = 1;
-					attachment.regionV2 = 0;
-				} else {
-					attachment.regionU2 = 0;
-					attachment.regionV2 = 1;
-					attachment.regionU = 1;
-					attachment.regionV = 0;
-				}
+				attachment.regionU2 = rectRegion.x / root.width;
+				attachment.regionV2 = rectRegion.y / root.height;
+				attachment.regionU = (rectRegion.x + texture.height) / root.width;
+				attachment.regionV = (rectRegion.y + texture.width) / root.height;
 			}
+			attachment.rendererObject = new Image(root);
+
 			var frame : Rectangle = texture.frame;
 			attachment.regionOffsetX = frame ? -frame.x : 0;
 			attachment.regionOffsetY = frame ? -frame.y : 0;
@@ -177,7 +145,7 @@ package spine.starling {
 		public function newPointAttachment(skin : Skin, name : String) : PointAttachment {
 			return new PointAttachment(name);
 		}
-		
+
 		public function newClippingAttachment(skin : Skin, name : String) : ClippingAttachment {
 			return new ClippingAttachment(name);
 		}

+ 2 - 2
spine-ts/README.md

@@ -18,7 +18,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
 
 ## Spine version
 
-spine-ts works with data exported from Spine 3.6.xx
+spine-ts works with data exported from Spine 3.6.xx.
 
 spine-ts WebGL & Widget backends supports all Spine features. 
 
@@ -29,7 +29,7 @@ spine-ts THREE.JS does not support color tinting, blend modes and clipping. The
 spine-ts does not yet support loading the binary format.
 
 ## Usage
-1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip).
+1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/3.6.zip).
 2. To use only the core library without rendering support, include the `build/spine-core.js` file in your project.
 3. To use the WebGL backend, include the `spine-webgl.js` file in your project.
 3. To use the Canvas backend, include the `spine-canvas.js` file in your project.

+ 300 - 296
spine-ts/build/spine-all.d.ts

@@ -1,97 +1,3 @@
-declare module spine {
-	class AssetManager implements Disposable {
-		private pathPrefix;
-		private textureLoader;
-		private assets;
-		private errors;
-		private toLoad;
-		private loaded;
-		constructor(textureLoader: (image: HTMLImageElement) => any, pathPrefix?: string);
-		loadText(path: string, success?: (path: string, text: string) => void, error?: (path: string, error: string) => void): void;
-		loadTexture(path: string, success?: (path: string, image: HTMLImageElement) => void, error?: (path: string, error: string) => void): void;
-		loadTextureData(path: string, data: string, success?: (path: string, image: HTMLImageElement) => void, error?: (path: string, error: string) => void): void;
-		get(path: string): any;
-		remove(path: string): void;
-		removeAll(): void;
-		isLoadingComplete(): boolean;
-		getToLoad(): number;
-		getLoaded(): number;
-		dispose(): void;
-		hasErrors(): boolean;
-		getErrors(): Map<string>;
-	}
-}
-declare module spine.canvas {
-	class AssetManager extends spine.AssetManager {
-		constructor(pathPrefix?: string);
-	}
-}
-declare module spine {
-	abstract class Texture {
-		protected _image: HTMLImageElement;
-		constructor(image: HTMLImageElement);
-		getImage(): HTMLImageElement;
-		abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
-		abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
-		abstract dispose(): void;
-		static filterFromString(text: string): TextureFilter;
-		static wrapFromString(text: string): TextureWrap;
-	}
-	enum TextureFilter {
-		Nearest = 9728,
-		Linear = 9729,
-		MipMap = 9987,
-		MipMapNearestNearest = 9984,
-		MipMapLinearNearest = 9985,
-		MipMapNearestLinear = 9986,
-		MipMapLinearLinear = 9987,
-	}
-	enum TextureWrap {
-		MirroredRepeat = 33648,
-		ClampToEdge = 33071,
-		Repeat = 10497,
-	}
-	class TextureRegion {
-		renderObject: any;
-		u: number;
-		v: number;
-		u2: number;
-		v2: number;
-		width: number;
-		height: number;
-		rotate: boolean;
-		offsetX: number;
-		offsetY: number;
-		originalWidth: number;
-		originalHeight: number;
-	}
-}
-declare module spine.canvas {
-	class CanvasTexture extends Texture {
-		constructor(image: HTMLImageElement);
-		setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
-		setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
-		dispose(): void;
-	}
-}
-declare module spine.canvas {
-	class SkeletonRenderer {
-		static QUAD_TRIANGLES: number[];
-		static VERTEX_SIZE: number;
-		private ctx;
-		triangleRendering: boolean;
-		debugRendering: boolean;
-		private vertices;
-		private tempColor;
-		constructor(context: CanvasRenderingContext2D);
-		draw(skeleton: Skeleton): void;
-		private drawImages(skeleton);
-		private drawTriangles(skeleton);
-		private drawTriangle(img, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2);
-		private computeRegionVertices(slot, region, pma);
-		private computeMeshVertices(slot, mesh, pma);
-	}
-}
 declare module spine {
 	class Animation {
 		name: string;
@@ -459,35 +365,32 @@ declare module spine {
 	}
 }
 declare module spine {
-	class AtlasAttachmentLoader implements AttachmentLoader {
-		atlas: TextureAtlas;
-		constructor(atlas: TextureAtlas);
-		newRegionAttachment(skin: Skin, name: string, path: string): RegionAttachment;
-		newMeshAttachment(skin: Skin, name: string, path: string): MeshAttachment;
-		newBoundingBoxAttachment(skin: Skin, name: string): BoundingBoxAttachment;
-		newPathAttachment(skin: Skin, name: string): PathAttachment;
-		newPointAttachment(skin: Skin, name: string): PointAttachment;
-		newClippingAttachment(skin: Skin, name: string): ClippingAttachment;
-	}
-}
-declare module spine {
-	abstract class Attachment {
-		name: string;
-		constructor(name: string);
-	}
-	abstract class VertexAttachment extends Attachment {
-		private static nextID;
-		id: number;
-		bones: Array<number>;
-		vertices: ArrayLike<number>;
-		worldVerticesLength: number;
-		constructor(name: string);
-		computeWorldVertices(slot: Slot, start: number, count: number, worldVertices: ArrayLike<number>, offset: number, stride: number): void;
-		applyDeform(sourceAttachment: VertexAttachment): boolean;
+	class AssetManager implements Disposable {
+		private pathPrefix;
+		private textureLoader;
+		private assets;
+		private errors;
+		private toLoad;
+		private loaded;
+		constructor(textureLoader: (image: HTMLImageElement) => any, pathPrefix?: string);
+		loadText(path: string, success?: (path: string, text: string) => void, error?: (path: string, error: string) => void): void;
+		loadTexture(path: string, success?: (path: string, image: HTMLImageElement) => void, error?: (path: string, error: string) => void): void;
+		loadTextureData(path: string, data: string, success?: (path: string, image: HTMLImageElement) => void, error?: (path: string, error: string) => void): void;
+		get(path: string): any;
+		remove(path: string): void;
+		removeAll(): void;
+		isLoadingComplete(): boolean;
+		getToLoad(): number;
+		getLoaded(): number;
+		dispose(): void;
+		hasErrors(): boolean;
+		getErrors(): Map<string>;
 	}
 }
 declare module spine {
-	interface AttachmentLoader {
+	class AtlasAttachmentLoader implements AttachmentLoader {
+		atlas: TextureAtlas;
+		constructor(atlas: TextureAtlas);
 		newRegionAttachment(skin: Skin, name: string, path: string): RegionAttachment;
 		newMeshAttachment(skin: Skin, name: string, path: string): MeshAttachment;
 		newBoundingBoxAttachment(skin: Skin, name: string): BoundingBoxAttachment;
@@ -496,130 +399,6 @@ declare module spine {
 		newClippingAttachment(skin: Skin, name: string): ClippingAttachment;
 	}
 }
-declare module spine {
-	enum AttachmentType {
-		Region = 0,
-		BoundingBox = 1,
-		Mesh = 2,
-		LinkedMesh = 3,
-		Path = 4,
-		Point = 5,
-	}
-}
-declare module spine {
-	class BoundingBoxAttachment extends VertexAttachment {
-		color: Color;
-		constructor(name: string);
-	}
-}
-declare module spine {
-	class ClippingAttachment extends VertexAttachment {
-		endSlot: SlotData;
-		color: Color;
-		constructor(name: string);
-	}
-}
-declare module spine {
-	class MeshAttachment extends VertexAttachment {
-		region: TextureRegion;
-		path: string;
-		regionUVs: ArrayLike<number>;
-		uvs: ArrayLike<number>;
-		triangles: Array<number>;
-		color: Color;
-		hullLength: number;
-		private parentMesh;
-		inheritDeform: boolean;
-		tempColor: Color;
-		constructor(name: string);
-		updateUVs(): void;
-		applyDeform(sourceAttachment: VertexAttachment): boolean;
-		getParentMesh(): MeshAttachment;
-		setParentMesh(parentMesh: MeshAttachment): void;
-	}
-}
-declare module spine {
-	class PathAttachment extends VertexAttachment {
-		lengths: Array<number>;
-		closed: boolean;
-		constantSpeed: boolean;
-		color: Color;
-		constructor(name: string);
-	}
-}
-declare module spine {
-	class PointAttachment extends VertexAttachment {
-		x: number;
-		y: number;
-		rotation: number;
-		color: Color;
-		constructor(name: string);
-		computeWorldPosition(bone: Bone, point: Vector2): Vector2;
-		computeWorldRotation(bone: Bone): number;
-	}
-}
-declare module spine {
-	class RegionAttachment extends Attachment {
-		static OX1: number;
-		static OY1: number;
-		static OX2: number;
-		static OY2: number;
-		static OX3: number;
-		static OY3: number;
-		static OX4: number;
-		static OY4: number;
-		static X1: number;
-		static Y1: number;
-		static C1R: number;
-		static C1G: number;
-		static C1B: number;
-		static C1A: number;
-		static U1: number;
-		static V1: number;
-		static X2: number;
-		static Y2: number;
-		static C2R: number;
-		static C2G: number;
-		static C2B: number;
-		static C2A: number;
-		static U2: number;
-		static V2: number;
-		static X3: number;
-		static Y3: number;
-		static C3R: number;
-		static C3G: number;
-		static C3B: number;
-		static C3A: number;
-		static U3: number;
-		static V3: number;
-		static X4: number;
-		static Y4: number;
-		static C4R: number;
-		static C4G: number;
-		static C4B: number;
-		static C4A: number;
-		static U4: number;
-		static V4: number;
-		x: number;
-		y: number;
-		scaleX: number;
-		scaleY: number;
-		rotation: number;
-		width: number;
-		height: number;
-		color: Color;
-		path: string;
-		rendererObject: any;
-		region: TextureRegion;
-		offset: ArrayLike<number>;
-		uvs: ArrayLike<number>;
-		tempColor: Color;
-		constructor(name: string);
-		updateOffset(): void;
-		setRegion(region: TextureRegion): void;
-		computeWorldVertices(bone: Bone, worldVertices: ArrayLike<number>, offset: number, stride: number): void;
-	}
-}
 declare module spine {
 	enum BlendMode {
 		Normal = 0,
@@ -1005,6 +784,46 @@ declare module spine {
 		constructor(index: number, name: string, boneData: BoneData);
 	}
 }
+declare module spine {
+	abstract class Texture {
+		protected _image: HTMLImageElement;
+		constructor(image: HTMLImageElement);
+		getImage(): HTMLImageElement;
+		abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
+		abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
+		abstract dispose(): void;
+		static filterFromString(text: string): TextureFilter;
+		static wrapFromString(text: string): TextureWrap;
+	}
+	enum TextureFilter {
+		Nearest = 9728,
+		Linear = 9729,
+		MipMap = 9987,
+		MipMapNearestNearest = 9984,
+		MipMapLinearNearest = 9985,
+		MipMapNearestLinear = 9986,
+		MipMapLinearLinear = 9987,
+	}
+	enum TextureWrap {
+		MirroredRepeat = 33648,
+		ClampToEdge = 33071,
+		Repeat = 10497,
+	}
+	class TextureRegion {
+		renderObject: any;
+		u: number;
+		v: number;
+		u2: number;
+		v2: number;
+		width: number;
+		height: number;
+		rotate: boolean;
+		offsetX: number;
+		offsetY: number;
+		originalWidth: number;
+		originalHeight: number;
+	}
+}
 declare module spine {
 	class TextureAtlas implements Disposable {
 		pages: TextureAtlasPage[];
@@ -1222,6 +1041,156 @@ declare module spine {
 		end(): void;
 	}
 }
+declare module spine {
+	abstract class Attachment {
+		name: string;
+		constructor(name: string);
+	}
+	abstract class VertexAttachment extends Attachment {
+		private static nextID;
+		id: number;
+		bones: Array<number>;
+		vertices: ArrayLike<number>;
+		worldVerticesLength: number;
+		constructor(name: string);
+		computeWorldVertices(slot: Slot, start: number, count: number, worldVertices: ArrayLike<number>, offset: number, stride: number): void;
+		applyDeform(sourceAttachment: VertexAttachment): boolean;
+	}
+}
+declare module spine {
+	interface AttachmentLoader {
+		newRegionAttachment(skin: Skin, name: string, path: string): RegionAttachment;
+		newMeshAttachment(skin: Skin, name: string, path: string): MeshAttachment;
+		newBoundingBoxAttachment(skin: Skin, name: string): BoundingBoxAttachment;
+		newPathAttachment(skin: Skin, name: string): PathAttachment;
+		newPointAttachment(skin: Skin, name: string): PointAttachment;
+		newClippingAttachment(skin: Skin, name: string): ClippingAttachment;
+	}
+}
+declare module spine {
+	enum AttachmentType {
+		Region = 0,
+		BoundingBox = 1,
+		Mesh = 2,
+		LinkedMesh = 3,
+		Path = 4,
+		Point = 5,
+	}
+}
+declare module spine {
+	class BoundingBoxAttachment extends VertexAttachment {
+		color: Color;
+		constructor(name: string);
+	}
+}
+declare module spine {
+	class ClippingAttachment extends VertexAttachment {
+		endSlot: SlotData;
+		color: Color;
+		constructor(name: string);
+	}
+}
+declare module spine {
+	class MeshAttachment extends VertexAttachment {
+		region: TextureRegion;
+		path: string;
+		regionUVs: ArrayLike<number>;
+		uvs: ArrayLike<number>;
+		triangles: Array<number>;
+		color: Color;
+		hullLength: number;
+		private parentMesh;
+		inheritDeform: boolean;
+		tempColor: Color;
+		constructor(name: string);
+		updateUVs(): void;
+		applyDeform(sourceAttachment: VertexAttachment): boolean;
+		getParentMesh(): MeshAttachment;
+		setParentMesh(parentMesh: MeshAttachment): void;
+	}
+}
+declare module spine {
+	class PathAttachment extends VertexAttachment {
+		lengths: Array<number>;
+		closed: boolean;
+		constantSpeed: boolean;
+		color: Color;
+		constructor(name: string);
+	}
+}
+declare module spine {
+	class PointAttachment extends VertexAttachment {
+		x: number;
+		y: number;
+		rotation: number;
+		color: Color;
+		constructor(name: string);
+		computeWorldPosition(bone: Bone, point: Vector2): Vector2;
+		computeWorldRotation(bone: Bone): number;
+	}
+}
+declare module spine {
+	class RegionAttachment extends Attachment {
+		static OX1: number;
+		static OY1: number;
+		static OX2: number;
+		static OY2: number;
+		static OX3: number;
+		static OY3: number;
+		static OX4: number;
+		static OY4: number;
+		static X1: number;
+		static Y1: number;
+		static C1R: number;
+		static C1G: number;
+		static C1B: number;
+		static C1A: number;
+		static U1: number;
+		static V1: number;
+		static X2: number;
+		static Y2: number;
+		static C2R: number;
+		static C2G: number;
+		static C2B: number;
+		static C2A: number;
+		static U2: number;
+		static V2: number;
+		static X3: number;
+		static Y3: number;
+		static C3R: number;
+		static C3G: number;
+		static C3B: number;
+		static C3A: number;
+		static U3: number;
+		static V3: number;
+		static X4: number;
+		static Y4: number;
+		static C4R: number;
+		static C4G: number;
+		static C4B: number;
+		static C4A: number;
+		static U4: number;
+		static V4: number;
+		x: number;
+		y: number;
+		scaleX: number;
+		scaleY: number;
+		rotation: number;
+		width: number;
+		height: number;
+		color: Color;
+		path: string;
+		rendererObject: any;
+		region: TextureRegion;
+		offset: ArrayLike<number>;
+		uvs: ArrayLike<number>;
+		tempColor: Color;
+		constructor(name: string);
+		updateOffset(): void;
+		setRegion(region: TextureRegion): void;
+		computeWorldVertices(bone: Bone, worldVertices: ArrayLike<number>, offset: number, stride: number): void;
+	}
+}
 declare module spine {
 	class JitterEffect implements VertexEffect {
 		jitterX: number;
@@ -1247,52 +1216,35 @@ declare module spine {
 		end(): void;
 	}
 }
-declare module spine.threejs {
+declare module spine.canvas {
 	class AssetManager extends spine.AssetManager {
 		constructor(pathPrefix?: string);
 	}
 }
-declare module spine.threejs {
-	class MeshBatcher {
-		mesh: THREE.Mesh;
-		private static VERTEX_SIZE;
-		private vertexBuffer;
-		private vertices;
-		private verticesLength;
-		private indices;
-		private indicesLength;
-		constructor(mesh: THREE.Mesh, maxVertices?: number);
-		begin(): void;
-		batch(vertices: ArrayLike<number>, verticesLength: number, indices: ArrayLike<number>, indicesLength: number, z?: number): void;
-		end(): void;
+declare module spine.canvas {
+	class CanvasTexture extends Texture {
+		constructor(image: HTMLImageElement);
+		setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
+		setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
+		dispose(): void;
 	}
 }
-declare module spine.threejs {
-	class SkeletonMesh extends THREE.Mesh {
-		skeleton: Skeleton;
-		state: AnimationState;
-		zOffset: number;
-		vertexEffect: VertexEffect;
-		private batcher;
-		private clipper;
+declare module spine.canvas {
+	class SkeletonRenderer {
 		static QUAD_TRIANGLES: number[];
 		static VERTEX_SIZE: number;
+		private ctx;
+		triangleRendering: boolean;
+		debugRendering: boolean;
 		private vertices;
 		private tempColor;
-		constructor(skeletonData: SkeletonData);
-		update(deltaTime: number): void;
-		private updateGeometry();
-	}
-}
-declare module spine.threejs {
-	class ThreeJsTexture extends Texture {
-		texture: THREE.Texture;
-		constructor(image: HTMLImageElement);
-		setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
-		setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
-		dispose(): void;
-		static toThreeJsTextureFilter(filter: TextureFilter): THREE.TextureFilter;
-		static toThreeJsTextureWrap(wrap: TextureWrap): THREE.Wrapping;
+		constructor(context: CanvasRenderingContext2D);
+		draw(skeleton: Skeleton): void;
+		private drawImages(skeleton);
+		private drawTriangles(skeleton);
+		private drawTriangle(img, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2);
+		private computeRegionVertices(slot, region, pma);
+		private computeMeshVertices(slot, mesh, pma);
 	}
 }
 declare module spine.webgl {
@@ -1386,22 +1338,22 @@ declare module spine.webgl {
 	}
 }
 declare module spine.webgl {
-	const M00: number;
-	const M01: number;
-	const M02: number;
-	const M03: number;
-	const M10: number;
-	const M11: number;
-	const M12: number;
-	const M13: number;
-	const M20: number;
-	const M21: number;
-	const M22: number;
-	const M23: number;
-	const M30: number;
-	const M31: number;
-	const M32: number;
-	const M33: number;
+	const M00 = 0;
+	const M01 = 4;
+	const M02 = 8;
+	const M03 = 12;
+	const M10 = 1;
+	const M11 = 5;
+	const M12 = 9;
+	const M13 = 13;
+	const M20 = 2;
+	const M21 = 6;
+	const M22 = 10;
+	const M23 = 14;
+	const M30 = 3;
+	const M31 = 7;
+	const M32 = 11;
+	const M33 = 15;
 	class Matrix4 {
 		temp: Float32Array;
 		values: Float32Array;
@@ -1725,6 +1677,58 @@ declare module spine.webgl {
 		static getSourceGLBlendMode(blendMode: BlendMode, premultipliedAlpha?: boolean): number;
 	}
 }
+declare module spine.threejs {
+	class AssetManager extends spine.AssetManager {
+		constructor(pathPrefix?: string);
+	}
+}
+declare module spine.threejs {
+	class MeshBatcher {
+		mesh: THREE.Mesh;
+		private static VERTEX_SIZE;
+		private vertexBuffer;
+		private vertices;
+		private verticesLength;
+		private indices;
+		private indicesLength;
+		constructor(mesh: THREE.Mesh, maxVertices?: number);
+		begin(): void;
+		batch(vertices: ArrayLike<number>, verticesLength: number, indices: ArrayLike<number>, indicesLength: number, z?: number): void;
+		end(): void;
+	}
+}
+declare module spine.threejs {
+	class SkeletonMesh extends THREE.Mesh {
+		tempPos: Vector2;
+		tempUv: Vector2;
+		tempLight: Color;
+		tempDark: Color;
+		skeleton: Skeleton;
+		state: AnimationState;
+		zOffset: number;
+		vertexEffect: VertexEffect;
+		private batcher;
+		private clipper;
+		static QUAD_TRIANGLES: number[];
+		static VERTEX_SIZE: number;
+		private vertices;
+		private tempColor;
+		constructor(skeletonData: SkeletonData);
+		update(deltaTime: number): void;
+		private updateGeometry();
+	}
+}
+declare module spine.threejs {
+	class ThreeJsTexture extends Texture {
+		texture: THREE.Texture;
+		constructor(image: HTMLImageElement);
+		setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
+		setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
+		dispose(): void;
+		static toThreeJsTextureFilter(filter: TextureFilter): THREE.TextureFilter;
+		static toThreeJsTextureWrap(wrap: TextureWrap): THREE.Wrapping;
+	}
+}
 declare module spine {
 	class SpineWidget {
 		skeleton: Skeleton;

File diff suppressed because it is too large
+ 167 - 584
spine-ts/build/spine-all.js


File diff suppressed because it is too large
+ 0 - 0
spine-ts/build/spine-all.js.map


+ 244 - 244
spine-ts/build/spine-canvas.d.ts

@@ -1,97 +1,3 @@
-declare module spine {
-	class AssetManager implements Disposable {
-		private pathPrefix;
-		private textureLoader;
-		private assets;
-		private errors;
-		private toLoad;
-		private loaded;
-		constructor(textureLoader: (image: HTMLImageElement) => any, pathPrefix?: string);
-		loadText(path: string, success?: (path: string, text: string) => void, error?: (path: string, error: string) => void): void;
-		loadTexture(path: string, success?: (path: string, image: HTMLImageElement) => void, error?: (path: string, error: string) => void): void;
-		loadTextureData(path: string, data: string, success?: (path: string, image: HTMLImageElement) => void, error?: (path: string, error: string) => void): void;
-		get(path: string): any;
-		remove(path: string): void;
-		removeAll(): void;
-		isLoadingComplete(): boolean;
-		getToLoad(): number;
-		getLoaded(): number;
-		dispose(): void;
-		hasErrors(): boolean;
-		getErrors(): Map<string>;
-	}
-}
-declare module spine.canvas {
-	class AssetManager extends spine.AssetManager {
-		constructor(pathPrefix?: string);
-	}
-}
-declare module spine {
-	abstract class Texture {
-		protected _image: HTMLImageElement;
-		constructor(image: HTMLImageElement);
-		getImage(): HTMLImageElement;
-		abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
-		abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
-		abstract dispose(): void;
-		static filterFromString(text: string): TextureFilter;
-		static wrapFromString(text: string): TextureWrap;
-	}
-	enum TextureFilter {
-		Nearest = 9728,
-		Linear = 9729,
-		MipMap = 9987,
-		MipMapNearestNearest = 9984,
-		MipMapLinearNearest = 9985,
-		MipMapNearestLinear = 9986,
-		MipMapLinearLinear = 9987,
-	}
-	enum TextureWrap {
-		MirroredRepeat = 33648,
-		ClampToEdge = 33071,
-		Repeat = 10497,
-	}
-	class TextureRegion {
-		renderObject: any;
-		u: number;
-		v: number;
-		u2: number;
-		v2: number;
-		width: number;
-		height: number;
-		rotate: boolean;
-		offsetX: number;
-		offsetY: number;
-		originalWidth: number;
-		originalHeight: number;
-	}
-}
-declare module spine.canvas {
-	class CanvasTexture extends Texture {
-		constructor(image: HTMLImageElement);
-		setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
-		setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
-		dispose(): void;
-	}
-}
-declare module spine.canvas {
-	class SkeletonRenderer {
-		static QUAD_TRIANGLES: number[];
-		static VERTEX_SIZE: number;
-		private ctx;
-		triangleRendering: boolean;
-		debugRendering: boolean;
-		private vertices;
-		private tempColor;
-		constructor(context: CanvasRenderingContext2D);
-		draw(skeleton: Skeleton): void;
-		private drawImages(skeleton);
-		private drawTriangles(skeleton);
-		private drawTriangle(img, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2);
-		private computeRegionVertices(slot, region, pma);
-		private computeMeshVertices(slot, mesh, pma);
-	}
-}
 declare module spine {
 	class Animation {
 		name: string;
@@ -459,35 +365,32 @@ declare module spine {
 	}
 }
 declare module spine {
-	class AtlasAttachmentLoader implements AttachmentLoader {
-		atlas: TextureAtlas;
-		constructor(atlas: TextureAtlas);
-		newRegionAttachment(skin: Skin, name: string, path: string): RegionAttachment;
-		newMeshAttachment(skin: Skin, name: string, path: string): MeshAttachment;
-		newBoundingBoxAttachment(skin: Skin, name: string): BoundingBoxAttachment;
-		newPathAttachment(skin: Skin, name: string): PathAttachment;
-		newPointAttachment(skin: Skin, name: string): PointAttachment;
-		newClippingAttachment(skin: Skin, name: string): ClippingAttachment;
-	}
-}
-declare module spine {
-	abstract class Attachment {
-		name: string;
-		constructor(name: string);
-	}
-	abstract class VertexAttachment extends Attachment {
-		private static nextID;
-		id: number;
-		bones: Array<number>;
-		vertices: ArrayLike<number>;
-		worldVerticesLength: number;
-		constructor(name: string);
-		computeWorldVertices(slot: Slot, start: number, count: number, worldVertices: ArrayLike<number>, offset: number, stride: number): void;
-		applyDeform(sourceAttachment: VertexAttachment): boolean;
+	class AssetManager implements Disposable {
+		private pathPrefix;
+		private textureLoader;
+		private assets;
+		private errors;
+		private toLoad;
+		private loaded;
+		constructor(textureLoader: (image: HTMLImageElement) => any, pathPrefix?: string);
+		loadText(path: string, success?: (path: string, text: string) => void, error?: (path: string, error: string) => void): void;
+		loadTexture(path: string, success?: (path: string, image: HTMLImageElement) => void, error?: (path: string, error: string) => void): void;
+		loadTextureData(path: string, data: string, success?: (path: string, image: HTMLImageElement) => void, error?: (path: string, error: string) => void): void;
+		get(path: string): any;
+		remove(path: string): void;
+		removeAll(): void;
+		isLoadingComplete(): boolean;
+		getToLoad(): number;
+		getLoaded(): number;
+		dispose(): void;
+		hasErrors(): boolean;
+		getErrors(): Map<string>;
 	}
 }
 declare module spine {
-	interface AttachmentLoader {
+	class AtlasAttachmentLoader implements AttachmentLoader {
+		atlas: TextureAtlas;
+		constructor(atlas: TextureAtlas);
 		newRegionAttachment(skin: Skin, name: string, path: string): RegionAttachment;
 		newMeshAttachment(skin: Skin, name: string, path: string): MeshAttachment;
 		newBoundingBoxAttachment(skin: Skin, name: string): BoundingBoxAttachment;
@@ -496,130 +399,6 @@ declare module spine {
 		newClippingAttachment(skin: Skin, name: string): ClippingAttachment;
 	}
 }
-declare module spine {
-	enum AttachmentType {
-		Region = 0,
-		BoundingBox = 1,
-		Mesh = 2,
-		LinkedMesh = 3,
-		Path = 4,
-		Point = 5,
-	}
-}
-declare module spine {
-	class BoundingBoxAttachment extends VertexAttachment {
-		color: Color;
-		constructor(name: string);
-	}
-}
-declare module spine {
-	class ClippingAttachment extends VertexAttachment {
-		endSlot: SlotData;
-		color: Color;
-		constructor(name: string);
-	}
-}
-declare module spine {
-	class MeshAttachment extends VertexAttachment {
-		region: TextureRegion;
-		path: string;
-		regionUVs: ArrayLike<number>;
-		uvs: ArrayLike<number>;
-		triangles: Array<number>;
-		color: Color;
-		hullLength: number;
-		private parentMesh;
-		inheritDeform: boolean;
-		tempColor: Color;
-		constructor(name: string);
-		updateUVs(): void;
-		applyDeform(sourceAttachment: VertexAttachment): boolean;
-		getParentMesh(): MeshAttachment;
-		setParentMesh(parentMesh: MeshAttachment): void;
-	}
-}
-declare module spine {
-	class PathAttachment extends VertexAttachment {
-		lengths: Array<number>;
-		closed: boolean;
-		constantSpeed: boolean;
-		color: Color;
-		constructor(name: string);
-	}
-}
-declare module spine {
-	class PointAttachment extends VertexAttachment {
-		x: number;
-		y: number;
-		rotation: number;
-		color: Color;
-		constructor(name: string);
-		computeWorldPosition(bone: Bone, point: Vector2): Vector2;
-		computeWorldRotation(bone: Bone): number;
-	}
-}
-declare module spine {
-	class RegionAttachment extends Attachment {
-		static OX1: number;
-		static OY1: number;
-		static OX2: number;
-		static OY2: number;
-		static OX3: number;
-		static OY3: number;
-		static OX4: number;
-		static OY4: number;
-		static X1: number;
-		static Y1: number;
-		static C1R: number;
-		static C1G: number;
-		static C1B: number;
-		static C1A: number;
-		static U1: number;
-		static V1: number;
-		static X2: number;
-		static Y2: number;
-		static C2R: number;
-		static C2G: number;
-		static C2B: number;
-		static C2A: number;
-		static U2: number;
-		static V2: number;
-		static X3: number;
-		static Y3: number;
-		static C3R: number;
-		static C3G: number;
-		static C3B: number;
-		static C3A: number;
-		static U3: number;
-		static V3: number;
-		static X4: number;
-		static Y4: number;
-		static C4R: number;
-		static C4G: number;
-		static C4B: number;
-		static C4A: number;
-		static U4: number;
-		static V4: number;
-		x: number;
-		y: number;
-		scaleX: number;
-		scaleY: number;
-		rotation: number;
-		width: number;
-		height: number;
-		color: Color;
-		path: string;
-		rendererObject: any;
-		region: TextureRegion;
-		offset: ArrayLike<number>;
-		uvs: ArrayLike<number>;
-		tempColor: Color;
-		constructor(name: string);
-		updateOffset(): void;
-		setRegion(region: TextureRegion): void;
-		computeWorldVertices(bone: Bone, worldVertices: ArrayLike<number>, offset: number, stride: number): void;
-	}
-}
 declare module spine {
 	enum BlendMode {
 		Normal = 0,
@@ -1005,6 +784,46 @@ declare module spine {
 		constructor(index: number, name: string, boneData: BoneData);
 	}
 }
+declare module spine {
+	abstract class Texture {
+		protected _image: HTMLImageElement;
+		constructor(image: HTMLImageElement);
+		getImage(): HTMLImageElement;
+		abstract setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
+		abstract setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
+		abstract dispose(): void;
+		static filterFromString(text: string): TextureFilter;
+		static wrapFromString(text: string): TextureWrap;
+	}
+	enum TextureFilter {
+		Nearest = 9728,
+		Linear = 9729,
+		MipMap = 9987,
+		MipMapNearestNearest = 9984,
+		MipMapLinearNearest = 9985,
+		MipMapNearestLinear = 9986,
+		MipMapLinearLinear = 9987,
+	}
+	enum TextureWrap {
+		MirroredRepeat = 33648,
+		ClampToEdge = 33071,
+		Repeat = 10497,
+	}
+	class TextureRegion {
+		renderObject: any;
+		u: number;
+		v: number;
+		u2: number;
+		v2: number;
+		width: number;
+		height: number;
+		rotate: boolean;
+		offsetX: number;
+		offsetY: number;
+		originalWidth: number;
+		originalHeight: number;
+	}
+}
 declare module spine {
 	class TextureAtlas implements Disposable {
 		pages: TextureAtlasPage[];
@@ -1222,6 +1041,156 @@ declare module spine {
 		end(): void;
 	}
 }
+declare module spine {
+	abstract class Attachment {
+		name: string;
+		constructor(name: string);
+	}
+	abstract class VertexAttachment extends Attachment {
+		private static nextID;
+		id: number;
+		bones: Array<number>;
+		vertices: ArrayLike<number>;
+		worldVerticesLength: number;
+		constructor(name: string);
+		computeWorldVertices(slot: Slot, start: number, count: number, worldVertices: ArrayLike<number>, offset: number, stride: number): void;
+		applyDeform(sourceAttachment: VertexAttachment): boolean;
+	}
+}
+declare module spine {
+	interface AttachmentLoader {
+		newRegionAttachment(skin: Skin, name: string, path: string): RegionAttachment;
+		newMeshAttachment(skin: Skin, name: string, path: string): MeshAttachment;
+		newBoundingBoxAttachment(skin: Skin, name: string): BoundingBoxAttachment;
+		newPathAttachment(skin: Skin, name: string): PathAttachment;
+		newPointAttachment(skin: Skin, name: string): PointAttachment;
+		newClippingAttachment(skin: Skin, name: string): ClippingAttachment;
+	}
+}
+declare module spine {
+	enum AttachmentType {
+		Region = 0,
+		BoundingBox = 1,
+		Mesh = 2,
+		LinkedMesh = 3,
+		Path = 4,
+		Point = 5,
+	}
+}
+declare module spine {
+	class BoundingBoxAttachment extends VertexAttachment {
+		color: Color;
+		constructor(name: string);
+	}
+}
+declare module spine {
+	class ClippingAttachment extends VertexAttachment {
+		endSlot: SlotData;
+		color: Color;
+		constructor(name: string);
+	}
+}
+declare module spine {
+	class MeshAttachment extends VertexAttachment {
+		region: TextureRegion;
+		path: string;
+		regionUVs: ArrayLike<number>;
+		uvs: ArrayLike<number>;
+		triangles: Array<number>;
+		color: Color;
+		hullLength: number;
+		private parentMesh;
+		inheritDeform: boolean;
+		tempColor: Color;
+		constructor(name: string);
+		updateUVs(): void;
+		applyDeform(sourceAttachment: VertexAttachment): boolean;
+		getParentMesh(): MeshAttachment;
+		setParentMesh(parentMesh: MeshAttachment): void;
+	}
+}
+declare module spine {
+	class PathAttachment extends VertexAttachment {
+		lengths: Array<number>;
+		closed: boolean;
+		constantSpeed: boolean;
+		color: Color;
+		constructor(name: string);
+	}
+}
+declare module spine {
+	class PointAttachment extends VertexAttachment {
+		x: number;
+		y: number;
+		rotation: number;
+		color: Color;
+		constructor(name: string);
+		computeWorldPosition(bone: Bone, point: Vector2): Vector2;
+		computeWorldRotation(bone: Bone): number;
+	}
+}
+declare module spine {
+	class RegionAttachment extends Attachment {
+		static OX1: number;
+		static OY1: number;
+		static OX2: number;
+		static OY2: number;
+		static OX3: number;
+		static OY3: number;
+		static OX4: number;
+		static OY4: number;
+		static X1: number;
+		static Y1: number;
+		static C1R: number;
+		static C1G: number;
+		static C1B: number;
+		static C1A: number;
+		static U1: number;
+		static V1: number;
+		static X2: number;
+		static Y2: number;
+		static C2R: number;
+		static C2G: number;
+		static C2B: number;
+		static C2A: number;
+		static U2: number;
+		static V2: number;
+		static X3: number;
+		static Y3: number;
+		static C3R: number;
+		static C3G: number;
+		static C3B: number;
+		static C3A: number;
+		static U3: number;
+		static V3: number;
+		static X4: number;
+		static Y4: number;
+		static C4R: number;
+		static C4G: number;
+		static C4B: number;
+		static C4A: number;
+		static U4: number;
+		static V4: number;
+		x: number;
+		y: number;
+		scaleX: number;
+		scaleY: number;
+		rotation: number;
+		width: number;
+		height: number;
+		color: Color;
+		path: string;
+		rendererObject: any;
+		region: TextureRegion;
+		offset: ArrayLike<number>;
+		uvs: ArrayLike<number>;
+		tempColor: Color;
+		constructor(name: string);
+		updateOffset(): void;
+		setRegion(region: TextureRegion): void;
+		computeWorldVertices(bone: Bone, worldVertices: ArrayLike<number>, offset: number, stride: number): void;
+	}
+}
 declare module spine {
 	class JitterEffect implements VertexEffect {
 		jitterX: number;
@@ -1247,3 +1216,34 @@ declare module spine {
 		end(): void;
 	}
 }
+declare module spine.canvas {
+	class AssetManager extends spine.AssetManager {
+		constructor(pathPrefix?: string);
+	}
+}
+declare module spine.canvas {
+	class CanvasTexture extends Texture {
+		constructor(image: HTMLImageElement);
+		setFilters(minFilter: TextureFilter, magFilter: TextureFilter): void;
+		setWraps(uWrap: TextureWrap, vWrap: TextureWrap): void;
+		dispose(): void;
+	}
+}
+declare module spine.canvas {
+	class SkeletonRenderer {
+		static QUAD_TRIANGLES: number[];
+		static VERTEX_SIZE: number;
+		private ctx;
+		triangleRendering: boolean;
+		debugRendering: boolean;
+		private vertices;
+		private tempColor;
+		constructor(context: CanvasRenderingContext2D);
+		draw(skeleton: Skeleton): void;
+		private drawImages(skeleton);
+		private drawTriangles(skeleton);
+		private drawTriangle(img, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2);
+		private computeRegionVertices(slot, region, pma);
+		private computeMeshVertices(slot, mesh, pma);
+	}
+}

Some files were not shown because too many files changed in this diff