Forráskód Böngészése

Merge branch '3.6' into 3.7-beta

badlogic 8 éve
szülő
commit
f5965b0fdf
28 módosított fájl, 1012 hozzáadás és 84 törlés
  1. 1 0
      .gitignore
  2. 1 0
      CHANGELOG.md
  3. 6 2
      spine-csharp/src/Atlas.cs
  4. 1 1
      spine-csharp/src/SkeletonBinary.cs
  5. 6 6
      spine-csharp/src/SkeletonClipping.cs
  6. 2 2
      spine-csharp/src/Triangulator.cs
  7. 2 1
      spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonClipping.java
  8. 1 1
      spine-ue4/README.md
  9. 288 0
      spine-unity/Assets/Examples/Other Examples/Instantiate from Script.unity
  10. 8 0
      spine-unity/Assets/Examples/Other Examples/Instantiate from Script.unity.meta
  11. 44 0
      spine-unity/Assets/Examples/Scripts/DataAssetsFromExportsExample.cs
  12. 12 0
      spine-unity/Assets/Examples/Scripts/DataAssetsFromExportsExample.cs.meta
  13. 17 18
      spine-unity/Assets/Examples/Scripts/MixAndMatch.cs
  14. 42 0
      spine-unity/Assets/Examples/Scripts/SpawnFromSkeletonDataExample.cs
  15. 12 0
      spine-unity/Assets/Examples/Scripts/SpawnFromSkeletonDataExample.cs.meta
  16. 1 1
      spine-unity/Assets/Examples/Spine/Dragon/dragon_SkeletonData.asset
  17. 76 0
      spine-unity/Assets/Examples/Spine/Runtime Template Material.mat
  18. 9 0
      spine-unity/Assets/Examples/Spine/Runtime Template Material.mat.meta
  19. 7 12
      spine-unity/Assets/spine-unity/Asset Types/AtlasAsset.cs
  20. 14 8
      spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs
  21. 5 5
      spine-unity/Assets/spine-unity/Mesh Generation/SpineMesh.cs
  22. 32 14
      spine-unity/Assets/spine-unity/Modules/AttachmentTools/AttachmentTools.cs
  23. 3 3
      spine-xna/example/spine-xna-example.csproj
  24. 19 7
      spine-xna/example/src/ExampleGame.cs
  25. 2 0
      spine-xna/spine-xna.csproj
  26. 168 0
      spine-xna/src/ShapeRenderer.cs
  27. 230 0
      spine-xna/src/SkeletonDebugRenderer.cs
  28. 3 3
      spine-xna/src/Util.cs

+ 1 - 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.*

+ 1 - 0
CHANGELOG.md

@@ -142,6 +142,7 @@
  * 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 support for `IVertexEffect` to modify vertices of skeletons on the CPU. `IVertexEffect` instances can be set on the `SkeletonRenderer`. See example project.
+ * Added `SkeletonDebugRenderer`
 
 ## Java
  * **Breaking changes**

