mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-21 01:36:02 +08:00
[unity] Update SkeletonInspectorPreview.
This commit is contained in:
parent
0a23ed3d85
commit
2a792c0247
@ -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 = "") {
|
||||
if (skeletonDataAsset == null) return;
|
||||
if (skeletonDataAsset.GetSkeletonData(false) == null)
|
||||
return;
|
||||
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) {
|
||||
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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user