Explorar o código

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

badlogic %!s(int64=4) %!d(string=hai) anos
pai
achega
9bcb5c16c4
Modificáronse 19 ficheiros con 147 adicións e 32 borrados
  1. 2 2
      spine-ts/build/spine-all.js
  2. 0 0
      spine-ts/build/spine-all.js.map
  3. 2 2
      spine-ts/build/spine-player.js
  4. 0 0
      spine-ts/build/spine-player.js.map
  5. 2 2
      spine-ts/player/src/Player.ts
  6. 10 0
      spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/EquipSystemExample.cs
  7. 6 1
      spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/EquipsVisualsComponentExample.cs
  8. 6 1
      spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/MixAndMatchSkinsExample.cs
  9. 8 0
      spine-unity/Assets/Spine Examples/Scripts/MixAndMatch.cs
  10. 8 0
      spine-unity/Assets/Spine Examples/Scripts/MixAndMatchGraphic.cs
  11. 15 1
      spine-unity/Assets/Spine/Editor/spine-unity/Editor/Asset Types/AnimationReferenceAssetEditor.cs
  12. 5 4
      spine-unity/Assets/Spine/Editor/spine-unity/Editor/Asset Types/SkeletonDataAssetInspector.cs
  13. 3 4
      spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/AssetUtility.cs
  14. 3 1
      spine-unity/Assets/Spine/Editor/spine-unity/Editor/Windows/SpinePreferences.cs
  15. 30 5
      spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs
  16. 8 0
      spine-unity/Assets/Spine/Runtime/spine-unity/Mesh Generation/MeshGenerator.cs
  17. 29 7
      spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs
  18. 6 1
      spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs
  19. 4 1
      spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentRegionExtensions.cs

+ 2 - 2
spine-ts/build/spine-all.js

@@ -12127,7 +12127,7 @@ var spine;
 					skeletonData = json.readSkeletonData(jsonText);
 					skeletonData = json.readSkeletonData(jsonText);
 				}
 				}
 				catch (e) {
 				catch (e) {
-					this.showError("Error: could not load skeleton .json.<br><br>" + escapeHtml(JSON.stringify(e)));
+					this.showError("Error: could not load skeleton .json.<br><br>" + e.toString());
 					return;
 					return;
 				}
 				}
 			}
 			}
@@ -12138,7 +12138,7 @@ var spine;
 					skeletonData = binary.readSkeletonData(binaryData);
 					skeletonData = binary.readSkeletonData(binaryData);
 				}
 				}
 				catch (e) {
 				catch (e) {
-					this.showError("Error: could not load skeleton .skel.<br><br>" + escapeHtml(JSON.stringify(e)));
+					this.showError("Error: could not load skeleton .skel.<br><br>" + e.toString());
 					return;
 					return;
 				}
 				}
 			}
 			}

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
spine-ts/build/spine-all.js.map


+ 2 - 2
spine-ts/build/spine-player.js

@@ -11438,7 +11438,7 @@ var spine;
 					skeletonData = json.readSkeletonData(jsonText);
 					skeletonData = json.readSkeletonData(jsonText);
 				}
 				}
 				catch (e) {
 				catch (e) {
-					this.showError("Error: could not load skeleton .json.<br><br>" + escapeHtml(JSON.stringify(e)));
+					this.showError("Error: could not load skeleton .json.<br><br>" + e.toString());
 					return;
 					return;
 				}
 				}
 			}
 			}
@@ -11449,7 +11449,7 @@ var spine;
 					skeletonData = binary.readSkeletonData(binaryData);
 					skeletonData = binary.readSkeletonData(binaryData);
 				}
 				}
 				catch (e) {
 				catch (e) {
-					this.showError("Error: could not load skeleton .skel.<br><br>" + escapeHtml(JSON.stringify(e)));
+					this.showError("Error: could not load skeleton .skel.<br><br>" + e.toString());
 					return;
 					return;
 				}
 				}
 			}
 			}

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
spine-ts/build/spine-player.js.map


+ 2 - 2
spine-ts/player/src/Player.ts

@@ -870,7 +870,7 @@ module spine {
 				try {
 				try {
 					skeletonData = json.readSkeletonData(jsonText);
 					skeletonData = json.readSkeletonData(jsonText);
 				} catch (e) {
 				} catch (e) {
-					this.showError("Error: could not load skeleton .json.<br><br>" + escapeHtml(JSON.stringify(e)));
+					this.showError("Error: could not load skeleton .json.<br><br>" + e.toString());
 					return;
 					return;
 				}
 				}
 			} else {
 			} else {
@@ -879,7 +879,7 @@ module spine {
 				try {
 				try {
 					skeletonData = binary.readSkeletonData(binaryData);
 					skeletonData = binary.readSkeletonData(binaryData);
 				} catch (e) {
 				} catch (e) {
-					this.showError("Error: could not load skeleton .skel.<br><br>" + escapeHtml(JSON.stringify(e)));
+					this.showError("Error: could not load skeleton .skel.<br><br>" + e.toString());
 					return;
 					return;
 				}
 				}
 			}
 			}

