Browse Source

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

badlogic 5 years ago
parent
commit
8a93522ce9

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

@@ -1064,7 +1064,7 @@ namespace Spine {
 				case MixBlend.Setup:
 					deformArray.Clear();
 					return;
-				case MixBlend.Replace:
+				case MixBlend.First:
 					if (alpha == 1) {
 						deformArray.Clear();
 						return;

+ 12 - 13
spine-csharp/src/AnimationState.cs

@@ -76,8 +76,7 @@ namespace Spine {
 		protected AnimationStateData data;
 		private readonly ExposedList<TrackEntry> tracks = new ExposedList<TrackEntry>();
 		private readonly ExposedList<Event> events = new ExposedList<Event>();
-
-		// difference to libgdx reference: delegates are used for event callbacks instead of 'Array<AnimationStateListener> listeners'.
+		// difference to libgdx reference: delegates are used for event callbacks instead of 'final SnapshotArray<AnimationStateListener> listeners'.
 		internal void OnStart (TrackEntry entry) { if (Start != null) Start(entry); }
 		internal void OnInterrupt (TrackEntry entry) { if (Interrupt != null) Interrupt(entry); }
 		internal void OnEnd (TrackEntry entry) { if (End != null) End(entry); }
@@ -85,12 +84,12 @@ namespace Spine {
 		internal void OnComplete (TrackEntry entry) { if (Complete != null) Complete(entry); }
 		internal void OnEvent (TrackEntry entry, Event e) { if (Event != null) Event(entry, e); }
 
-		public delegate void TrackEntryDelegate(TrackEntry trackEntry);
+		public delegate void TrackEntryDelegate (TrackEntry trackEntry);
 		public event TrackEntryDelegate Start, Interrupt, End, Dispose, Complete;
 
-		public delegate void TrackEntryEventDelegate(TrackEntry trackEntry, Event e);
+		public delegate void TrackEntryEventDelegate (TrackEntry trackEntry, Event e);
 		public event TrackEntryEventDelegate Event;
-
+		// end of difference
 		private readonly EventQueue queue; // Initialized by constructor.
 		private readonly HashSet<int> propertyIDs = new HashSet<int>();
 		private bool animationsChanged;
@@ -98,7 +97,7 @@ namespace Spine {
 
 		private readonly Pool<TrackEntry> trackEntryPool = new Pool<TrackEntry>();
 
-		public AnimationState(AnimationStateData data) {
+		public AnimationState (AnimationStateData data) {
 			if (data == null) throw new ArgumentNullException("data", "data cannot be null.");
 			this.data = data;
 			this.queue = new EventQueue(
@@ -233,8 +232,8 @@ namespace Spine {
 				} else {
 					var timelineMode = current.timelineMode.Items;
 
-					bool firstFrame = current.timelinesRotation.Count == 0;
-					if (firstFrame) current.timelinesRotation.EnsureCapacity(timelines.Count << 1);
+					bool firstFrame = current.timelinesRotation.Count != timelineCount << 1;
+					if (firstFrame) current.timelinesRotation.Resize(timelines.Count << 1);
 					var timelinesRotation = current.timelinesRotation.Items;
 
 					for (int ii = 0; ii < timelineCount; ii++) {
@@ -242,8 +241,8 @@ namespace Spine {
 						MixBlend timelineBlend = (timelineMode[ii] & AnimationState.NotLast - 1) == AnimationState.Subsequent ? blend : MixBlend.Setup;
 						var rotateTimeline = timeline as RotateTimeline;
 						if (rotateTimeline != null)
-							ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1,
-												firstFrame);
+							ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation,
+												ii << 1, firstFrame);
 						else
 							timeline.Apply(skeleton, animationLast, animationTime, events, mix, timelineBlend, MixDirection.In);
 					}
@@ -287,7 +286,7 @@ namespace Spine {
 				var timelineMode = from.timelineMode.Items;
 				var timelineHoldMix = from.timelineHoldMix.Items;
 
-				bool firstFrame = from.timelinesRotation.Count == 0;
+				bool firstFrame = from.timelinesRotation.Count != timelineCount << 1;
 				if (firstFrame)	from.timelinesRotation.Resize(timelines.Count << 1); // from.timelinesRotation.setSize
 				var timelinesRotation = from.timelinesRotation.Items;
 
@@ -325,8 +324,8 @@ namespace Spine {
 
 					var rotateTimeline = timeline as RotateTimeline;
 					if (rotateTimeline != null) {
-						ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1,
-											firstFrame);
+						ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation,
+											i << 1, firstFrame);
 					} else {
 						if (timelineBlend == MixBlend.Setup) {
 							if (timeline is AttachmentTimeline) {

+ 19 - 3
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java

@@ -37,6 +37,7 @@ import com.badlogic.gdx.graphics.Color;
 import com.badlogic.gdx.math.MathUtils;
 import com.badlogic.gdx.utils.Array;
 import com.badlogic.gdx.utils.FloatArray;
+import com.badlogic.gdx.utils.IntSet;
 
 import com.esotericsoftware.spine.attachments.Attachment;
 import com.esotericsoftware.spine.attachments.VertexAttachment;
@@ -44,21 +45,36 @@ import com.esotericsoftware.spine.attachments.VertexAttachment;
 /** A simple container for a list of timelines and a name. */
 public class Animation {
 	final String name;
-	final Array<Timeline> timelines;
+	Array<Timeline> timelines;
+	final IntSet timelineIDs = new IntSet();
 	float duration;
 
 	public Animation (String name, Array<Timeline> timelines, float duration) {
 		if (name == null) throw new IllegalArgumentException("name cannot be null.");
-		if (timelines == null) throw new IllegalArgumentException("timelines cannot be null.");
 		this.name = name;
-		this.timelines = timelines;
 		this.duration = duration;
+		setTimelines(timelines);
 	}
 
+	/** If the returned array or the timelines it contains are modified, {@link #setTimelines(Array)} must be called. */
 	public Array<Timeline> getTimelines () {
 		return timelines;
 	}
 
+	public void setTimelines (Array<Timeline> timelines) {
+		if (timelines == null) throw new IllegalArgumentException("timelines cannot be null.");
+		this.timelines = timelines;
+
+		timelineIDs.clear();
+		for (Timeline timeline : timelines)
+			timelineIDs.add(timeline.getPropertyId());
+	}
+
+	/** Return true if this animation contains a timeline with the specified property ID. **/
+	public boolean hasTimeline (int id) {
+		return timelineIDs.contains(id);
+	}
+
 	/** The duration of the animation in seconds, which is the highest time of all keys in the timeline. */
 	public float getDuration () {
 		return duration;

+ 3 - 9
spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java

@@ -37,6 +37,7 @@ import com.badlogic.gdx.utils.IntArray;
 import com.badlogic.gdx.utils.IntSet;
 import com.badlogic.gdx.utils.Pool;
 import com.badlogic.gdx.utils.Pool.Poolable;
+
 import com.esotericsoftware.spine.Animation.AttachmentTimeline;
 import com.esotericsoftware.spine.Animation.DrawOrderTimeline;
 import com.esotericsoftware.spine.Animation.EventTimeline;
@@ -745,11 +746,11 @@ public class AnimationState {
 			if (!propertyIDs.add(id))
 				timelineMode[i] = SUBSEQUENT;
 			else if (to == null || timeline instanceof AttachmentTimeline || timeline instanceof DrawOrderTimeline
-				|| timeline instanceof EventTimeline || !hasTimeline(to, id)) {
+				|| timeline instanceof EventTimeline || !to.animation.hasTimeline(id)) {
 				timelineMode[i] = FIRST;
 			} else {
 				for (TrackEntry next = to.mixingTo; next != null; next = next.mixingTo) {
-					if (hasTimeline(next, id)) continue;
+					if (next.animation.hasTimeline(id)) continue;
 					if (next.mixDuration > 0) {
 						timelineMode[i] = HOLD_MIX;
 						timelineHoldMix[i] = next;
@@ -776,13 +777,6 @@ public class AnimationState {
 		}
 	}
 
-	private boolean hasTimeline (TrackEntry entry, int id) {
-		Object[] timelines = entry.animation.timelines.items;
-		for (int i = 0, n = entry.animation.timelines.size; i < n; i++)
-			if (((Timeline)timelines[i]).getPropertyId() == id) return true;
-		return false;
-	}
-
 	/** Returns the track entry for the animation currently playing on the track, or null if no animation is currently playing. */
 	public TrackEntry getCurrent (int trackIndex) {
 		if (trackIndex < 0) throw new IllegalArgumentException("trackIndex must be >= 0.");

+ 2 - 2
spine-ue4/README.md

@@ -1,5 +1,5 @@
 # spine-ue4
-The spine-ue4 runtime provides functionality to load, manipulate and render [Spine](http://esotericsoftware.com) skeletal animation data using [Unreal Engine 4.18+](https://www.unrealengine.com/). spine-ue4 is based on [spine-cpp](../spine-cpp).
+The spine-ue4 runtime provides functionality to load, manipulate and render [Spine](http://esotericsoftware.com) skeletal animation data using [Unreal Engine 4.21+](https://www.unrealengine.com/). spine-ue4 is based on [spine-cpp](../spine-cpp).
 
 ## Licensing
 
@@ -33,7 +33,7 @@ See the [Spine Runtimes documentation](http://esotericsoftware.com/spine-documen
 ## Example
 ### [Please see the spine-ue4 guide for full documentation](http://esotericsoftware.com/spine-ue4)
 
-The Spine UE4 example works on all platforms supported by Unreal Engine. The samples require Unreal Engine 4.18.
+The Spine UE4 example works on all platforms supported by Unreal Engine. The samples require Unreal Engine 4.23+.
 
 1. Copy the `spine-cpp` folder from this repositories root directory to your `Plugins/SpinePlugin/Sources/SpinePlugin/Public/` directory.
 2. Open the SpineUE4.uproject file with Unreal Editor

+ 1 - 1
spine-ue4/SpineUE4.uproject

@@ -1,6 +1,6 @@
 {
 	"FileVersion": 3,
-	"EngineAssociation": "4.22",
+	"EngineAssociation": "4.23",
 	"Category": "",
 	"Description": "",
 	"Modules": [

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

@@ -659,7 +659,7 @@ namespace Spine.Unity.Editor {
 		}
 
 		void DoReimport () {
-			AssetUtility.ImportSpineContent(new [] { AssetDatabase.GetAssetPath(skeletonJSON.objectReferenceValue) }, true);
+			AssetUtility.ImportSpineContent(new [] { AssetDatabase.GetAssetPath(skeletonJSON.objectReferenceValue) }, null, true);
 			preview.Clear();
 			InitializeEditor();
 			EditorUtility.SetDirty(targetSkeletonDataAsset);

+ 11 - 22
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/AssetUtility.cs

@@ -65,7 +65,7 @@ namespace Spine.Unity.Editor {
 		public static readonly List<ScriptableObject> protectFromStackGarbageCollection = new List<ScriptableObject>();
 		public static HashSet<string> assetsImportedInWrongState = new HashSet<string>();
 
-		public static void HandleOnPostprocessAllAssets (string[] imported) {
+		public static void HandleOnPostprocessAllAssets (string[] imported, List<string> texturesWithoutMetaFile) {
 			// In case user used "Assets -> Reimport All", during the import process,
 			// asset database is not initialized until some point. During that period,
 			// all attempts to load any assets using API (i.e. AssetDatabase.LoadAssetAtPath)
@@ -87,7 +87,7 @@ namespace Spine.Unity.Editor {
 			if (AssetDatabaseAvailabilityDetector.IsAssetDatabaseAvailable()) {
 				string[] combinedAssets = AssetUtility.assetsImportedInWrongState.ToArray();
 				AssetUtility.assetsImportedInWrongState.Clear();
-				AssetUtility.ImportSpineContent(combinedAssets);
+				AssetUtility.ImportSpineContent(combinedAssets, texturesWithoutMetaFile);
 			}
 		}
 
@@ -243,7 +243,9 @@ namespace Spine.Unity.Editor {
 		}
 #endregion
 
-		public static void ImportSpineContent (string[] imported, bool reimport = false) {
+		public static void ImportSpineContent (string[] imported, List<string> texturesWithoutMetaFile, 
+			bool reimport = false) {
+
 			var atlasPaths = new List<string>();
 			var imagePaths = new List<string>();
 			var skeletonPaths = new List<PathAndProblemInfo>();
@@ -285,7 +287,7 @@ namespace Spine.Unity.Editor {
 				if (ap.StartsWith("Packages"))
 					continue;
 				TextAsset atlasText = AssetDatabase.LoadAssetAtPath<TextAsset>(ap);
-				AtlasAssetBase atlas = IngestSpineAtlas(atlasText);
+				AtlasAssetBase atlas = IngestSpineAtlas(atlasText, texturesWithoutMetaFile);
 				atlases.Add(atlas);
 			}
 
@@ -428,7 +430,7 @@ namespace Spine.Unity.Editor {
 			return arr;
 		}
 
-		static AtlasAssetBase IngestSpineAtlas (TextAsset atlasText) {
+		static AtlasAssetBase IngestSpineAtlas (TextAsset atlasText, List<string> texturesWithoutMetaFile) {
 			if (atlasText == null) {
 				Debug.LogWarning("Atlas source cannot be null!");
 				return null;
@@ -469,8 +471,9 @@ namespace Spine.Unity.Editor {
 			for (int i = 0; i < pageFiles.Count; i++) {
 				string texturePath = assetPath + "/" + pageFiles[i];
 				Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D));
-				if (SpineEditorUtilities.Preferences.setTextureImporterSettings) {
-					SetDefaultTextureSettingsIfNew(texturePath, atlasAsset);
+				bool textureIsUninitialized = texturesWithoutMetaFile != null && texturesWithoutMetaFile.Contains(texturePath);
+				if (SpineEditorUtilities.Preferences.setTextureImporterSettings && textureIsUninitialized) {
+					SetDefaultTextureSettings(texturePath, atlasAsset);
 				}
 
 				string pageName = Path.GetFileNameWithoutExtension(pageFiles[i]);
@@ -546,27 +549,13 @@ namespace Spine.Unity.Editor {
 			return (AtlasAssetBase)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(AtlasAssetBase));
 		}
 
-		static bool SetDefaultTextureSettingsIfNew (string texturePath, SpineAtlasAsset atlasAsset) {
+		static bool SetDefaultTextureSettings (string texturePath, SpineAtlasAsset atlasAsset) {
 			TextureImporter texImporter = (TextureImporter)TextureImporter.GetAtPath(texturePath);
 			if (texImporter == null) {
 				Debug.LogWarning(string.Format("{0}: Texture asset \"{1}\" not found. Skipping. Please check your atlas file for renamed files.", atlasAsset.name, texturePath));
 				return false;
 			}
 
-		#if UNITY_2018_1_OR_NEWER
-			bool customTextureSettingsExist = !texImporter.importSettingsMissing;
-		#else
-			// unfortunately, importSettingsMissing is not available in Unity 2017,
-			// so we check if any settings deviate from Unity's default texture settings.
-			bool customTextureSettingsExist = texImporter.mipmapEnabled != true ||
-				texImporter.maxTextureSize != 2048 ||
-				texImporter.alphaIsTransparency != true ||
-				texImporter.wrapMode != TextureWrapMode.Repeat ||
-				texImporter.filterMode != FilterMode.Bilinear;
-		#endif
-			if (customTextureSettingsExist)
-				return false;
-
 			texImporter.textureCompression = TextureImporterCompression.Uncompressed;
 			texImporter.alphaSource = TextureImporterAlphaSource.FromInput;
 			texImporter.mipmapEnabled = false;

+ 9 - 7
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/Preferences.cs

@@ -129,8 +129,8 @@ namespace Spine.Unity.Editor {
 
 			public const float DEFAULT_MIPMAPBIAS = SpinePreferences.DEFAULT_MIPMAPBIAS;
 
-			public const float DEFAULT_SCENE_ICONS_SCALE = SpinePreferences.DEFAULT_SCENE_ICONS_SCALE;
-			public const string SCENE_ICONS_SCALE_KEY = SpinePreferences.SCENE_ICONS_SCALE_KEY;
+			public const string SCENE_ICONS_SCALE_KEY = "SPINE_SCENE_ICONS_SCALE";
+			public static float handleScale = SpinePreferences.DEFAULT_SCENE_ICONS_SCALE;
 
 			const string AUTO_RELOAD_SCENESKELETONS_KEY = "SPINE_AUTO_RELOAD_SCENESKELETONS";
 			public static bool autoReloadSceneSkeletons = SpinePreferences.DEFAULT_AUTO_RELOAD_SCENESKELETONS;
@@ -141,6 +141,7 @@ namespace Spine.Unity.Editor {
 			const string TIMELINE_USE_BLEND_DURATION_KEY = "SPINE_TIMELINE_USE_BLEND_DURATION_KEY";
 			public static bool timelineUseBlendDuration = SpinePreferences.DEFAULT_TIMELINE_USE_BLEND_DURATION;
 
+
 			static bool preferencesLoaded = false;
 
 			public static void Load () {
@@ -158,8 +159,7 @@ namespace Spine.Unity.Editor {
 				atlasTxtImportWarning = EditorPrefs.GetBool(ATLASTXT_WARNING_KEY, SpinePreferences.DEFAULT_ATLASTXT_WARNING);
 				textureImporterWarning = EditorPrefs.GetBool(TEXTUREIMPORTER_WARNING_KEY, SpinePreferences.DEFAULT_TEXTUREIMPORTER_WARNING);
 				timelineUseBlendDuration = EditorPrefs.GetBool(TIMELINE_USE_BLEND_DURATION_KEY, SpinePreferences.DEFAULT_TIMELINE_USE_BLEND_DURATION);
-
-				SpineHandles.handleScale = EditorPrefs.GetFloat(SCENE_ICONS_SCALE_KEY, DEFAULT_SCENE_ICONS_SCALE);
+				handleScale = EditorPrefs.GetFloat(SCENE_ICONS_SCALE_KEY, SpinePreferences.DEFAULT_SCENE_ICONS_SCALE);
 				preferencesLoaded = true;
 			}
 
@@ -176,6 +176,7 @@ namespace Spine.Unity.Editor {
 				newPreferences.atlasTxtImportWarning = EditorPrefs.GetBool(ATLASTXT_WARNING_KEY, SpinePreferences.DEFAULT_ATLASTXT_WARNING);
 				newPreferences.textureImporterWarning = EditorPrefs.GetBool(TEXTUREIMPORTER_WARNING_KEY, SpinePreferences.DEFAULT_TEXTUREIMPORTER_WARNING);
 				newPreferences.timelineUseBlendDuration = EditorPrefs.GetBool(TIMELINE_USE_BLEND_DURATION_KEY, SpinePreferences.DEFAULT_TIMELINE_USE_BLEND_DURATION);
+				newPreferences.handleScale = EditorPrefs.GetFloat(SCENE_ICONS_SCALE_KEY, SpinePreferences.DEFAULT_SCENE_ICONS_SCALE);
 			}
 
 			public static void SaveToEditorPrefs(SpinePreferences preferences) {
@@ -190,6 +191,7 @@ namespace Spine.Unity.Editor {
 				EditorPrefs.SetBool(ATLASTXT_WARNING_KEY, preferences.atlasTxtImportWarning);
 				EditorPrefs.SetBool(TEXTUREIMPORTER_WARNING_KEY, preferences.textureImporterWarning);
 				EditorPrefs.SetBool(TIMELINE_USE_BLEND_DURATION_KEY, preferences.timelineUseBlendDuration);
+				EditorPrefs.SetFloat(SCENE_ICONS_SCALE_KEY, preferences.handleScale);
 			}
 #endif
 
@@ -254,10 +256,10 @@ namespace Spine.Unity.Editor {
 				EditorGUILayout.LabelField("Handles and Gizmos", EditorStyles.boldLabel);
 				{
 					EditorGUI.BeginChangeCheck();
-					SpineHandles.handleScale = EditorGUILayout.Slider("Editor Bone Scale", SpineHandles.handleScale, 0.01f, 2f);
-					SpineHandles.handleScale = Mathf.Max(0.01f, SpineHandles.handleScale);
+					handleScale = EditorGUILayout.Slider("Editor Bone Scale", handleScale, 0.01f, 2f);
+					handleScale = Mathf.Max(0.01f, handleScale);
 					if (EditorGUI.EndChangeCheck()) {
-						EditorPrefs.SetFloat(SCENE_ICONS_SCALE_KEY, SpineHandles.handleScale);
+						EditorPrefs.SetFloat(SCENE_ICONS_SCALE_KEY, handleScale);
 						SceneView.RepaintAll();
 					}
 				}

+ 20 - 4
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/SpineEditorUtilities.cs

@@ -65,13 +65,27 @@ namespace Spine.Unity.Editor {
 		public static string editorPath = "";
 		public static string editorGUIPath = "";
 		public static bool initialized;
+		private static List<string> texturesWithoutMetaFile = new List<string>();
 
-		// Auto-import entry point
+		// Auto-import entry point for textures
+		void OnPreprocessTexture () {
+		#if UNITY_2018_1_OR_NEWER
+			bool customTextureSettingsExist = !assetImporter.importSettingsMissing;
+		#else
+			bool customTextureSettingsExist = System.IO.File.Exists(assetImporter.assetPath + ".meta");
+		#endif
+			if (!customTextureSettingsExist) {
+				texturesWithoutMetaFile.Add(assetImporter.assetPath);
+			}
+		}
+
+		// Auto-import post process entry point for all assets
 		static void OnPostprocessAllAssets (string[] imported, string[] deleted, string[] moved, string[] movedFromAssetPaths) {
 			if (imported.Length == 0)
 				return;
 
-			AssetUtility.HandleOnPostprocessAllAssets(imported);
+			AssetUtility.HandleOnPostprocessAllAssets(imported, texturesWithoutMetaFile);
+			texturesWithoutMetaFile.Clear();
 		}
 
 #region Initialization
@@ -80,14 +94,16 @@ namespace Spine.Unity.Editor {
 		}
 
 		static void Initialize () {
-			if (EditorApplication.isPlayingOrWillChangePlaymode) return;
-
+			// Note: Preferences need to be loaded when changing play mode
+			// to initialize handle scale correctly.
 			#if !NEW_PREFERENCES_SETTINGS_PROVIDER
 			Preferences.Load();
 			#else
 			SpinePreferences.Load();
 			#endif
 
+			if (EditorApplication.isPlayingOrWillChangePlaymode) return;
+
 			string[] assets = AssetDatabase.FindAssets("t:script SpineEditorUtilities");
 			string assetPath = AssetDatabase.GUIDToAssetPath(assets[0]);
 			editorPath = Path.GetDirectoryName(assetPath).Replace("\\", "/");

+ 9 - 10
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/SpineHandles.cs

@@ -44,7 +44,6 @@ namespace Spine.Unity.Editor {
 	using EventType = UnityEngine.EventType;
 
 	public static class SpineHandles {
-		internal static float handleScale = 1f;
 		public static Color BoneColor { get { return new Color(0.8f, 0.8f, 0.8f, 0.4f); } }
 		public static Color PathColor { get { return new Color(254/255f, 127/255f, 0); } }
 		public static Color TransformContraintColor { get { return new Color(170/255f, 226/255f, 35/255f); } }
@@ -200,7 +199,7 @@ namespace Spine.Unity.Editor {
 				Quaternion rot = Quaternion.Euler(0, 0, b.WorldRotationX);
 				Vector3 scale = Vector3.one * length * b.WorldScaleX * skeletonRenderScale;
 				const float my = 1.5f;
-				scale.y *= (SpineHandles.handleScale + 1) * 0.5f;
+				scale.y *= (SpineEditorUtilities.Preferences.handleScale + 1) * 0.5f;
 				scale.y = Mathf.Clamp(scale.x, -my * skeletonRenderScale, my * skeletonRenderScale);
 				Handles.DrawPolyLine(GetBoneWireBuffer(transform.localToWorldMatrix * Matrix4x4.TRS(pos, rot, scale)));
 				var wp = transform.TransformPoint(pos);
@@ -218,7 +217,7 @@ namespace Spine.Unity.Editor {
 				Quaternion rot = Quaternion.Euler(0, 0, b.WorldRotationX);
 				Vector3 scale = Vector3.one * length * b.WorldScaleX * skeletonRenderScale;
 				const float my = 1.5f;
-				scale.y *= (SpineHandles.handleScale + 1f) * 0.5f;
+				scale.y *= (SpineEditorUtilities.Preferences.handleScale + 1f) * 0.5f;
 				scale.y = Mathf.Clamp(scale.x, -my * skeletonRenderScale, my * skeletonRenderScale);
 				SpineHandles.GetBoneMaterial().SetPass(0);
 				Graphics.DrawMeshNow(SpineHandles.BoneMesh, transform.localToWorldMatrix * Matrix4x4.TRS(pos, rot, scale));
@@ -235,7 +234,7 @@ namespace Spine.Unity.Editor {
 				Quaternion rot = Quaternion.Euler(0, 0, b.WorldRotationX);
 				Vector3 scale = Vector3.one * length * b.WorldScaleX;
 				const float my = 1.5f;
-				scale.y *= (SpineHandles.handleScale + 1f) * 0.5f;
+				scale.y *= (SpineEditorUtilities.Preferences.handleScale + 1f) * 0.5f;
 				scale.y = Mathf.Clamp(scale.x, -my, my);
 				SpineHandles.GetBoneMaterial(color).SetPass(0);
 				Graphics.DrawMeshNow(SpineHandles.BoneMesh, transform.localToWorldMatrix * Matrix4x4.TRS(pos, rot, scale));
@@ -425,13 +424,13 @@ namespace Spine.Unity.Editor {
 		}
 
 		static void DrawCrosshairs2D (Vector3 position, float scale, float skeletonRenderScale = 1f) {
-			scale *= SpineHandles.handleScale * skeletonRenderScale;
+			scale *= SpineEditorUtilities.Preferences.handleScale * skeletonRenderScale;
 			Handles.DrawLine(position + new Vector3(-scale, 0), position + new Vector3(scale, 0));
 			Handles.DrawLine(position + new Vector3(0, -scale), position + new Vector3(0, scale));
 		}
 
 		static void DrawCrosshairs (Vector3 position, float scale, float a, float b, float c, float d, Transform transform, float skeletonRenderScale = 1f) {
-			scale *= SpineHandles.handleScale * skeletonRenderScale;
+			scale *= SpineEditorUtilities.Preferences.handleScale * skeletonRenderScale;
 
 			var xOffset = (Vector3)(new Vector2(a, c).normalized * scale);
 			var yOffset = (Vector3)(new Vector2(b, d).normalized * scale);
@@ -443,7 +442,7 @@ namespace Spine.Unity.Editor {
 		}
 
 		static void DrawArrowhead2D (Vector3 pos, float localRotation, float scale = 1f) {
-			scale *= SpineHandles.handleScale;
+			scale *= SpineEditorUtilities.Preferences.handleScale;
 
 			SpineHandles.IKMaterial.SetPass(0);
 			Graphics.DrawMeshNow(SpineHandles.ArrowheadMesh, Matrix4x4.TRS(pos, Quaternion.Euler(0, 0, localRotation), new Vector3(scale, scale, scale)));
@@ -454,7 +453,7 @@ namespace Spine.Unity.Editor {
 		}
 
 		static void DrawArrowhead (Matrix4x4 m) {
-			float s = SpineHandles.handleScale;
+			float s = SpineEditorUtilities.Preferences.handleScale;
 			m.m00 *= s;
 			m.m01 *= s;
 			m.m02 *= s;
@@ -470,14 +469,14 @@ namespace Spine.Unity.Editor {
 		}
 
 		static void DrawBoneCircle (Vector3 pos, Color outlineColor, Vector3 normal, float scale = 1f) {
-			scale *= SpineHandles.handleScale;
+			scale *= SpineEditorUtilities.Preferences.handleScale;
 
 			Color o = Handles.color;
 			Handles.color = outlineColor;
 			float firstScale = 0.08f * scale;
 			Handles.DrawSolidDisc(pos, normal, firstScale);
 			const float Thickness = 0.03f;
-			float secondScale = firstScale - (Thickness * SpineHandles.handleScale * scale);
+			float secondScale = firstScale - (Thickness * SpineEditorUtilities.Preferences.handleScale * scale);
 
 			if (secondScale > 0f) {
 				Handles.color = new Color(0.3f, 0.3f, 0.3f, 0.5f);

+ 7 - 6
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Windows/SpinePreferences.cs

@@ -86,8 +86,10 @@ namespace Spine.Unity.Editor {
 		public const bool DEFAULT_AUTO_RELOAD_SCENESKELETONS = true;
 		public bool autoReloadSceneSkeletons = DEFAULT_AUTO_RELOAD_SCENESKELETONS;
 
-		internal const float DEFAULT_SCENE_ICONS_SCALE = 1f;
 		public const string SCENE_ICONS_SCALE_KEY = "SPINE_SCENE_ICONS_SCALE";
+		internal const float DEFAULT_SCENE_ICONS_SCALE = 1f;
+		[Range(0.01f, 2f)]
+		public float handleScale = DEFAULT_SCENE_ICONS_SCALE;
 
 		public const bool DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME = true;
 		public bool mecanimEventIncludeFolderName = DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME;
@@ -95,10 +97,9 @@ namespace Spine.Unity.Editor {
 		// Timeline extension module
 		public const bool DEFAULT_TIMELINE_USE_BLEND_DURATION = true;
 		public bool timelineUseBlendDuration = DEFAULT_TIMELINE_USE_BLEND_DURATION;
-
+		
 #if NEW_PREFERENCES_SETTINGS_PROVIDER
 		public static void Load () {
-			SpineHandles.handleScale = EditorPrefs.GetFloat(SCENE_ICONS_SCALE_KEY, DEFAULT_SCENE_ICONS_SCALE);
 			GetOrCreateSettings();
 		}
 
@@ -172,10 +173,10 @@ namespace Spine.Unity.Editor {
 				EditorGUILayout.LabelField("Handles and Gizmos", EditorStyles.boldLabel);
 				{
 					EditorGUI.BeginChangeCheck();
-					SpineHandles.handleScale = EditorGUILayout.Slider("Editor Bone Scale", SpineHandles.handleScale, 0.01f, 2f);
-					SpineHandles.handleScale = Mathf.Max(0.01f, SpineHandles.handleScale);
+					var scaleProperty = settings.FindProperty("handleScale");
+					EditorGUILayout.PropertyField(scaleProperty, new GUIContent("Editor Bone Scale"));
 					if (EditorGUI.EndChangeCheck()) {
-						EditorPrefs.SetFloat(SpinePreferences.SCENE_ICONS_SCALE_KEY, SpineHandles.handleScale);
+						EditorPrefs.SetFloat(SpinePreferences.SCENE_ICONS_SCALE_KEY, scaleProperty.floatValue);
 						SceneView.RepaintAll();
 					}
 				}