Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /******************************************************************************
- * Spine Runtimes Software License v2.5
- *
- * Copyright (c) 2013-2016, Esoteric Software
- * All rights reserved.
- *
- * You are granted a perpetual, non-exclusive, non-sublicensable, and
- * non-transferable license to use, install, execute, and perform the Spine
- * Runtimes software and derivative works solely for personal or internal
- * use. Without the written permission of Esoteric Software (see Section 2 of
- * the Spine Software License Agreement), you may not (a) modify, translate,
- * adapt, or develop new applications using the Spine Runtimes or otherwise
- * create derivative works or improvements of the Spine Runtimes or (b) remove,
- * delete, alter, or obscure any trademarks or any copyright, trademark, patent,
- * or other intellectual property or proprietary rights notices on or in the
- * Software, including any copy thereof. Redistributions in binary or source
- * form must include this license and terms.
- *
- * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
- * USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
- // Contributed by: Mitch Thompson
- #define SPINE_SKELETON_ANIMATOR
- //#define SPINE_BAKING
- using System;
- using System.Collections.Generic;
- using UnityEditor;
- using UnityEngine;
- using Spine;
- namespace Spine.Unity.Editor {
- using Event = UnityEngine.Event;
- using Icons = SpineEditorUtilities.Icons;
- [CustomEditor(typeof(SkeletonDataAsset)), CanEditMultipleObjects]
- public class SkeletonDataAssetInspector : UnityEditor.Editor {
- static bool showAnimationStateData = true;
- static bool showAnimationList = true;
- static bool showSlotList = false;
- static bool showAttachments = false;
- #if SPINE_BAKING
- static bool isBakingExpanded = false;
- static bool bakeAnimations = true;
- static bool bakeIK = true;
- static SendMessageOptions bakeEventOptions = SendMessageOptions.DontRequireReceiver;
- const string ShowBakingPrefsKey = "SkeletonDataAssetInspector_showUnity";
- #endif
- SerializedProperty atlasAssets, skeletonJSON, scale, fromAnimation, toAnimation, duration, defaultMix;
- #if SPINE_TK2D
- SerializedProperty spriteCollection;
- #endif
- #if SPINE_SKELETON_ANIMATOR
- static bool isMecanimExpanded = false;
- SerializedProperty controller;
- #endif
- bool m_initialized = false;
- SkeletonDataAsset m_skeletonDataAsset;
- SkeletonData m_skeletonData;
- string m_skeletonDataAssetGUID;
- bool needToSerialize;
- readonly List<string> warnings = new List<string>();
- 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.");
- void OnEnable () {
- SpineEditorUtilities.ConfirmInitialization();
- m_skeletonDataAsset = (SkeletonDataAsset)target;
- atlasAssets = serializedObject.FindProperty("atlasAssets");
- skeletonJSON = serializedObject.FindProperty("skeletonJSON");
- scale = serializedObject.FindProperty("scale");
- fromAnimation = serializedObject.FindProperty("fromAnimation");
- toAnimation = serializedObject.FindProperty("toAnimation");
- duration = serializedObject.FindProperty("duration");
- defaultMix = serializedObject.FindProperty("defaultMix");
- #if SPINE_SKELETON_ANIMATOR
- controller = serializedObject.FindProperty("controller");
- #endif
- #if SPINE_TK2D
- atlasAssets.isExpanded = false;
- spriteCollection = serializedObject.FindProperty("spriteCollection");
- #else
- atlasAssets.isExpanded = true;
- #endif
- #if SPINE_BAKING
- isBakingExpanded = EditorPrefs.GetBool(ShowBakingPrefsKey, false);
- #endif
- m_skeletonDataAssetGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_skeletonDataAsset));
- EditorApplication.update += EditorUpdate;
- RepopulateWarnings();
- m_skeletonData = warnings.Count == 0 ? m_skeletonDataAsset.GetSkeletonData(false) : null;
- }
- void OnDestroy () {
- m_initialized = false;
- EditorApplication.update -= EditorUpdate;
- this.DestroyPreviewInstances();
- if (this.m_previewUtility != null) {
- this.m_previewUtility.Cleanup();
- this.m_previewUtility = null;
- }
- }
- override public void OnInspectorGUI () {
- if (serializedObject.isEditingMultipleObjects) {
- using (new SpineInspectorUtility.BoxScope()) {
- EditorGUILayout.LabelField("SkeletonData", EditorStyles.boldLabel);
- EditorGUILayout.PropertyField(skeletonJSON, new GUIContent(skeletonJSON.displayName, Icons.spine));
- EditorGUILayout.PropertyField(scale);
- }
- using (new SpineInspectorUtility.BoxScope()) {
- EditorGUILayout.LabelField("Atlas", EditorStyles.boldLabel);
- #if !SPINE_TK2D
- EditorGUILayout.PropertyField(atlasAssets, true);
- #else
- using (new EditorGUI.DisabledGroupScope(spriteCollection.objectReferenceValue != null)) {
- EditorGUILayout.PropertyField(atlasAssets, true);
- }
- EditorGUILayout.LabelField("spine-tk2d", EditorStyles.boldLabel);
- EditorGUILayout.PropertyField(spriteCollection, true);
- #endif
- }
- using (new SpineInspectorUtility.BoxScope()) {
- EditorGUILayout.LabelField("Mix Settings", EditorStyles.boldLabel);
- SpineInspectorUtility.PropertyFieldWideLabel(defaultMix, DefaultMixLabel, 160);
- EditorGUILayout.Space();
- }
- return;
- }
- {
- // Lazy initialization because accessing EditorStyles values in OnEnable during a recompile causes UnityEditor to throw null exceptions. (Unity 5.3.5)
- idlePlayButtonStyle = idlePlayButtonStyle ?? new GUIStyle(EditorStyles.miniButton);
- if (activePlayButtonStyle == null) {
- activePlayButtonStyle = new GUIStyle(idlePlayButtonStyle);
- activePlayButtonStyle.normal.textColor = Color.red;
- }
- }
- serializedObject.Update();
- EditorGUILayout.LabelField(new GUIContent(target.name + " (SkeletonDataAsset)", Icons.spine), EditorStyles.whiteLargeLabel);
- if (m_skeletonData != null) {
- EditorGUILayout.LabelField("(Drag and Drop to instantiate.)", EditorStyles.miniLabel);
- }
- EditorGUI.BeginChangeCheck();
- // SkeletonData
- using (new SpineInspectorUtility.BoxScope()) {
- using (new EditorGUILayout.HorizontalScope()) {
- EditorGUILayout.LabelField("SkeletonData", EditorStyles.boldLabel);
- // if (m_skeletonData != null) {
- // var sd = m_skeletonData;
- // string m = string.Format("{8} - {0} {1}\nBones: {2}\tConstraints: {5} IK + {6} Path + {7} Transform\nSlots: {3}\t\tSkins: {4}\n",
- // sd.Version, string.IsNullOrEmpty(sd.Version) ? "" : "export", sd.Bones.Count, sd.Slots.Count, sd.Skins.Count, sd.IkConstraints.Count, sd.PathConstraints.Count, sd.TransformConstraints.Count, skeletonJSON.objectReferenceValue.name);
- // EditorGUILayout.LabelField(new GUIContent("SkeletonData"), new GUIContent("+", m), EditorStyles.boldLabel);
- // }
- }
- EditorGUILayout.PropertyField(skeletonJSON, new GUIContent(skeletonJSON.displayName, Icons.spine));
- EditorGUILayout.PropertyField(scale);
- }
- // if (m_skeletonData != null) {
- // if (SpineInspectorUtility.CenteredButton(new GUIContent("Instantiate", Icons.spine, "Creates a new Spine GameObject in the active scene using this Skeleton Data.\nYou can also instantiate by dragging the SkeletonData asset from Project view into Scene View.")))
- // SpineEditorUtilities.ShowInstantiateContextMenu(this.m_skeletonDataAsset, Vector3.zero);
- // }
- // Atlas
- using (new SpineInspectorUtility.BoxScope()) {
- EditorGUILayout.LabelField("Atlas", EditorStyles.boldLabel);
- #if !SPINE_TK2D
- EditorGUILayout.PropertyField(atlasAssets, true);
- #else
- using (new EditorGUI.DisabledGroupScope(spriteCollection.objectReferenceValue != null)) {
- EditorGUILayout.PropertyField(atlasAssets, true);
- }
- EditorGUILayout.LabelField("spine-tk2d", EditorStyles.boldLabel);
- EditorGUILayout.PropertyField(spriteCollection, true);
- #endif
- }
- if (EditorGUI.EndChangeCheck()) {
- if (serializedObject.ApplyModifiedProperties()) {
- if (m_previewUtility != null) {
- m_previewUtility.Cleanup();
- m_previewUtility = null;
- }
- m_skeletonDataAsset.Clear();
- m_skeletonData = null;
- OnEnable(); // Should call RepopulateWarnings.
- return;
- }
- }
- // Some code depends on the existence of m_skeletonAnimation instance.
- // If m_skeletonAnimation is lazy-instantiated elsewhere, this can cause contents to change between Layout and Repaint events, causing GUILayout control count errors.
- InitPreview();
- if (m_skeletonData != null) {
- GUILayout.Space(20f);
- using (new SpineInspectorUtility.BoxScope()) {
- EditorGUILayout.LabelField("Mix Settings", EditorStyles.boldLabel);
- DrawAnimationStateInfo();
- EditorGUILayout.Space();
- }
- EditorGUILayout.LabelField("Preview", EditorStyles.boldLabel);
- DrawAnimationList();
- EditorGUILayout.Space();
- DrawSlotList();
- EditorGUILayout.Space();
- DrawUnityTools();
- } else {
- #if !SPINE_TK2D
- // Reimport Button
- using (new EditorGUI.DisabledGroupScope(skeletonJSON.objectReferenceValue == null)) {
- if (GUILayout.Button(new GUIContent("Attempt Reimport", Icons.warning))) {
- DoReimport();
- }
- }
- #else
- EditorGUILayout.HelpBox("Couldn't load SkeletonData.", MessageType.Error);
- #endif
- // List warnings.
- foreach (var line in warnings)
- EditorGUILayout.LabelField(new GUIContent(line, Icons.warning));
- }
- if (!Application.isPlaying)
- serializedObject.ApplyModifiedProperties();
- }
- void DrawUnityTools () {
- #if SPINE_SKELETON_ANIMATOR
- using (new SpineInspectorUtility.BoxScope()) {
- isMecanimExpanded = EditorGUILayout.Foldout(isMecanimExpanded, new GUIContent("SkeletonAnimator", Icons.unityIcon));
- if (isMecanimExpanded) {
- EditorGUI.indentLevel++;
- EditorGUILayout.PropertyField(controller, new GUIContent("Controller", Icons.controllerIcon));
- if (controller.objectReferenceValue == null) {
- // Generate Mecanim Controller Button
- using (new GUILayout.HorizontalScope()) {
- GUILayout.Space(EditorGUIUtility.labelWidth);
- if (GUILayout.Button(new GUIContent("Generate Mecanim Controller"), GUILayout.Height(20)))
- SkeletonBaker.GenerateMecanimAnimationClips(m_skeletonDataAsset);
- }
- EditorGUILayout.HelpBox("SkeletonAnimator is the Mecanim alternative to SkeletonAnimation.\nIt is not required.", MessageType.Info);
- } else {
- // Update AnimationClips button.
- using (new GUILayout.HorizontalScope()) {
- GUILayout.Space(EditorGUIUtility.labelWidth);
- if (GUILayout.Button(new GUIContent("Force Update AnimationClips"), GUILayout.Height(20)))
- SkeletonBaker.GenerateMecanimAnimationClips(m_skeletonDataAsset);
- }
- }
- EditorGUI.indentLevel--;
- }
- }
- #endif
- #if SPINE_BAKING
- bool pre = isBakingExpanded;
- isBakingExpanded = EditorGUILayout.Foldout(isBakingExpanded, new GUIContent("Baking", Icons.unityIcon));
- if (pre != isBakingExpanded)
- EditorPrefs.SetBool(ShowBakingPrefsKey, isBakingExpanded);
- if (isBakingExpanded) {
- EditorGUI.indentLevel++;
- const string BakingWarningMessage =
- // "WARNING!" +
- // "\nBaking is NOT the same as SkeletonAnimator!" +
- // "\n\n" +
- "The main use of Baking is to export Spine projects to be used without the Spine Runtime (ie: for sale on the Asset Store, or background objects that are animated only with a wind noise generator)" +
- "\n\nBaking does not support the following:" +
- "\n\tDisabled transform inheritance" +
- "\n\tShear" +
- "\n\tColor Keys" +
- "\n\tDraw Order Keys" +
- "\n\tAll Constraint types" +
- "\n\nCurves are sampled at 60fps and are not realtime." +
- "\nPlease read SkeletonBaker.cs comments for full details.";
- EditorGUILayout.HelpBox(BakingWarningMessage, MessageType.Info, true);
- EditorGUI.indentLevel++;
- bakeAnimations = EditorGUILayout.Toggle("Bake Animations", bakeAnimations);
- using (new EditorGUI.DisabledGroupScope(!bakeAnimations)) {
- EditorGUI.indentLevel++;
- bakeIK = EditorGUILayout.Toggle("Bake IK", bakeIK);
- bakeEventOptions = (SendMessageOptions)EditorGUILayout.EnumPopup("Event Options", bakeEventOptions);
- EditorGUI.indentLevel--;
- }
- // Bake Skin buttons.
- using (new GUILayout.HorizontalScope()) {
- if (GUILayout.Button(new GUIContent("Bake All Skins", Icons.unityIcon), GUILayout.Height(32), GUILayout.Width(150)))
- SkeletonBaker.BakeToPrefab(m_skeletonDataAsset, m_skeletonData.Skins, "", bakeAnimations, bakeIK, bakeEventOptions);
- if (m_skeletonAnimation != null && m_skeletonAnimation.skeleton != null) {
- Skin bakeSkin = m_skeletonAnimation.skeleton.Skin;
- string skinName = "<No Skin>";
- if (bakeSkin == null) {
- skinName = "Default";
- bakeSkin = m_skeletonData.Skins.Items[0];
- } else
- skinName = m_skeletonAnimation.skeleton.Skin.Name;
- using (new GUILayout.VerticalScope()) {
- if (GUILayout.Button(new GUIContent("Bake \"" + skinName + "\"", Icons.unityIcon), GUILayout.Height(32), GUILayout.Width(250)))
- SkeletonBaker.BakeToPrefab(m_skeletonDataAsset, new ExposedList<Skin>(new [] { bakeSkin }), "", bakeAnimations, bakeIK, bakeEventOptions);
- using (new GUILayout.HorizontalScope()) {
- GUILayout.Label(new GUIContent("Skins", Icons.skinsRoot), GUILayout.Width(50));
- if (GUILayout.Button(skinName, EditorStyles.popup, GUILayout.Width(196))) {
- DrawSkinDropdown();
- }
- }
- }
- }
- }
- EditorGUI.indentLevel--;
- EditorGUI.indentLevel--;
- }
- #endif
- }
- void DoReimport () {
- SpineEditorUtilities.ImportSpineContent(new string[] { AssetDatabase.GetAssetPath(skeletonJSON.objectReferenceValue) }, true);
- if (m_previewUtility != null) {
- m_previewUtility.Cleanup();
- m_previewUtility = null;
- }
- OnEnable(); // Should call RepopulateWarnings.
- EditorUtility.SetDirty(m_skeletonDataAsset);
- }
- void DrawAnimationStateInfo () {
- showAnimationStateData = EditorGUILayout.Foldout(showAnimationStateData, "Animation State Data");
- if (!showAnimationStateData)
- return;
- EditorGUI.BeginChangeCheck();
- SpineInspectorUtility.PropertyFieldWideLabel(defaultMix, DefaultMixLabel, 160);
- var animations = new string[m_skeletonData.Animations.Count];
- for (int i = 0; i < animations.Length; i++)
- animations[i] = m_skeletonData.Animations.Items[i].Name;
- for (int i = 0; i < fromAnimation.arraySize; i++) {
- SerializedProperty from = fromAnimation.GetArrayElementAtIndex(i);
- SerializedProperty to = toAnimation.GetArrayElementAtIndex(i);
- SerializedProperty durationProp = duration.GetArrayElementAtIndex(i);
- using (new EditorGUILayout.HorizontalScope()) {
- from.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, from.stringValue), 0), animations)];
- to.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, to.stringValue), 0), animations)];
- durationProp.floatValue = EditorGUILayout.FloatField(durationProp.floatValue);
- if (GUILayout.Button("Delete")) {
- duration.DeleteArrayElementAtIndex(i);
- toAnimation.DeleteArrayElementAtIndex(i);
- fromAnimation.DeleteArrayElementAtIndex(i);
- }
- }
- }
- using (new EditorGUILayout.HorizontalScope()) {
- EditorGUILayout.Space();
- if (GUILayout.Button("Add Mix")) {
- duration.arraySize++;
- toAnimation.arraySize++;
- fromAnimation.arraySize++;
- }
- EditorGUILayout.Space();
- }
- if (EditorGUI.EndChangeCheck()) {
- m_skeletonDataAsset.FillStateData();
- EditorUtility.SetDirty(m_skeletonDataAsset);
- serializedObject.ApplyModifiedProperties();
- needToSerialize = true;
- }
- }
- void DrawAnimationList () {
- showAnimationList = EditorGUILayout.Foldout(showAnimationList, new GUIContent(string.Format("Animations [{0}]", m_skeletonData.Animations.Count), Icons.animationRoot));
- if (!showAnimationList)
- return;
- if (m_skeletonAnimation != null && m_skeletonAnimation.state != null) {
- if (GUILayout.Button(new GUIContent("Setup Pose", Icons.skeleton), GUILayout.Width(105), GUILayout.Height(18))) {
- StopAnimation();
- m_skeletonAnimation.skeleton.SetToSetupPose();
- m_requireRefresh = true;
- }
- } else {
- EditorGUILayout.HelpBox("Animations can be previewed if you expand the Preview window below.", MessageType.Info);
- }
- EditorGUILayout.LabelField("Name", "Duration");
- foreach (Spine.Animation animation in m_skeletonData.Animations) {
- using (new GUILayout.HorizontalScope()) {
- if (m_skeletonAnimation != null && m_skeletonAnimation.state != null) {
- var activeTrack = m_skeletonAnimation.state.GetCurrent(0);
- if (activeTrack != null && activeTrack.Animation == animation) {
- if (GUILayout.Button("\u25BA", activePlayButtonStyle, GUILayout.Width(24))) {
- StopAnimation();
- }
- } else {
- if (GUILayout.Button("\u25BA", idlePlayButtonStyle, GUILayout.Width(24))) {
- PlayAnimation(animation.Name, true);
- }
- }
- } else {
- GUILayout.Label("-", GUILayout.Width(24));
- }
- EditorGUILayout.LabelField(new GUIContent(animation.Name, Icons.animation), new GUIContent(animation.Duration.ToString("f3") + "s" + ("(" + (Mathf.RoundToInt(animation.Duration * 30)) + ")").PadLeft(12, ' ')));
- }
- }
- }
- void DrawSlotList () {
- showSlotList = EditorGUILayout.Foldout(showSlotList, new GUIContent("Slots", Icons.slotRoot));
- if (!showSlotList) return;
- if (m_skeletonAnimation == null || m_skeletonAnimation.skeleton == null) return;
- EditorGUI.indentLevel++;
- showAttachments = EditorGUILayout.ToggleLeft("Show Attachments", showAttachments);
- var slotAttachments = new List<Attachment>();
- var slotAttachmentNames = new List<string>();
- var defaultSkinAttachmentNames = new List<string>();
- var defaultSkin = m_skeletonData.Skins.Items[0];
- Skin skin = m_skeletonAnimation.skeleton.Skin ?? defaultSkin;
- var slotsItems = m_skeletonAnimation.skeleton.Slots.Items;
- for (int i = m_skeletonAnimation.skeleton.Slots.Count - 1; i >= 0; i--) {
- Slot slot = slotsItems[i];
- EditorGUILayout.LabelField(new GUIContent(slot.Data.Name, Icons.slot));
- if (showAttachments) {
- EditorGUI.indentLevel++;
- slotAttachments.Clear();
- slotAttachmentNames.Clear();
- defaultSkinAttachmentNames.Clear();
- skin.FindNamesForSlot(i, slotAttachmentNames);
- skin.FindAttachmentsForSlot(i, slotAttachments);
- if (skin != defaultSkin) {
- defaultSkin.FindNamesForSlot(i, defaultSkinAttachmentNames);
- defaultSkin.FindNamesForSlot(i, slotAttachmentNames);
- defaultSkin.FindAttachmentsForSlot(i, slotAttachments);
- } else {
- defaultSkin.FindNamesForSlot(i, defaultSkinAttachmentNames);
- }
- for (int a = 0; a < slotAttachments.Count; a++) {
- Attachment attachment = slotAttachments[a];
- string attachmentName = slotAttachmentNames[a];
- Texture2D icon = Icons.GetAttachmentIcon(attachment);
- bool initialState = slot.Attachment == attachment;
- bool toggled = EditorGUILayout.ToggleLeft(new GUIContent(attachmentName, icon), slot.Attachment == attachment);
- if (!defaultSkinAttachmentNames.Contains(attachmentName)) {
- Rect skinPlaceHolderIconRect = GUILayoutUtility.GetLastRect();
- skinPlaceHolderIconRect.width = Icons.skinPlaceholder.width;
- skinPlaceHolderIconRect.height = Icons.skinPlaceholder.height;
- GUI.DrawTexture(skinPlaceHolderIconRect, Icons.skinPlaceholder);
- }
- if (toggled != initialState) {
- slot.Attachment = toggled ? attachment : null;
- m_requireRefresh = true;
- }
- }
- EditorGUI.indentLevel--;
- }
- }
- EditorGUI.indentLevel--;
- }
- void RepopulateWarnings () {
- warnings.Clear();
- // Clear null entries.
- {
- bool hasNulls = false;
- foreach (var a in m_skeletonDataAsset.atlasAssets) {
- if (a == null) {
- hasNulls = true;
- break;
- }
- }
- if (hasNulls) {
- var trimmedAtlasAssets = new List<AtlasAsset>();
- foreach (var a in m_skeletonDataAsset.atlasAssets) {
- if (a != null) trimmedAtlasAssets.Add(a);
- }
- m_skeletonDataAsset.atlasAssets = trimmedAtlasAssets.ToArray();
- }
- serializedObject.Update();
- }
- if (skeletonJSON.objectReferenceValue == null) {
- warnings.Add("Missing Skeleton JSON");
- } else {
- if (SpineEditorUtilities.IsSpineData((TextAsset)skeletonJSON.objectReferenceValue) == false) {
- warnings.Add("Skeleton data file is not a valid JSON or binary file.");
- } else {
- #if SPINE_TK2D
- bool searchForSpineAtlasAssets = true;
- bool isSpriteCollectionNull = spriteCollection.objectReferenceValue == null;
- if (!isSpriteCollectionNull) searchForSpineAtlasAssets = false;
- #else
- const bool searchForSpineAtlasAssets = true;
- #endif
- if (searchForSpineAtlasAssets) {
- bool detectedNullAtlasEntry = false;
- var atlasList = new List<Atlas>();
- var actualAtlasAssets = m_skeletonDataAsset.atlasAssets;
- for (int i = 0; i < actualAtlasAssets.Length; i++) {
- if (m_skeletonDataAsset.atlasAssets[i] == null) {
- detectedNullAtlasEntry = true;
- break;
- } else {
- atlasList.Add(actualAtlasAssets[i].GetAtlas());
- }
- }
- if (detectedNullAtlasEntry) {
- warnings.Add("AtlasAsset elements should not be null.");
- } else {
- // Get requirements.
- var missingPaths = SpineEditorUtilities.GetRequiredAtlasRegions(AssetDatabase.GetAssetPath((TextAsset)skeletonJSON.objectReferenceValue));
- foreach (var atlas in atlasList) {
- for (int i = 0; i < missingPaths.Count; i++) {
- if (atlas.FindRegion(missingPaths[i]) != null) {
- missingPaths.RemoveAt(i);
- i--;
- }
- }
- }
- #if SPINE_TK2D
- if (missingPaths.Count > 0)
- warnings.Add("Missing regions. SkeletonDataAsset requires tk2DSpriteCollectionData or Spine AtlasAssets.");
- #endif
- foreach (var str in missingPaths)
- warnings.Add("Missing Region: '" + str + "'");
- }
- }
- }
- }
- }
- #region Preview Window
- PreviewRenderUtility m_previewUtility;
- GameObject m_previewInstance;
- Vector2 previewDir;
- SkeletonAnimation m_skeletonAnimation;
- static readonly int SliderHash = "Slider".GetHashCode();
- float m_lastTime;
- bool m_playing;
- bool m_requireRefresh;
- Color m_originColor = new Color(0.3f, 0.3f, 0.3f, 1);
- void StopAnimation () {
- if (m_skeletonAnimation == null) {
- Debug.LogWarning("Animation was stopped but preview doesn't exist. It's possible that the Preview Panel is closed.");
- }
- m_skeletonAnimation.state.ClearTrack(0);
- m_playing = false;
- }
- List<Spine.Event> m_animEvents = new List<Spine.Event>();
- List<float> m_animEventFrames = new List<float>();
- void PlayAnimation (string animName, bool loop) {
- m_animEvents.Clear();
- m_animEventFrames.Clear();
- m_skeletonAnimation.state.SetAnimation(0, animName, loop);
- Spine.Animation a = m_skeletonAnimation.state.GetCurrent(0).Animation;
- foreach (Timeline t in a.Timelines) {
- if (t.GetType() == typeof(EventTimeline)) {
- var et = (EventTimeline)t;
- for (int i = 0; i < et.Events.Length; i++) {
- m_animEvents.Add(et.Events[i]);
- m_animEventFrames.Add(et.Frames[i]);
- }
- }
- }
- m_playing = true;
- }
- void InitPreview () {
- if (this.m_previewUtility == null) {
- this.m_lastTime = Time.realtimeSinceStartup;
- this.m_previewUtility = new PreviewRenderUtility(true);
- var c = this.m_previewUtility.m_Camera;
- c.orthographic = true;
- c.orthographicSize = 1;
- c.cullingMask = -2147483648;
- c.nearClipPlane = 0.01f;
- c.farClipPlane = 1000f;
- this.CreatePreviewInstances();
- }
- }
- void CreatePreviewInstances () {
- this.DestroyPreviewInstances();
- if (warnings.Count > 0) {
- m_skeletonDataAsset.Clear();
- return;
- }
- var skeletonDataAsset = (SkeletonDataAsset)target;
- if (skeletonDataAsset.GetSkeletonData(false) == null)
- return;
- if (this.m_previewInstance == null) {
- string skinName = EditorPrefs.GetString(m_skeletonDataAssetGUID + "_lastSkin", "");
- try {
- m_previewInstance = SpineEditorUtilities.InstantiateSkeletonAnimation(skeletonDataAsset, skinName).gameObject;
- if (m_previewInstance != null) {
- m_previewInstance.hideFlags = HideFlags.HideAndDontSave;
- m_previewInstance.layer = 0x1f;
- m_skeletonAnimation = m_previewInstance.GetComponent<SkeletonAnimation>();
- m_skeletonAnimation.initialSkinName = skinName;
- m_skeletonAnimation.LateUpdate();
- m_skeletonData = m_skeletonAnimation.skeletonDataAsset.GetSkeletonData(true);
- m_previewInstance.GetComponent<Renderer>().enabled = false;
- m_initialized = true;
- }
- AdjustCameraGoals(true);
- } catch {
- DestroyPreviewInstances();
- }
- }
- }
- void DestroyPreviewInstances () {
- if (this.m_previewInstance != null) {
- DestroyImmediate(this.m_previewInstance);
- m_previewInstance = null;
- }
- m_initialized = false;
- }
- public override bool HasPreviewGUI () {
- if (serializedObject.isEditingMultipleObjects) {
- // JOHN: Implement multi-preview.
- return false;
- }
- for (int i = 0; i < atlasAssets.arraySize; i++) {
- var prop = atlasAssets.GetArrayElementAtIndex(i);
- if (prop.objectReferenceValue == null)
- return false;
- }
- return skeletonJSON.objectReferenceValue != null;
- }
- Texture m_previewTex = new Texture();
- public override void OnInteractivePreviewGUI (Rect r, GUIStyle background) {
- this.InitPreview();
- if (Event.current.type == EventType.Repaint) {
- if (m_requireRefresh) {
- this.m_previewUtility.BeginPreview(r, background);
- this.DoRenderPreview(true);
- this.m_previewTex = this.m_previewUtility.EndPreview();
- m_requireRefresh = false;
- }
- if (this.m_previewTex != null)
- GUI.DrawTexture(r, m_previewTex, ScaleMode.StretchToFill, false);
- }
- DrawSkinToolbar(r);
- NormalizedTimeBar(r);
- // MITCH: left a todo: Implement panning
- // this.previewDir = Drag2D(this.previewDir, r);
- MouseScroll(r);
- }
- float m_orthoGoal = 1;
- Vector3 m_posGoal = new Vector3(0, 0, -10);
- double m_adjustFrameEndTime = 0;
- void AdjustCameraGoals (bool calculateMixTime) {
- if (this.m_previewInstance == null)
- return;
- if (calculateMixTime) {
- if (m_skeletonAnimation.state.GetCurrent(0) != null)
- m_adjustFrameEndTime = EditorApplication.timeSinceStartup + m_skeletonAnimation.state.GetCurrent(0).Alpha;
- }
- GameObject go = this.m_previewInstance;
- Bounds bounds = go.GetComponent<Renderer>().bounds;
- m_orthoGoal = bounds.size.y;
- m_posGoal = bounds.center + new Vector3(0, 0, -10f);
- }
- void AdjustCameraGoals () {
- AdjustCameraGoals(false);
- }
- void AdjustCamera () {
- if (m_previewUtility == null)
- return;
- if (EditorApplication.timeSinceStartup < m_adjustFrameEndTime)
- AdjustCameraGoals();
- float orthoSet = Mathf.Lerp(this.m_previewUtility.m_Camera.orthographicSize, m_orthoGoal, 0.1f);
- this.m_previewUtility.m_Camera.orthographicSize = orthoSet;
- float dist = Vector3.Distance(m_previewUtility.m_Camera.transform.position, m_posGoal);
- if(dist > 0f) {
- Vector3 pos = Vector3.Lerp(this.m_previewUtility.m_Camera.transform.position, m_posGoal, 0.1f);
- pos.x = 0;
- this.m_previewUtility.m_Camera.transform.position = pos;
- this.m_previewUtility.m_Camera.transform.rotation = Quaternion.identity;
- m_requireRefresh = true;
- }
- }
- void DoRenderPreview (bool drawHandles) {
- GameObject go = this.m_previewInstance;
- if (m_requireRefresh && go != null) {
- go.GetComponent<Renderer>().enabled = true;
- if (!EditorApplication.isPlaying)
- m_skeletonAnimation.Update((Time.realtimeSinceStartup - m_lastTime));
- m_lastTime = Time.realtimeSinceStartup;
- if (!EditorApplication.isPlaying)
- m_skeletonAnimation.LateUpdate();
- if (drawHandles) {
- Handles.SetCamera(m_previewUtility.m_Camera);
- Handles.color = m_originColor;
- Handles.DrawLine(new Vector3(-1000 * m_skeletonDataAsset.scale, 0, 0), new Vector3(1000 * m_skeletonDataAsset.scale, 0, 0));
- Handles.DrawLine(new Vector3(0, 1000 * m_skeletonDataAsset.scale, 0), new Vector3(0, -1000 * m_skeletonDataAsset.scale, 0));
- }
- this.m_previewUtility.m_Camera.Render();
- if (drawHandles) {
- Handles.SetCamera(m_previewUtility.m_Camera);
- SpineHandles.DrawBoundingBoxes(m_skeletonAnimation.transform, m_skeletonAnimation.skeleton);
- if (showAttachments) SpineHandles.DrawPaths(m_skeletonAnimation.transform, m_skeletonAnimation.skeleton);
- }
- go.GetComponent<Renderer>().enabled = false;
- }
- }
- void EditorUpdate () {
- AdjustCamera();
- if (m_playing) {
- m_requireRefresh = true;
- Repaint();
- } else if (m_requireRefresh) {
- Repaint();
- }
- //else {
- //only needed if using smooth menus
- //}
- if (needToSerialize) {
- needToSerialize = false;
- serializedObject.ApplyModifiedProperties();
- }
- }
- void DrawSkinToolbar (Rect r) {
- if (m_skeletonAnimation == null)
- return;
- if (m_skeletonAnimation.skeleton != null) {
- string label = (m_skeletonAnimation.skeleton != null && m_skeletonAnimation.skeleton.Skin != null) ? m_skeletonAnimation.skeleton.Skin.Name : "default";
- Rect popRect = new Rect(r);
- popRect.y += 32;
- popRect.x += 4;
- popRect.height = 24;
- popRect.width = 40;
- EditorGUI.DropShadowLabel(popRect, new GUIContent("Skin", Icons.skinsRoot));
- popRect.y += 11;
- popRect.width = 150;
- popRect.x += 44;
- if (GUI.Button(popRect, label, EditorStyles.popup)) {
- DrawSkinDropdown();
- }
- }
- }
- void NormalizedTimeBar (Rect r) {
- if (m_skeletonAnimation == null)
- return;
- Rect barRect = new Rect(r);
- barRect.height = 32;
- barRect.x += 4;
- barRect.width -= 4;
- GUI.Box(barRect, "");
- Rect lineRect = new Rect(barRect);
- float width = lineRect.width;
- TrackEntry t = m_skeletonAnimation.state.GetCurrent(0);
- if (t != null) {
- int loopCount = (int)(t.TrackTime / t.TrackEnd);
- float currentTime = t.TrackTime - (t.TrackEnd * loopCount);
- float normalizedTime = currentTime / t.Animation.Duration;
- float wrappedTime = normalizedTime % 1;
- lineRect.x = barRect.x + (width * wrappedTime) - 0.5f;
- lineRect.width = 2;
- GUI.color = Color.red;
- GUI.DrawTexture(lineRect, EditorGUIUtility.whiteTexture);
- GUI.color = Color.white;
- for (int i = 0; i < m_animEvents.Count; i++) {
- float fr = m_animEventFrames[i];
- var evRect = new Rect(barRect);
- evRect.x = Mathf.Clamp(((fr / t.Animation.Duration) * width) - (Icons.userEvent.width / 2), barRect.x, float.MaxValue);
- evRect.width = Icons.userEvent.width;
- evRect.height = Icons.userEvent.height;
- evRect.y += Icons.userEvent.height;
- GUI.DrawTexture(evRect, Icons.userEvent);
- Event ev = Event.current;
- if (ev.type == EventType.Repaint) {
- if (evRect.Contains(ev.mousePosition)) {
- Rect tooltipRect = new Rect(evRect);
- GUIStyle tooltipStyle = EditorStyles.helpBox;
- tooltipRect.width = tooltipStyle.CalcSize(new GUIContent(m_animEvents[i].Data.Name)).x;
- tooltipRect.y -= 4;
- tooltipRect.x += 4;
- GUI.Label(tooltipRect, m_animEvents[i].Data.Name, tooltipStyle);
- GUI.tooltip = m_animEvents[i].Data.Name;
- }
- }
- }
- }
- }
- void MouseScroll (Rect position) {
- Event current = Event.current;
- int controlID = GUIUtility.GetControlID(SliderHash, FocusType.Passive);
- switch (current.GetTypeForControl(controlID)) {
- case EventType.ScrollWheel:
- if (position.Contains(current.mousePosition)) {
- m_orthoGoal += current.delta.y * 0.06f;
- m_orthoGoal = Mathf.Max(0.01f, m_orthoGoal);
- GUIUtility.hotControl = controlID;
- current.Use();
- }
- break;
- }
- }
- // MITCH: left todo: Implement preview panning
- /*
- static Vector2 Drag2D(Vector2 scrollPosition, Rect position)
- {
- int controlID = GUIUtility.GetControlID(sliderHash, FocusType.Passive);
- UnityEngine.Event current = UnityEngine.Event.current;
- switch (current.GetTypeForControl(controlID))
- {
- case EventType.MouseDown:
- if (position.Contains(current.mousePosition) && (position.width > 50f))
- {
- GUIUtility.hotControl = controlID;
- current.Use();
- EditorGUIUtility.SetWantsMouseJumping(1);
- }
- return scrollPosition;
- case EventType.MouseUp:
- if (GUIUtility.hotControl == controlID)
- {
- GUIUtility.hotControl = 0;
- }
- EditorGUIUtility.SetWantsMouseJumping(0);
- return scrollPosition;
- case EventType.MouseMove:
- return scrollPosition;
- case EventType.MouseDrag:
- if (GUIUtility.hotControl == controlID)
- {
- scrollPosition -= (Vector2) (((current.delta * (!current.shift ? ((float) 1) : ((float) 3))) / Mathf.Min(position.width, position.height)) * 140f);
- scrollPosition.y = Mathf.Clamp(scrollPosition.y, -90f, 90f);
- current.Use();
- GUI.changed = true;
- }
- return scrollPosition;
- }
- return scrollPosition;
- }
- */
- public override GUIContent GetPreviewTitle () {
- return new GUIContent("Preview");
- }
- public override void OnPreviewSettings () {
- const float SliderWidth = 100;
- if (!m_initialized) {
- GUILayout.HorizontalSlider(0, 0, 2, GUILayout.MaxWidth(SliderWidth));
- } else {
- float speed = GUILayout.HorizontalSlider(m_skeletonAnimation.timeScale, 0, 2, GUILayout.MaxWidth(SliderWidth));
- const float SliderSnap = 0.25f;
- float y = speed / SliderSnap;
- int q = Mathf.RoundToInt(y);
- speed = q * SliderSnap;
- m_skeletonAnimation.timeScale = speed;
- }
- }
- public override Texture2D RenderStaticPreview (string assetPath, UnityEngine.Object[] subAssets, int width, int height) {
- var tex = new Texture2D(width, height, TextureFormat.ARGB32, false);
- this.InitPreview();
- if (this.m_previewUtility.m_Camera == null)
- return null;
- m_requireRefresh = true;
- this.DoRenderPreview(false);
- AdjustCameraGoals(false);
- this.m_previewUtility.m_Camera.orthographicSize = m_orthoGoal / 2;
- this.m_previewUtility.m_Camera.transform.position = m_posGoal;
- this.m_previewUtility.BeginStaticPreview(new Rect(0, 0, width, height));
- this.DoRenderPreview(false);
- tex = this.m_previewUtility.EndStaticPreview();
- return tex;
- }
- #endregion
- #region Skin Dropdown Context Menu
- void DrawSkinDropdown () {
- var menu = new GenericMenu();
- foreach (Skin s in m_skeletonData.Skins)
- menu.AddItem(new GUIContent(s.Name), this.m_skeletonAnimation.skeleton.Skin == s, SetSkin, s);
- menu.ShowAsContext();
- }
- void SetSkin (object o) {
- Skin skin = (Skin)o;
- m_skeletonAnimation.initialSkinName = skin.Name;
- m_skeletonAnimation.Initialize(true);
- m_requireRefresh = true;
- EditorPrefs.SetString(m_skeletonDataAssetGUID + "_lastSkin", skin.Name);
- }
- #endregion
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement