123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
- #if UNITY_EDITOR && UNITY_IMGUI
- #pragma warning disable CS0649 // Field is never assigned to, and will always have its default value.
- using System;
- using System.Collections.Generic;
- using UnityEditor;
- using UnityEditor.SceneManagement;
- using UnityEngine;
- using UnityEngine.SceneManagement;
- using Object = UnityEngine.Object;
- namespace Animancer.Editor.Previews
- {
- /// https://kybernetik.com.au/animancer/api/Animancer.Editor.Previews/TransitionPreviewWindow
- partial class TransitionPreviewWindow
- {
- /************************************************************************************************************************/
- /// <summary>The <see cref="Scene"/> of the current <see cref="TransitionPreviewWindow"/> instance.</summary>
- public static Scene InstanceScene
- => _Instance != null
- ? _Instance._Scene
- : null;
- /************************************************************************************************************************/
- /// <summary>Temporary scene management for the <see cref="TransitionPreviewWindow"/>.</summary>
- /// <remarks>
- /// <strong>Documentation:</strong>
- /// <see href="https://kybernetik.com.au/animancer/docs/manual/transitions#previews">
- /// Previews</see>
- /// </remarks>
- [Serializable]
- public class Scene :
- AnimancerPreviewObject.IEventHandler
- {
- /************************************************************************************************************************/
- #region Fields and Properties
- /************************************************************************************************************************/
- /// <summary>The scene displayed by the <see cref="TransitionPreviewWindow"/>.</summary>
- [SerializeField]
- private UnityEngine.SceneManagement.Scene _Scene;
- /// <summary>The root object in the preview scene.</summary>
- public Transform PreviewSceneRoot { get; private set; }
- /// <summary>The root of the model in the preview scene. A child of the <see cref="PreviewSceneRoot"/>.</summary>
- public Transform InstanceRoot { get; private set; }
- /// <summary>
- /// An instance of the <see cref="TransitionPreviewSettings.SceneEnvironment"/>.
- /// A child of the <see cref="PreviewSceneRoot"/>.
- /// </summary>
- public GameObject EnvironmentInstance { get; private set; }
- /************************************************************************************************************************/
- [SerializeField]
- private AnimancerPreviewObject _PreviewObject;
- /// <summary>[<see cref="SerializeField"/>] The object being previewed.</summary>
- public AnimancerPreviewObject PreviewObject
- => AnimancerPreviewObject.Initialize(ref _PreviewObject, this, PreviewSceneRoot);
- /************************************************************************************************************************/
- private Vector3 _PreviousPreviewObjectPosition;
- private Vector3 CurrentPreviewObjectPosition
- => PreviewObject.SelectedInstanceAnimator.transform.position;
- /************************************************************************************************************************/
- #endregion
- /************************************************************************************************************************/
- #region Initialization
- /************************************************************************************************************************/
- /// <summary>Initializes this <see cref="Scene"/>.</summary>
- public void OnEnable()
- {
- duringSceneGui += DoCustomGUI;
- CreateScene();
- PreviewObject.TrySelectBestModel(Transition);
- }
- /************************************************************************************************************************/
- private void CreateScene()
- {
- _Scene = EditorSceneManager.NewPreviewScene();
- _Scene.name = "Transition Preview";
- _Instance.customScene = _Scene;
- var root = AnimancerPreviewObject.CreateEmpty(nameof(TransitionPreviewWindow));
- PreviewSceneRoot = root.transform;
- SceneManager.MoveGameObjectToScene(root, _Scene);
- _Instance.customParentForDraggedObjects = PreviewSceneRoot;
- OnEnvironmentPrefabChanged();
- }
- /************************************************************************************************************************/
- internal void OnEnvironmentPrefabChanged()
- {
- DestroyImmediate(EnvironmentInstance);
- var prefab = TransitionPreviewSettings.SceneEnvironment;
- if (prefab != null)
- EnvironmentInstance = Instantiate(prefab, PreviewSceneRoot);
- }
- /************************************************************************************************************************/
- /// <inheritdoc/>
- void AnimancerPreviewObject.IEventHandler.OnInstantiateObject()
- {
- FocusCamera();
- _Instance._Animations.GatherAnimations();
- }
- /************************************************************************************************************************/
- /// <inheritdoc/>
- void AnimancerPreviewObject.IEventHandler.OnSetSelectedAnimator()
- {
- _Instance.in2DMode = PreviewObject.SelectedInstanceType == AnimationType.Sprite;
- }
- /// <inheritdoc/>
- void AnimancerPreviewObject.IEventHandler.OnCreateGraph()
- {
- PreviewObject.Graph.RequirePostUpdate(new Animations.WindowMatchStateTime());
- _Instance._Animations.NormalizedTime = _Instance._Animations.NormalizedTime;
- }
- /************************************************************************************************************************/
- /// <summary>Called when the target transition property is changed.</summary>
- public void OnTargetPropertyChanged()
- {
- _ExpandedHierarchy?.Clear();
- var previewObject = PreviewObject;
- previewObject.OriginalObject = AnimancerUtilities.FindRoot(_Instance._TransitionProperty.TargetObject);
- previewObject.TrySelectBestModel(Transition);
- _Instance._Animations.NormalizedTime = 0;
- _Instance.in2DMode = previewObject.SelectedInstanceType == AnimationType.Sprite;
- }
- /************************************************************************************************************************/
- private void FocusCamera()
- {
- if (InstanceRoot == null)
- return;
- var bounds = CalculateBounds(InstanceRoot);
- var rotation = _Instance.in2DMode ?
- Quaternion.identity :
- Quaternion.Euler(35, 135, 0);
- var size = bounds.extents.magnitude * 1.5f;
- if (size == float.PositiveInfinity)
- return;
- else if (size == 0)
- size = 10;
- _Instance.LookAt(bounds.center, rotation, size, _Instance.in2DMode, true);
- }
- /************************************************************************************************************************/
- private static Bounds CalculateBounds(Transform transform)
- {
- if (transform == null)
- return default;
- var renderers = transform.GetComponentsInChildren<Renderer>();
- if (renderers.Length == 0)
- return default;
- var bounds = renderers[0].bounds;
- for (int i = 1; i < renderers.Length; i++)
- {
- bounds.Encapsulate(renderers[i].bounds);
- }
- return bounds;
- }
- /************************************************************************************************************************/
- #endregion
- /************************************************************************************************************************/
- #region Execution
- /************************************************************************************************************************/
- /// <summary>Called when the window GUI is drawn.</summary>
- public void OnGUI()
- {
- if (_PreviewObject != null &&
- _PreviewObject.Graph != null &&
- _PreviewObject.Graph.IsGraphPlaying)
- AnimancerGUI.RepaintEverything();
- if (Selection.activeObject == _Instance &&
- Event.current.type == EventType.KeyUp &&
- Event.current.keyCode == KeyCode.F)
- FocusCamera();
- }
- /************************************************************************************************************************/
- private void DoCustomGUI(SceneView sceneView)
- {
- FollowPreviewObject(sceneView);
- var animancer = PreviewObject.Graph;
- if (animancer == null ||
- sceneView is not TransitionPreviewWindow instance ||
- !AnimancerUtilities.TryGetWrappedObject(Transition, out ITransitionGUI gui) ||
- instance._TransitionProperty == null)
- return;
- EditorGUI.BeginChangeCheck();
- using (new TransitionDrawer.DrawerContext(instance._TransitionProperty))
- {
- try
- {
- gui.OnPreviewSceneGUI(new(animancer));
- }
- catch (Exception exception)
- {
- Debug.LogException(exception);
- }
- }
- if (EditorGUI.EndChangeCheck())
- AnimancerGUI.RepaintEverything();
- }
- /************************************************************************************************************************/
- private void FollowPreviewObject(SceneView sceneView)
- {
- var currentPreviewObjectPosition = CurrentPreviewObjectPosition;
- if (_PreviousPreviewObjectPosition == currentPreviewObjectPosition)
- return;
- sceneView.pivot += currentPreviewObjectPosition - _PreviousPreviewObjectPosition;
- _PreviousPreviewObjectPosition = currentPreviewObjectPosition;
- }
- /************************************************************************************************************************/
- /// <summary>Is the `obj` a <see cref="GameObject"/> in the preview scene?</summary>
- public bool IsSceneObject(Object obj)
- => obj is GameObject gameObject
- && gameObject.transform.IsChildOf(PreviewSceneRoot);
- /************************************************************************************************************************/
- [SerializeField]
- private List<Transform> _ExpandedHierarchy;
- /// <summary>A list of all objects with their child hierarchy expanded.</summary>
- public List<Transform> ExpandedHierarchy
- => _ExpandedHierarchy ??= new();
- /************************************************************************************************************************/
- #endregion
- /************************************************************************************************************************/
- #region Cleanup
- /************************************************************************************************************************/
- /// <summary>Called by <see cref="TransitionPreviewWindow.OnDisable"/>.</summary>
- public void OnDisable()
- {
- duringSceneGui -= DoCustomGUI;
- _PreviewObject?.Dispose();
- EditorSceneManager.ClosePreviewScene(_Scene);
- }
- /************************************************************************************************************************/
- /// <summary>Called by <see cref="TransitionPreviewWindow.OnDestroy"/>.</summary>
- public void OnDestroy()
- {
- if (PreviewSceneRoot != null)
- {
- DestroyImmediate(PreviewSceneRoot.gameObject);
- PreviewSceneRoot = null;
- }
- }
- /************************************************************************************************************************/
- #endregion
- /************************************************************************************************************************/
- }
- }
- }
- #endif
|