Browse Source

[unity] Update SkeletonInspectorPreview.

pharan 7 years ago
parent
commit
2a792c0247
1 changed files with 138 additions and 59 deletions
  1. 138 59
      spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs

+ 138 - 59
spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs

@@ -31,9 +31,12 @@
 #define SPINE_SKELETON_ANIMATOR
 
 using System;
+using System.Reflection;
 using System.Collections.Generic;
 using UnityEditor;
 using UnityEngine;
+
+
 using Spine;
 
 namespace Spine.Unity.Editor {
@@ -60,7 +63,6 @@ namespace Spine.Unity.Editor {
 
 		SkeletonDataAsset targetSkeletonDataAsset;
 		SkeletonData targetSkeletonData;
-		string targetSkeletonDataAssetGUIDString;
 
 		readonly List<string> warnings = new List<string>();
 		readonly SkeletonInspectorPreview preview = new SkeletonInspectorPreview();
@@ -68,17 +70,21 @@ namespace Spine.Unity.Editor {
 		GUIStyle activePlayButtonStyle, idlePlayButtonStyle;
 		readonly GUIContent DefaultMixLabel = new GUIContent("Default Mix Duration", "Sets 'SkeletonDataAsset.defaultMix' in the asset and 'AnimationState.data.defaultMix' at runtime load time.");
 
-		string LastSkinKey { get { return targetSkeletonDataAssetGUIDString + "_lastSkin"; } }
+		string TargetAssetGUID { get { return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(targetSkeletonDataAsset)); } }
+		string LastSkinKey { get { return TargetAssetGUID + "_lastSkin"; } }
 		string LastSkinName { get { return EditorPrefs.GetString(LastSkinKey, ""); } }
 
 		void OnEnable () {
 			InitializeEditor();
 		}
 
+		void OnDestroy () {
+			HandleOnDestroyPreview();
+		}
+
 		void InitializeEditor () {
 			SpineEditorUtilities.ConfirmInitialization();
 			targetSkeletonDataAsset = (SkeletonDataAsset)target;
-			targetSkeletonDataAssetGUIDString = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(targetSkeletonDataAsset));
 
 			bool newAtlasAssets = atlasAssets == null;
 			if (newAtlasAssets) atlasAssets = serializedObject.FindProperty("atlasAssets");
@@ -101,8 +107,8 @@ namespace Spine.Unity.Editor {
 			if (newAtlasAssets) atlasAssets.isExpanded = true;
 			#endif
 
-			EditorApplication.update -= EditorUpdate;
-			EditorApplication.update += EditorUpdate;
+			EditorApplication.update -= preview.HandleEditorUpdate;
+			EditorApplication.update += preview.HandleEditorUpdate;
 			preview.OnSkinChanged -= HandlePreviewSkinChanged;
 			preview.OnSkinChanged += HandlePreviewSkinChanged;
 
@@ -115,23 +121,11 @@ namespace Spine.Unity.Editor {
 			targetSkeletonData = warnings.Count == 0 ? targetSkeletonDataAsset.GetSkeletonData(false) : null;
 
 			if (targetSkeletonData != null && warnings.Count <= 0) {
-				preview.Initialize(targetSkeletonDataAsset, this.LastSkinName);
+				preview.Initialize(this.Repaint, targetSkeletonDataAsset, this.LastSkinName);
 			}
 				
 		}
 
-		void EditorUpdate () {
-			preview.AdjustCamera();
-
-			if (preview.IsPlayingAnimation) {
-				preview.RefreshOnNextUpdate();
-				Repaint();
-			} else if (preview.requiresRefresh) {
-				Repaint();
-			} // else // needed if using smooth menus
-
-		}
-
 		void Clear () {
 			preview.Clear();
 			targetSkeletonDataAsset.Clear();
@@ -180,7 +174,7 @@ namespace Spine.Unity.Editor {
 
 			// Unity Quirk: Some code depends on valid preview. If preview is initialized elsewhere, this can cause contents to change between Layout and Repaint events, causing GUILayout control count errors.
 			if (warnings.Count <= 0)
-				preview.Initialize(targetSkeletonDataAsset, this.LastSkinName);
+				preview.Initialize(this.Repaint, targetSkeletonDataAsset, this.LastSkinName);
 
 			if (targetSkeletonData != null) {
 				GUILayout.Space(20f);
@@ -193,6 +187,13 @@ namespace Spine.Unity.Editor {
 
 				EditorGUILayout.LabelField("Preview", EditorStyles.boldLabel);
 				DrawAnimationList();
+				if (targetSkeletonData.Animations.Count > 0) {
+					const string AnimationReferenceButtonText = "Create Animation Reference Assets";
+					const string AnimationReferenceTooltipText = "AnimationReferenceAsset acts as Unity asset for a reference to a Spine.Animation. This can be used in inspectors.\n\nIt serializes  a reference to a SkeletonDataAsset and an animationName.\n\nAt runtime, a reference to its Spine.Animation is loaded and cached into the object to be used as needed. This skips the need to find and cache animation references in individual MonoBehaviours.";
+					if (GUILayout.Button(SpineInspectorUtility.TempContent(AnimationReferenceButtonText, Icons.animationRoot, AnimationReferenceTooltipText), GUILayout.Width(250), GUILayout.Height(26))) {
+						CreateAnimationReferenceAssets();
+					}
+				}
 				EditorGUILayout.Space();
 				DrawSlotList();
 				EditorGUILayout.Space();
@@ -217,6 +218,28 @@ namespace Spine.Unity.Editor {
 				serializedObject.ApplyModifiedProperties();
 		}
 
+		void CreateAnimationReferenceAssets () {
+			const string AssetFolderName = "ReferenceAssets";
+			string parentFolder = AssetDatabase.GetAssetPath(targetSkeletonDataAsset);
+			string dataPath = System.IO.Path.GetDirectoryName(parentFolder) + "/" + AssetFolderName;
+			if (!AssetDatabase.IsValidFolder(dataPath)) {
+				AssetDatabase.CreateFolder(parentFolder, AssetFolderName);
+			}
+
+			FieldInfo nameField = typeof(AnimationReferenceAsset).GetField("animationName", BindingFlags.NonPublic | BindingFlags.Instance);
+			FieldInfo skeletonDataAssetField = typeof(AnimationReferenceAsset).GetField("skeletonDataAsset", BindingFlags.NonPublic | BindingFlags.Instance);
+			foreach (var animation in targetSkeletonData.Animations) {
+				string assetPath = string.Format("{0}/{1}.asset", dataPath, SpineEditorUtilities.GetPathSafeName(animation.Name));
+				AnimationReferenceAsset existingAsset = AssetDatabase.LoadAssetAtPath<AnimationReferenceAsset>(assetPath);
+				if (existingAsset == null) {
+					AnimationReferenceAsset newAsset = ScriptableObject.CreateInstance<AnimationReferenceAsset>();
+					skeletonDataAssetField.SetValue(newAsset, targetSkeletonDataAsset);
+					nameField.SetValue(newAsset, animation.Name);
+					AssetDatabase.CreateAsset(newAsset, assetPath);
+				}
+			}
+		}
+
 		void OnInspectorGUIMulti () {
 			
 			// Skeleton data file field.
@@ -359,7 +382,7 @@ namespace Spine.Unity.Editor {
 				return;
 
 			bool isPreviewWindowOpen = preview.IsValid;
-
+			
 			if (isPreviewWindowOpen) {
 				if (GUILayout.Button(SpineInspectorUtility.TempContent("Setup Pose", Icons.skeleton), GUILayout.Width(105), GUILayout.Height(18))) {
 					preview.ClearAnimationSetupPose();
@@ -500,7 +523,7 @@ namespace Spine.Unity.Editor {
 				warnings.Add("Missing Skeleton JSON");
 			} else {
 				var fieldValue = (TextAsset)skeletonJSON.objectReferenceValue;
-				if (!SpineEditorUtilities.IsSpineData(fieldValue)) {
+				if (!SpineEditorUtilities.SkeletonDataFileValidator.IsSpineData(fieldValue)) {
 					warnings.Add("Skeleton data file is not a valid JSON or binary file.");
 				} else {
 					#if SPINE_TK2D
@@ -571,12 +594,12 @@ namespace Spine.Unity.Editor {
 			EditorPrefs.SetString(LastSkinKey, skinName);
 		}
 
-		void OnDestroy () {
-			EditorApplication.update -= EditorUpdate;
+		#region Preview Handlers
+		void HandleOnDestroyPreview () {
+			EditorApplication.update -= preview.HandleEditorUpdate;
 			preview.OnDestroy();
 		}
 
-		#region Preview Handlers
 		override public bool HasPreviewGUI () {			
 			if (serializedObject.isEditingMultipleObjects)
 				return false;
@@ -590,37 +613,20 @@ namespace Spine.Unity.Editor {
 			return skeletonJSON.objectReferenceValue != null;
 		}
 
-		override public GUIContent GetPreviewTitle () {
-			return SpineInspectorUtility.TempContent("Preview");
-		}
-
 		override public void OnInteractivePreviewGUI (Rect r, GUIStyle background) {
 			if (warnings.Count <= 0) {
-				preview.Initialize(targetSkeletonDataAsset, this.LastSkinName);
+				preview.Initialize(this.Repaint, targetSkeletonDataAsset, this.LastSkinName);
 				preview.HandleInteractivePreviewGUI(r, background);
 			}
 		}
 
-		public override void OnPreviewSettings () {
-			const float SliderWidth = 150;
-			const float SliderSnap = 0.25f;
-			const float SliderMin = 0f;
-			const float SliderMax = 2f;
-
-			if (preview.IsValid) {
-				float timeScale = GUILayout.HorizontalSlider(preview.TimeScale, SliderMin, SliderMax, GUILayout.MaxWidth(SliderWidth));
-				timeScale = Mathf.RoundToInt(timeScale/SliderSnap) * SliderSnap;
-				preview.TimeScale = timeScale;
-			}
-		}
-
-		public override Texture2D RenderStaticPreview (string assetPath, UnityEngine.Object[] subAssets, int width, int height) {
-			return preview.GetStaticPreview(width, height);
-		}
+		override public GUIContent GetPreviewTitle () { return SpineInspectorUtility.TempContent("Preview"); }
+		public override void OnPreviewSettings () { preview.HandleDrawSettings(); }
+		public override Texture2D RenderStaticPreview (string assetPath, UnityEngine.Object[] subAssets, int width, int height) { return preview.GetStaticPreview(width, height); }
 		#endregion
 	}
 
-	class SkeletonInspectorPreview {
+	internal class SkeletonInspectorPreview {
 		Color OriginColor = new Color(0.3f, 0.3f, 0.3f, 1);
 		static readonly int SliderHash = "Slider".GetHashCode();
 
@@ -632,17 +638,14 @@ namespace Spine.Unity.Editor {
 		internal bool requiresRefresh;
 		float animationLastTime;
 
+		Action Repaint;
 		public event Action<string> OnSkinChanged;
 
 		Texture previewTexture;
 		PreviewRenderUtility previewRenderUtility;
 		Camera PreviewUtilityCamera {
 			get {
-				if (previewRenderUtility == null) {
-
-					return null;
-				}
-
+				if (previewRenderUtility == null) return null;
 				#if UNITY_2017_1_OR_NEWER
 				return previewRenderUtility.camera;
 				#else
@@ -651,6 +654,8 @@ namespace Spine.Unity.Editor {
 			}
 		}
 
+		static Vector3 lastCameraPositionGoal;
+		static float lastCameraOrthoGoal;
 		float cameraOrthoGoal = 1;
 		Vector3 cameraPositionGoal = new Vector3(0, 0, -10);
 		double cameraAdjustEndFrame = 0;
@@ -679,14 +684,27 @@ namespace Spine.Unity.Editor {
 			get { return IsValid ? skeletonAnimation.AnimationState.GetCurrent(0) : null; }
 		}
 
-		public void Initialize (SkeletonDataAsset skeletonDataAsset, string skinName = "") {
+		public Vector3 PreviewCameraPosition {
+			get { return PreviewUtilityCamera.transform.position; }
+			set { PreviewUtilityCamera.transform.position = value; }
+		}
+
+		public void Initialize (Action repaintCallback, SkeletonDataAsset skeletonDataAsset, string skinName = "") {
 			if (skeletonDataAsset == null) return;
-			if (skeletonDataAsset.GetSkeletonData(false) == null)
+			if (skeletonDataAsset.GetSkeletonData(false) == null) {
+				DestroyPreviewGameObject();
 				return;
+			}
 
+			this.Repaint = repaintCallback;
 			this.skeletonDataAsset = skeletonDataAsset;
 			this.skeletonData = skeletonDataAsset.GetSkeletonData(false);
 
+			if (skeletonData == null) {
+				DestroyPreviewGameObject();
+				return;
+			}
+
 			if (previewRenderUtility == null) {
 				previewRenderUtility = new PreviewRenderUtility(true);
 				animationLastTime = Time.realtimeSinceStartup;
@@ -697,10 +715,11 @@ namespace Spine.Unity.Editor {
 				{
 					var c = this.PreviewUtilityCamera;
 					c.orthographic = true;
-					c.orthographicSize = 1;
 					c.cullingMask = PreviewCameraCullingMask;
 					c.nearClipPlane = 0.01f;
-					c.farClipPlane = 1000f;	
+					c.farClipPlane = 1000f;
+					c.orthographicSize = lastCameraOrthoGoal;
+					c.transform.position = lastCameraPositionGoal;
 				}
 
 				DestroyPreviewGameObject();
@@ -727,6 +746,19 @@ namespace Spine.Unity.Editor {
 			}
 		}
 
+		public void HandleDrawSettings () {
+			const float SliderWidth = 150;
+			const float SliderSnap = 0.25f;
+			const float SliderMin = 0f;
+			const float SliderMax = 2f;
+
+			if (IsValid) {
+				float timeScale = GUILayout.HorizontalSlider(TimeScale, SliderMin, SliderMax, GUILayout.MaxWidth(SliderWidth));
+				timeScale = Mathf.RoundToInt(timeScale / SliderSnap) * SliderSnap;
+				TimeScale = timeScale;
+			}
+		}
+
 		public void OnDestroy () {
 			DisposePreviewRenderUtility();
 			DestroyPreviewGameObject();
@@ -765,8 +797,19 @@ namespace Spine.Unity.Editor {
 		}
 
 		public void PlayPauseAnimation (string animationName, bool loop) {
+			if (skeletonData == null) return;
+
 			if (skeletonAnimation == null) {
-				Debug.LogWarning("Animation was stopped but preview doesn't exist. It's possible that the Preview Panel is closed.");
+				//Debug.LogWarning("Animation was stopped but preview doesn't exist. It's possible that the Preview Panel is closed.");
+				return;
+			}
+
+			if (!skeletonAnimation.valid) return;
+
+			if (string.IsNullOrEmpty(animationName)) {
+				skeletonAnimation.Skeleton.SetToSetupPose();
+				skeletonAnimation.AnimationState.ClearTracks();
+				return;
 			}
 
 			var targetAnimation = skeletonData.FindAnimation(animationName);
@@ -805,7 +848,7 @@ namespace Spine.Unity.Editor {
 					}
 				}
 			} else {
-				Debug.LogFormat("Something went wrong. The Spine.Animation named '{0}' was not found.", animationName);
+				Debug.LogFormat("The Spine.Animation named '{0}' was not found for this Skeleton.", animationName);
 			}
 
 		}
@@ -823,6 +866,7 @@ namespace Spine.Unity.Editor {
 			}
 
 			DrawSkinToolbar(r);
+			//DrawSetupPoseButton(r);
 			DrawTimeBar(r);
 			MouseScroll(r);
 		}
@@ -848,13 +892,16 @@ namespace Spine.Unity.Editor {
 			if (EditorApplication.timeSinceStartup < cameraAdjustEndFrame)
 				AdjustCameraGoals();
 
+			lastCameraPositionGoal = cameraPositionGoal;
+			lastCameraOrthoGoal = cameraOrthoGoal;
+
 			var c = this.PreviewUtilityCamera;
 			float orthoSet = Mathf.Lerp(c.orthographicSize, cameraOrthoGoal, 0.1f);
 
 			c.orthographicSize = orthoSet;
 
 			float dist = Vector3.Distance(c.transform.position, cameraPositionGoal);
-			if(dist > 0f) {
+			if (dist > 0f) {
 				Vector3 pos = Vector3.Lerp(c.transform.position, cameraPositionGoal, 0.1f);
 				pos.x = 0;
 				c.transform.position = pos;
@@ -877,6 +924,16 @@ namespace Spine.Unity.Editor {
 			return tex;
 		}
 
+		public void HandleEditorUpdate () {
+			AdjustCamera();
+			if (IsPlayingAnimation) {
+				RefreshOnNextUpdate();
+				Repaint();
+			} else if (requiresRefresh) {
+				Repaint();
+			}
+		}
+
 		public void DoRenderPreview (bool drawHandles) {
 			if (this.PreviewUtilityCamera.activeTexture == null || this.PreviewUtilityCamera.targetTexture == null )
 				return;
@@ -940,6 +997,28 @@ namespace Spine.Unity.Editor {
 			}
 		}
 
+		void DrawSetupPoseButton (Rect r) {
+			if (!this.IsValid)
+				return;
+
+			var skeleton = this.Skeleton;
+
+			Rect popRect = new Rect(r);
+			popRect.y += 64;
+			popRect.x += 4;
+			popRect.height = 24;
+			popRect.width = 40;
+
+			//popRect.y += 11;
+			popRect.width = 150;
+			//popRect.x += 44;
+
+			if (GUI.Button(popRect, SpineInspectorUtility.TempContent("Reset to SetupPose", Icons.skeleton))) {
+				ClearAnimationSetupPose();
+				RefreshOnNextUpdate();
+			}
+		}
+
 		void DrawSkinDropdown () {
 			var menu = new GenericMenu();
 			foreach (Skin s in skeletonData.Skins)
@@ -953,7 +1032,7 @@ namespace Spine.Unity.Editor {
 			skeletonAnimation.initialSkinName = skin.Name;
 			skeletonAnimation.Initialize(true);
 			RefreshOnNextUpdate();
-			OnSkinChanged(skin.Name);
+			if (OnSkinChanged != null) OnSkinChanged(skin.Name);
 		}
 
 		void DrawTimeBar (Rect r) {