+ 6 - 2
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;
@@ -44,7 +48,7 @@ namespace Spine {
 		List<AtlasRegion> regions = new List<AtlasRegion>();
 		TextureLoader textureLoader;
 
-		#if !(UNITY_5 || UNITY_4 || UNITY_WSA || UNITY_WP8 || UNITY_WP8_1) // !UNITY
+		#if !(IS_UNITY)
 		#if WINDOWS_STOREAPP
 		private async Task ReadFile(string path, TextureLoader textureLoader) {
 			var folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
@@ -82,7 +86,7 @@ namespace Spine {
 		}
 		#endif // WINDOWS_STOREAPP
 
-		#endif // !(UNITY)
+		#endif
 
 		public Atlas (TextReader reader, string dir, TextureLoader textureLoader) {
 			Load(reader, dir, textureLoader);

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

+ 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 - 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-ue4/README.md

@@ -21,7 +21,7 @@ spine-ue4 does not support multiply and screen blending. spine-ue4 does not supp
 1. Create a new Unreal Engine code project. You don't need to write C++, but the code project is needed for the plugin to compile. See the [Unreal Engine documentation](https://docs.unrealengine.com/latest/INT/) 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/3.6.zip)
 3. Copy the `Plugins` folder from this directory to your new project's root directory.
-4. Copy the `spine-c` folder from this repositories root directory to your project's `Plugins/SpinePlugin/Sources/SpinePlugin/Public/` directory.
+4. Copy the folder `spine-runtimes/spine-c/spine-c` to your project's `Plugins/SpinePlugin/Source/SpinePlugin/Public/` folder.
 5. Open the Unreal Project in the Unreal Editor
 
 See the [Spine Runtimes documentation](http://esotericsoftware.com/spine-documentation#runtimesTitle) on how to use the APIs or check out the Spine UE4 example.

+ 288 - 0
spine-unity/Assets/Examples/Other Examples/Instantiate from Script.unity

@@ -0,0 +1,288 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_OcclusionBakeSettings:
+    smallestOccluder: 5
+    smallestHole: 0.25
+    backfaceThreshold: 100
+  m_SceneGUID: 00000000000000000000000000000000
+  m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 8
+  m_Fog: 0
+  m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+  m_FogMode: 3
+  m_FogDensity: 0.01
+  m_LinearFogStart: 0
+  m_LinearFogEnd: 300
+  m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+  m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+  m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+  m_AmbientIntensity: 1
+  m_AmbientMode: 3
+  m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+  m_SkyboxMaterial: {fileID: 0}
+  m_HaloStrength: 0.5
+  m_FlareStrength: 1
+  m_FlareFadeSpeed: 3
+  m_HaloTexture: {fileID: 0}
+  m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+  m_DefaultReflectionMode: 0
+  m_DefaultReflectionResolution: 128
+  m_ReflectionBounces: 1
+  m_ReflectionIntensity: 1
+  m_CustomReflection: {fileID: 0}
+  m_Sun: {fileID: 0}
+  m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
+--- !u!157 &3
+LightmapSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 9
+  m_GIWorkflowMode: 1
+  m_GISettings:
+    serializedVersion: 2
+    m_BounceScale: 1
+    m_IndirectOutputScale: 1
+    m_AlbedoBoost: 1
+    m_TemporalCoherenceThreshold: 1
+    m_EnvironmentLightingMode: 0
+    m_EnableBakedLightmaps: 0
+    m_EnableRealtimeLightmaps: 0
+  m_LightmapEditorSettings:
+    serializedVersion: 8
+    m_Resolution: 2
+    m_BakeResolution: 40
+    m_TextureWidth: 1024
+    m_TextureHeight: 1024
+    m_AO: 0
+    m_AOMaxDistance: 1
+    m_CompAOExponent: 1
+    m_CompAOExponentDirect: 0
+    m_Padding: 2
+    m_LightmapParameters: {fileID: 0}
+    m_LightmapsBakeMode: 1
+    m_TextureCompression: 1
+    m_FinalGather: 0
+    m_FinalGatherFiltering: 1
+    m_FinalGatherRayCount: 256
+    m_ReflectionCompression: 2
+    m_MixedBakeMode: 3
+    m_BakeBackend: 0
+    m_PVRSampling: 1
+    m_PVRDirectSampleCount: 32
+    m_PVRSampleCount: 500
+    m_PVRBounces: 2
+    m_PVRFiltering: 0
+    m_PVRFilteringMode: 1
+    m_PVRCulling: 1
+    m_PVRFilteringGaussRadiusDirect: 1
+    m_PVRFilteringGaussRadiusIndirect: 5
+    m_PVRFilteringGaussRadiusAO: 2
+    m_PVRFilteringAtrousColorSigma: 1
+    m_PVRFilteringAtrousNormalSigma: 1
+    m_PVRFilteringAtrousPositionSigma: 1
+  m_LightingDataAsset: {fileID: 0}
+  m_ShadowMaskMode: 2
+--- !u!196 &4
+NavMeshSettings:
+  serializedVersion: 2
+  m_ObjectHideFlags: 0
+  m_BuildSettings:
+    serializedVersion: 2
+    agentTypeID: 0
+    agentRadius: 0.5
+    agentHeight: 2
+    agentSlope: 45
+    agentClimb: 0.4
+    ledgeDropHeight: 0
+    maxJumpAcrossDistance: 0
+    minRegionArea: 2
+    manualCellSize: 0
+    cellSize: 0.16666667
+    manualTileSize: 0
+    tileSize: 256
+    accuratePlacement: 0
+  m_NavMeshData: {fileID: 0}
+--- !u!1 &433620963
+GameObject:
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  serializedVersion: 5
+  m_Component:
+  - component: {fileID: 433620968}
+  - component: {fileID: 433620967}
+  - component: {fileID: 433620966}
+  - component: {fileID: 433620965}
+  - component: {fileID: 433620964}
+  m_Layer: 0
+  m_Name: Main Camera
+  m_TagString: MainCamera
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!81 &433620964
+AudioListener:
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  m_GameObject: {fileID: 433620963}
+  m_Enabled: 1
+--- !u!124 &433620965
+Behaviour:
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  m_GameObject: {fileID: 433620963}
+  m_Enabled: 1
+--- !u!92 &433620966
+Behaviour:
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  m_GameObject: {fileID: 433620963}
+  m_Enabled: 1
+--- !u!20 &433620967
+Camera:
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  m_GameObject: {fileID: 433620963}
+  m_Enabled: 1
+  serializedVersion: 2
+  m_ClearFlags: 1
+  m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
+  m_NormalizedViewPortRect:
+    serializedVersion: 2
+    x: 0
+    y: 0
+    width: 1
+    height: 1
+  near clip plane: 0.3
+  far clip plane: 1000
+  field of view: 60
+  orthographic: 1
+  orthographic size: 5
+  m_Depth: -1
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingPath: -1
+  m_TargetTexture: {fileID: 0}
+  m_TargetDisplay: 0
+  m_TargetEye: 3
+  m_HDR: 1
+  m_AllowMSAA: 1
+  m_ForceIntoRT: 0
+  m_OcclusionCulling: 1
+  m_StereoConvergence: 10
+  m_StereoSeparation: 0.022
+  m_StereoMirrorMode: 0
+--- !u!4 &433620968
+Transform:
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  m_GameObject: {fileID: 433620963}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: -10}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &651278528
+GameObject:
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  serializedVersion: 5
+  m_Component:
+  - component: {fileID: 651278530}
+  - component: {fileID: 651278529}
+  m_Layer: 0
+  m_Name: 2 DataAssets from Exports
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!114 &651278529
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  m_GameObject: {fileID: 651278528}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: bb0837af7345d504db63d0c662fd12dc, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  skeletonJson: {fileID: 4900000, guid: e3b64d7eaf0de4e45a00b7065166554d, type: 3}
+  atlasText: {fileID: 4900000, guid: 5c0a5c36970a46e4d8378760ab4a4cfc, type: 3}
+  textures:
+  - {fileID: 2800000, guid: 49bb65eefe08e424bbf7a38bc98ec638, type: 3}
+  materialPropertySource: {fileID: 2100000, guid: 365eb017d7ae7134d820c8b808eeb121,
+    type: 2}
+--- !u!4 &651278530
+Transform:
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  m_GameObject: {fileID: 651278528}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 2
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &1807176298
+GameObject:
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  serializedVersion: 5
+  m_Component:
+  - component: {fileID: 1807176300}
+  - component: {fileID: 1807176299}
+  m_Layer: 0
+  m_Name: 1 Spawn from SkeletonData
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!114 &1807176299
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  m_GameObject: {fileID: 1807176298}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 7193e2e00836b124191dcae19e6c9741, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  skeletonDataAsset: {fileID: 11400000, guid: 57484171e9b9c7243aa3117bc663e7b9, type: 2}
+  count: 50
+  startingAnimation: animation
+--- !u!4 &1807176300
+Transform:
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  m_GameObject: {fileID: 1807176298}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

+ 8 - 0
spine-unity/Assets/Examples/Other Examples/Instantiate from Script.unity.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 59dc5776e19e2f041b1cac961a86924f
+timeCreated: 1500249265
+licenseType: Free
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 44 - 0
spine-unity/Assets/Examples/Scripts/DataAssetsFromExportsExample.cs

@@ -0,0 +1,44 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Spine.Unity.Examples {
+	public class DataAssetsFromExportsExample : MonoBehaviour {
+
+		public TextAsset skeletonJson;
+		public TextAsset atlasText;
+		public Texture2D[] textures;
+		public Material materialPropertySource;
+
+		AtlasAsset runtimeAtlasAsset;
+		SkeletonDataAsset runtimeSkeletonDataAsset;
+		SkeletonAnimation runtimeSkeletonAnimation;
+
+		void CreateRuntimeAssetsAndGameObject () {
+			// 1. Create the AtlasAsset (needs atlas text asset and textures, and materials/shader);
+			// 2. Create SkeletonDataAsset (needs json or binary asset file, and an AtlasAsset)
+			// 3. Create SkeletonAnimation (needs a valid SkeletonDataAsset)
+
+			runtimeAtlasAsset = AtlasAsset.CreateRuntimeInstance(atlasText, textures, materialPropertySource, true);
+			runtimeSkeletonDataAsset = SkeletonDataAsset.CreateRuntimeInstance(skeletonJson, runtimeAtlasAsset, true);
+		}
+
+		IEnumerator Start () {
+			CreateRuntimeAssetsAndGameObject();
+			runtimeSkeletonDataAsset.GetSkeletonData(false); // preload.
+			yield return new WaitForSeconds(0.5f);
+
+			runtimeSkeletonAnimation = SkeletonAnimation.NewSkeletonAnimationGameObject(runtimeSkeletonDataAsset);
+
+			// Extra Stuff
+			runtimeSkeletonAnimation.Initialize(false);
+			runtimeSkeletonAnimation.Skeleton.SetSkin("base");
+			runtimeSkeletonAnimation.Skeleton.SetSlotsToSetupPose();
+			runtimeSkeletonAnimation.AnimationState.SetAnimation(0, "run", true);
+			runtimeSkeletonAnimation.GetComponent<MeshRenderer>().sortingOrder = 10;
+			runtimeSkeletonAnimation.transform.Translate(Vector3.down * 2);
+
+		}
+	}
+
+}

+ 12 - 0
spine-unity/Assets/Examples/Scripts/DataAssetsFromExportsExample.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: bb0837af7345d504db63d0c662fd12dc
+timeCreated: 1500249349
+licenseType: Free
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 17 - 18
spine-unity/Assets/Examples/Scripts/MixAndMatch.cs

@@ -39,7 +39,7 @@ namespace Spine.Unity.Examples {
 
 		#region Inspector
 		[SpineSkin]
-		public string baseSkinName = "base";
+		public string templateAttachmentsSkin = "base";
 		public Material sourceMaterial; // This will be used as the basis for shader and material property settings.
 
 		[Header("Visor")]
@@ -83,26 +83,25 @@ namespace Spine.Unity.Examples {
 			// STEP 0: PREPARE SKINS
 			// Let's prepare a new skin to be our custom skin with equips/customizations. We get a clone so our original skins are unaffected.
 			customSkin = customSkin ?? new Skin("custom skin"); // This requires that all customizations are done with skin placeholders defined in Spine.
-			//customSkin = customSkin ?? skeleton.UnshareSkin(true, false, skeletonAnimation.AnimationState); // use this if you are not customizing on the default skin and don't plan to remove 
-			// Next let's 
-			var baseSkin = skeleton.Data.FindSkin(baseSkinName);
+			//customSkin = customSkin ?? skeleton.UnshareSkin(true, false, skeletonAnimation.AnimationState); // use this if you are not customizing on the default skin.
+			var templateSkin = skeleton.Data.FindSkin(templateAttachmentsSkin);
 
 			// STEP 1: "EQUIP" ITEMS USING SPRITES
-			// STEP 1.1 Find the original attachment.
-			// Step 1.2 Get a clone of the original attachment.
+			// STEP 1.1 Find the original/template attachment.
+			// Step 1.2 Get a clone of the original/template attachment.
 			// Step 1.3 Apply the Sprite image to the clone.
 			// Step 1.4 Add the remapped clone to the new custom skin.
 
 			// Let's do this for the visor.
 			int visorSlotIndex = skeleton.FindSlotIndex(visorSlot); // You can access GetAttachment and SetAttachment via string, but caching the slotIndex is faster.
-			Attachment baseAttachment = baseSkin.GetAttachment(visorSlotIndex, visorKey);  // STEP 1.1
-			Attachment newAttachment = baseAttachment.GetRemappedClone(visorSprite, sourceMaterial); // STEP 1.2 - 1.3
+			Attachment templateAttachment = templateSkin.GetAttachment(visorSlotIndex, visorKey);  // STEP 1.1
+			Attachment newAttachment = templateAttachment.GetRemappedClone(visorSprite, sourceMaterial); // STEP 1.2 - 1.3
 			customSkin.SetAttachment(visorSlotIndex, visorKey, newAttachment); // STEP 1.4
 
 			// And now for the gun.
 			int gunSlotIndex = skeleton.FindSlotIndex(gunSlot);
-			Attachment baseGun = baseSkin.GetAttachment(gunSlotIndex, gunKey); // STEP 1.1
-			Attachment newGun = baseGun.GetRemappedClone(gunSprite, sourceMaterial); // STEP 1.2 - 1.3
+			Attachment templateGun = templateSkin.GetAttachment(gunSlotIndex, gunKey); // STEP 1.1
+			Attachment newGun = templateGun.GetRemappedClone(gunSprite, sourceMaterial); // STEP 1.2 - 1.3
 			if (newGun != null) customSkin.SetAttachment(gunSlotIndex, gunKey, newGun); // STEP 1.4
 
 			// customSkin.RemoveAttachment(gunSlotIndex, gunKey); // To remove an item.
@@ -119,17 +118,17 @@ namespace Spine.Unity.Examples {
 			//				Under the hood, this relies on 
 			if (repack)	{
 				var repackedSkin = new Skin("repacked skin");
-				repackedSkin.Append(skeleton.Data.DefaultSkin);
-				repackedSkin.Append(customSkin);
-				repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", sourceMaterial, out runtimeMaterial, out runtimeAtlas);
-				skeleton.SetSkin(repackedSkin);
+				repackedSkin.Append(skeleton.Data.DefaultSkin); // Include the "default" skin. (everything outside of skin placeholders)
+				repackedSkin.Append(customSkin); // Include your new custom skin.
+				repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", sourceMaterial, out runtimeMaterial, out runtimeAtlas); // Pack all the items in the skin.
+				skeleton.SetSkin(repackedSkin); // Assign the repacked skin to your Skeleton.
 				if (bbFollower != null) bbFollower.Initialize(true);
 			} else {
-				skeleton.SetSkin(customSkin);
+				skeleton.SetSkin(customSkin); // Just use the custom skin directly.
 			}
-
-			skeleton.SetSlotsToSetupPose();
-			skeletonAnimation.Update(0);
+				
+			skeleton.SetSlotsToSetupPose(); // Use the pose from setup pose.
+			skeletonAnimation.Update(0); // Use the pose in the currently active animation.
 
 			Resources.UnloadUnusedAssets();
 		}

+ 42 - 0
spine-unity/Assets/Examples/Scripts/SpawnFromSkeletonDataExample.cs

@@ -0,0 +1,42 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Spine.Unity.Examples {
+	public class SpawnFromSkeletonDataExample : MonoBehaviour {
+
+		public SkeletonDataAsset skeletonDataAsset;
+		[Range(0, 100)]
+		public int count = 20;
+
+		[SpineAnimation(dataField:"skeletonDataAsset")]
+		public string startingAnimation;
+
+		IEnumerator Start () {
+			if (skeletonDataAsset == null) yield break;
+			skeletonDataAsset.GetSkeletonData(false); // Preload SkeletonDataAsset.
+			yield return new WaitForSeconds(1f); // Pretend stuff is happening.
+
+			var spineAnimation = skeletonDataAsset.GetSkeletonData(false).FindAnimation(startingAnimation);
+			for (int i = 0; i < count; i++) {
+				var sa = SkeletonAnimation.NewSkeletonAnimationGameObject(skeletonDataAsset); // Spawn a new SkeletonAnimation GameObject.
+				DoExtraStuff(sa, spineAnimation); // optional stuff for fun.
+				sa.gameObject.name = i.ToString();
+				yield return new WaitForSeconds(1f/8f);
+			}
+
+		}
+
+		void DoExtraStuff (SkeletonAnimation sa, Spine.Animation spineAnimation) {
+			sa.transform.localPosition = Random.insideUnitCircle * 6f;
+			sa.transform.SetParent(this.transform, false);
+
+			if (spineAnimation != null) {
+				sa.Initialize(false);
+				sa.AnimationState.SetAnimation(0, spineAnimation, true);
+			}
+		}
+
+	}
+
+}

+ 12 - 0
spine-unity/Assets/Examples/Scripts/SpawnFromSkeletonDataExample.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 7193e2e00836b124191dcae19e6c9741
+timeCreated: 1500249330
+licenseType: Free
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 1 - 1
spine-unity/Assets/Examples/Spine/Dragon/dragon_SkeletonData.asset

@@ -13,8 +13,8 @@ MonoBehaviour:
   m_EditorClassIdentifier: 
   atlasAssets:
   - {fileID: 11400000, guid: 6f86779b1deba7c4aaec1f5895510b57, type: 2}
-  skeletonJSON: {fileID: 4900000, guid: 95c98e245823e2243a1d8e7a1ef16c51, type: 3}
   scale: 0.01
+  skeletonJSON: {fileID: 4900000, guid: 95c98e245823e2243a1d8e7a1ef16c51, type: 3}
   fromAnimation: []
   toAnimation: []
   duration: []

+ 76 - 0
spine-unity/Assets/Examples/Spine/Runtime Template Material.mat

@@ -0,0 +1,76 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!21 &2100000
+Material:
+  serializedVersion: 6
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  m_Name: Runtime Template Material
+  m_Shader: {fileID: 4800000, guid: 1e8a610c9e01c3648bac42585e5fc676, type: 3}
+  m_ShaderKeywords: 
+  m_LightmapFlags: 4
+  m_EnableInstancingVariants: 0
+  m_DoubleSidedGI: 0
+  m_CustomRenderQueue: -1
+  stringTagMap: {}
+  disabledShaderPasses: []
+  m_SavedProperties:
+    serializedVersion: 3
+    m_TexEnvs:
+    - _BumpMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailAlbedoMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailMask:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _DetailNormalMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _EmissionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MainTex:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _MetallicGlossMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _OcclusionMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    - _ParallaxMap:
+        m_Texture: {fileID: 0}
+        m_Scale: {x: 1, y: 1}
+        m_Offset: {x: 0, y: 0}
+    m_Floats:
+    - _BumpScale: 1
+    - _Cutoff: 0.5
+    - _DetailNormalMapScale: 1
+    - _DstBlend: 0
+    - _GlossMapScale: 1
+    - _Glossiness: 0.5
+    - _GlossyReflections: 1
+    - _Metallic: 0
+    - _Mode: 0
+    - _OcclusionStrength: 1
+    - _Parallax: 0.02
+    - _SmoothnessTextureChannel: 0
+    - _SpecularHighlights: 1
+    - _SrcBlend: 1
+    - _UVSec: 0
+    - _ZWrite: 1
+    m_Colors:
+    - _Color: {r: 1, g: 1, b: 1, a: 1}
+    - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}

+ 9 - 0
spine-unity/Assets/Examples/Spine/Runtime Template Material.mat.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 365eb017d7ae7134d820c8b808eeb121
+timeCreated: 1500250447
+licenseType: Free
+NativeFormatImporter:
+  mainObjectFileID: 2100000
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 7 - 12
spine-unity/Assets/spine-unity/Asset Types/AtlasAsset.cs

@@ -60,10 +60,7 @@ namespace Spine.Unity {
 
 		/// <summary>
 		/// Creates a runtime AtlasAsset. Only providing the textures is slower because it has to search for atlas page matches. <seealso cref="Spine.Unity.AtlasAsset.CreateRuntimeInstance(TextAsset, Material[], bool)"/></summary>
-		public static AtlasAsset CreateRuntimeInstance (TextAsset atlasText, Texture2D[] textures, Shader shader, bool initialize) {
-			if (shader == null)
-				shader = Shader.Find("Spine/Skeleton");
-
+		public static AtlasAsset CreateRuntimeInstance (TextAsset atlasText, Texture2D[] textures, Material materialPropertySource, bool initialize) {
 			// Get atlas page names.
 			string atlasString = atlasText.text;
 			atlasString = atlasString.Replace("\r", "");
@@ -84,7 +81,7 @@ namespace Spine.Unity {
 				for (int j = 0, m = textures.Length; j < m; j++) {
 					if (string.Equals(pageName, textures[j].name, System.StringComparison.OrdinalIgnoreCase)) {
 						// Match found.
-						mat = new Material(shader);
+						mat = new Material(materialPropertySource);
 						mat.mainTexture = textures[j];
 						break;
 					}
@@ -102,14 +99,12 @@ namespace Spine.Unity {
 
 		/// <summary>
 		/// Creates a runtime AtlasAsset. Only providing the textures is slower because it has to search for atlas page matches. <seealso cref="Spine.Unity.AtlasAsset.CreateRuntimeInstance(TextAsset, Material[], bool)"/></summary>
-		public static AtlasAsset CreateRuntimeInstance (TextAsset atlasText, Texture2D[] textures, Material materialPropertySource, bool initialize) {
-			var shader = materialPropertySource.shader;
-			var oa = CreateRuntimeInstance(atlasText, textures, shader, initialize);
+		public static AtlasAsset CreateRuntimeInstance (TextAsset atlasText, Texture2D[] textures, Shader shader, bool initialize) {
+			if (shader == null)
+				shader = Shader.Find("Spine/Skeleton");
 
-			foreach (var m in oa.materials) {
-				m.CopyPropertiesFromMaterial(materialPropertySource);
-				m.shaderKeywords = materialPropertySource.shaderKeywords;
-			}
+			Material materialProperySource = new Material(shader);
+			var oa = CreateRuntimeInstance(atlasText, textures, materialProperySource, initialize);
 
 			return oa;
 		}

+ 14 - 8
spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs

@@ -1213,7 +1213,7 @@ namespace Spine.Unity.Editor {
 		#endregion
 
 		#region Checking Methods
-		static int[][] compatibleVersions = { new[] {3, 6, 0} };
+		static int[][] compatibleVersions = { new[] {3, 6, 0}, new[] {3, 5, 0} };
 		//static bool isFixVersionRequired = false;
 
 		static bool CheckForValidSkeletonData (string skeletonJSONPath) {
@@ -1272,10 +1272,10 @@ namespace Spine.Unity.Editor {
 
 			// Version warning
 			if (isSpineData) {
-				string runtimeVersion = compatibleVersions[0][0] + "." + compatibleVersions[0][1];
+				string runtimeVersionDebugString = compatibleVersions[0][0] + "." + compatibleVersions[0][1];
 
 				if (string.IsNullOrEmpty(rawVersion)) {
-					Debug.LogWarningFormat("Skeleton '{0}' has no version information. It may be incompatible with your runtime version: spine-unity v{1}", asset.name, runtimeVersion);
+					Debug.LogWarningFormat("Skeleton '{0}' has no version information. It may be incompatible with your runtime version: spine-unity v{1}", asset.name, runtimeVersionDebugString);
 				} else {
 					string[] versionSplit = rawVersion.Split('.');
 					bool match = false;
@@ -1292,7 +1292,7 @@ namespace Spine.Unity.Editor {
 					}
 
 					if (!match)
-						Debug.LogWarningFormat("Skeleton '{0}' (exported with Spine {1}) may be incompatible with your runtime version: spine-unity v{2}", asset.name, rawVersion, runtimeVersion);
+						Debug.LogWarningFormat("Skeleton '{0}' (exported with Spine {1}) may be incompatible with your runtime version: spine-unity v{2}", asset.name, rawVersion, runtimeVersionDebugString);
 				}
 			}
 
@@ -1476,11 +1476,18 @@ namespace Spine.Unity.Editor {
 		#region TK2D Support
 		const string SPINE_TK2D_DEFINE = "SPINE_TK2D";
 
+		static bool IsInvalidGroup (BuildTargetGroup group) {
+			int gi = (int)group;
+			return
+				gi == 15 || gi == 16
+				||
+				group == BuildTargetGroup.Unknown;
+		}
+
 		static void EnableTK2D () {
 			bool added = false;
 			foreach (BuildTargetGroup group in System.Enum.GetValues(typeof(BuildTargetGroup))) {				
-				int gi = (int)group;
-				if (gi == 15 || gi == 16 || group == BuildTargetGroup.Unknown)
+				if (IsInvalidGroup(group))
 					continue;
 
 				string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(group);
@@ -1506,8 +1513,7 @@ namespace Spine.Unity.Editor {
 		static void DisableTK2D () {
 			bool removed = false;
 			foreach (BuildTargetGroup group in System.Enum.GetValues(typeof(BuildTargetGroup))) {
-				int gi = (int)group;
-				if (gi == 15 || gi == 16 || group == BuildTargetGroup.Unknown)
+				if (IsInvalidGroup(group))
 					continue;
 				
 				string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(group);

+ 5 - 5
spine-unity/Assets/spine-unity/Mesh Generation/SpineMesh.cs

@@ -502,16 +502,16 @@ namespace Spine.Unity {
 				} else {
 					var mesh = attachment as MeshAttachment;
 					if (mesh != null) {
-						int meshVertexCount = mesh.worldVerticesLength;
-						if (workingVerts.Length < meshVertexCount) {
-							workingVerts = new float[meshVertexCount];
+						int meshVerticesLength = mesh.worldVerticesLength;
+						if (workingVerts.Length < meshVerticesLength) {
+							workingVerts = new float[meshVerticesLength];
 							this.tempVerts = workingVerts;
 						}
-						mesh.ComputeWorldVertices(slot, 0, meshVertexCount, workingVerts, 0); //meshAttachment.ComputeWorldVertices(slot, tempVerts);
+						mesh.ComputeWorldVertices(slot, 0, meshVerticesLength, workingVerts, 0); //meshAttachment.ComputeWorldVertices(slot, tempVerts);
 						uvs = mesh.uvs;
 						attachmentTriangleIndices = mesh.triangles;
 						c.r = mesh.r; c.g = mesh.g; c.b = mesh.b; c.a = mesh.a;
-						attachmentVertexCount = meshVertexCount >> 1; // meshVertexCount / 2;
+						attachmentVertexCount = meshVerticesLength >> 1; // meshVertexCount / 2;
 						attachmentIndexCount = mesh.triangles.Length;
 					} else {
 						if (useClipping) {

+ 32 - 14
spine-unity/Assets/spine-unity/Modules/AttachmentTools/AttachmentTools.cs

@@ -469,9 +469,9 @@ namespace Spine.Unity.Modules.AttachmentTools {
 				a.SetRegion(repackedRegions[regionIndexes[i]]);
 			}
 
-			// Clean up
-			foreach (var ttp in texturesToPack)
-				UnityEngine.Object.Destroy(ttp);
+//			// Clean up
+//			foreach (var ttp in texturesToPack)
+//				UnityEngine.Object.Destroy(ttp);
 
 			t = newTexture;
 			m = newMaterial;
@@ -482,20 +482,38 @@ namespace Spine.Unity.Modules.AttachmentTools {
 			return Sprite.Create(ar.GetMainTexture(), ar.GetUnityRect(), new Vector2(0.5f, 0.5f), pixelsPerUnit);
 		}
 
+		static Dictionary<AtlasRegion, Texture2D> CachedRegionTextures = new Dictionary<AtlasRegion, Texture2D>();
+		static List<Texture2D> CachedRegionTexturesList = new List<Texture2D>();
+
+		public static void ClearCache () {
+			foreach (var t in CachedRegionTexturesList) {
+				UnityEngine.Object.Destroy(t);
+			}
+			CachedRegionTextures.Clear();
+			CachedRegionTexturesList.Clear();
+		}
+
 		/// <summary>Creates a new Texture2D object based on an AtlasRegion.
 		/// If applyImmediately is true, Texture2D.Apply is called immediately after the Texture2D is filled with data.</summary>
 		public static Texture2D ToTexture (this AtlasRegion ar, bool applyImmediately = true, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps) {
-			Texture2D sourceTexture = ar.GetMainTexture();
-			Rect r = ar.GetUnityRect(sourceTexture.height);
-			int width = (int)r.width;
-			int height = (int)r.height;
-			Texture2D output = new Texture2D(width, height, textureFormat, mipmaps);
-			output.name = ar.name;
-			Color[] pixelBuffer = sourceTexture.GetPixels((int)r.x, (int)r.y, width, height);
-			output.SetPixels(pixelBuffer);
-
-			if (applyImmediately)
-				output.Apply();
+			Texture2D output;
+
+			CachedRegionTextures.TryGetValue(ar, out output);
+			if (output == null) {
+				Texture2D sourceTexture = ar.GetMainTexture();
+				Rect r = ar.GetUnityRect(sourceTexture.height);
+				int width = (int)r.width;
+				int height = (int)r.height;
+				output = new Texture2D(width, height, textureFormat, mipmaps);
+				output.name = ar.name;
+				Color[] pixelBuffer = sourceTexture.GetPixels((int)r.x, (int)r.y, width, height);
+				output.SetPixels(pixelBuffer);
+				CachedRegionTextures.Add(ar, output);
+				CachedRegionTexturesList.Add(output);
+
+				if (applyImmediately)
+					output.Apply();
+			}
 
 			return output;
 		}

+ 3 - 3
spine-xna/example/spine-xna-example.csproj

@@ -122,6 +122,9 @@
     <None Include="data\coin-pro.skel">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
+    <None Include="data\goblins-mesh.atlas">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
     <None Include="data\goblins.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
@@ -195,9 +198,6 @@
     <None Include="data\coin-pro.json">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>
-    <None Include="data\goblins-mesh.atlas">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </None>
     <None Include="data\goblins-pro.json">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </None>

+ 19 - 7
spine-xna/example/src/ExampleGame.cs

@@ -43,6 +43,7 @@ namespace Spine {
 	public class Example : Microsoft.Xna.Framework.Game {
 		GraphicsDeviceManager graphics;
 		SkeletonRenderer skeletonRenderer;
+		SkeletonDebugRenderer skeletonDebugRenderer;
 		Skeleton skeleton;
 		Slot headSlot;
 		AnimationState state;
@@ -79,12 +80,17 @@ namespace Spine {
 			skeletonRenderer.PremultipliedAlpha = false;
 			skeletonRenderer.Effect = spineEffect;
 
+			skeletonDebugRenderer = new SkeletonDebugRenderer(GraphicsDevice);
+			skeletonDebugRenderer.DisableAll();
+			skeletonDebugRenderer.DrawClipping = true;
+
 			// String name = "spineboy-ess";
-			// String name = "goblins-pro";
+			String name = "goblins-pro";
 			// String name = "raptor-pro";
 			// String name = "tank-pro";
-			String name = "coin-pro";
+			// String name = "coin-pro";
 			String atlasName = name.Replace("-pro", "").Replace("-ess", "");
+			if (name == "goblins-pro") atlasName = "goblins-mesh";
 			bool binaryData = false;
 
 			Atlas atlas = new Atlas(assetsFolder + atlasName + ".atlas", new XnaTextureLoader(GraphicsDevice));			
@@ -122,27 +128,28 @@ namespace Spine {
 				state.Complete += Complete;
 				state.Event += Event;
 
-				state.SetAnimation(0, "test", false);
+				state.SetAnimation(0, "run", true);
 				TrackEntry entry = state.AddAnimation(0, "jump", false, 0);
 				entry.End += End; // Event handling for queued animations.
 				state.AddAnimation(0, "run", true, 0);
 			}
 			else if (name == "raptor-pro") {
 				state.SetAnimation(0, "walk", true);
-				state.AddAnimation(1, "gungrab", false, 2);
+				state.AddAnimation(1, "gun-grab", false, 2);
 			}
 			else if (name == "coin-pro") {
 				state.SetAnimation(0, "rotate", true);
 			}
 			else if (name == "tank-pro") {
+				skeleton.X += 300;
 				state.SetAnimation(0, "drive", true);
-			}			
+			}	
 			else {
 				state.SetAnimation(0, "walk", true);
 			}
 
-			skeleton.X = 400 + (name == "tank-pro" ? 300: 0);
-			skeleton.Y = GraphicsDevice.Viewport.Height;
+			skeleton.X += 400;
+			skeleton.Y += GraphicsDevice.Viewport.Height;
 			skeleton.UpdateWorldTransform();
 
 			headSlot = skeleton.FindSlot("head");
@@ -176,6 +183,11 @@ namespace Spine {
 			skeletonRenderer.Draw(skeleton);
 			skeletonRenderer.End();
 
+			skeletonDebugRenderer.Effect.Projection = Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 1, 0);
+			skeletonDebugRenderer.Begin();
+			skeletonDebugRenderer.Draw(skeleton);
+			skeletonDebugRenderer.End();
+
 			bounds.Update(skeleton, true);
 			MouseState mouse = Mouse.GetState();
 			if (headSlot != null) {

+ 2 - 0
spine-xna/spine-xna.csproj

@@ -111,6 +111,8 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="src\MeshBatcher.cs" />
     <Compile Include="src\VertexEffect.cs" />
+    <Compile Include="src\ShapeRenderer.cs" />
+    <Compile Include="src\SkeletonDebugRenderer.cs" />
     <Compile Include="src\XnaTextureLoader.cs" />
     <Compile Include="src\Util.cs" />
   </ItemGroup>

+ 168 - 0
spine-xna/src/ShapeRenderer.cs

@@ -0,0 +1,168 @@
+/******************************************************************************
+ * Spine Runtimes Software License
+ * Version 2.3
+ * 
+ * Copyright (c) 2013-2015, Esoteric Software
+ * All rights reserved.
+ * 
+ * You are granted a perpetual, non-exclusive, non-sublicensable and
+ * non-transferable license to use, install, execute and perform the Spine
+ * Runtimes Software (the "Software") and derivative works solely for personal
+ * or internal use. Without the written permission of Esoteric Software (see
+ * Section 2 of the Spine Software License Agreement), you may not (a) modify,
+ * translate, adapt or otherwise create derivative works, improvements of the
+ * Software or develop new applications using the Software or (b) remove,
+ * delete, alter or obscure any trademarks or any copyright, trademark, patent
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Spine {
+	/// <summary>
+	/// Batch drawing of lines and shapes that can be derrived from lines.
+	/// 
+	/// Call drawing methods in between Begin()/End()
+	/// </summary>
+	public class ShapeRenderer {
+		GraphicsDevice device;		
+		List<VertexPositionColor> vertices = new List<VertexPositionColor>();
+		Color color = Color.White;
+		BasicEffect effect;
+		public BasicEffect Effect { get { return effect; } set { effect = value; } }
+
+		public ShapeRenderer(GraphicsDevice device) {
+			this.device = device;
+			this.effect = new BasicEffect(device);
+			effect.World = Matrix.Identity;
+			effect.View = Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 1.0f), Vector3.Zero, Vector3.Up);
+			effect.TextureEnabled = false;
+			effect.VertexColorEnabled = true;
+		}
+
+		public void SetColor(Color color) {
+			this.color = color;
+		}
+
+		public void Begin() {
+			device.RasterizerState = new RasterizerState();
+			device.BlendState = BlendState.AlphaBlend;
+		}
+
+		public void Line(float x1, float y1, float x2, float y2) {
+			vertices.Add(new VertexPositionColor(new Vector3(x1, y1, 0), color));
+			vertices.Add(new VertexPositionColor(new Vector3(x2, y2, 0), color));
+		}
+
+		/** Calls {@link #circle(float, float, float, int)} by estimating the number of segments needed for a smooth circle. */
+		public void Circle(float x, float y, float radius) {
+			Circle(x, y, radius, Math.Max(1, (int)(6 * (float)Math.Pow(radius, 1.0f / 3.0f))));
+		}
+
+		/** Draws a circle using {@link ShapeType#Line} or {@link ShapeType#Filled}. */
+		public void Circle(float x, float y, float radius, int segments) {
+			if (segments <= 0) throw new ArgumentException("segments must be > 0.");			
+			float angle = 2 * MathUtils.PI / segments;
+			float cos = MathUtils.Cos(angle);
+			float sin = MathUtils.Sin(angle);
+			float cx = radius, cy = 0;
+			float temp = 0;
+							
+			for (int i = 0; i < segments; i++) {				
+				vertices.Add(new VertexPositionColor(new Vector3(x + cx, y + cy, 0), color));
+				temp = cx;
+				cx = cos * cx - sin * cy;
+				cy = sin * temp + cos * cy;				
+				vertices.Add(new VertexPositionColor(new Vector3(x + cx, y + cy, 0), color));
+			}
+			vertices.Add(new VertexPositionColor(new Vector3(x + cx, y + cy, 0), color));
+
+			temp = cx;
+			cx = radius;
+			cy = 0;
+			vertices.Add(new VertexPositionColor(new Vector3(x + cx, y + cy, 0), color));
+		}
+
+		public void Triangle(float x1, float y1, float x2, float y2, float x3, float y3) {
+			vertices.Add(new VertexPositionColor(new Vector3(x1, y1, 0), color));
+			vertices.Add(new VertexPositionColor(new Vector3(x2, y2, 0), color));
+
+			vertices.Add(new VertexPositionColor(new Vector3(x2, y2, 0), color));
+			vertices.Add(new VertexPositionColor(new Vector3(x3, y3, 0), color));
+
+			vertices.Add(new VertexPositionColor(new Vector3(x3, y3, 0), color));
+			vertices.Add(new VertexPositionColor(new Vector3(x1, y1, 0), color));
+		}
+
+		public void X(float x, float y, float len) {
+			Line(x + len, y + len, x - len, y - len);
+			Line(x - len, y + len, x + len, y - len);
+		}
+
+		public void Polygon(float[] polygonVertices, int offset, int count) {
+			if (count< 3) throw new ArgumentException("Polygon must contain at least 3 vertices");
+
+			offset <<= 1;
+			count <<= 1;
+
+			var firstX = polygonVertices[offset];
+			var firstY = polygonVertices[offset + 1];
+			var last = offset + count;
+
+			for (int i = offset, n = offset + count - 2; i<n; i += 2) {
+				var x1 = polygonVertices[i];
+				var y1 = polygonVertices[i + 1];
+
+				var x2 = 0f;
+				var y2 = 0f;
+
+				if (i + 2 >= last) {
+					x2 = firstX;
+					y2 = firstY;
+				} else {
+					x2 = polygonVertices[i + 2];
+					y2 = polygonVertices[i + 3];
+				}
+
+				Line(x1, y1, x2, y2);
+			}
+		}
+
+		public void Rect(float x, float y, float width, float height) {
+			Line(x, y, x + width, y);
+			Line(x + width, y, x + width, y + height);
+			Line(x + width, y + height, x, y + height);
+			Line(x, y + height, x, y);
+		}
+
+		public void End() {
+			if (vertices.Count == 0) return;
+			var verticesArray = vertices.ToArray();
+
+			foreach (EffectPass pass in effect.CurrentTechnique.Passes) {
+				pass.Apply();
+				device.DrawUserPrimitives(PrimitiveType.LineList, verticesArray, 0, verticesArray.Length / 2);		
+			}
+
+			vertices.Clear();
+		}
+	}
+}

+ 230 - 0
spine-xna/src/SkeletonDebugRenderer.cs

@@ -0,0 +1,230 @@
+/******************************************************************************
+ * Spine Runtimes Software License
+ * Version 2.3
+ * 
+ * Copyright (c) 2013-2015, Esoteric Software
+ * All rights reserved.
+ * 
+ * You are granted a perpetual, non-exclusive, non-sublicensable and
+ * non-transferable license to use, install, execute and perform the Spine
+ * Runtimes Software (the "Software") and derivative works solely for personal
+ * or internal use. Without the written permission of Esoteric Software (see
+ * Section 2 of the Spine Software License Agreement), you may not (a) modify,
+ * translate, adapt or otherwise create derivative works, improvements of the
+ * Software or develop new applications using the Software or (b) remove,
+ * delete, alter or obscure any trademarks or any copyright, trademark, patent
+ * or other intellectual property or proprietary rights notices on or in the
+ * Software, including any copy thereof. Redistributions in binary or source
+ * form must include this license and terms.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Spine {
+	public class SkeletonDebugRenderer {
+		ShapeRenderer renderer;
+
+		private static Color boneLineColor = new Color(1f, 0f, 0f, 1f);
+		private static Color boneOriginColor = new Color(0f, 1f, 0f, 1f);
+		private static Color attachmentLineColor = new Color(0f, 0f, 1f, 0.5f);
+		private static Color triangleLineColor = new Color(1f, 0.64f, 0f, 0.5f);
+		private static Color pathColor = new Color(1f, 0.5f, 0f, 1f);
+		private static Color clipColor = new Color(0.8f, 0f, 0f, 1f);
+		private static Color clipDecomposedColor = new Color(0.8f, 0.8f, 0f, 1f);
+		private static Color aabbColor = new Color(0f, 1f, 0f, 0.5f);
+
+		public BasicEffect Effect { get { return renderer.Effect; } set { renderer.Effect = value; } }
+		public bool DrawBones { get; set; }
+		public bool DrawRegionAttachments { get; set; }
+		public bool DrawBoundingBoxes { get; set; }
+		public bool DrawMeshHull { get; set; }
+		public bool DrawMeshTriangles { get; set; }
+		public bool DrawPaths { get; set; }
+		public bool DrawClipping { get; set; }
+		public bool DrawClippingDecomposed { get; set; }
+		public bool DrawSkeletonXY { get; set; }
+		public void DisableAll() {
+			DrawBones = false;
+			DrawRegionAttachments = false;
+			DrawBoundingBoxes = false;
+			DrawMeshHull = false;
+			DrawMeshTriangles = false;
+			DrawPaths = false;
+			DrawClipping = false;
+			DrawSkeletonXY = false;
+		}
+
+		public void EnableAll() {
+			DrawBones = true;
+			DrawRegionAttachments = true;
+			DrawBoundingBoxes = true;
+			DrawMeshHull = true;
+			DrawMeshTriangles = true;
+			DrawPaths = true;
+			DrawClipping = true;
+			DrawSkeletonXY = true;
+		}
+
+		private float[] vertices = new float[1024 * 2];
+		private SkeletonBounds bounds = new SkeletonBounds();
+		private Triangulator triangulator = new Triangulator();
+
+		public SkeletonDebugRenderer (GraphicsDevice device) {
+			renderer = new ShapeRenderer(device);
+			EnableAll();
+		}
+
+		public void Begin() {
+			renderer.Begin();
+		}
+
+		public void Draw(Skeleton skeleton) {
+			var skeletonX = skeleton.X;
+			var skeletonY = skeleton.Y;
+
+			var bones = skeleton.Bones;
+			if (DrawBones) {
+				renderer.SetColor(boneLineColor);
+				for (int i = 0, n = bones.Count; i < n; i++) {
+					var bone = bones.Items[i];
+					if (bone.Parent == null) continue;
+					var x = bone.Data.Length * bone.A + bone.WorldX;
+					var y = bone.Data.Length * bone.C + bone.WorldY;
+					renderer.Line(bone.WorldX, bone.WorldY, x, y);					
+				}
+				if (DrawSkeletonXY) renderer.X(skeletonX, skeletonY, 4);
+			}
+
+			if (DrawRegionAttachments) {
+				renderer.SetColor(attachmentLineColor);
+				var slots = skeleton.Slots;
+				for (int i = 0, n = slots.Count; i < n; i++) {
+					var slot = slots.Items[i];
+					var attachment = slot.Attachment;
+					if (attachment is RegionAttachment) {
+						var regionAttachment = (RegionAttachment) attachment;
+						var vertices = this.vertices;
+						regionAttachment.ComputeWorldVertices(slot.Bone, vertices, 0, 2);
+						renderer.Line(vertices[0], vertices[1], vertices[2], vertices[3]);
+						renderer.Line(vertices[2], vertices[3], vertices[4], vertices[5]);
+						renderer.Line(vertices[4], vertices[5], vertices[6], vertices[7]);
+						renderer.Line(vertices[6], vertices[7], vertices[0], vertices[1]);
+					}
+				}
+			}
+
+			if (DrawMeshHull || DrawMeshTriangles) {
+				var slots = skeleton.Slots;
+				for (int i = 0, n = slots.Count; i < n; i++) {
+					var slot = slots.Items[i];
+					var attachment = slot.Attachment;
+					if (!(attachment is MeshAttachment)) continue;
+					var mesh = (MeshAttachment)attachment;
+					var world = vertices = vertices.Length < mesh.WorldVerticesLength ? new float[mesh.WorldVerticesLength] : vertices;
+					mesh.ComputeWorldVertices(slot, 0, mesh.WorldVerticesLength, world, 0, 2);
+					int[] triangles = mesh.Triangles;
+					var hullLength = mesh.HullLength;
+					if (DrawMeshTriangles) {
+						renderer.SetColor(triangleLineColor);
+						for (int ii = 0, nn = triangles.Count(); ii < nn; ii += 3) {
+							int v1 = triangles[ii] * 2, v2 = triangles[ii + 1] * 2, v3 = triangles[ii + 2] * 2;
+							renderer.Triangle(world[v1], world[v1 + 1], //
+								world[v2], world[v2 + 1], //
+								world[v3], world[v3 + 1] //
+							);
+						}
+					}
+					if (DrawMeshHull && hullLength > 0) {
+						renderer.SetColor(attachmentLineColor);
+						hullLength = (hullLength >> 1) * 2;
+						float lastX = vertices[hullLength - 2], lastY = vertices[hullLength - 1];
+						for (int ii = 0, nn = hullLength; ii < nn; ii += 2) {
+							float x = vertices[ii], y = vertices[ii + 1];
+							renderer.Line(x, y, lastX, lastY);
+							lastX = x;
+							lastY = y;
+						}
+					}
+				}
+			}
+
+			if (DrawBoundingBoxes) {
+				var bounds = this.bounds;
+				bounds.Update(skeleton, true);
+				renderer.SetColor(aabbColor);
+				renderer.Rect(bounds.MinX, bounds.MinY, bounds.Width, bounds.Height);
+				var polygons = bounds.Polygons;
+				var boxes = bounds.BoundingBoxes;
+				for (int i = 0, n = polygons.Count; i < n; i++) {
+					var polygon = polygons.Items[i];
+					renderer.Polygon(polygon.Vertices, 0, polygon.Count);
+				}
+			}
+
+			if (DrawBones) {
+				renderer.SetColor(boneOriginColor);
+				for (int i = 0, n = bones.Count; i < n; i++) {
+					var bone = bones.Items[i];
+					renderer.Circle(bone.WorldX, bone.WorldY, 3);
+				}
+			}
+
+			if (DrawClipping) {
+				var slots = skeleton.Slots;
+				renderer.SetColor(clipColor);
+				for (int i = 0, n = slots.Count; i < n; i++) {
+					var slot = slots.Items[i];
+					var attachment = slot.Attachment;
+					if (!(attachment is ClippingAttachment)) continue;
+					var clip = (ClippingAttachment)attachment;
+					var nn = clip.WorldVerticesLength;
+					var world = vertices = vertices.Length < nn ? new float[nn] : vertices;
+					clip.ComputeWorldVertices(slot, 0, nn, world, 0, 2);
+					ExposedList<float> clippingPolygon = new ExposedList<float>();
+					for (int ii = 0; ii < nn; ii += 2) {
+						var x = world[ii];
+						var y = world[ii + 1];
+						var x2 = world[(ii + 2) % nn];
+						var y2 = world[(ii + 3) % nn];
+						renderer.Line(x, y, x2, y2);
+						clippingPolygon.Add(x);
+						clippingPolygon.Add(y);
+					}
+
+					if (DrawClippingDecomposed) {
+						SkeletonClipping.MakeClockwise(clippingPolygon);
+						var triangles = triangulator.Triangulate(clippingPolygon);
+						var clippingPolygons = triangulator.Decompose(clippingPolygon, triangles);
+						renderer.SetColor(clipDecomposedColor);
+						foreach (var polygon in clippingPolygons) {
+							SkeletonClipping.MakeClockwise(polygon);
+							polygon.Add(polygon.Items[0]);
+							polygon.Add(polygon.Items[1]);
+							renderer.Polygon(polygon.Items, 0, polygon.Count >> 1);
+						}
+					}
+				}
+			}
+		}
+
+		public void End() {
+			renderer.End();
+		}
+	}
+}

+ 3 - 3
spine-xna/src/Util.cs

@@ -27,8 +27,8 @@
  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
-
+ *****************************************************************************/
+
 using System;
 using System.IO;
 using Microsoft.Xna.Framework;
@@ -79,4 +79,4 @@ namespace Spine {
 			return Texture2D.FromStream(device, input);
 		}
 	}
-}
+}