+ 10 - 0
spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/EquipSystemExample.cs

@@ -82,6 +82,8 @@ namespace Spine.Unity.Examples {
 				var templateSkin = skeletonData.FindSkin(templateSkinName);
 				var templateSkin = skeletonData.FindSkin(templateSkinName);
 				Attachment templateAttachment = templateSkin.GetAttachment(slotIndex, templateAttachmentName);
 				Attachment templateAttachment = templateSkin.GetAttachment(slotIndex, templateAttachmentName);
 				attachment = templateAttachment.GetRemappedClone(asset.sprite, sourceMaterial, premultiplyAlpha: this.applyPMA);
 				attachment = templateAttachment.GetRemappedClone(asset.sprite, sourceMaterial, premultiplyAlpha: this.applyPMA);
+				// Note: Each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` creates
+				// a cached Texture copy which can be cleared by calling AtlasUtilities.ClearCache() as shown in the method below.
 
 
 				cachedAttachments.Add(asset, attachment); // Cache this value for next time this asset is used.
 				cachedAttachments.Add(asset, attachment); // Cache this value for next time this asset is used.
 			}
 			}
@@ -91,6 +93,14 @@ namespace Spine.Unity.Examples {
 
 
 		public void Done () {
 		public void Done () {
 			target.OptimizeSkin();
 			target.OptimizeSkin();
+			// `GetRepackedSkin()` and each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true`
+			// creates cached Texture copies which can be cleared by calling AtlasUtilities.ClearCache().
+			// You can optionally clear the textures cache after multiple repack operations.
+			// Just be aware that while this cleanup frees up memory, it is also a costly operation
+			// and will likely cause a spike in the framerate.
+
+			//AtlasUtilities.ClearCache();
+			//Resources.UnloadUnusedAssets();
 		}
 		}
 
 
 	}
 	}

+ 6 - 1
spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/EquipsVisualsComponentExample.cs

@@ -78,9 +78,14 @@ namespace Spine.Unity.Examples {
 				Destroy(runtimeMaterial);
 				Destroy(runtimeMaterial);
 			if (runtimeAtlas)
 			if (runtimeAtlas)
 				Destroy(runtimeAtlas);
 				Destroy(runtimeAtlas);
-			var repackedSkin = collectedSkin.GetRepackedSkin("Repacked skin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, out runtimeMaterial, out runtimeAtlas);
+			var repackedSkin = collectedSkin.GetRepackedSkin("Repacked skin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial,
+				out runtimeMaterial, out runtimeAtlas, maxAtlasSize : 1024, clearCache: false);
 			collectedSkin.Clear();
 			collectedSkin.Clear();
 
 
+			// You can optionally clear the textures cache after each ore multiple repack operations are done.
+			//AtlasUtilities.ClearCache();
+			//Resources.UnloadUnusedAssets();
+
 			// 3. Use the repacked skin.
 			// 3. Use the repacked skin.
 			skeletonAnimation.Skeleton.Skin = repackedSkin;
 			skeletonAnimation.Skeleton.Skin = repackedSkin;
 			RefreshSkeletonAttachments();
 			RefreshSkeletonAttachments();

+ 6 - 1
spine-unity/Assets/Spine Examples/Scripts/Mix and Match Character Customize/MixAndMatchSkinsExample.cs

@@ -149,8 +149,13 @@ namespace Spine.Unity.Examples {
 			skeletonAnimation.Skeleton.SetSlotsToSetupPose();
 			skeletonAnimation.Skeleton.SetSlotsToSetupPose();
 			skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton);
 			skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton);
 
 
-			// You can optionally clear the cache after multiple repack operations.
+			// `GetRepackedSkin()` and each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true`
+			// cache necessarily created Texture copies which can be cleared by calling AtlasUtilities.ClearCache().
+			// You can optionally clear the textures cache after multiple repack operations.
+			// Just be aware that while this cleanup frees up memory, it is also a costly operation
+			// and will likely cause a spike in the framerate.
 			AtlasUtilities.ClearCache();
 			AtlasUtilities.ClearCache();
+			Resources.UnloadUnusedAssets();
 		}
 		}
 
 
 		void UpdateCharacterSkin () {
 		void UpdateCharacterSkin () {

+ 8 - 0
spine-unity/Assets/Spine Examples/Scripts/MixAndMatch.cs

@@ -95,6 +95,8 @@ namespace Spine.Unity.Examples {
 			int visorSlotIndex = skeleton.FindSlotIndex(visorSlot); // You can access GetAttachment and SetAttachment via string, but caching the slotIndex is faster.
 			int visorSlotIndex = skeleton.FindSlotIndex(visorSlot); // You can access GetAttachment and SetAttachment via string, but caching the slotIndex is faster.
 			Attachment templateAttachment = templateSkin.GetAttachment(visorSlotIndex, visorKey); // STEP 1.1
 			Attachment templateAttachment = templateSkin.GetAttachment(visorSlotIndex, visorKey); // STEP 1.1
 			Attachment newAttachment = templateAttachment.GetRemappedClone(visorSprite, sourceMaterial, pivotShiftsMeshUVCoords : false); // STEP 1.2 - 1.3
 			Attachment newAttachment = templateAttachment.GetRemappedClone(visorSprite, sourceMaterial, pivotShiftsMeshUVCoords : false); // STEP 1.2 - 1.3
+			// Note: Each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` creates
+			// a cached Texture copy which can be cleared by calling AtlasUtilities.ClearCache() as done in the method below.
 			customSkin.SetAttachment(visorSlotIndex, visorKey, newAttachment); // STEP 1.4
 			customSkin.SetAttachment(visorSlotIndex, visorKey, newAttachment); // STEP 1.4
 
 
 			// And now for the gun.
 			// And now for the gun.
@@ -136,6 +138,12 @@ namespace Spine.Unity.Examples {
 			skeleton.SetSlotsToSetupPose(); // Use the pose from setup pose.
 			skeleton.SetSlotsToSetupPose(); // Use the pose from setup pose.
 			skeletonAnimation.Update(0); // Use the pose in the currently active animation.
 			skeletonAnimation.Update(0); // Use the pose in the currently active animation.
 
 
+			// `GetRepackedSkin()` and each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true`
+			// cache necessarily created Texture copies which can be cleared by calling AtlasUtilities.ClearCache().
+			// You can optionally clear the textures cache after multiple repack operations.
+			// Just be aware that while this cleanup frees up memory, it is also a costly operation
+			// and will likely cause a spike in the framerate.
+			AtlasUtilities.ClearCache();
 			Resources.UnloadUnusedAssets();
 			Resources.UnloadUnusedAssets();
 		}
 		}
 	}
 	}

+ 8 - 0
spine-unity/Assets/Spine Examples/Scripts/MixAndMatchGraphic.cs

@@ -96,6 +96,8 @@ namespace Spine.Unity.Examples {
 			int visorSlotIndex = skeleton.FindSlotIndex(visorSlot); // You can access GetAttachment and SetAttachment via string, but caching the slotIndex is faster.
 			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 baseAttachment = baseSkin.GetAttachment(visorSlotIndex, visorKey); // STEP 1.1
 			Attachment newAttachment = baseAttachment.GetRemappedClone(visorSprite, sourceMaterial); // STEP 1.2 - 1.3
 			Attachment newAttachment = baseAttachment.GetRemappedClone(visorSprite, sourceMaterial); // STEP 1.2 - 1.3
+			// Note: Each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` creates
+			// a cached Texture copy which can be cleared by calling AtlasUtilities.ClearCache() as done below.
 			customSkin.SetAttachment(visorSlotIndex, visorKey, newAttachment); // STEP 1.4
 			customSkin.SetAttachment(visorSlotIndex, visorKey, newAttachment); // STEP 1.4
 
 
 			// And now for the gun.
 			// And now for the gun.
@@ -135,6 +137,12 @@ namespace Spine.Unity.Examples {
 			skeletonGraphic.Update(0);
 			skeletonGraphic.Update(0);
 			skeletonGraphic.OverrideTexture = runtimeAtlas;
 			skeletonGraphic.OverrideTexture = runtimeAtlas;
 
 
+			// `GetRepackedSkin()` and each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true`
+			// cache necessarily created Texture copies which can be cleared by calling AtlasUtilities.ClearCache().
+			// You can optionally clear the textures cache after multiple repack operations.
+			// Just be aware that while this cleanup frees up memory, it is also a costly operation
+			// and will likely cause a spike in the framerate.
+			AtlasUtilities.ClearCache();
 			Resources.UnloadUnusedAssets();
 			Resources.UnloadUnusedAssets();
 		}
 		}
 	}
 	}

+ 15 - 1
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Asset Types/AnimationReferenceAssetEditor.cs

@@ -33,6 +33,7 @@ using UnityEngine;
 using UnityEditor;
 using UnityEditor;
 
 
 using System.Reflection;
 using System.Reflection;
