Selaa lähdekoodia

Merge branch '3.6-beta' of https://github.com/esotericsoftware/spine-runtimes into 3.6-beta

badlogic 8 vuotta sitten
vanhempi
commit
6fdded7bf8
27 muutettua tiedostoa jossa 318 lisäystä ja 344 poistoa
  1. 1 1
      spine-csharp/README.md
  2. 16 16
      spine-csharp/src/Atlas.cs
  3. 37 49
      spine-csharp/src/Attachments/RegionAttachment.cs
  4. 7 7
      spine-csharp/src/SkeletonJson.cs
  5. 2 2
      spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs
  6. 1 1
      spine-unity/Assets/spine-unity/Editor/SkeletonBaker.cs
  7. 5 2
      spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs
  8. 5 1
      spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs
  9. 62 11
      spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysMeshGenerator.cs
  10. 11 0
      spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs
  11. 9 2
      spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs
  12. 11 1
      spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs
  13. 1 0
      spine-unity/Assets/spine-unity/Mesh Generation/ISimpleMeshGenerator.cs
  14. 2 0
      spine-unity/Assets/spine-unity/Mesh Generation/ISubmeshedMeshGenerator.cs
  15. 6 4
      spine-unity/Assets/spine-unity/Modules/AttachmentTools/AttachmentTools.cs
  16. 3 8
      spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs
  17. 3 47
      spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs
  18. 0 2
      spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderSeparator.cs
  19. 0 8
      spine-unity/Assets/spine-unity/Modules/YieldInstructions/WaitForSpineAnimationComplete.cs
  20. 0 14
      spine-unity/Assets/spine-unity/Modules/YieldInstructions/WaitForSpineEvent.cs
  21. 0 8
      spine-unity/Assets/spine-unity/Modules/YieldInstructions/WaitForSpineTrackEntryEnd.cs
  22. 106 0
      spine-unity/Assets/spine-unity/Shaders/Skeleton TintBlack.shader
  23. 7 0
      spine-unity/Assets/spine-unity/Shaders/Skeleton TintBlack.shader.meta
  24. 1 1
      spine-unity/Assets/spine-unity/SkeletonAnimator.cs
  25. 20 157
      spine-unity/Assets/spine-unity/SkeletonRenderer.cs
  26. 1 1
      spine-unity/Assets/spine-unity/version.txt
  27. 1 1
      spine-unity/README.md

+ 1 - 1
spine-csharp/README.md

@@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
 
 
 ## Spine version
 ## Spine version
 
 
-spine-csharp works with data exported from Spine 3.5.xx.
+spine-csharp works with data exported from Spine 3.6.xx.
 
 
 spine-csharp supports all Spine features.
 spine-csharp supports all Spine features.
 
 

+ 16 - 16
spine-csharp/src/Atlas.cs

@@ -40,7 +40,7 @@ using Windows.Storage;
 
 
 namespace Spine {
 namespace Spine {
 	public class Atlas {
 	public class Atlas {
-		List<AtlasPage> pages = new List<AtlasPage>();
+		readonly List<AtlasPage> pages = new List<AtlasPage>();
 		List<AtlasRegion> regions = new List<AtlasRegion>();
 		List<AtlasRegion> regions = new List<AtlasRegion>();
 		TextureLoader textureLoader;
 		TextureLoader textureLoader;
 
 
@@ -58,12 +58,12 @@ namespace Spine {
 			}
 			}
 		}
 		}
 
 
-		public Atlas(String path, TextureLoader textureLoader) {
+		public Atlas(string path, TextureLoader textureLoader) {
 			this.ReadFile(path, textureLoader).Wait();
 			this.ReadFile(path, textureLoader).Wait();
 		}
 		}
 		#else
 		#else
 
 
-		public Atlas (String path, TextureLoader textureLoader) {
+		public Atlas (string path, TextureLoader textureLoader) {
 
 
 			#if WINDOWS_PHONE
 			#if WINDOWS_PHONE
 			Stream stream = Microsoft.Xna.Framework.TitleContainer.OpenStream(path);
 			Stream stream = Microsoft.Xna.Framework.TitleContainer.OpenStream(path);
@@ -84,7 +84,7 @@ namespace Spine {
 
 
 		#endif // !(UNITY)
 		#endif // !(UNITY)
 
 
-		public Atlas (TextReader reader, String dir, TextureLoader textureLoader) {
+		public Atlas (TextReader reader, string dir, TextureLoader textureLoader) {
 			Load(reader, dir, textureLoader);
 			Load(reader, dir, textureLoader);
 		}
 		}
 
 
@@ -94,14 +94,14 @@ namespace Spine {
 			this.textureLoader = null;
 			this.textureLoader = null;
 		}
 		}
 
 
-		private void Load (TextReader reader, String imagesDir, TextureLoader textureLoader) {
+		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 cannot be null.");
 			this.textureLoader = textureLoader;
 			this.textureLoader = textureLoader;
 
 
-			String[] tuple = new String[4];
+			string[] tuple = new string[4];
 			AtlasPage page = null;
 			AtlasPage page = null;
 			while (true) {
 			while (true) {
-				String line = reader.ReadLine();
+				string line = reader.ReadLine();
 				if (line == null) break;
 				if (line == null) break;
 				if (line.Trim().Length == 0)
 				if (line.Trim().Length == 0)
 					page = null;
 					page = null;
@@ -120,7 +120,7 @@ namespace Spine {
 					page.minFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[0], false);
 					page.minFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[0], false);
 					page.magFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[1], false);
 					page.magFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[1], false);
 
 
-					String direction = ReadValue(reader);
+					string direction = ReadValue(reader);
 					page.uWrap = TextureWrap.ClampToEdge;
 					page.uWrap = TextureWrap.ClampToEdge;
 					page.vWrap = TextureWrap.ClampToEdge;
 					page.vWrap = TextureWrap.ClampToEdge;
 					if (direction == "x")
 					if (direction == "x")
@@ -189,16 +189,16 @@ namespace Spine {
 			}
 			}
 		}
 		}
 
 
-		static String ReadValue (TextReader reader) {
-			String line = reader.ReadLine();
+		static string ReadValue (TextReader reader) {
+			string line = reader.ReadLine();
 			int colon = line.IndexOf(':');
 			int colon = line.IndexOf(':');
 			if (colon == -1) throw new Exception("Invalid line: " + line);
 			if (colon == -1) throw new Exception("Invalid line: " + line);
 			return line.Substring(colon + 1).Trim();
 			return line.Substring(colon + 1).Trim();
 		}
 		}
 
 
 		/// <summary>Returns the number of tuple values read (1, 2 or 4).</summary>
 		/// <summary>Returns the number of tuple values read (1, 2 or 4).</summary>
-		static int ReadTuple (TextReader reader, String[] tuple) {
-			String line = reader.ReadLine();
+		static int ReadTuple (TextReader reader, string[] tuple) {
+			string line = reader.ReadLine();
 			int colon = line.IndexOf(':');
 			int colon = line.IndexOf(':');
 			if (colon == -1) throw new Exception("Invalid line: " + line);
 			if (colon == -1) throw new Exception("Invalid line: " + line);
 			int i = 0, lastMatch = colon + 1;
 			int i = 0, lastMatch = colon + 1;
@@ -223,7 +223,7 @@ namespace Spine {
 		/// <summary>Returns the first region found with the specified name. This method uses string comparison to find the region, so the result
 		/// <summary>Returns the first region found with the specified name. This method uses string comparison to find the region, so the result
 		/// should be cached rather than calling this method multiple times.</summary>
 		/// should be cached rather than calling this method multiple times.</summary>
 		/// <returns>The region, or null.</returns>
 		/// <returns>The region, or null.</returns>
-		public AtlasRegion FindRegion (String name) {
+		public AtlasRegion FindRegion (string name) {
 			for (int i = 0, n = regions.Count; i < n; i++)
 			for (int i = 0, n = regions.Count; i < n; i++)
 				if (regions[i].name == name) return regions[i];
 				if (regions[i].name == name) return regions[i];
 			return null;
 			return null;
@@ -263,7 +263,7 @@ namespace Spine {
 	}
 	}
 
 
 	public class AtlasPage {
 	public class AtlasPage {
-		public String name;
+		public string name;
 		public Format format;
 		public Format format;
 		public TextureFilter minFilter;
 		public TextureFilter minFilter;
 		public TextureFilter magFilter;
 		public TextureFilter magFilter;
@@ -275,7 +275,7 @@ namespace Spine {
 
 
 	public class AtlasRegion {
 	public class AtlasRegion {
 		public AtlasPage page;
 		public AtlasPage page;
-		public String name;
+		public string name;
 		public int x, y, width, height;
 		public int x, y, width, height;
 		public float u, v, u2, v2;
 		public float u, v, u2, v2;
 		public float offsetX, offsetY;
 		public float offsetX, offsetY;
@@ -287,7 +287,7 @@ namespace Spine {
 	}
 	}
 
 
 	public interface TextureLoader {
 	public interface TextureLoader {
-		void Load (AtlasPage page, String path);
+		void Load (AtlasPage page, string path);
 		void Unload (Object texture);
 		void Unload (Object texture);
 	}
 	}
 }
 }

+ 37 - 49
spine-csharp/src/Attachments/RegionAttachment.cs

@@ -76,29 +76,6 @@ namespace Spine {
 			: base(name) {
 			: base(name) {
 		}
 		}
 
 
-		public void SetUVs (float u, float v, float u2, float v2, bool rotate) {
-			float[] uvs = this.uvs;
-			if (rotate) {
-				uvs[ULX] = u;
-				uvs[ULY] = v2;
-				uvs[URX] = u;
-				uvs[URY] = v;
-				uvs[BRX] = u2;
-				uvs[BRY] = v;
-				uvs[BLX] = u2;
-				uvs[BLY] = v2;
-			} else {
-				uvs[BLX] = u;
-				uvs[BLY] = v2;
-				uvs[ULX] = u;
-				uvs[ULY] = v;
-				uvs[URX] = u2;
-				uvs[URY] = v;
-				uvs[BRX] = u2;
-				uvs[BRY] = v2;
-			}
-		}
-
 		public void UpdateOffset () {
 		public void UpdateOffset () {
 			float width = this.width;
 			float width = this.width;
 			float height = this.height;
 			float height = this.height;
@@ -134,20 +111,29 @@ namespace Spine {
 			offset[BRY] = localYCos + localX2Sin;
 			offset[BRY] = localYCos + localX2Sin;
 		}
 		}
 
 
-//		[Obsolete("Please use the new ComputeWorldVertices that requires offset and stride parameters introduced in 3.6")]
-//		public void ComputeWorldVertices (Bone bone, float[] worldVertices) {
-//			float x = bone.worldX, y = bone.worldY;			
-//			float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
-//			float[] offset = this.offset;
-//			worldVertices[BLX] = offset[BLX] * a + offset[BLY] * b + x;
-//			worldVertices[BLY] = offset[BLX] * c + offset[BLY] * d + y;
-//			worldVertices[ULX] = offset[ULX] * a + offset[ULY] * b + x;
-//			worldVertices[ULY] = offset[ULX] * c + offset[ULY] * d + y;
-//			worldVertices[URX] = offset[URX] * a + offset[URY] * b + x;
-//			worldVertices[URY] = offset[URX] * c + offset[URY] * d + y;
-//			worldVertices[BRX] = offset[BRX] * a + offset[BRY] * b + x;
-//			worldVertices[BRY] = offset[BRX] * c + offset[BRY] * d + y;
-//		}
+		public void SetUVs (float u, float v, float u2, float v2, bool rotate) {
+			float[] uvs = this.uvs;
+			// UV values differ from RegionAttachment.java
+			if (rotate) {
+				uvs[ULX] = u;
+				uvs[ULY] = v2;
+				uvs[URX] = u;
+				uvs[URY] = v;
+				uvs[BRX] = u2;
+				uvs[BRY] = v;
+				uvs[BLX] = u2;
+				uvs[BLY] = v2;
+			} else {
+				uvs[BLX] = u;
+				uvs[BLY] = v2;
+				uvs[ULX] = u;
+				uvs[ULY] = v;
+				uvs[URX] = u2;
+				uvs[URY] = v;
+				uvs[BRX] = u2;
+				uvs[BRY] = v2;
+			}
+		}
 
 
 		/// <summary>Transforms the attachment's four vertices to world coordinates.</summary>
 		/// <summary>Transforms the attachment's four vertices to world coordinates.</summary>
 		/// <param name="bone">The parent bone.</param>
 		/// <param name="bone">The parent bone.</param>
@@ -160,28 +146,30 @@ namespace Spine {
 			float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
 			float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
 			float offsetX, offsetY;
 			float offsetX, offsetY;
 
 
-			offsetX = vertexOffset[BRX];
-			offsetY = vertexOffset[BRY];
-			worldVertices[offset] = offsetX * a + offsetY * b + bwx; // br
-			worldVertices[offset + 1] = offsetX * c + offsetY * d + bwy;
-			offset += stride;
-
-			offsetX = vertexOffset[BLX];
-			offsetY = vertexOffset[BLY];
+			// Vertex order is different from RegionAttachment.java
+			offsetX = vertexOffset[BLX]; // 0
+			offsetY = vertexOffset[BLY]; // 1
 			worldVertices[offset] = offsetX * a + offsetY * b + bwx; // bl
 			worldVertices[offset] = offsetX * a + offsetY * b + bwx; // bl
 			worldVertices[offset + 1] = offsetX * c + offsetY * d + bwy;
 			worldVertices[offset + 1] = offsetX * c + offsetY * d + bwy;
 			offset += stride;
 			offset += stride;
 
 
-			offsetX = vertexOffset[ULX];
-			offsetY = vertexOffset[ULY];
+			offsetX = vertexOffset[ULX]; // 2
+			offsetY = vertexOffset[ULY]; // 3
 			worldVertices[offset] = offsetX * a + offsetY * b + bwx; // ul
 			worldVertices[offset] = offsetX * a + offsetY * b + bwx; // ul
 			worldVertices[offset + 1] = offsetX * c + offsetY * d + bwy;
 			worldVertices[offset + 1] = offsetX * c + offsetY * d + bwy;
 			offset += stride;
 			offset += stride;
 
 
-			offsetX = vertexOffset[URX];
-			offsetY = vertexOffset[URY];
+			offsetX = vertexOffset[URX]; // 4
+			offsetY = vertexOffset[URY]; // 5
 			worldVertices[offset] = offsetX * a + offsetY * b + bwx; // ur
 			worldVertices[offset] = offsetX * a + offsetY * b + bwx; // ur
 			worldVertices[offset + 1] = offsetX * c + offsetY * d + bwy;
 			worldVertices[offset + 1] = offsetX * c + offsetY * d + bwy;
+			offset += stride;
+
+			offsetX = vertexOffset[BRX]; // 6
+			offsetY = vertexOffset[BRY]; // 7
+			worldVertices[offset] = offsetX * a + offsetY * b + bwx; // br
+			worldVertices[offset + 1] = offsetX * c + offsetY * d + bwy;
+			//offset += stride;
 		}
 		}
 	}
 	}
 }
 }

+ 7 - 7
spine-csharp/src/SkeletonJson.cs

@@ -149,9 +149,9 @@ namespace Spine {
 
 
 					if (slotMap.ContainsKey("dark")) {
 					if (slotMap.ContainsKey("dark")) {
 						var color2 = (String)slotMap["dark"];
 						var color2 = (String)slotMap["dark"];
-						data.r2 = ToColor(color2, 0);
-						data.g2 = ToColor(color2, 1);
-						data.b2 = ToColor(color2, 2);
+						data.r2 = ToColor(color2, 0, 6); // expectedLength = 6. ie. "RRGGBB"
+						data.g2 = ToColor(color2, 1, 6);
+						data.b2 = ToColor(color2, 2, 6);
 						data.hasSecondColor = true;
 						data.hasSecondColor = true;
 					}
 					}
 						
 						
@@ -500,7 +500,7 @@ namespace Spine {
 								string light = (string)valueMap["light"];
 								string light = (string)valueMap["light"];
 								string dark = (string)valueMap["dark"];
 								string dark = (string)valueMap["dark"];
 								timeline.SetFrame(frameIndex, time, ToColor(light, 0), ToColor(light, 1), ToColor(light, 2), ToColor(light, 3),
 								timeline.SetFrame(frameIndex, time, ToColor(light, 0), ToColor(light, 1), ToColor(light, 2), ToColor(light, 3),
-									ToColor(dark, 0), ToColor(dark, 1), ToColor(dark, 2));
+									ToColor(dark, 0, 6), ToColor(dark, 1, 6), ToColor(dark, 2, 6));
 								ReadCurve(valueMap, timeline, frameIndex);
 								ReadCurve(valueMap, timeline, frameIndex);
 								frameIndex++;
 								frameIndex++;
 							}
 							}
@@ -840,9 +840,9 @@ namespace Spine {
 			return (String)map[name];
 			return (String)map[name];
 		}
 		}
 
 
-		static float ToColor(String hexString, int colorIndex) {
-			if (hexString.Length != 8)
-				throw new ArgumentException("Color hexidecimal length must be 8, recieved: " + hexString, "hexString");
+		static float ToColor(String hexString, int colorIndex, int expectedLength = 8) {
+			if (hexString.Length != expectedLength)
+				throw new ArgumentException("Color hexidecimal length must be " + expectedLength + ", recieved: " + hexString, "hexString");
 			return Convert.ToInt32(hexString.Substring(colorIndex * 2, 2), 16) / (float)255;
 			return Convert.ToInt32(hexString.Substring(colorIndex * 2, 2), 16) / (float)255;
 		}
 		}
 	}
 	}

+ 2 - 2
spine-unity/Assets/spine-unity/Asset Types/Editor/SkeletonDataAssetInspector.cs

@@ -574,8 +574,8 @@ namespace Spine.Unity.Editor {
 					#else
 					#else
 					if (spriteCollection.objectReferenceValue == null)
 					if (spriteCollection.objectReferenceValue == null)
 						warnings.Add("SkeletonDataAsset requires tk2DSpriteCollectionData.");
 						warnings.Add("SkeletonDataAsset requires tk2DSpriteCollectionData.");
-					else
-						warnings.Add("Your sprite collection may have missing images.");
+//					else
+//						warnings.Add("Your sprite collection may have missing images.");
 					#endif
 					#endif
 				}
 				}
 			}
 			}

+ 1 - 1
spine-unity/Assets/spine-unity/Editor/SkeletonBaker.cs

@@ -543,7 +543,7 @@ namespace Spine.Unity.Editor {
 
 
 			Vector2[] uvs = ExtractUV(attachment.UVs);
 			Vector2[] uvs = ExtractUV(attachment.UVs);
 			float[] floatVerts = new float[8];
 			float[] floatVerts = new float[8];
-			attachment.ComputeWorldVertices(bone, floatVerts);
+			attachment.ComputeWorldVertices(bone, floatVerts, 0);
 			Vector3[] verts = ExtractVerts(floatVerts);
 			Vector3[] verts = ExtractVerts(floatVerts);
 
 
 			//unrotate verts now that they're centered
 			//unrotate verts now that they're centered

+ 5 - 2
spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs

@@ -43,12 +43,12 @@ namespace Spine.Unity.Editor {
 		protected static bool advancedFoldout;
 		protected static bool advancedFoldout;
 		protected static bool showBoneNames, showPaths, showShapes, showConstraints = true;
 		protected static bool showBoneNames, showPaths, showShapes, showConstraints = true;
 
 
-		protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes, immutableTriangles, separatorSlotNames, frontFacing, zSpacing, pmaVertexColors, clearStateOnDisable;
+		protected SerializedProperty skeletonDataAsset, initialSkinName, normals, tangents, meshes, immutableTriangles, separatorSlotNames, frontFacing, zSpacing, pmaVertexColors, clearStateOnDisable, tintBlack;
 		protected SpineInspectorUtility.SerializedSortingProperties sortingProperties;
 		protected SpineInspectorUtility.SerializedSortingProperties sortingProperties;
 		protected bool isInspectingPrefab;
 		protected bool isInspectingPrefab;
 
 
 		protected GUIContent SkeletonDataAssetLabel, SkeletonUtilityButtonContent;
 		protected GUIContent SkeletonDataAssetLabel, SkeletonUtilityButtonContent;
-		protected GUIContent PMAVertexColorsLabel, ClearStateOnDisableLabel, ZSpacingLabel, MeshesLabel, ImmubleTrianglesLabel;
+		protected GUIContent PMAVertexColorsLabel, ClearStateOnDisableLabel, ZSpacingLabel, MeshesLabel, ImmubleTrianglesLabel, TintBlackLabel;
 		protected GUIContent NormalsLabel, TangentsLabel;
 		protected GUIContent NormalsLabel, TangentsLabel;
 		const string ReloadButtonLabel = "Reload";
 		const string ReloadButtonLabel = "Reload";
 
 
@@ -83,6 +83,7 @@ namespace Spine.Unity.Editor {
 			ZSpacingLabel = new GUIContent("Z Spacing", "A value other than 0 adds a space between each rendered attachment to prevent Z Fighting when using shaders that read or write to the depth buffer. Large values may cause unwanted parallax and spaces depending on camera setup.");
 			ZSpacingLabel = new GUIContent("Z Spacing", "A value other than 0 adds a space between each rendered attachment to prevent Z Fighting when using shaders that read or write to the depth buffer. Large values may cause unwanted parallax and spaces depending on camera setup.");
 			NormalsLabel = new GUIContent("Add Normals", "Use this if your shader requires vertex normals. A more efficient solution for 2D setups is to modify the shader to assume a single normal value for the whole mesh.");
 			NormalsLabel = new GUIContent("Add Normals", "Use this if your shader requires vertex normals. A more efficient solution for 2D setups is to modify the shader to assume a single normal value for the whole mesh.");
 			TangentsLabel = new GUIContent("Solve Tangents", "Calculates the tangents per frame. Use this if you are using lit shaders (usually with normal maps) that require vertex tangents.");
 			TangentsLabel = new GUIContent("Solve Tangents", "Calculates the tangents per frame. Use this if you are using lit shaders (usually with normal maps) that require vertex tangents.");
+			TintBlackLabel = new GUIContent("Tint Black", "Adds black tint vertex data to the mesh as UV2 and UV3. Black tinting requires that the shader interpret UV2 and UV3 as black tint colors for this effect to work. You may also use the default [Spine/Skeleton Tint Black] shader.\n\nIf you only need to tint the whole skeleton and not individual parts, the [Spine/Skeleton Tint] shader is recommended for better efficiency and changing/animating the _Black material property via MaterialPropertyBlock.");
 
 
 			var so = this.serializedObject;
 			var so = this.serializedObject;
 			skeletonDataAsset = so.FindProperty("skeletonDataAsset");
 			skeletonDataAsset = so.FindProperty("skeletonDataAsset");
@@ -93,6 +94,7 @@ namespace Spine.Unity.Editor {
 			immutableTriangles = so.FindProperty("immutableTriangles");
 			immutableTriangles = so.FindProperty("immutableTriangles");
 			pmaVertexColors = so.FindProperty("pmaVertexColors");
 			pmaVertexColors = so.FindProperty("pmaVertexColors");
 			clearStateOnDisable = so.FindProperty("clearStateOnDisable");
 			clearStateOnDisable = so.FindProperty("clearStateOnDisable");
+			tintBlack = so.FindProperty("tintBlack");
 
 
 			separatorSlotNames = so.FindProperty("separatorSlotNames");
 			separatorSlotNames = so.FindProperty("separatorSlotNames");
 			separatorSlotNames.isExpanded = true;
 			separatorSlotNames.isExpanded = true;
@@ -237,6 +239,7 @@ namespace Spine.Unity.Editor {
 							// Optimization options
 							// Optimization options
 							EditorGUILayout.PropertyField(meshes, MeshesLabel);
 							EditorGUILayout.PropertyField(meshes, MeshesLabel);
 							EditorGUILayout.PropertyField(immutableTriangles, ImmubleTrianglesLabel);
 							EditorGUILayout.PropertyField(immutableTriangles, ImmubleTrianglesLabel);
+							EditorGUILayout.PropertyField(tintBlack, TintBlackLabel);
 							EditorGUILayout.PropertyField(clearStateOnDisable, ClearStateOnDisableLabel);
 							EditorGUILayout.PropertyField(clearStateOnDisable, ClearStateOnDisableLabel);
 							EditorGUILayout.Space();
 							EditorGUILayout.Space();
 						}
 						}

+ 5 - 1
spine-unity/Assets/spine-unity/Editor/SpineEditorUtilities.cs

@@ -914,6 +914,10 @@ namespace Spine.Unity.Editor {
 			public PathAttachment NewPathAttachment (Skin skin, string name) {
 			public PathAttachment NewPathAttachment (Skin skin, string name) {
 				return new PathAttachment(name);
 				return new PathAttachment(name);
 			}
 			}
+
+			public PointAttachment NewPointAttachment (Skin skin, string name) {
+				return new PointAttachment(name);
+			}
 		}
 		}
 		#endregion
 		#endregion
 
 
@@ -1165,7 +1169,7 @@ namespace Spine.Unity.Editor {
 		#endregion
 		#endregion
 
 
 		#region Checking Methods
 		#region Checking Methods
-		static int[][] compatibleVersions = { new[] {3, 5, 0} };
+		static int[][] compatibleVersions = { new[] {3, 6, 0} };
 		//static bool isFixVersionRequired = false;
 		//static bool isFixVersionRequired = false;
 
 
 		static bool CheckForValidSkeletonData (string skeletonJSONPath) {
 		static bool CheckForValidSkeletonData (string skeletonJSONPath) {

+ 62 - 11
spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysMeshGenerator.cs

@@ -39,6 +39,8 @@ namespace Spine.Unity.MeshGeneration {
 		public bool AddNormals { get { return addNormals; } set { addNormals = value; } }
 		public bool AddNormals { get { return addNormals; } set { addNormals = value; } }
 		protected bool addTangents;
 		protected bool addTangents;
 		public bool AddTangents { get { return addTangents; } set { addTangents = value; } }
 		public bool AddTangents { get { return addTangents; } set { addTangents = value; } }
+		protected bool addBlackTint;
+		public bool AddBlackTint { get { return addBlackTint; } set { addBlackTint = value; } }
 		#endregion
 		#endregion
 
 
 		protected float[] attachmentVertexBuffer = new float[8];
 		protected float[] attachmentVertexBuffer = new float[8];
@@ -52,6 +54,8 @@ namespace Spine.Unity.MeshGeneration {
 		protected Vector4[] meshTangents;
 		protected Vector4[] meshTangents;
 		protected Vector2[] tempTanBuffer;
 		protected Vector2[] tempTanBuffer;
 
 
+		protected Vector2[] uv2, uv3; // Black tint
+
 		public void TryAddNormalsTo (Mesh mesh, int targetVertexCount) {
 		public void TryAddNormalsTo (Mesh mesh, int targetVertexCount) {
 			#if SPINE_OPTIONAL_NORMALS
 			#if SPINE_OPTIONAL_NORMALS
 			if (addNormals) {
 			if (addNormals) {
@@ -88,6 +92,19 @@ namespace Spine.Unity.MeshGeneration {
 			return verticesWasResized;
 			return verticesWasResized;
 		}
 		}
 
 
+		public static bool EnsureSize (int targetVertexCount, ref Vector2[] buffer) {
+			Vector2[] buff = buffer;
+			bool verticesWasResized = (buffer == null || targetVertexCount > buffer.Length);
+			if (verticesWasResized) {
+				buffer = new Vector2[targetVertexCount];
+			} else {
+				Vector3 zero = Vector3.zero;
+				for (int i = targetVertexCount, n = buff.Length; i < n; i++)
+					buff[i] = zero;
+			}
+			return verticesWasResized;
+		}
+
 		public static bool EnsureTriangleBuffersSize (ExposedList<SubmeshTriangleBuffer> submeshBuffers, int targetSubmeshCount, SubmeshInstruction[] instructionItems) {
 		public static bool EnsureTriangleBuffersSize (ExposedList<SubmeshTriangleBuffer> submeshBuffers, int targetSubmeshCount, SubmeshInstruction[] instructionItems) {
 			bool submeshBuffersWasResized = submeshBuffers.Count < targetSubmeshCount;
 			bool submeshBuffersWasResized = submeshBuffers.Count < targetSubmeshCount;
 			if (submeshBuffersWasResized) {
 			if (submeshBuffersWasResized) {
@@ -98,6 +115,40 @@ namespace Spine.Unity.MeshGeneration {
 			return submeshBuffersWasResized;
 			return submeshBuffersWasResized;
 		}
 		}
 
 
+		public static void FillBlackUVs (Skeleton skeleton, int startSlot, int endSlot, Vector2[] uv2, Vector2[] uv3, int vertexIndex, bool renderMeshes = true) {
+			var skeletonDrawOrderItems = skeleton.DrawOrder.Items;
+			Vector2 rg, b2;
+			int vi = vertexIndex;
+			b2.y = 1f;
+
+			// drawOrder[endSlot] is excluded
+			for (int slotIndex = startSlot; slotIndex < endSlot; slotIndex++) {
+				var slot = skeletonDrawOrderItems[slotIndex];
+				var attachment = slot.attachment;
+
+				rg.x = slot.r2; //r
+				rg.y = slot.g2; //g
+				b2.x = slot.b2; //b
+
+				var regionAttachment = attachment as RegionAttachment;
+				if (regionAttachment != null) {
+					uv2[vi] = rg; uv2[vi + 1] = rg; uv2[vi + 2] = rg; uv2[vi + 3] = rg;
+					uv3[vi] = b2; uv3[vi + 1] = b2; uv3[vi + 2] = b2; uv3[vi + 3] = b2;
+					vi += 4;
+				} else if (renderMeshes) {
+					var meshAttachment = attachment as MeshAttachment;
+					if (meshAttachment != null) {
+						int meshVertexCount = meshAttachment.worldVerticesLength;
+						for (int iii = 0; iii < meshVertexCount; iii += 2) {
+							uv2[vi] = rg;
+							uv3[vi] = b2;
+							vi++;
+						}
+					}
+				}
+			}
+		}
+
 		/// <summary>Fills Unity vertex data buffers with verts from the Spine Skeleton.</summary>
 		/// <summary>Fills Unity vertex data buffers with verts from the Spine Skeleton.</summary>
 		/// <param name="skeleton">Spine.Skeleton source of the drawOrder array</param>
 		/// <param name="skeleton">Spine.Skeleton source of the drawOrder array</param>
 		/// <param name="startSlot">Slot index of the first slot.</param>
 		/// <param name="startSlot">Slot index of the first slot.</param>
@@ -130,12 +181,12 @@ namespace Spine.Unity.MeshGeneration {
 
 
 				var regionAttachment = attachment as RegionAttachment;
 				var regionAttachment = attachment as RegionAttachment;
 				if (regionAttachment != null) {
 				if (regionAttachment != null) {
-					regionAttachment.ComputeWorldVertices(slot.bone, tempVerts);
+					regionAttachment.ComputeWorldVertices(slot.bone, tempVerts, 0);
 
 
-					float x1 = tempVerts[RegionAttachment.X1], y1 = tempVerts[RegionAttachment.Y1];
-					float x2 = tempVerts[RegionAttachment.X2], y2 = tempVerts[RegionAttachment.Y2];
-					float x3 = tempVerts[RegionAttachment.X3], y3 = tempVerts[RegionAttachment.Y3];
-					float x4 = tempVerts[RegionAttachment.X4], y4 = tempVerts[RegionAttachment.Y4];
+					float x1 = tempVerts[RegionAttachment.BLX], y1 = tempVerts[RegionAttachment.BLY];
+					float x2 = tempVerts[RegionAttachment.ULX], y2 = tempVerts[RegionAttachment.ULY];
+					float x3 = tempVerts[RegionAttachment.URX], y3 = tempVerts[RegionAttachment.URY];
+					float x4 = tempVerts[RegionAttachment.BRX], y4 = tempVerts[RegionAttachment.BRY];
 					verts[vi].x = x1; verts[vi].y = y1; verts[vi].z = z;
 					verts[vi].x = x1; verts[vi].y = y1; verts[vi].z = z;
 					verts[vi + 1].x = x4; verts[vi + 1].y = y4; verts[vi + 1].z = z;
 					verts[vi + 1].x = x4; verts[vi + 1].y = y4; verts[vi + 1].z = z;
 					verts[vi + 2].x = x2; verts[vi + 2].y = y2; verts[vi + 2].z = z;
 					verts[vi + 2].x = x2; verts[vi + 2].y = y2; verts[vi + 2].z = z;
@@ -146,7 +197,7 @@ namespace Spine.Unity.MeshGeneration {
 						color.r = (byte)(r * slot.r * regionAttachment.r * color.a);
 						color.r = (byte)(r * slot.r * regionAttachment.r * color.a);
 						color.g = (byte)(g * slot.g * regionAttachment.g * color.a);
 						color.g = (byte)(g * slot.g * regionAttachment.g * color.a);
 						color.b = (byte)(b * slot.b * regionAttachment.b * color.a);
 						color.b = (byte)(b * slot.b * regionAttachment.b * color.a);
-						if (slot.data.blendMode == BlendMode.additive) color.a = 0;
+						if (slot.data.blendMode == BlendMode.Additive) color.a = 0;
 					} else {
 					} else {
 						color.a = (byte)(a * slot.a * regionAttachment.a);
 						color.a = (byte)(a * slot.a * regionAttachment.a);
 						color.r = (byte)(r * slot.r * regionAttachment.r * 255);
 						color.r = (byte)(r * slot.r * regionAttachment.r * 255);
@@ -157,10 +208,10 @@ namespace Spine.Unity.MeshGeneration {
 					colors[vi] = color; colors[vi + 1] = color; colors[vi + 2] = color; colors[vi + 3] = color;
 					colors[vi] = color; colors[vi + 1] = color; colors[vi + 2] = color; colors[vi + 3] = color;
 
 
 					float[] regionUVs = regionAttachment.uvs;
 					float[] regionUVs = regionAttachment.uvs;
-					uvs[vi].x = regionUVs[RegionAttachment.X1]; uvs[vi].y = regionUVs[RegionAttachment.Y1];
-					uvs[vi + 1].x = regionUVs[RegionAttachment.X4]; uvs[vi + 1].y = regionUVs[RegionAttachment.Y4];
-					uvs[vi + 2].x = regionUVs[RegionAttachment.X2]; uvs[vi + 2].y = regionUVs[RegionAttachment.Y2];
-					uvs[vi + 3].x = regionUVs[RegionAttachment.X3]; uvs[vi + 3].y = regionUVs[RegionAttachment.Y3];
+					uvs[vi].x = regionUVs[RegionAttachment.BLX]; uvs[vi].y = regionUVs[RegionAttachment.BLY];
+					uvs[vi + 1].x = regionUVs[RegionAttachment.BRX]; uvs[vi + 1].y = regionUVs[RegionAttachment.BRY];
+					uvs[vi + 2].x = regionUVs[RegionAttachment.ULX]; uvs[vi + 2].y = regionUVs[RegionAttachment.ULY];
+					uvs[vi + 3].x = regionUVs[RegionAttachment.URX]; uvs[vi + 3].y = regionUVs[RegionAttachment.URY];
 
 
 					if (x1 < bmin.x) bmin.x = x1; // Potential first attachment bounds initialization. Initial min should not block initial max. Same for Y below.
 					if (x1 < bmin.x) bmin.x = x1; // Potential first attachment bounds initialization. Initial min should not block initial max. Same for Y below.
 					if (x1 > bmax.x) bmax.x = x1;
 					if (x1 > bmax.x) bmax.x = x1;
@@ -193,7 +244,7 @@ namespace Spine.Unity.MeshGeneration {
 							color.r = (byte)(r * slot.r * meshAttachment.r * color.a);
 							color.r = (byte)(r * slot.r * meshAttachment.r * color.a);
 							color.g = (byte)(g * slot.g * meshAttachment.g * color.a);
 							color.g = (byte)(g * slot.g * meshAttachment.g * color.a);
 							color.b = (byte)(b * slot.b * meshAttachment.b * color.a);
 							color.b = (byte)(b * slot.b * meshAttachment.b * color.a);
-							if (slot.data.blendMode == BlendMode.additive) color.a = 0;
+							if (slot.data.blendMode == BlendMode.Additive) color.a = 0;
 						} else {
 						} else {
 							color.a = (byte)(a * slot.a * meshAttachment.a);
 							color.a = (byte)(a * slot.a * meshAttachment.a);
 							color.r = (byte)(r * slot.r * meshAttachment.r * 255);
 							color.r = (byte)(r * slot.r * meshAttachment.r * 255);

+ 11 - 0
spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSimpleMeshGenerator.cs

@@ -74,6 +74,11 @@ namespace Spine.Unity.MeshGeneration {
 
 
 			// STEP 2 : Ensure buffers are the correct size
 			// STEP 2 : Ensure buffers are the correct size
 			ArraysMeshGenerator.EnsureSize(totalVertexCount, ref this.meshVertices, ref this.meshUVs, ref this.meshColors32);
 			ArraysMeshGenerator.EnsureSize(totalVertexCount, ref this.meshVertices, ref this.meshUVs, ref this.meshColors32);
+			if (addBlackTint) {
+				ArraysMeshGenerator.EnsureSize(totalVertexCount, ref this.uv2);
+				ArraysMeshGenerator.EnsureSize(totalVertexCount, ref this.uv3);
+			}
+
 			this.triangles = this.triangles ?? new int[totalTriangleCount];
 			this.triangles = this.triangles ?? new int[totalTriangleCount];
 				
 				
 			// STEP 3 : Update vertex buffer
 			// STEP 3 : Update vertex buffer
@@ -92,6 +97,7 @@ namespace Spine.Unity.MeshGeneration {
 				meshBoundsMax.z = zFauxHalfThickness * scale;
 				meshBoundsMax.z = zFauxHalfThickness * scale;
 
 
 				int vertexIndex = 0;
 				int vertexIndex = 0;
+				if (addBlackTint) ArraysMeshGenerator.FillBlackUVs(skeleton, 0, drawOrderCount, this.uv2, this.uv3, vertexIndex);
 				ArraysMeshGenerator.FillVerts(skeleton, 0, drawOrderCount, this.ZSpacing, this.PremultiplyVertexColors, this.meshVertices, this.meshUVs, this.meshColors32, ref vertexIndex, ref this.attachmentVertexBuffer, ref meshBoundsMin, ref meshBoundsMax);
 				ArraysMeshGenerator.FillVerts(skeleton, 0, drawOrderCount, this.ZSpacing, this.PremultiplyVertexColors, this.meshVertices, this.meshUVs, this.meshColors32, ref vertexIndex, ref this.attachmentVertexBuffer, ref meshBoundsMin, ref meshBoundsMax);
 
 
 				// Apply scale to vertices
 				// Apply scale to vertices
@@ -116,6 +122,11 @@ namespace Spine.Unity.MeshGeneration {
 			mesh.uv = meshUVs;
 			mesh.uv = meshUVs;
 			mesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax);
 			mesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax);
 			mesh.triangles = triangles;
 			mesh.triangles = triangles;
+			if (addBlackTint) {
+				mesh.uv2 = this.uv2;
+				mesh.uv3 = this.uv3;
+			}
+
 			TryAddNormalsTo(mesh, totalVertexCount);
 			TryAddNormalsTo(mesh, totalVertexCount);
 
 
 			if (addTangents) { 
 			if (addTangents) { 

+ 9 - 2
spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshSetMeshGenerator.cs

@@ -69,6 +69,10 @@ namespace Spine.Unity.MeshGeneration {
 			// STEP 1: Ensure correct buffer sizes.
 			// STEP 1: Ensure correct buffer sizes.
 			bool vertBufferResized = ArraysMeshGenerator.EnsureSize(vertexCount, ref this.meshVertices, ref this.meshUVs, ref this.meshColors32); 
 			bool vertBufferResized = ArraysMeshGenerator.EnsureSize(vertexCount, ref this.meshVertices, ref this.meshUVs, ref this.meshColors32); 
 			bool submeshBuffersResized = ArraysMeshGenerator.EnsureTriangleBuffersSize(submeshBuffers, submeshCount, currentInstructionsItems);
 			bool submeshBuffersResized = ArraysMeshGenerator.EnsureTriangleBuffersSize(submeshBuffers, submeshCount, currentInstructionsItems);
+			if (addBlackTint) {
+				ArraysMeshGenerator.EnsureSize(vertexCount, ref this.uv2);
+				ArraysMeshGenerator.EnsureSize(vertexCount, ref this.uv3);
+			}
 
 
 			// STEP 2: Update buffers based on Skeleton.
 			// STEP 2: Update buffers based on Skeleton.
 
 
@@ -109,6 +113,7 @@ namespace Spine.Unity.MeshGeneration {
 					var ca = skeletonDrawOrderItems[i].attachment;
 					var ca = skeletonDrawOrderItems[i].attachment;
 					if (ca != null) workingAttachments.Add(ca); // Includes BoundingBoxes. This is ok.
 					if (ca != null) workingAttachments.Add(ca); // Includes BoundingBoxes. This is ok.
 				}
 				}
+				if (addBlackTint) ArraysMeshGenerator.FillBlackUVs(skeleton, startSlot, endSlot, this.uv2, this.uv3, vertexIndex);
 				ArraysMeshGenerator.FillVerts(skeleton, startSlot, endSlot, zSpacing, this.PremultiplyVertexColors, this.meshVertices, this.meshUVs, this.meshColors32, ref vertexIndex, ref this.attachmentVertexBuffer, ref meshBoundsMin, ref meshBoundsMax);
 				ArraysMeshGenerator.FillVerts(skeleton, startSlot, endSlot, zSpacing, this.PremultiplyVertexColors, this.meshVertices, this.meshUVs, this.meshColors32, ref vertexIndex, ref this.attachmentVertexBuffer, ref meshBoundsMin, ref meshBoundsMax);
 			}
 			}
 
 
@@ -135,13 +140,15 @@ namespace Spine.Unity.MeshGeneration {
 					meshVertices[i].y *= scale;
 					meshVertices[i].y *= scale;
 					//meshVertices[i].z *= scale;
 					//meshVertices[i].z *= scale;
 				}
 				}
-					
 			}
 			}
 
 
 			// STEP 3: Assign the buffers into the Mesh.
 			// STEP 3: Assign the buffers into the Mesh.
 			smartMesh.Set(this.meshVertices, this.meshUVs, this.meshColors32, workingAttachments, currentInstructions);
 			smartMesh.Set(this.meshVertices, this.meshUVs, this.meshColors32, workingAttachments, currentInstructions);
 			mesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax);
 			mesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax);
-
+			if (addBlackTint) {
+				mesh.uv2 = this.uv2;
+				mesh.uv3 = this.uv3;
+			}
 
 
 			if (structureDoesntMatch) {
 			if (structureDoesntMatch) {
 				// Push new triangles if doesn't match.
 				// Push new triangles if doesn't match.

+ 11 - 1
spine-unity/Assets/spine-unity/Mesh Generation/Arrays/ArraysSubmeshedMeshGenerator.cs

@@ -41,7 +41,6 @@ namespace Spine.Unity.MeshGeneration {
 		public List<Slot> Separators { get { return this.separators; } }
 		public List<Slot> Separators { get { return this.separators; } }
 
 
 		#region Settings
 		#region Settings
-		// ArraysMeshGenerator.PremultiplyAlpha
 		public float ZSpacing { get; set; }
 		public float ZSpacing { get; set; }
 		#endregion
 		#endregion
 
 
@@ -160,6 +159,11 @@ namespace Spine.Unity.MeshGeneration {
 			bool vertBufferResized = ArraysMeshGenerator.EnsureSize(vertexCount, ref this.meshVertices, ref this.meshUVs, ref this.meshColors32);
 			bool vertBufferResized = ArraysMeshGenerator.EnsureSize(vertexCount, ref this.meshVertices, ref this.meshUVs, ref this.meshColors32);
 			Vector3[] vertices = this.meshVertices;
 			Vector3[] vertices = this.meshVertices;
 
 
+			if (addBlackTint) {
+				ArraysMeshGenerator.EnsureSize(vertexCount, ref this.uv2);
+				ArraysMeshGenerator.EnsureSize(vertexCount, ref this.uv3);
+			}
+
 			// STEP 2: Update buffers based on Skeleton.
 			// STEP 2: Update buffers based on Skeleton.
 			float zSpacing = this.ZSpacing;
 			float zSpacing = this.ZSpacing;
 			Vector3 meshBoundsMin;
 			Vector3 meshBoundsMin;
@@ -190,7 +194,9 @@ namespace Spine.Unity.MeshGeneration {
 				int start = submeshInstruction.startSlot;
 				int start = submeshInstruction.startSlot;
 				int end = submeshInstruction.endSlot;
 				int end = submeshInstruction.endSlot;
 				var skeleton = submeshInstruction.skeleton;
 				var skeleton = submeshInstruction.skeleton;
+				if (addBlackTint) ArraysMeshGenerator.FillBlackUVs(skeleton, start, end, this.uv2, this.uv3, vertexIndex);
 				ArraysMeshGenerator.FillVerts(skeleton, start, end, zSpacing, this.PremultiplyVertexColors, vertices, this.meshUVs, this.meshColors32, ref vertexIndex, ref this.attachmentVertexBuffer, ref meshBoundsMin, ref meshBoundsMax);
 				ArraysMeshGenerator.FillVerts(skeleton, start, end, zSpacing, this.PremultiplyVertexColors, vertices, this.meshUVs, this.meshColors32, ref vertexIndex, ref this.attachmentVertexBuffer, ref meshBoundsMin, ref meshBoundsMax);
+
 				if (structureDoesntMatch) {
 				if (structureDoesntMatch) {
 					var currentBuffer = submeshBuffers.Items[submeshIndex];
 					var currentBuffer = submeshBuffers.Items[submeshIndex];
 					bool isLastSubmesh = (submeshIndex == submeshCount - 1);
 					bool isLastSubmesh = (submeshIndex == submeshCount - 1);
@@ -207,6 +213,10 @@ namespace Spine.Unity.MeshGeneration {
 
 
 			// STEP 3: Assign the buffers into the Mesh.
 			// STEP 3: Assign the buffers into the Mesh.
 			smartMesh.Set(this.meshVertices, this.meshUVs, this.meshColors32, meshInstructions);
 			smartMesh.Set(this.meshVertices, this.meshUVs, this.meshColors32, meshInstructions);
+			if (addBlackTint) {
+				mesh.uv2 = this.uv2;
+				mesh.uv3 = this.uv3;
+			}
 			mesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax);
 			mesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax);
 
 
 			if (structureDoesntMatch) {
 			if (structureDoesntMatch) {

+ 1 - 0
spine-unity/Assets/spine-unity/Mesh Generation/ISimpleMeshGenerator.cs

@@ -43,5 +43,6 @@ namespace Spine.Unity.MeshGeneration {
 
 
 		bool AddNormals { get; set; }
 		bool AddNormals { get; set; }
 		bool AddTangents { get; set; }
 		bool AddTangents { get; set; }
+		bool AddBlackTint { get; set; }
 	}
 	}
 }
 }

+ 2 - 0
spine-unity/Assets/spine-unity/Mesh Generation/ISubmeshedMeshGenerator.cs

@@ -47,6 +47,7 @@ namespace Spine.Unity.MeshGeneration {
 		bool PremultiplyVertexColors { get; set; }
 		bool PremultiplyVertexColors { get; set; }
 		bool AddNormals { get; set; }
 		bool AddNormals { get; set; }
 		bool AddTangents { get; set; }
 		bool AddTangents { get; set; }
+		bool AddBlackTint { get; set; }
 	}
 	}
 
 
 	// ISubmeshSetMeshGenerator
 	// ISubmeshSetMeshGenerator
@@ -62,6 +63,7 @@ namespace Spine.Unity.MeshGeneration {
 		bool PremultiplyVertexColors { get; set; }
 		bool PremultiplyVertexColors { get; set; }
 		bool AddNormals { get; set; }
 		bool AddNormals { get; set; }
 		bool AddTangents { get; set; }
 		bool AddTangents { get; set; }
+		bool AddBlackTint { get; set; }
 	}
 	}
 
 
 	/// <summary>Primarily a collection of Submesh Instructions. This constitutes instructions for how to construct a mesh containing submeshes.</summary>
 	/// <summary>Primarily a collection of Submesh Instructions. This constitutes instructions for how to construct a mesh containing submeshes.</summary>

+ 6 - 4
spine-unity/Assets/spine-unity/Modules/AttachmentTools/AttachmentTools.cs

@@ -341,6 +341,8 @@ namespace Spine.Unity.Modules.AttachmentTools {
 			return Sprite.Create(ar.GetMainTexture(), ar.GetUnityRect(), new Vector2(0.5f, 0.5f), pixelsPerUnit);
 			return Sprite.Create(ar.GetMainTexture(), ar.GetUnityRect(), new Vector2(0.5f, 0.5f), pixelsPerUnit);
 		}
 		}
 
 
+		/// <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) {
 		public static Texture2D ToTexture (this AtlasRegion ar, bool applyImmediately = true) {
 			Texture2D sourceTexture = ar.GetMainTexture();
 			Texture2D sourceTexture = ar.GetMainTexture();
 			Rect r = ar.GetUnityRect(sourceTexture.height);
 			Rect r = ar.GetUnityRect(sourceTexture.height);
@@ -657,9 +659,9 @@ namespace Spine.Unity.Modules.AttachmentTools {
 			};
 			};
 
 
 			// Linked mesh
 			// Linked mesh
-			if (o.parentMesh != null) {
+			if (o.ParentMesh != null) {
 				// bones, vertices, worldVerticesLength, regionUVs, triangles, HullLength, Edges, Width, Height
 				// bones, vertices, worldVerticesLength, regionUVs, triangles, HullLength, Edges, Width, Height
-				ma.ParentMesh = o.parentMesh;
+				ma.ParentMesh = o.ParentMesh;
 			} else {
 			} else {
 				CloneVertexAttachment(o, ma); // bones, vertices, worldVerticesLength
 				CloneVertexAttachment(o, ma); // bones, vertices, worldVerticesLength
 				ma.regionUVs = o.regionUVs.Clone() as float[];
 				ma.regionUVs = o.regionUVs.Clone() as float[];
@@ -704,8 +706,8 @@ namespace Spine.Unity.Modules.AttachmentTools {
 			if (region == null) throw new System.ArgumentNullException("region");
 			if (region == null) throw new System.ArgumentNullException("region");
 
 
 			// If parentMesh is a linked mesh, create a link to its parent. Preserves Deform animations.
 			// If parentMesh is a linked mesh, create a link to its parent. Preserves Deform animations.
-			if (o.parentMesh != null)
-				o = o.parentMesh;
+			if (o.ParentMesh != null)
+				o = o.ParentMesh;
 
 
 			// 1. NewMeshAttachment (AtlasAttachmentLoader.cs)
 			// 1. NewMeshAttachment (AtlasAttachmentLoader.cs)
 			var mesh = new MeshAttachment(newLinkedMeshName);
 			var mesh = new MeshAttachment(newLinkedMeshName);

+ 3 - 8
spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs

@@ -28,10 +28,6 @@
  * POSSIBILITY OF SUCH DAMAGE.
  * POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
  *****************************************************************************/
 
 
-#if (UNITY_5_0 || UNITY_5_1 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7)
-#define PREUNITY_5_2
-#endif
-
 using UnityEngine;
 using UnityEngine;
 using UnityEditor;
 using UnityEditor;
 using Spine;
 using Spine;
@@ -44,8 +40,7 @@ namespace Spine.Unity.Editor {
 	public class SkeletonGraphicInspector : UnityEditor.Editor {
 	public class SkeletonGraphicInspector : UnityEditor.Editor {
 		SerializedProperty material_, color_;
 		SerializedProperty material_, color_;
 		SerializedProperty skeletonDataAsset_, initialSkinName_;
 		SerializedProperty skeletonDataAsset_, initialSkinName_;
-		SerializedProperty startingAnimation_, startingLoop_, timeScale_, freeze_, unscaledTime_;
-	#if !PREUNITY_5_2
+		SerializedProperty startingAnimation_, startingLoop_, timeScale_, freeze_, unscaledTime_, tintBlack_;
 		SerializedProperty raycastTarget_;
 		SerializedProperty raycastTarget_;
 
 
 		SkeletonGraphic thisSkeletonGraphic;
 		SkeletonGraphic thisSkeletonGraphic;
@@ -62,6 +57,7 @@ namespace Spine.Unity.Editor {
 			// SkeletonRenderer
 			// SkeletonRenderer
 			skeletonDataAsset_ = so.FindProperty("skeletonDataAsset");
 			skeletonDataAsset_ = so.FindProperty("skeletonDataAsset");
 			initialSkinName_ = so.FindProperty("initialSkinName");
 			initialSkinName_ = so.FindProperty("initialSkinName");
+			//tintBlack_ = so.FindProperty("tintBlack");
 
 
 			// SkeletonAnimation
 			// SkeletonAnimation
 			startingAnimation_ = so.FindProperty("startingAnimation");
 			startingAnimation_ = so.FindProperty("startingAnimation");
@@ -87,6 +83,7 @@ namespace Spine.Unity.Editor {
 
 
 			EditorGUILayout.Space();
 			EditorGUILayout.Space();
 			EditorGUILayout.PropertyField(initialSkinName_);
 			EditorGUILayout.PropertyField(initialSkinName_);
+			//EditorGUILayout.PropertyField(tintBlack_);
 			EditorGUILayout.Space();
 			EditorGUILayout.Space();
 			EditorGUILayout.LabelField("Animation", EditorStyles.boldLabel);
 			EditorGUILayout.LabelField("Animation", EditorStyles.boldLabel);
 			EditorGUILayout.PropertyField(startingAnimation_);
 			EditorGUILayout.PropertyField(startingAnimation_);
@@ -228,7 +225,5 @@ namespace Spine.Unity.Editor {
 		}
 		}
 
 
 		#endregion
 		#endregion
-
-	#endif
 	}
 	}
 }
 }

+ 3 - 47
spine-unity/Assets/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs

@@ -28,40 +28,6 @@
  * POSSIBILITY OF SUCH DAMAGE.
  * POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
  *****************************************************************************/
 
 
-/******************************************************************************
- * Spine Runtimes Software License
- * Version 2.3
- * 
- * Copyright (c) 2013-2015, Esoteric Software
- * All rights reserved.
- * 
- * You are granted a perpetual, non-exclusive, non-sublicensable and
- * non-transferable license to use, install, execute and perform the Spine
- * Runtimes Software (the "Software") and derivative works solely for personal
- * or internal use. Without the written permission of Esoteric Software (see
- * Section 2 of the Spine Software License Agreement), you may not (a) modify,
- * translate, adapt or otherwise create derivative works, improvements of the
- * Software or develop new applications using the Software or (b) remove,
- * delete, alter or obscure any trademarks or any copyright, trademark, patent
- * or other intellectual property or proprietary rights notices on or in the
- * Software, including any copy thereof. Redistributions in binary or source
- * form must include this license and terms.
- * 
- * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
-#if (UNITY_5_0 || UNITY_5_1 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7)
-#define PREUNITY_5_2
-#endif
-
 using UnityEngine;
 using UnityEngine;
 using UnityEngine.UI;
 using UnityEngine.UI;
 using Spine;
 using Spine;
@@ -84,12 +50,12 @@ namespace Spine.Unity {
 		public float timeScale = 1f;
 		public float timeScale = 1f;
 		public bool freeze;
 		public bool freeze;
 		public bool unscaledTime;
 		public bool unscaledTime;
+		//public bool tintBlack = false;
 
 
 		#if UNITY_EDITOR
 		#if UNITY_EDITOR
 		protected override void OnValidate () {
 		protected override void OnValidate () {
 			// This handles Scene View preview.
 			// This handles Scene View preview.
 			base.OnValidate ();
 			base.OnValidate ();
-			#if !PREUNITY_5_2
 			if (this.IsValid) {
 			if (this.IsValid) {
 				if (skeletonDataAsset == null) {
 				if (skeletonDataAsset == null) {
 					Clear();
 					Clear();
@@ -109,11 +75,7 @@ namespace Spine.Unity {
 			} else {
 			} else {
 				if (skeletonDataAsset != null)
 				if (skeletonDataAsset != null)
 					Initialize(true);
 					Initialize(true);
-			}
-			#else
-			Debug.LogWarning("SkeletonGraphic requres Unity 5.2 or higher.\nUnityEngine.UI 5.1 and below does not accept meshes and can't be used to render Spine skeletons. You may delete the SkeletonGraphic folder under `Modules` if you want to exclude it from your project." );
-			#endif
-				
+			}				
 		}
 		}
 
 
 		protected override void Reset () {
 		protected override void Reset () {
@@ -124,7 +86,6 @@ namespace Spine.Unity {
 		#endif
 		#endif
 		#endregion
 		#endregion
 
 
-		#if !PREUNITY_5_2
 		#region Internals
 		#region Internals
 		// This is used by the UI system to determine what to put in the MaterialPropertyBlock.
 		// This is used by the UI system to determine what to put in the MaterialPropertyBlock.
 		public override Texture mainTexture {
 		public override Texture mainTexture {
@@ -220,6 +181,7 @@ namespace Spine.Unity {
 
 
 			this.skeleton = new Skeleton(skeletonData);
 			this.skeleton = new Skeleton(skeletonData);
 			this.spineMeshGenerator = new Spine.Unity.MeshGeneration.ArraysSimpleMeshGenerator(); // You can switch this out with any other implementer of Spine.Unity.MeshGeneration.ISimpleMeshGenerator
 			this.spineMeshGenerator = new Spine.Unity.MeshGeneration.ArraysSimpleMeshGenerator(); // You can switch this out with any other implementer of Spine.Unity.MeshGeneration.ISimpleMeshGenerator
+			//this.spineMeshGenerator.AddBlackTint = this.tintBlack;
 			this.spineMeshGenerator.PremultiplyVertexColors = true;
 			this.spineMeshGenerator.PremultiplyVertexColors = true;
 
 
 			// Set the initial Skin and Animation
 			// Set the initial Skin and Animation
@@ -241,11 +203,5 @@ namespace Spine.Unity {
 			}
 			}
 		}
 		}
 		#endregion
 		#endregion
-		#else
-		public Skeleton Skeleton { get { return null; } }
-		public AnimationState AnimationState { get { return null; } }
-		public event UpdateBonesDelegate UpdateLocal, UpdateWorld, UpdateComplete;
-		public void LateUpdate () { }
-		#endif
 	}
 	}
 }
 }

+ 0 - 2
spine-unity/Assets/spine-unity/Modules/SkeletonRenderSeparator/SkeletonRenderSeparator.cs

@@ -125,8 +125,6 @@ namespace Spine.Unity.Modules {
 			int rendererCount = partsRenderers.Count;
 			int rendererCount = partsRenderers.Count;
 			if (rendererCount <= 0) return;
 			if (rendererCount <= 0) return;
 
 
-
-
 			if (copyPropertyBlock)
 			if (copyPropertyBlock)
 				mainMeshRenderer.GetPropertyBlock(copiedBlock);
 				mainMeshRenderer.GetPropertyBlock(copiedBlock);
 
 

+ 0 - 8
spine-unity/Assets/spine-unity/Modules/YieldInstructions/WaitForSpineAnimationComplete.cs

@@ -28,10 +28,6 @@
  * POSSIBILITY OF SUCH DAMAGE.
  * POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
  *****************************************************************************/
 
 
-#if (UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7)
-#define PREUNITY_5_3
-#endif
-
 using UnityEngine;
 using UnityEngine;
 using System.Collections;
 using System.Collections;
 using Spine;
 using Spine;
@@ -45,10 +41,6 @@ namespace Spine.Unity {
 		bool m_WasFired = false;
 		bool m_WasFired = false;
 
 
 		public WaitForSpineAnimationComplete (Spine.TrackEntry trackEntry) {
 		public WaitForSpineAnimationComplete (Spine.TrackEntry trackEntry) {
-			#if PREUNITY_5_3
-			Debug.LogWarning("Unity 5.3 or later is required for Spine Unity custom yield instructions to function correctly.");
-			#endif
-
 			SafeSubscribe(trackEntry);
 			SafeSubscribe(trackEntry);
 		}
 		}
 
 

+ 0 - 14
spine-unity/Assets/spine-unity/Modules/YieldInstructions/WaitForSpineEvent.cs

@@ -28,10 +28,6 @@
  * POSSIBILITY OF SUCH DAMAGE.
  * POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
  *****************************************************************************/
 
 
-#if (UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7)
-#define PREUNITY_5_3
-#endif
-
 using UnityEngine;
 using UnityEngine;
 using System.Collections;
 using System.Collections;
 using Spine;
 using Spine;
@@ -51,10 +47,6 @@ namespace Spine.Unity {
 
 
 		#region Constructors
 		#region Constructors
 		void Subscribe (Spine.AnimationState state, Spine.EventData eventDataReference, bool unsubscribe) {
 		void Subscribe (Spine.AnimationState state, Spine.EventData eventDataReference, bool unsubscribe) {
-			#if PREUNITY_5_3
-			Debug.LogWarning("Unity 5.3 or later is required for Spine Unity custom yield instructions to function correctly.");
-			#endif
-
 			if (state == null) {
 			if (state == null) {
 				Debug.LogWarning("AnimationState argument was null. Coroutine will continue immediately.");
 				Debug.LogWarning("AnimationState argument was null. Coroutine will continue immediately.");
 				m_WasFired = true;
 				m_WasFired = true;
@@ -74,10 +66,6 @@ namespace Spine.Unity {
 		}
 		}
 
 
 		void SubscribeByName (Spine.AnimationState state, string eventName, bool unsubscribe) {
 		void SubscribeByName (Spine.AnimationState state, string eventName, bool unsubscribe) {
-			#if PREUNITY_5_3
-			Debug.LogWarning("Unity 5.3 or later is required for Spine Unity custom yield instructions to function correctly.");
-			#endif
-
 			if (state == null) {
 			if (state == null) {
 				Debug.LogWarning("AnimationState argument was null. Coroutine will continue immediately.");
 				Debug.LogWarning("AnimationState argument was null. Coroutine will continue immediately.");
 				m_WasFired = true;
 				m_WasFired = true;
@@ -168,7 +156,5 @@ namespace Spine.Unity {
 		void IEnumerator.Reset () { m_WasFired = false; }
 		void IEnumerator.Reset () { m_WasFired = false; }
 		object IEnumerator.Current { get { return null; } }
 		object IEnumerator.Current { get { return null; } }
 		#endregion
 		#endregion
-
-
 	}
 	}
 }
 }

+ 0 - 8
spine-unity/Assets/spine-unity/Modules/YieldInstructions/WaitForSpineTrackEntryEnd.cs

@@ -28,10 +28,6 @@
  * POSSIBILITY OF SUCH DAMAGE.
  * POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
  *****************************************************************************/
 
 
-#if (UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7)
-#define PREUNITY_5_3
-#endif
-
 using UnityEngine;
 using UnityEngine;
 using System.Collections;
 using System.Collections;
 using Spine;
 using Spine;
@@ -45,10 +41,6 @@ namespace Spine.Unity {
 		bool m_WasFired = false;
 		bool m_WasFired = false;
 
 
 		public WaitForSpineTrackEntryEnd (Spine.TrackEntry trackEntry) {
 		public WaitForSpineTrackEntryEnd (Spine.TrackEntry trackEntry) {
-			#if PREUNITY_5_3
-			Debug.LogWarning("Unity 5.3 or later is required for Spine Unity custom yield instructions to function correctly.");
-			#endif
-
 			SafeSubscribe(trackEntry);
 			SafeSubscribe(trackEntry);
 		}
 		}
 
 

+ 106 - 0
spine-unity/Assets/spine-unity/Shaders/Skeleton TintBlack.shader

@@ -0,0 +1,106 @@
+// Spine/Skeleton Tint Black
+// - Two color tint
+// - UV2 and UV3 as Black Tint color.
+// - Final black tint is (UV black data and _Black/"Black Point")
+// - unlit
+// - Premultiplied alpha blending
+// - No depth, no backface culling, no fog.
+
+Shader "Spine/Skeleton Tint Black" {
+	Properties {
+		_Color ("Tint Color", Color) = (1,1,1,1)
+		_Black ("Black Point", Color) = (0,0,0,0)
+		[NoScaleOffset] _MainTex ("MainTex", 2D) = "black" {}
+		_Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1
+	}
+
+	SubShader {
+		Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
+		LOD 100
+
+		Fog { Mode Off }
+		Cull Off
+		ZWrite Off
+		Blend One OneMinusSrcAlpha
+		Lighting Off
+
+		Pass {
+			CGPROGRAM
+			#pragma vertex vert
+			#pragma fragment frag
+			#include "UnityCG.cginc"
+			uniform sampler2D _MainTex;
+			uniform float4 _Color;
+			uniform float4 _Black;
+
+			struct VertexInput {
+				float4 vertex : POSITION;
+				float2 uv : TEXCOORD0;
+				float2 uv1 : TEXCOORD1;
+				float2 uv2 : TEXCOORD2;
+				float4 vertexColor : COLOR;
+			};
+
+			struct VertexOutput {
+				float4 pos : SV_POSITION;
+				float2 uv : TEXCOORD0;
+				float2 uv1 : TEXCOORD1;
+				float2 uv2 : TEXCOORD2;
+				float4 vertexColor : COLOR;
+			};
+
+			VertexOutput vert (VertexInput v) {
+				VertexOutput o;
+				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
+				o.uv = v.uv;
+				o.vertexColor = v.vertexColor * float4(_Color.rgb * _Color.a, _Color.a); // Combine a PMA version of _Color with vertexColor.
+				o.uv1 = v.uv1;
+				o.uv2 = v.uv2;
+				return o;
+			}
+
+			float4 frag (VertexOutput i) : COLOR {
+				float4 texColor = tex2D(_MainTex, i.uv);
+				return (texColor * i.vertexColor) + float4(((1-texColor.rgb) * texColor.a * (_Black.rgb + float3(i.uv1.r, i.uv1.g, i.uv2.r))), 1);
+			}
+			ENDCG
+		}
+
+		Pass {
+			Name "Caster"
+			Tags { "LightMode"="ShadowCaster" }
+			Offset 1, 1
+
+			ZWrite On
+			ZTest LEqual
+
+			CGPROGRAM
+			#pragma vertex vert
+			#pragma fragment frag
+			#pragma multi_compile_shadowcaster
+			#pragma fragmentoption ARB_precision_hint_fastest
+			#include "UnityCG.cginc"
+			struct v2f { 
+				V2F_SHADOW_CASTER;
+				float2 uv : TEXCOORD1;
+			};
+
+			v2f vert (appdata_base v) {
+				v2f o;
+				TRANSFER_SHADOW_CASTER(o)
+				o.uv = v.texcoord;
+				return o;
+			}
+
+			uniform sampler2D _MainTex;
+			uniform fixed _Cutoff;
+
+			float4 frag (v2f i) : COLOR {
+				fixed4 texcol = tex2D(_MainTex, i.uv);
+				clip(texcol.a - _Cutoff);
+				SHADOW_CASTER_FRAGMENT(i)
+			}
+			ENDCG
+		}
+	}
+}

+ 7 - 0
spine-unity/Assets/spine-unity/Shaders/Skeleton TintBlack.shader.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: deee23ab4aa38564ead2ac05e112c169
+ShaderImporter:
+  defaultTextures: []
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 1 - 1
spine-unity/Assets/spine-unity/SkeletonAnimator.cs

@@ -40,7 +40,7 @@ namespace Spine.Unity {
 		public enum MixMode { AlwaysMix, MixNext, SpineStyle }
 		public enum MixMode { AlwaysMix, MixNext, SpineStyle }
 		public MixMode[] layerMixModes = new MixMode[0];
 		public MixMode[] layerMixModes = new MixMode[0];
 
 
-		public bool autoReset = false;
+		public bool autoReset = true;
 		List<Animation> previousAnimations = new List<Animation>();
 		List<Animation> previousAnimations = new List<Animation>();
 
 
 		#region Bone Callbacks (ISkeletonAnimation)
 		#region Bone Callbacks (ISkeletonAnimation)

+ 20 - 157
spine-unity/Assets/spine-unity/SkeletonRenderer.cs

@@ -33,8 +33,6 @@
 #define SPINE_OPTIONAL_NORMALS
 #define SPINE_OPTIONAL_NORMALS
 #define SPINE_OPTIONAL_SOLVETANGENTS
 #define SPINE_OPTIONAL_SOLVETANGENTS
 
 
-//#define SPINE_OPTIONAL_FRONTFACING
-
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine;
@@ -65,6 +63,7 @@ namespace Spine.Unity {
 		public bool renderMeshes = true, immutableTriangles;
 		public bool renderMeshes = true, immutableTriangles;
 		public bool pmaVertexColors = true;
 		public bool pmaVertexColors = true;
 		public bool clearStateOnDisable = false;
 		public bool clearStateOnDisable = false;
+		public bool tintBlack = false;
 
 
 		#if SPINE_OPTIONAL_NORMALS
 		#if SPINE_OPTIONAL_NORMALS
 		public bool calculateNormals;
 		public bool calculateNormals;
@@ -72,9 +71,6 @@ namespace Spine.Unity {
 		#if SPINE_OPTIONAL_SOLVETANGENTS
 		#if SPINE_OPTIONAL_SOLVETANGENTS
 		public bool calculateTangents;
 		public bool calculateTangents;
 		#endif
 		#endif
-		#if SPINE_OPTIONAL_FRONTFACING
-		public bool frontFacing;
-		#endif
 
 
 		public bool logErrors = false;
 		public bool logErrors = false;
 
 
@@ -131,6 +127,10 @@ namespace Spine.Unity {
 		Vector3[] vertices;
 		Vector3[] vertices;
 		Color32[] colors;
 		Color32[] colors;
 		Vector2[] uvs;
 		Vector2[] uvs;
+
+		Vector2[] uv2;
+		Vector2[] uv3;
+
 		#if SPINE_OPTIONAL_NORMALS
 		#if SPINE_OPTIONAL_NORMALS
 		Vector3[] normals;
 		Vector3[] normals;
 		#endif
 		#endif
@@ -252,14 +252,6 @@ namespace Spine.Unity {
 			workingAttachments.Count = drawOrderCount;
 			workingAttachments.Count = drawOrderCount;
 			var workingAttachmentsItems = workingInstruction.attachments.Items;
 			var workingAttachmentsItems = workingInstruction.attachments.Items;
 
 
-			#if SPINE_OPTIONAL_FRONTFACING
-			var workingFlips = workingInstruction.attachmentFlips;
-			workingFlips.Clear(false);
-			workingFlips.GrowIfNeeded(drawOrderCount);
-			workingFlips.Count = drawOrderCount;
-			var workingFlipsItems = workingFlips.Items;
-			#endif
-
 			var workingSubmeshInstructions = workingInstruction.submeshInstructions;	// Items array should not be cached. There is dynamic writing to this list.
 			var workingSubmeshInstructions = workingInstruction.submeshInstructions;	// Items array should not be cached. There is dynamic writing to this list.
 			workingSubmeshInstructions.Clear(false);
 			workingSubmeshInstructions.Clear(false);
 
 
@@ -277,11 +269,6 @@ namespace Spine.Unity {
 				Attachment attachment = slot.attachment;
 				Attachment attachment = slot.attachment;
 				workingAttachmentsItems[i] = attachment;
 				workingAttachmentsItems[i] = attachment;
 
 
-				#if SPINE_OPTIONAL_FRONTFACING
-				bool flip = frontFacing && (slot.bone.WorldSignX != slot.bone.WorldSignY);
-				workingFlipsItems[i] = flip;
-				#endif
-
 				object rendererObject = null; // An AtlasRegion in plain Spine-Unity. Spine-TK2D hooks into TK2D's system. eventual source of Material object.
 				object rendererObject = null; // An AtlasRegion in plain Spine-Unity. Spine-TK2D hooks into TK2D's system. eventual source of Material object.
 				int attachmentVertexCount, attachmentTriangleCount;
 				int attachmentVertexCount, attachmentTriangleCount;
 				bool noRender = false;
 				bool noRender = false;
@@ -390,9 +377,6 @@ namespace Spine.Unity {
 
 
 			workingInstruction.vertexCount = vertexCount;
 			workingInstruction.vertexCount = vertexCount;
 			workingInstruction.immutableTriangles = this.immutableTriangles;
 			workingInstruction.immutableTriangles = this.immutableTriangles;
-			#if SPINE_OPTIONAL_FRONTFACING
-			workingInstruction.frontFacing = this.frontFacing;
-			#endif
 
 
 
 
 			// STEP 1.9. Post-process workingInstructions. ============================================================
 			// STEP 1.9. Post-process workingInstructions. ============================================================
@@ -423,6 +407,10 @@ namespace Spine.Unity {
 			// STEP 2. Update vertex buffer based on verts from the attachments.  ============================================================
 			// STEP 2. Update vertex buffer based on verts from the attachments.  ============================================================
 			// Uses values that were also stored in workingInstruction.
 			// Uses values that were also stored in workingInstruction.
 			bool vertexCountIncreased = ArraysMeshGenerator.EnsureSize(vertexCount, ref this.vertices, ref this.uvs, ref this.colors);
 			bool vertexCountIncreased = ArraysMeshGenerator.EnsureSize(vertexCount, ref this.vertices, ref this.uvs, ref this.colors);
+			if (tintBlack) {
+				ArraysMeshGenerator.EnsureSize(vertexCount, ref this.uv2);
+				ArraysMeshGenerator.EnsureSize(vertexCount, ref this.uv3);
+			}
 			#if SPINE_OPTIONAL_NORMALS
 			#if SPINE_OPTIONAL_NORMALS
 			if (vertexCountIncreased && calculateNormals) {
 			if (vertexCountIncreased && calculateNormals) {
 				Vector3[] localNormals = this.normals = new Vector3[vertexCount];
 				Vector3[] localNormals = this.normals = new Vector3[vertexCount];
@@ -452,9 +440,14 @@ namespace Spine.Unity {
 				}
 				}
 			}
 			}
 			int vertexIndex = 0;
 			int vertexIndex = 0;
+
+			if (tintBlack)
+				ArraysMeshGenerator.FillBlackUVs(skeleton, 0, drawOrderCount, this.uv2, this.uv3, vertexIndex, renderMeshes); // This needs to be called before FillVerts so we have the correct vertexIndex argument.
+
 			ArraysMeshGenerator.FillVerts(skeleton, 0, drawOrderCount, this.zSpacing, pmaVertexColors, this.vertices, this.uvs, this.colors, ref vertexIndex, ref tempVertices, ref meshBoundsMin, ref meshBoundsMax, renderMeshes);
 			ArraysMeshGenerator.FillVerts(skeleton, 0, drawOrderCount, this.zSpacing, pmaVertexColors, this.vertices, this.uvs, this.colors, ref vertexIndex, ref tempVertices, ref meshBoundsMin, ref meshBoundsMax, renderMeshes);
 
 
 
 
+
 			// Step 3. Move the mesh data into a UnityEngine.Mesh ============================================================
 			// Step 3. Move the mesh data into a UnityEngine.Mesh ============================================================
 			var currentSmartMesh = doubleBufferedMesh.GetNext();	// Double-buffer for performance.
 			var currentSmartMesh = doubleBufferedMesh.GetNext();	// Double-buffer for performance.
 			var currentMesh = currentSmartMesh.mesh;
 			var currentMesh = currentSmartMesh.mesh;
@@ -463,6 +456,11 @@ namespace Spine.Unity {
 			currentMesh.uv = uvs;
 			currentMesh.uv = uvs;
 			currentMesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax);
 			currentMesh.bounds = ArraysMeshGenerator.ToBounds(meshBoundsMin, meshBoundsMax);
 
 
+			if (tintBlack) {
+				currentMesh.uv2 = this.uv2;
+				currentMesh.uv3 = this.uv3;
+			}
+
 			var currentSmartMeshInstructionUsed = currentSmartMesh.instructionUsed;
 			var currentSmartMeshInstructionUsed = currentSmartMesh.instructionUsed;
 			#if SPINE_OPTIONAL_NORMALS
 			#if SPINE_OPTIONAL_NORMALS
 			if (calculateNormals && currentSmartMeshInstructionUsed.vertexCount < vertexCount)
 			if (calculateNormals && currentSmartMeshInstructionUsed.vertexCount < vertexCount)
@@ -490,8 +488,7 @@ namespace Spine.Unity {
 					var submeshInstruction = workingSubmeshInstructions.Items[i];
 					var submeshInstruction = workingSubmeshInstructions.Items[i];
 
 
 					if (mutableTriangles || i >= oldSubmeshCount) {
 					if (mutableTriangles || i >= oldSubmeshCount) {
-	
-						#if !SPINE_OPTIONAL_FRONTFACING
+
 						var currentSubmesh = submeshes.Items[i];
 						var currentSubmesh = submeshes.Items[i];
 						int instructionTriangleCount = submeshInstruction.triangleCount;
 						int instructionTriangleCount = submeshInstruction.triangleCount;
 						if (renderMeshes) {
 						if (renderMeshes) {
@@ -500,9 +497,6 @@ namespace Spine.Unity {
 						} else {
 						} else {
 							ArraysMeshGenerator.FillTrianglesQuads(ref currentSubmesh.triangles, ref currentSubmesh.triangleCount, ref currentSubmesh.firstVertex, submeshInstruction.firstVertexIndex, instructionTriangleCount, (i == last));
 							ArraysMeshGenerator.FillTrianglesQuads(ref currentSubmesh.triangles, ref currentSubmesh.triangleCount, ref currentSubmesh.firstVertex, submeshInstruction.firstVertexIndex, instructionTriangleCount, (i == last));
 						}
 						}
-						#else
-						SetSubmesh(i, submeshInstruction, currentInstructions.attachmentFlips, i == last);
-						#endif
 
 
 					}
 					}
 
 
@@ -594,19 +588,6 @@ namespace Spine.Unity {
 					return true;
 					return true;
 			}
 			}
 
 
-			#if SPINE_OPTIONAL_FRONTFACING
-			if (a.frontFacing != b.frontFacing) { 	// if settings changed
-				return true;
-			} else if (a.frontFacing) { 			// if settings matched, only need to check one.
-				var flipsA = a.attachmentFlips.Items;
-				var flipsB = b.attachmentFlips.Items;
-				for (int i = 0; i < attachmentCountB; i++) {
-					if (flipsA[i] != flipsB[i])
-						return true;
-				}
-			}
-			#endif
-
 			// Submesh count changed
 			// Submesh count changed
 			int submeshCountA = a.submeshInstructions.Count;
 			int submeshCountA = a.submeshInstructions.Count;
 			int submeshCountB = b.submeshInstructions.Count;
 			int submeshCountB = b.submeshInstructions.Count;
@@ -633,106 +614,6 @@ namespace Spine.Unity {
 			return false;
 			return false;
 		}
 		}
 
 
-		#if SPINE_OPTIONAL_FRONTFACING
-		void SetSubmesh (int submeshIndex, Spine.Unity.MeshGeneration.SubmeshInstruction submeshInstructions, ExposedList<bool> flipStates, bool isLastSubmesh) {
-			var currentSubmesh = submeshes.Items[submeshIndex];
-			int[] triangles = currentSubmesh.triangles;
-
-			int triangleCount = submeshInstructions.triangleCount;
-			int firstVertex = submeshInstructions.firstVertexIndex;
-
-			int trianglesCapacity = triangles.Length;
-			if (isLastSubmesh && trianglesCapacity > triangleCount) {
-				// Last submesh may have more triangles than required, so zero triangles to the end.
-				for (int i = triangleCount; i < trianglesCapacity; i++)
-					triangles[i] = 0;
-
-				currentSubmesh.triangleCount = triangleCount;
-
-			} else if (trianglesCapacity != triangleCount) {
-				// Reallocate triangles when not the exact size needed.
-				currentSubmesh.triangles = triangles = new int[triangleCount];
-				currentSubmesh.triangleCount = 0;
-			}
-				
-			if (!this.renderMeshes && !this.frontFacing) {
-				// Use stored triangles if possible.
-				if (currentSubmesh.firstVertex != firstVertex || currentSubmesh.triangleCount < triangleCount) { //|| currentSubmesh.triangleCount == 0
-					currentSubmesh.triangleCount = triangleCount;
-					currentSubmesh.firstVertex = firstVertex;
-
-					for (int i = 0; i < triangleCount; i += 6, firstVertex += 4) {
-						triangles[i] = firstVertex;
-						triangles[i + 1] = firstVertex + 2;
-						triangles[i + 2] = firstVertex + 1;
-						triangles[i + 3] = firstVertex + 2;
-						triangles[i + 4] = firstVertex + 3;
-						triangles[i + 5] = firstVertex + 1;
-					}
-				}
-				return;
-			}
-				
-			var flipStatesItems = flipStates.Items;
-
-			// Iterate through all slots and store their triangles. 
-			var drawOrderItems = skeleton.DrawOrder.Items;
-			int triangleIndex = 0; // Modified by loop
-			for (int i = submeshInstructions.startSlot, n = submeshInstructions.endSlot; i < n; i++) {			
-				Attachment attachment = drawOrderItems[i].attachment;
-				bool flip = frontFacing && flipStatesItems[i];
-
-				// Add RegionAttachment triangles
-				if (attachment is RegionAttachment) {
-					if (!flip) {
-						triangles[triangleIndex] = firstVertex;
-						triangles[triangleIndex + 1] = firstVertex + 2;
-						triangles[triangleIndex + 2] = firstVertex + 1;
-						triangles[triangleIndex + 3] = firstVertex + 2;
-						triangles[triangleIndex + 4] = firstVertex + 3;
-						triangles[triangleIndex + 5] = firstVertex + 1;
-					} else {
-						triangles[triangleIndex] = firstVertex + 1;
-						triangles[triangleIndex + 1] = firstVertex + 2;
-						triangles[triangleIndex + 2] = firstVertex;
-						triangles[triangleIndex + 3] = firstVertex + 1;
-						triangles[triangleIndex + 4] = firstVertex + 3;
-						triangles[triangleIndex + 5] = firstVertex + 2;
-					}
-
-					triangleIndex += 6;
-					firstVertex += 4;
-					continue;
-				}
-
-				// Add (Weighted)MeshAttachment triangles
-				int[] attachmentTriangles;
-				int attachmentVertexCount;
-				var meshAttachment = attachment as MeshAttachment;
-				if (meshAttachment != null) {
-					attachmentVertexCount = meshAttachment.worldVerticesLength >> 1; // length/2
-					attachmentTriangles = meshAttachment.triangles;
-				} else {
-					continue;
-				}
-
-				if (flip) {
-					for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii += 3, triangleIndex += 3) {
-						triangles[triangleIndex + 2] = firstVertex + attachmentTriangles[ii];
-						triangles[triangleIndex + 1] = firstVertex + attachmentTriangles[ii + 1];
-						triangles[triangleIndex] = firstVertex + attachmentTriangles[ii + 2];
-					}
-				} else {
-					for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleIndex++) {
-						triangles[triangleIndex] = firstVertex + attachmentTriangles[ii];
-					}
-				}
-
-				firstVertex += attachmentVertexCount;
-			}
-		}
-		#endif
-
 		///<summary>This is a Mesh that also stores the instructions SkeletonRenderer generated for it.</summary>
 		///<summary>This is a Mesh that also stores the instructions SkeletonRenderer generated for it.</summary>
 		public class SmartMesh {
 		public class SmartMesh {
 			public Mesh mesh = Spine.Unity.SpineMesh.NewMesh();
 			public Mesh mesh = Spine.Unity.SpineMesh.NewMesh();
@@ -744,18 +625,9 @@ namespace Spine.Unity {
 				public readonly ExposedList<Attachment> attachments = new ExposedList<Attachment>();
 				public readonly ExposedList<Attachment> attachments = new ExposedList<Attachment>();
 				public readonly ExposedList<Spine.Unity.MeshGeneration.SubmeshInstruction> submeshInstructions = new ExposedList<Spine.Unity.MeshGeneration.SubmeshInstruction>();
 				public readonly ExposedList<Spine.Unity.MeshGeneration.SubmeshInstruction> submeshInstructions = new ExposedList<Spine.Unity.MeshGeneration.SubmeshInstruction>();
 
 
-				#if SPINE_OPTIONAL_FRONTFACING
-				public bool frontFacing;
-				public readonly ExposedList<bool> attachmentFlips = new ExposedList<bool>();
-				#endif
-
 				public void Clear () {
 				public void Clear () {
 					this.attachments.Clear(false);
 					this.attachments.Clear(false);
 					this.submeshInstructions.Clear(false);
 					this.submeshInstructions.Clear(false);
-
-					#if SPINE_OPTIONAL_FRONTFACING
-					this.attachmentFlips.Clear(false);
-					#endif
 				}
 				}
 
 
 				public void Set (Instruction other) {
 				public void Set (Instruction other) {
@@ -767,15 +639,6 @@ namespace Spine.Unity {
 					this.attachments.Count = other.attachments.Count;
 					this.attachments.Count = other.attachments.Count;
 					other.attachments.CopyTo(this.attachments.Items);
 					other.attachments.CopyTo(this.attachments.Items);
 
 
-					#if SPINE_OPTIONAL_FRONTFACING
-					this.frontFacing = other.frontFacing;
-					this.attachmentFlips.Clear(false);
-					this.attachmentFlips.GrowIfNeeded(other.attachmentFlips.Capacity);
-					this.attachmentFlips.Count = other.attachmentFlips.Count;
-					if (this.frontFacing)
-						other.attachmentFlips.CopyTo(this.attachmentFlips.Items);
-					#endif
-
 					this.submeshInstructions.Clear(false);
 					this.submeshInstructions.Clear(false);
 					this.submeshInstructions.GrowIfNeeded(other.submeshInstructions.Capacity);
 					this.submeshInstructions.GrowIfNeeded(other.submeshInstructions.Capacity);
 					this.submeshInstructions.Count = other.submeshInstructions.Count;
 					this.submeshInstructions.Count = other.submeshInstructions.Count;

+ 1 - 1
spine-unity/Assets/spine-unity/version.txt

@@ -1 +1 @@
-This Spine-Unity runtime works with data exported from Spine Editor version: 3.5.xx
+This Spine-Unity runtime works with data exported from Spine Editor version: 3.6.xx

+ 1 - 1
spine-unity/README.md

@@ -14,7 +14,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
 
 
 ## Spine version
 ## Spine version
 
 
-spine-unity works with data exported from Spine 3.5.xx.
+spine-unity works with data exported from Spine 3.6.xx.
 
 
 spine-unity supports all Spine features.
 spine-unity supports all Spine features.