+using System;
 
 
 namespace Spine.Unity.Editor {
 namespace Spine.Unity.Editor {
 	using Editor = UnityEditor.Editor;
 	using Editor = UnityEditor.Editor;
@@ -58,7 +59,11 @@ namespace Spine.Unity.Editor {
 		SkeletonData lastSkeletonData;
 		SkeletonData lastSkeletonData;
 
 
 		void OnEnable () { HandleOnEnablePreview(); }
 		void OnEnable () { HandleOnEnablePreview(); }
-		void OnDestroy () { HandleOnDestroyPreview(); }
+		void OnDestroy () {
+			HandleOnDestroyPreview();
+			AppDomain.CurrentDomain.DomainUnload -= OnDomainUnload;
+			EditorApplication.update -= preview.HandleEditorUpdate;
+		}
 
 
 		public override void OnInspectorGUI () {
 		public override void OnInspectorGUI () {
 			animationNameProperty = animationNameProperty ?? serializedObject.FindProperty("animationName");
 			animationNameProperty = animationNameProperty ?? serializedObject.FindProperty("animationName");
@@ -133,6 +138,11 @@ namespace Spine.Unity.Editor {
 		void HandleOnEnablePreview () {
 		void HandleOnEnablePreview () {
 			if (ThisSkeletonDataAsset != null && ThisSkeletonDataAsset.skeletonJSON == null)
 			if (ThisSkeletonDataAsset != null && ThisSkeletonDataAsset.skeletonJSON == null)
 				return;
 				return;
+			SpineEditorUtilities.ConfirmInitialization();
+
+			// This handles the case where the managed editor assembly is unloaded before recompilation when code changes.
+			AppDomain.CurrentDomain.DomainUnload -= OnDomainUnload;
+			AppDomain.CurrentDomain.DomainUnload += OnDomainUnload;
 
 
 			preview.Initialize(this.Repaint, ThisSkeletonDataAsset, LastSkinName);
 			preview.Initialize(this.Repaint, ThisSkeletonDataAsset, LastSkinName);
 			preview.PlayPauseAnimation(ThisAnimationName, true);
 			preview.PlayPauseAnimation(ThisAnimationName, true);
@@ -142,6 +152,10 @@ namespace Spine.Unity.Editor {
 			EditorApplication.update += preview.HandleEditorUpdate;
 			EditorApplication.update += preview.HandleEditorUpdate;
 		}
 		}
 
 
+		private void OnDomainUnload (object sender, EventArgs e) {
+			OnDestroy();
+		}
+
 		private void HandleOnSkinChanged (string skinName) {
 		private void HandleOnSkinChanged (string skinName) {
 			EditorPrefs.SetString(LastSkinKey, skinName);
 			EditorPrefs.SetString(LastSkinKey, skinName);
 			preview.PlayPauseAnimation(ThisAnimationName, true);
 			preview.PlayPauseAnimation(ThisAnimationName, true);

+ 5 - 4
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Asset Types/SkeletonDataAssetInspector.cs

@@ -1158,7 +1158,7 @@ namespace Spine.Unity.Editor {
 			float lineRectWidth = lineRect.width;
 			float lineRectWidth = lineRect.width;
 			TrackEntry t = skeletonAnimation.AnimationState.GetCurrent(0);
 			TrackEntry t = skeletonAnimation.AnimationState.GetCurrent(0);
 
 
-			if (t != null) {
+			if (t != null && Icons.userEvent != null) { // when changing to play mode, Icons.userEvent  will not be reset
 				int loopCount = (int)(t.TrackTime / t.TrackEnd);
 				int loopCount = (int)(t.TrackTime / t.TrackEnd);
 				float currentTime = t.TrackTime - (t.TrackEnd * loopCount);
 				float currentTime = t.TrackTime - (t.TrackEnd * loopCount);
 				float normalizedTime = currentTime / t.Animation.Duration;
 				float normalizedTime = currentTime / t.Animation.Duration;
@@ -1176,14 +1176,15 @@ namespace Spine.Unity.Editor {
 				for (int i = 0; i < currentAnimationEvents.Count; i++) {
 				for (int i = 0; i < currentAnimationEvents.Count; i++) {
 					float eventTime = currentAnimationEventTimes[i];
 					float eventTime = currentAnimationEventTimes[i];
 					var userEventIcon = Icons.userEvent;
 					var userEventIcon = Icons.userEvent;
+					float iconX = Mathf.Max(((eventTime / t.Animation.Duration) * lineRectWidth) - (userEventIcon.width / 2), barRect.x);
+					float iconY = barRect.y + userEventIcon.height;
 					var evRect = new Rect(barRect) {
 					var evRect = new Rect(barRect) {
-						x = Mathf.Max(((eventTime / t.Animation.Duration) * lineRectWidth) - (userEventIcon.width / 2), barRect.x),
-						y = barRect.y + userEventIcon.height,
+						x = iconX,
+						y = iconY,
 						width = userEventIcon.width,
 						width = userEventIcon.width,
 						height = userEventIcon.height
 						height = userEventIcon.height
 					};
 					};
 					GUI.DrawTexture(evRect, userEventIcon);
 					GUI.DrawTexture(evRect, userEventIcon);
-
 					Event ev = Event.current;
 					Event ev = Event.current;
 					if (ev.type == EventType.Repaint) {
 					if (ev.type == EventType.Repaint) {
 						if (evRect.Contains(ev.mousePosition)) {
 						if (evRect.Contains(ev.mousePosition)) {

+ 3 - 4
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/AssetUtility.cs

@@ -919,15 +919,14 @@ namespace Spine.Unity.Editor {
 						skeletonDataAsset.scale = SpineEditorUtilities.Preferences.defaultScale;
 						skeletonDataAsset.scale = SpineEditorUtilities.Preferences.defaultScale;
 						skeletonDataAsset.blendModeMaterials.applyAdditiveMaterial = !SpineEditorUtilities.Preferences.UsesPMAWorkflow;
 						skeletonDataAsset.blendModeMaterials.applyAdditiveMaterial = !SpineEditorUtilities.Preferences.UsesPMAWorkflow;
 					}
 					}
-
 					AssetDatabase.CreateAsset(skeletonDataAsset, filePath);
 					AssetDatabase.CreateAsset(skeletonDataAsset, filePath);
-					AssetDatabase.SaveAssets();
 				} else {
 				} else {
 					skeletonDataAsset.atlasAssets = atlasAssets;
 					skeletonDataAsset.atlasAssets = atlasAssets;
 					skeletonDataAsset.Clear();
 					skeletonDataAsset.Clear();
-					var skeletonData = skeletonDataAsset.GetSkeletonData(true);
-					BlendModeMaterialsUtility.UpdateBlendModeMaterials(skeletonDataAsset, ref skeletonData);
 				}
 				}
+				var skeletonData = skeletonDataAsset.GetSkeletonData(true);
+				BlendModeMaterialsUtility.UpdateBlendModeMaterials(skeletonDataAsset, ref skeletonData);
+				AssetDatabase.SaveAssets();
 
 
 				return skeletonDataAsset;
 				return skeletonDataAsset;
 			} else {
 			} else {

+ 3 - 1
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Windows/SpinePreferences.cs

@@ -236,7 +236,9 @@ namespace Spine.Unity.Editor {
 					if (string.IsNullOrEmpty(textureSettingsRef.stringValue)) {
 					if (string.IsNullOrEmpty(textureSettingsRef.stringValue)) {
 						var pmaTextureSettingsReferenceGUIDS = AssetDatabase.FindAssets("PMATexturePreset");
 						var pmaTextureSettingsReferenceGUIDS = AssetDatabase.FindAssets("PMATexturePreset");
 						if (pmaTextureSettingsReferenceGUIDS.Length > 0) {
 						if (pmaTextureSettingsReferenceGUIDS.Length > 0) {
-							textureSettingsRef.stringValue = AssetDatabase.GUIDToAssetPath(pmaTextureSettingsReferenceGUIDS[0]);
+							var assetPath = AssetDatabase.GUIDToAssetPath(pmaTextureSettingsReferenceGUIDS[0]);
+							if (!string.IsNullOrEmpty(assetPath))
+								textureSettingsRef.stringValue = assetPath;
 						}
 						}
 					}
 					}
 
 

+ 30 - 5
spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs

@@ -218,6 +218,11 @@ namespace Spine.Unity {
 			}
 			}
 		}
 		}
 
 
+		protected override void OnDestroy () {
+			Clear();
+			base.OnDestroy();
+		}
+
 		public override void Rebuild (CanvasUpdate update) {
 		public override void Rebuild (CanvasUpdate update) {
 			base.Rebuild(update);
 			base.Rebuild(update);
 			if (canvasRenderer.cull) return;
 			if (canvasRenderer.cull) return;
@@ -458,9 +463,8 @@ namespace Spine.Unity {
 
 
 			for (int i = 0; i < canvasRenderers.Count; ++i)
 			for (int i = 0; i < canvasRenderers.Count; ++i)
 				canvasRenderers[i].Clear();
 				canvasRenderers[i].Clear();
-			foreach (var mesh in meshes)
-				Destroy(mesh);
-			meshes.Clear();
+			DestroyMeshes();
+			DisposeMeshBuffers();
 		}
 		}
 
 
 		public void TrimRenderers () {
 		public void TrimRenderers () {
@@ -562,6 +566,14 @@ namespace Spine.Unity {
 			}
 			}
 		}
 		}
 
 
+		protected void DisposeMeshBuffers () {
+			if (meshBuffers != null) {
+				meshBuffers.GetNext().Dispose();
+				meshBuffers.GetNext().Dispose();
+				meshBuffers = null;
+			}
+		}
+
 		protected void UpdateMeshSingleCanvasRenderer () {
 		protected void UpdateMeshSingleCanvasRenderer () {
 			if (canvasRenderers.Count > 0)
 			if (canvasRenderers.Count > 0)
 				DisableUnusedCanvasRenderers(usedCount : 0);
 				DisableUnusedCanvasRenderers(usedCount : 0);
@@ -724,9 +736,22 @@ namespace Spine.Unity {
 		protected void EnsureMeshesCount (int targetCount) {
 		protected void EnsureMeshesCount (int targetCount) {
 			int oldCount = meshes.Count;
 			int oldCount = meshes.Count;
 			meshes.EnsureCapacity(targetCount);
 			meshes.EnsureCapacity(targetCount);
-			var meshesItems = meshes.Items;
 			for (int i = oldCount; i < targetCount; i++)
 			for (int i = oldCount; i < targetCount; i++)
-				if (meshesItems[i] == null) meshesItems[i] = new Mesh();
+				meshes.Add(SpineMesh.NewSkeletonMesh());
+		}
+
+		protected void DestroyMeshes () {
+			foreach (var mesh in meshes) {
+#if UNITY_EDITOR
+				if (Application.isEditor && !Application.isPlaying)
+					UnityEngine.Object.DestroyImmediate(mesh);
+				else
+					UnityEngine.Object.Destroy(mesh);
+#else
+					UnityEngine.Object.Destroy(mesh);
+#endif
+			}
+			meshes.Clear();
 		}
 		}
 
 
 		protected void EnsureSeparatorPartCount () {
 		protected void EnsureSeparatorPartCount () {

+ 8 - 0
spine-unity/Assets/Spine/Runtime/spine-unity/Mesh Generation/MeshGenerator.cs

@@ -27,6 +27,10 @@
  * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
  *****************************************************************************/
 
 
+#if UNITY_2019_3_OR_NEWER
+#define MESH_SET_TRIANGLES_PROVIDES_LENGTH_PARAM
+#endif
+
 // Not for optimization. Do not disable.
 // Not for optimization. Do not disable.
 #define SPINE_TRIANGLECHECK // Avoid calling SetTriangles at the cost of checking for mesh differences (vertex counts, memberwise attachment list compare) every frame.
 #define SPINE_TRIANGLECHECK // Avoid calling SetTriangles at the cost of checking for mesh differences (vertex counts, memberwise attachment list compare) every frame.
 //#define SPINE_DEBUG
 //#define SPINE_DEBUG
@@ -1117,7 +1121,11 @@ namespace Spine.Unity {
 			mesh.subMeshCount = submeshCount;
 			mesh.subMeshCount = submeshCount;
 
 
 			for (int i = 0; i < submeshCount; i++)
 			for (int i = 0; i < submeshCount; i++)
+#if MESH_SET_TRIANGLES_PROVIDES_LENGTH_PARAM
+				mesh.SetTriangles(submeshesItems[i].Items, 0, submeshesItems[i].Count, i, false);
+#else
 				mesh.SetTriangles(submeshesItems[i].Items, i, false);
 				mesh.SetTriangles(submeshesItems[i].Items, i, false);
+#endif
 		}
 		}
 		#endregion
 		#endregion
 
 

+ 29 - 7
spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs

@@ -242,11 +242,17 @@ namespace Spine.Unity.AttachmentTools {
 		/// Fills the outputAttachments list with new attachment objects based on the attachments in sourceAttachments,
 		/// Fills the outputAttachments list with new attachment objects based on the attachments in sourceAttachments,
 		/// but mapped to a new single texture using the same material.</summary>
 		/// but mapped to a new single texture using the same material.</summary>
 		/// <remarks>Returned <c>Material</c> and <c>Texture</c> behave like <c>new Texture2D()</c>, thus you need to call <c>Destroy()</c>
 		/// <remarks>Returned <c>Material</c> and <c>Texture</c> behave like <c>new Texture2D()</c>, thus you need to call <c>Destroy()</c>
-		/// to free resources.</remarks>
+		/// to free resources.
+		/// This method caches necessary Texture copies for later re-use, which might steadily increase the texture memory
+		/// footprint when used excessively. Set <paramref name="clearCache"/> to <c>true</c>
+		/// or call <see cref="AtlasUtilities.ClearCache()"/> to clear this texture cache.
+		/// You may want to call <c>Resources.UnloadUnusedAssets()</c> after that.
+		/// </remarks>
 		/// <param name="sourceAttachments">The list of attachments to be repacked.</param>
 		/// <param name="sourceAttachments">The list of attachments to be repacked.</param>
 		/// <param name = "outputAttachments">The List(Attachment) to populate with the newly created Attachment objects.</param>
 		/// <param name = "outputAttachments">The List(Attachment) to populate with the newly created Attachment objects.</param>
-		///
 		/// <param name="materialPropertySource">May be null. If no Material property source is provided, no special </param>
 		/// <param name="materialPropertySource">May be null. If no Material property source is provided, no special </param>
+		/// <param name="clearCache">When set to <c>true</c>, <see cref="AtlasUtilities.ClearCache()"/> is called after
+		/// repacking to clear the texture cache. See remarks for additional info.</param>
 		public static void GetRepackedAttachments (List<Attachment> sourceAttachments, List<Attachment> outputAttachments, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, string newAssetName = "Repacked Attachments", bool clearCache = false, bool useOriginalNonrenderables = true) {
 		public static void GetRepackedAttachments (List<Attachment> sourceAttachments, List<Attachment> outputAttachments, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, string newAssetName = "Repacked Attachments", bool clearCache = false, bool useOriginalNonrenderables = true) {
 			if (sourceAttachments == null) throw new System.ArgumentNullException("sourceAttachments");
 			if (sourceAttachments == null) throw new System.ArgumentNullException("sourceAttachments");
 			if (outputAttachments == null) throw new System.ArgumentNullException("outputAttachments");
 			if (outputAttachments == null) throw new System.ArgumentNullException("outputAttachments");
@@ -337,7 +343,14 @@ namespace Spine.Unity.AttachmentTools {
 		/// <remarks>GetRepackedSkin is an expensive operation, preferably call it at level load time.
 		/// <remarks>GetRepackedSkin is an expensive operation, preferably call it at level load time.
 		/// No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them.
 		/// No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them.
 		/// Returned <c>Material</c> and <c>Texture</c> behave like <c>new Texture2D()</c>, thus you need to call <c>Destroy()</c>
 		/// Returned <c>Material</c> and <c>Texture</c> behave like <c>new Texture2D()</c>, thus you need to call <c>Destroy()</c>
-		/// to free resources.</remarks>
+		/// to free resources.
+		/// This method caches necessary Texture copies for later re-use, which might steadily increase the texture memory
+		/// footprint when used excessively. Set <paramref name="clearCache"/> to <c>true</c>
+		/// or call <see cref="AtlasUtilities.ClearCache()"/> to clear this texture cache.
+		/// You may want to call <c>Resources.UnloadUnusedAssets()</c> after that.
+		/// </remarks>
+		/// <param name="clearCache">When set to <c>true</c>, <see cref="AtlasUtilities.ClearCache()"/> is called after
+		/// repacking to clear the texture cache. See remarks for additional info.</param>
 		/// <param name="additionalTexturePropertyIDsToCopy">Optional additional textures (such as normal maps) to copy while repacking.
 		/// <param name="additionalTexturePropertyIDsToCopy">Optional additional textures (such as normal maps) to copy while repacking.
 		/// To copy e.g. the main texture and normal maps, pass 'new int[] { Shader.PropertyToID("_BumpMap") }' at this parameter.</param>
 		/// To copy e.g. the main texture and normal maps, pass 'new int[] { Shader.PropertyToID("_BumpMap") }' at this parameter.</param>
 		/// <param name="additionalOutputTextures">When <c>additionalTexturePropertyIDsToCopy</c> is non-null,
 		/// <param name="additionalOutputTextures">When <c>additionalTexturePropertyIDsToCopy</c> is non-null,
@@ -368,10 +381,7 @@ namespace Spine.Unity.AttachmentTools {
 		/// <summary>
 		/// <summary>
 		/// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas
 		/// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas
 		/// comprised of all the regions from the original skin.</summary>
 		/// comprised of all the regions from the original skin.</summary>
-		/// <remarks>GetRepackedSkin is an expensive operation, preferably call it at level load time.
-		/// No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them.
-		/// Returned <c>Material</c> and <c>Texture</c> behave like <c>new Texture2D()</c>, thus you need to call <c>Destroy()</c>
-		/// to free resources.</remarks>
+		/// See documentation of <see cref="GetRepackedSkin"/> for details.
 		public static Skin GetRepackedSkin (this Skin o, string newName, Shader shader, out Material outputMaterial, out Texture2D outputTexture,
 		public static Skin GetRepackedSkin (this Skin o, string newName, Shader shader, out Material outputMaterial, out Texture2D outputTexture,
 			int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps,
 			int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps,
 			Material materialPropertySource = null, bool clearCache = false, bool useOriginalNonrenderables = true,
 			Material materialPropertySource = null, bool clearCache = false, bool useOriginalNonrenderables = true,
@@ -525,6 +535,18 @@ namespace Spine.Unity.AttachmentTools {
 		static Dictionary<IntAndAtlasRegionKey, Texture2D> CachedRegionTextures = new Dictionary<IntAndAtlasRegionKey, Texture2D>();
 		static Dictionary<IntAndAtlasRegionKey, Texture2D> CachedRegionTextures = new Dictionary<IntAndAtlasRegionKey, Texture2D>();
 		static List<Texture2D> CachedRegionTexturesList = new List<Texture2D>();
 		static List<Texture2D> CachedRegionTexturesList = new List<Texture2D>();
 
 
+		/// <summary>
+		/// Frees up textures cached by repacking and remapping operations.
+		///
+		/// Calling <see cref="AttachmentCloneExtensions.GetRemappedClone"/> with parameter <c>premultiplyAlpha=true</c>,
+		/// <see cref="GetRepackedAttachments"/> or <see cref="GetRepackedSkin"/> will cache textures for later re-use,
+		///	which might steadily increase the texture memory footprint when used excessively.
+		///	You can clear this Texture cache by calling <see cref="AtlasUtilities.ClearCache()"/>.
+		/// You may also want to call <c>Resources.UnloadUnusedAssets()</c> after that. Be aware that while this cleanup
+		/// frees up memory, it is also a costly operation and will likely cause a spike in the framerate.
+		/// Thus it is recommended to perform costly repacking and cleanup operations after e.g. a character customization
+		/// screen has been exited, and if required additionally after a certain number of <c>GetRemappedClone()</c> calls.
+		/// </summary>
 		public static void ClearCache () {
 		public static void ClearCache () {
 			foreach (var t in CachedRegionTexturesList) {
 			foreach (var t in CachedRegionTexturesList) {
 				UnityEngine.Object.Destroy(t);
 				UnityEngine.Object.Destroy(t);

+ 6 - 1
spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentCloneExtensions.cs

@@ -80,7 +80,8 @@ namespace Spine.Unity.AttachmentTools {
 		/// <param name="o">The original attachment.</param>
 		/// <param name="o">The original attachment.</param>
 		/// <param name="sprite">The sprite whose texture to use.</param>
 		/// <param name="sprite">The sprite whose texture to use.</param>
 		/// <param name="sourceMaterial">The source material used to copy the shader and material properties from.</param>
 		/// <param name="sourceMaterial">The source material used to copy the shader and material properties from.</param>
-		/// <param name="premultiplyAlpha">If <c>true</c>, a premultiply alpha clone of the original texture will be created.</param>
+		/// <param name="premultiplyAlpha">If <c>true</c>, a premultiply alpha clone of the original texture will be created.
+		/// See remarks below for additional info.</param>
 		/// <param name="cloneMeshAsLinked">If <c>true</c> MeshAttachments will be cloned as linked meshes and will inherit animation from the original attachment.</param>
 		/// <param name="cloneMeshAsLinked">If <c>true</c> MeshAttachments will be cloned as linked meshes and will inherit animation from the original attachment.</param>
 		/// <param name="useOriginalRegionSize">If <c>true</c> the size of the original attachment will be followed, instead of using the Sprite size.</param>
 		/// <param name="useOriginalRegionSize">If <c>true</c> the size of the original attachment will be followed, instead of using the Sprite size.</param>
 		/// <param name="pivotShiftsMeshUVCoords">If <c>true</c> and the original Attachment is a MeshAttachment, then
 		/// <param name="pivotShiftsMeshUVCoords">If <c>true</c> and the original Attachment is a MeshAttachment, then
@@ -89,6 +90,10 @@ namespace Spine.Unity.AttachmentTools {
 		///	<param name="useOriginalRegionScale">If <c>true</c> and the original Attachment is a RegionAttachment, then
 		///	<param name="useOriginalRegionScale">If <c>true</c> and the original Attachment is a RegionAttachment, then
 		///	the original region's scale value is used instead of the Sprite's pixels per unit property. Since uniform scale is used,
 		///	the original region's scale value is used instead of the Sprite's pixels per unit property. Since uniform scale is used,
 		///	x scale of the original attachment (width scale) is used, scale in y direction (height scale) is ignored.</param>
 		///	x scale of the original attachment (width scale) is used, scale in y direction (height scale) is ignored.</param>
+		///	<remarks>When parameter <c>premultiplyAlpha</c> is set to <c>true</c>, a premultiply alpha clone of the
+		///	original texture will be created. Additionally, this PMA Texture clone is cached for later re-use,
+		///	which might steadily increase the Texture memory footprint when used excessively.
+		///	See <see cref="AtlasUtilities.ClearCache()"/> on how to clear these cached textures.</remarks>
 		public static Attachment GetRemappedClone (this Attachment o, Sprite sprite, Material sourceMaterial,
 		public static Attachment GetRemappedClone (this Attachment o, Sprite sprite, Material sourceMaterial,
 			bool premultiplyAlpha = true, bool cloneMeshAsLinked = true, bool useOriginalRegionSize = false,
 			bool premultiplyAlpha = true, bool cloneMeshAsLinked = true, bool useOriginalRegionSize = false,
 			bool pivotShiftsMeshUVCoords = true, bool useOriginalRegionScale = false) {
 			bool pivotShiftsMeshUVCoords = true, bool useOriginalRegionScale = false) {

+ 4 - 1
spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentRegionExtensions.cs

@@ -125,7 +125,10 @@ namespace Spine.Unity.AttachmentTools {
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
-		/// Creates a Spine.AtlasRegion that uses a premultiplied alpha duplicate texture of the Sprite's texture data. Returns a RegionAttachment that uses it. Use this if you plan to use a premultiply alpha shader such as "Spine/Skeleton"</summary>
+		/// Creates a Spine.AtlasRegion that uses a premultiplied alpha duplicate texture of the Sprite's texture data.
+		/// Returns a RegionAttachment that uses it. Use this if you plan to use a premultiply alpha shader such as "Spine/Skeleton".</summary>
+		/// <remarks>The duplicate texture is cached for later re-use. See documentation of
+		/// <see cref="AttachmentCloneExtensions.GetRemappedClone"/> for additional details.</remarks>
 		public static RegionAttachment ToRegionAttachmentPMAClone (this Sprite sprite, Shader shader, TextureFormat textureFormat = AtlasUtilities.SpineTextureFormat, bool mipmaps = AtlasUtilities.UseMipMaps, Material materialPropertySource = null, float rotation = 0f) {
 		public static RegionAttachment ToRegionAttachmentPMAClone (this Sprite sprite, Shader shader, TextureFormat textureFormat = AtlasUtilities.SpineTextureFormat, bool mipmaps = AtlasUtilities.UseMipMaps, Material materialPropertySource = null, float rotation = 0f) {
 			if (sprite == null) throw new System.ArgumentNullException("sprite");
 			if (sprite == null) throw new System.ArgumentNullException("sprite");
 			if (shader == null) throw new System.ArgumentNullException("shader");
 			if (shader == null) throw new System.ArgumentNullException("shader");

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio