| @@ -0,0 +1,206 @@ | ||
| using System.Collections.Generic; | ||
| using UnityEditor; | ||
| using UnityEngine; | ||
|
|
||
| namespace Cinemachine.Editor | ||
| { | ||
| [CustomEditor(typeof(CinemachineBlendListCamera))] | ||
| internal sealed class CinemachineBlendListCameraEditor | ||
| : CinemachineVirtualCameraBaseEditor<CinemachineBlendListCamera> | ||
| { | ||
| protected override List<string> GetExcludedPropertiesInInspector() | ||
| { | ||
| List<string> excluded = base.GetExcludedPropertiesInInspector(); | ||
| excluded.Add(FieldPath(x => x.m_Instructions)); | ||
| return excluded; | ||
| } | ||
|
|
||
| private UnityEditorInternal.ReorderableList mChildList; | ||
| private UnityEditorInternal.ReorderableList mInstructionList; | ||
|
|
||
| protected override void OnEnable() | ||
| { | ||
| base.OnEnable(); | ||
| mChildList = null; | ||
| mInstructionList = null; | ||
| } | ||
|
|
||
| protected override void OnDisable() | ||
| { | ||
| base.OnDisable(); | ||
| } | ||
|
|
||
| public override void OnInspectorGUI() | ||
| { | ||
| BeginInspector(); | ||
| if (mInstructionList == null) | ||
| SetupInstructionList(); | ||
| if (mChildList == null) | ||
| SetupChildList(); | ||
|
|
||
| // Ordinary properties | ||
| DrawHeaderInInspector(); | ||
| DrawPropertyInInspector(FindProperty(x => x.m_Priority)); | ||
| DrawTargetsInInspector(FindProperty(x => x.m_Follow), FindProperty(x => x.m_LookAt)); | ||
| DrawRemainingPropertiesInInspector(); | ||
|
|
||
| // Instructions | ||
| UpdateCameraCandidates(); | ||
| EditorGUI.BeginChangeCheck(); | ||
| EditorGUILayout.Separator(); | ||
| mInstructionList.DoLayoutList(); | ||
|
|
||
| // vcam children | ||
| EditorGUILayout.Separator(); | ||
| mChildList.DoLayoutList(); | ||
| if (EditorGUI.EndChangeCheck()) | ||
| { | ||
| serializedObject.ApplyModifiedProperties(); | ||
| Target.ValidateInstructions(); | ||
| } | ||
|
|
||
| // Extensions | ||
| DrawExtensionsWidgetInInspector(); | ||
| } | ||
|
|
||
| private string[] mCameraCandidates; | ||
| private Dictionary<CinemachineVirtualCameraBase, int> mCameraIndexLookup; | ||
| private void UpdateCameraCandidates() | ||
| { | ||
| List<string> vcams = new List<string>(); | ||
| mCameraIndexLookup = new Dictionary<CinemachineVirtualCameraBase, int>(); | ||
| vcams.Add("(none)"); | ||
| CinemachineVirtualCameraBase[] children = Target.ChildCameras; | ||
| foreach (var c in children) | ||
| { | ||
| mCameraIndexLookup[c] = vcams.Count; | ||
| vcams.Add(c.Name); | ||
| } | ||
| mCameraCandidates = vcams.ToArray(); | ||
| } | ||
|
|
||
| private int GetCameraIndex(Object obj) | ||
| { | ||
| if (obj == null || mCameraIndexLookup == null) | ||
| return 0; | ||
| CinemachineVirtualCameraBase vcam = obj as CinemachineVirtualCameraBase; | ||
| if (vcam == null) | ||
| return 0; | ||
| if (!mCameraIndexLookup.ContainsKey(vcam)) | ||
| return 0; | ||
| return mCameraIndexLookup[vcam]; | ||
| } | ||
|
|
||
| void SetupInstructionList() | ||
| { | ||
| mInstructionList = new UnityEditorInternal.ReorderableList(serializedObject, | ||
| serializedObject.FindProperty(() => Target.m_Instructions), | ||
| true, true, true, true); | ||
|
|
||
| // Needed for accessing field names as strings | ||
| CinemachineBlendListCamera.Instruction def = new CinemachineBlendListCamera.Instruction(); | ||
|
|
||
| float vSpace = 2; | ||
| float hSpace = 3; | ||
| float floatFieldWidth = EditorGUIUtility.singleLineHeight * 2.5f; | ||
| float hBigSpace = EditorGUIUtility.singleLineHeight * 2 / 3; | ||
| mInstructionList.drawHeaderCallback = (Rect rect) => | ||
| { | ||
| float sharedWidth = rect.width - EditorGUIUtility.singleLineHeight | ||
| - floatFieldWidth - hSpace - hBigSpace; | ||
| rect.x += EditorGUIUtility.singleLineHeight; rect.width = sharedWidth / 2; | ||
| EditorGUI.LabelField(rect, "Child"); | ||
|
|
||
| rect.x += rect.width + hSpace; | ||
| EditorGUI.LabelField(rect, "Blend in"); | ||
|
|
||
| rect.x += rect.width + hBigSpace; rect.width = floatFieldWidth; | ||
| EditorGUI.LabelField(rect, "Hold"); | ||
| }; | ||
|
|
||
| mInstructionList.drawElementCallback | ||
| = (Rect rect, int index, bool isActive, bool isFocused) => | ||
| { | ||
| SerializedProperty instProp = mInstructionList.serializedProperty.GetArrayElementAtIndex(index); | ||
| float sharedWidth = rect.width - floatFieldWidth - hSpace - hBigSpace; | ||
| rect.y += vSpace; rect.height = EditorGUIUtility.singleLineHeight; | ||
|
|
||
| rect.width = sharedWidth / 2; | ||
| SerializedProperty vcamSelProp = instProp.FindPropertyRelative(() => def.m_VirtualCamera); | ||
| int currentVcam = GetCameraIndex(vcamSelProp.objectReferenceValue); | ||
| int vcamSelection = EditorGUI.Popup(rect, currentVcam, mCameraCandidates); | ||
| if (currentVcam != vcamSelection) | ||
| vcamSelProp.objectReferenceValue = (vcamSelection == 0) | ||
| ? null : Target.ChildCameras[vcamSelection - 1]; | ||
|
|
||
| rect.x += rect.width + hSpace; rect.width = sharedWidth / 2; | ||
| if (index > 0) | ||
| EditorGUI.PropertyField(rect, instProp.FindPropertyRelative(() => def.m_Blend), | ||
| GUIContent.none); | ||
|
|
||
| if (index < mInstructionList.count - 1) | ||
| { | ||
| float oldWidth = EditorGUIUtility.labelWidth; | ||
| EditorGUIUtility.labelWidth = hBigSpace; | ||
|
|
||
| rect.x += rect.width; rect.width = floatFieldWidth + hBigSpace; | ||
| SerializedProperty holdProp = instProp.FindPropertyRelative(() => def.m_Hold); | ||
| EditorGUI.PropertyField(rect, holdProp, new GUIContent(" ", holdProp.tooltip)); | ||
| holdProp.floatValue = Mathf.Max(holdProp.floatValue, 0); | ||
|
|
||
| EditorGUIUtility.labelWidth = oldWidth; | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| void SetupChildList() | ||
| { | ||
| float vSpace = 2; | ||
| mChildList = new UnityEditorInternal.ReorderableList(serializedObject, | ||
| serializedObject.FindProperty(() => Target.m_ChildCameras), | ||
| true, true, true, true); | ||
|
|
||
| mChildList.drawHeaderCallback = (Rect rect) => | ||
| { | ||
| EditorGUI.LabelField(rect, "Virtual Camera Children"); | ||
| }; | ||
| mChildList.drawElementCallback | ||
| = (Rect rect, int index, bool isActive, bool isFocused) => | ||
| { | ||
| rect.y += vSpace; | ||
| Vector2 pos = rect.position; | ||
| rect.height = EditorGUIUtility.singleLineHeight; | ||
| SerializedProperty element | ||
| = mChildList.serializedProperty.GetArrayElementAtIndex(index); | ||
| EditorGUI.PropertyField(rect, element, GUIContent.none); | ||
| }; | ||
| mChildList.onChangedCallback = (UnityEditorInternal.ReorderableList l) => | ||
| { | ||
| if (l.index < 0 || l.index >= l.serializedProperty.arraySize) | ||
| return; | ||
| Object o = l.serializedProperty.GetArrayElementAtIndex( | ||
| l.index).objectReferenceValue; | ||
| CinemachineVirtualCameraBase vcam = (o != null) | ||
| ? (o as CinemachineVirtualCameraBase) : null; | ||
| if (vcam != null) | ||
| vcam.transform.SetSiblingIndex(l.index); | ||
| }; | ||
| mChildList.onAddCallback = (UnityEditorInternal.ReorderableList l) => | ||
| { | ||
| var index = l.serializedProperty.arraySize; | ||
| var vcam = CinemachineMenu.CreateDefaultVirtualCamera(); | ||
| Undo.SetTransformParent(vcam.transform, Target.transform, ""); | ||
| vcam.transform.SetSiblingIndex(index); | ||
| }; | ||
| mChildList.onRemoveCallback = (UnityEditorInternal.ReorderableList l) => | ||
| { | ||
| Object o = l.serializedProperty.GetArrayElementAtIndex( | ||
| l.index).objectReferenceValue; | ||
| CinemachineVirtualCameraBase vcam = (o != null) | ||
| ? (o as CinemachineVirtualCameraBase) : null; | ||
| if (vcam != null) | ||
| Undo.DestroyObjectImmediate(vcam.gameObject); | ||
| }; | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,161 @@ | ||
| using UnityEngine; | ||
| using UnityEditor; | ||
| using UnityEditorInternal; | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Cinemachine.Editor | ||
| { | ||
| [CustomEditor(typeof(CinemachineBlenderSettings))] | ||
| internal sealed class CinemachineBlenderSettingsEditor : BaseEditor<CinemachineBlenderSettings> | ||
| { | ||
| private ReorderableList mBlendList; | ||
|
|
||
| /// <summary> | ||
| /// Called when building the Camera popup menus, to get the domain of possible | ||
| /// cameras. If no delegate is set, will find all top-level (non-slave) | ||
| /// virtual cameras in the scene. | ||
| /// </summary> | ||
| public GetAllVirtualCamerasDelegate GetAllVirtualCameras; | ||
| public delegate CinemachineVirtualCameraBase[] GetAllVirtualCamerasDelegate(); | ||
|
|
||
| protected override List<string> GetExcludedPropertiesInInspector() | ||
| { | ||
| List<string> excluded = base.GetExcludedPropertiesInInspector(); | ||
| excluded.Add(FieldPath(x => x.m_CustomBlends)); | ||
| return excluded; | ||
| } | ||
|
|
||
| public override void OnInspectorGUI() | ||
| { | ||
| BeginInspector(); | ||
| if (mBlendList == null) | ||
| SetupBlendList(); | ||
|
|
||
| DrawRemainingPropertiesInInspector(); | ||
|
|
||
| UpdateCameraCandidates(); | ||
| mBlendList.DoLayoutList(); | ||
| serializedObject.ApplyModifiedProperties(); | ||
| } | ||
|
|
||
| private string[] mCameraCandidates; | ||
| private Dictionary<string, int> mCameraIndexLookup; | ||
| private void UpdateCameraCandidates() | ||
| { | ||
| List<string> vcams = new List<string>(); | ||
| mCameraIndexLookup = new Dictionary<string, int>(); | ||
|
|
||
| CinemachineVirtualCameraBase[] candidates; | ||
| if (GetAllVirtualCameras != null) | ||
| candidates = GetAllVirtualCameras(); | ||
| else | ||
| { | ||
| // Get all top-level (i.e. non-slave) virtual cameras | ||
| candidates = Resources.FindObjectsOfTypeAll( | ||
| typeof(CinemachineVirtualCameraBase)) as CinemachineVirtualCameraBase[]; | ||
|
|
||
| for (int i = 0; i < candidates.Length; ++i) | ||
| if (candidates[i].ParentCamera != null) | ||
| candidates[i] = null; | ||
| } | ||
| vcams.Add("(none)"); | ||
| vcams.Add(CinemachineBlenderSettings.kBlendFromAnyCameraLabel); | ||
| foreach (CinemachineVirtualCameraBase c in candidates) | ||
| if (c != null && !vcams.Contains(c.Name)) | ||
| vcams.Add(c.Name); | ||
|
|
||
| mCameraCandidates = vcams.ToArray(); | ||
| for (int i = 0; i < mCameraCandidates.Length; ++i) | ||
| mCameraIndexLookup[mCameraCandidates[i]] = i; | ||
| } | ||
|
|
||
| private int GetCameraIndex(string name) | ||
| { | ||
| if (name == null || mCameraIndexLookup == null) | ||
| return 0; | ||
| if (!mCameraIndexLookup.ContainsKey(name)) | ||
| return 0; | ||
| return mCameraIndexLookup[name]; | ||
| } | ||
|
|
||
| void SetupBlendList() | ||
| { | ||
| mBlendList = new ReorderableList(serializedObject, | ||
| serializedObject.FindProperty(() => Target.m_CustomBlends), | ||
| true, true, true, true); | ||
|
|
||
| // Needed for accessing string names of fields | ||
| CinemachineBlenderSettings.CustomBlend def = new CinemachineBlenderSettings.CustomBlend(); | ||
| CinemachineBlendDefinition def2 = new CinemachineBlendDefinition(); | ||
|
|
||
| float vSpace = 2; | ||
| float hSpace = 3; | ||
| float floatFieldWidth = EditorGUIUtility.singleLineHeight * 2.5f; | ||
| mBlendList.drawHeaderCallback = (Rect rect) => | ||
| { | ||
| rect.width -= (EditorGUIUtility.singleLineHeight + 2 * hSpace); | ||
| rect.width /= 3; | ||
| Vector2 pos = rect.position; pos.x += EditorGUIUtility.singleLineHeight; | ||
| rect.position = pos; | ||
| EditorGUI.LabelField(rect, "From"); | ||
|
|
||
| pos.x += rect.width + hSpace; rect.position = pos; | ||
| EditorGUI.LabelField(rect, "To"); | ||
|
|
||
| pos.x += rect.width + hSpace; rect.width -= floatFieldWidth + hSpace; rect.position = pos; | ||
| EditorGUI.LabelField(rect, "Style"); | ||
|
|
||
| pos.x += rect.width + hSpace; rect.width = floatFieldWidth; rect.position = pos; | ||
| EditorGUI.LabelField(rect, "Time"); | ||
| }; | ||
|
|
||
| mBlendList.drawElementCallback | ||
| = (Rect rect, int index, bool isActive, bool isFocused) => | ||
| { | ||
| SerializedProperty element | ||
| = mBlendList.serializedProperty.GetArrayElementAtIndex(index); | ||
|
|
||
| rect.y += vSpace; | ||
| rect.height = EditorGUIUtility.singleLineHeight; | ||
| Vector2 pos = rect.position; | ||
| rect.width -= 2 * hSpace; rect.width /= 3; | ||
| SerializedProperty fromProp = element.FindPropertyRelative(() => def.m_From); | ||
| int current = GetCameraIndex(fromProp.stringValue); | ||
| int sel = EditorGUI.Popup(rect, current, mCameraCandidates); | ||
| if (current != sel) | ||
| fromProp.stringValue = mCameraCandidates[sel]; | ||
|
|
||
| pos.x += rect.width + hSpace; rect.position = pos; | ||
| SerializedProperty toProp = element.FindPropertyRelative(() => def.m_To); | ||
| current = GetCameraIndex(toProp.stringValue); | ||
| sel = EditorGUI.Popup(rect, current, mCameraCandidates); | ||
| if (current != sel) | ||
| toProp.stringValue = mCameraCandidates[sel]; | ||
|
|
||
| SerializedProperty blendProp = element.FindPropertyRelative(() => def.m_Blend); | ||
| pos.x += rect.width + hSpace; rect.width -= floatFieldWidth; rect.position = pos; | ||
| SerializedProperty styleProp = blendProp.FindPropertyRelative(() => def2.m_Style); | ||
| EditorGUI.PropertyField(rect, styleProp, GUIContent.none); | ||
|
|
||
| if (styleProp.intValue != (int)CinemachineBlendDefinition.Style.Cut) | ||
| { | ||
| pos.x += rect.width + hSpace; rect.width = floatFieldWidth; rect.position = pos; | ||
| SerializedProperty timeProp = blendProp.FindPropertyRelative(() => def2.m_Time); | ||
| EditorGUI.PropertyField(rect, timeProp, GUIContent.none); | ||
| } | ||
| }; | ||
|
|
||
| mBlendList.onAddCallback = (ReorderableList l) => | ||
| { | ||
| var index = l.serializedProperty.arraySize; | ||
| ++l.serializedProperty.arraySize; | ||
| SerializedProperty blendProp = l.serializedProperty.GetArrayElementAtIndex( | ||
| index).FindPropertyRelative(() => def.m_Blend); | ||
|
|
||
| blendProp.FindPropertyRelative(() => def2.m_Style).enumValueIndex | ||
| = (int)CinemachineBlendDefinition.Style.EaseInOut; | ||
| blendProp.FindPropertyRelative(() => def2.m_Time).floatValue = 2f; | ||
| }; | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,168 @@ | ||
| using UnityEngine; | ||
| using UnityEditor; | ||
| using System.Collections.Generic; | ||
| using Cinemachine.Utility; | ||
| using System.IO; | ||
|
|
||
| namespace Cinemachine.Editor | ||
| { | ||
| [CustomEditor(typeof(CinemachineBrain))] | ||
| internal sealed class CinemachineBrainEditor : BaseEditor<CinemachineBrain> | ||
| { | ||
| EmbeddeAssetEditor<CinemachineBlenderSettings> m_BlendsEditor; | ||
| bool mEventsExpanded = false; | ||
|
|
||
| protected override List<string> GetExcludedPropertiesInInspector() | ||
| { | ||
| List<string> excluded = base.GetExcludedPropertiesInInspector(); | ||
| excluded.Add(FieldPath(x => x.m_CameraCutEvent)); | ||
| excluded.Add(FieldPath(x => x.m_CameraActivatedEvent)); | ||
| excluded.Add(FieldPath(x => x.m_CustomBlends)); | ||
| return excluded; | ||
| } | ||
|
|
||
| private void OnEnable() | ||
| { | ||
| m_BlendsEditor = new EmbeddeAssetEditor<CinemachineBlenderSettings>( | ||
| FieldPath(x => x.m_CustomBlends), this); | ||
| m_BlendsEditor.OnChanged = (CinemachineBlenderSettings b) => | ||
| { | ||
| UnityEditorInternal.InternalEditorUtility.RepaintAllViews(); | ||
| }; | ||
| } | ||
|
|
||
| private void OnDisable() | ||
| { | ||
| if (m_BlendsEditor != null) | ||
| m_BlendsEditor.OnDisable(); | ||
| } | ||
|
|
||
| public override void OnInspectorGUI() | ||
| { | ||
| BeginInspector(); | ||
|
|
||
| // Show the active camera and blend | ||
| GUI.enabled = false; | ||
| ICinemachineCamera vcam = Target.ActiveVirtualCamera; | ||
| Transform activeCam = (vcam != null && vcam.VirtualCameraGameObject != null) | ||
| ? vcam.VirtualCameraGameObject.transform : null; | ||
| EditorGUILayout.ObjectField("Live Camera", activeCam, typeof(Transform), true); | ||
| EditorGUILayout.DelayedTextField( | ||
| "Live Blend", Target.ActiveBlend != null | ||
| ? Target.ActiveBlend.Description : string.Empty); | ||
| GUI.enabled = true; | ||
|
|
||
| // Normal properties | ||
| DrawRemainingPropertiesInInspector(); | ||
|
|
||
| // Blender | ||
| m_BlendsEditor.DrawEditorCombo( | ||
| "Create New Blender Asset", | ||
| Target.gameObject.name + " Blends", "asset", string.Empty, | ||
| "Custom Blends", false); | ||
|
|
||
| mEventsExpanded = EditorGUILayout.Foldout(mEventsExpanded, "Events"); | ||
| if (mEventsExpanded) | ||
| { | ||
| EditorGUILayout.PropertyField(FindProperty(x => x.m_CameraCutEvent)); | ||
| EditorGUILayout.PropertyField(FindProperty(x => x.m_CameraActivatedEvent)); | ||
| } | ||
| serializedObject.ApplyModifiedProperties(); | ||
| } | ||
|
|
||
| [DrawGizmo(GizmoType.Selected | GizmoType.NonSelected, typeof(CinemachineBrain))] | ||
| private static void DrawBrainGizmos(CinemachineBrain brain, GizmoType drawType) | ||
| { | ||
| if (brain.OutputCamera != null && brain.m_ShowCameraFrustum) | ||
| { | ||
| DrawCameraFrustumGizmo( | ||
| brain, LensSettings.FromCamera(brain.OutputCamera), | ||
| brain.transform.localToWorldMatrix, | ||
| Color.white); // GML why is this color hardcoded? | ||
| } | ||
| } | ||
|
|
||
| internal static void DrawCameraFrustumGizmo( | ||
| CinemachineBrain brain, LensSettings lens, | ||
| Matrix4x4 transform, Color color) | ||
| { | ||
| float aspect = 1; | ||
| bool ortho = false; | ||
| if (brain != null) | ||
| { | ||
| aspect = brain.OutputCamera.aspect; | ||
| ortho = brain.OutputCamera.orthographic; | ||
| } | ||
|
|
||
| Matrix4x4 originalMatrix = Gizmos.matrix; | ||
| Color originalGizmoColour = Gizmos.color; | ||
| Gizmos.color = color; | ||
| Gizmos.matrix = transform; | ||
| if (ortho) | ||
| { | ||
| Vector3 size = new Vector3( | ||
| aspect * lens.OrthographicSize * 2, | ||
| lens.OrthographicSize * 2, | ||
| lens.NearClipPlane + lens.FarClipPlane); | ||
| Gizmos.DrawWireCube( | ||
| new Vector3(0, 0, (size.z / 2) + lens.NearClipPlane), size); | ||
| } | ||
| else | ||
| { | ||
| Gizmos.DrawFrustum( | ||
| Vector3.zero, lens.FieldOfView, | ||
| lens.FarClipPlane, lens.NearClipPlane, aspect); | ||
| } | ||
| Gizmos.matrix = originalMatrix; | ||
| Gizmos.color = originalGizmoColour; | ||
| } | ||
|
|
||
| [DrawGizmo(GizmoType.Active | GizmoType.InSelectionHierarchy | GizmoType.Pickable, typeof(CinemachineVirtualCameraBase))] | ||
| internal static void DrawVirtualCameraBaseGizmos(CinemachineVirtualCameraBase vcam, GizmoType selectionType) | ||
| { | ||
| // Don't draw gizmos on hidden stuff | ||
| if ((vcam.VirtualCameraGameObject.hideFlags & (HideFlags.HideInHierarchy | HideFlags.HideInInspector)) != 0) | ||
| return; | ||
|
|
||
| if (vcam.ParentCamera != null && (selectionType & GizmoType.Active) == 0) | ||
| return; | ||
|
|
||
| CameraState state = vcam.State; | ||
| Gizmos.DrawIcon(state.FinalPosition, kGizmoFileName, true); | ||
|
|
||
| DrawCameraFrustumGizmo( | ||
| CinemachineCore.Instance.FindPotentialTargetBrain(vcam), | ||
| state.Lens, | ||
| Matrix4x4.TRS( | ||
| state.FinalPosition, | ||
| UnityQuaternionExtensions.Normalized(state.FinalOrientation), Vector3.one), | ||
| CinemachineCore.Instance.IsLive(vcam) | ||
| ? CinemachineSettings.CinemachineCoreSettings.ActiveGizmoColour | ||
| : CinemachineSettings.CinemachineCoreSettings.InactiveGizmoColour); | ||
| } | ||
|
|
||
| static string kGizmoFileName = "Cinemachine/cm_logo_lg.png"; | ||
| [InitializeOnLoad] | ||
| static class InstallGizmos | ||
| { | ||
| static InstallGizmos() | ||
| { | ||
| string srcFile = ScriptableObjectUtility.CinemachineInstallPath + "/Gizmos/" + kGizmoFileName; | ||
| if (File.Exists(srcFile)) | ||
| { | ||
| string dstFile = Application.dataPath + "/Gizmos"; | ||
| if (!Directory.Exists(dstFile)) | ||
| Directory.CreateDirectory(dstFile); | ||
| dstFile += "/" + kGizmoFileName; | ||
| if (!File.Exists(dstFile) | ||
| || File.GetCreationTime(dstFile) < File.GetCreationTime(srcFile)) | ||
| { | ||
| if (!Directory.Exists(Path.GetDirectoryName(dstFile))) | ||
| Directory.CreateDirectory(Path.GetDirectoryName(dstFile)); | ||
| File.Copy(srcFile, dstFile, true); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,211 @@ | ||
| using UnityEditor; | ||
| using UnityEngine; | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Cinemachine.Editor | ||
| { | ||
| [CustomEditor(typeof(CinemachineClearShot))] | ||
| internal sealed class CinemachineClearShotEditor | ||
| : CinemachineVirtualCameraBaseEditor<CinemachineClearShot> | ||
| { | ||
| EmbeddeAssetEditor<CinemachineBlenderSettings> m_BlendsEditor; | ||
| ColliderState m_ColliderState; | ||
|
|
||
| private UnityEditorInternal.ReorderableList mChildList; | ||
|
|
||
| protected override void OnEnable() | ||
| { | ||
| base.OnEnable(); | ||
| m_BlendsEditor = new EmbeddeAssetEditor<CinemachineBlenderSettings>( | ||
| FieldPath(x => x.m_CustomBlends), this); | ||
| m_BlendsEditor.OnChanged = (CinemachineBlenderSettings b) => | ||
| { | ||
| UnityEditorInternal.InternalEditorUtility.RepaintAllViews(); | ||
| }; | ||
| m_BlendsEditor.OnCreateEditor = (UnityEditor.Editor ed) => | ||
| { | ||
| CinemachineBlenderSettingsEditor editor = ed as CinemachineBlenderSettingsEditor; | ||
| if (editor != null) | ||
| editor.GetAllVirtualCameras = () => { return Target.ChildCameras; }; | ||
| }; | ||
| mChildList = null; | ||
| } | ||
|
|
||
| protected override void OnDisable() | ||
| { | ||
| base.OnDisable(); | ||
| if (m_BlendsEditor != null) | ||
| m_BlendsEditor.OnDisable(); | ||
| } | ||
|
|
||
| public override void OnInspectorGUI() | ||
| { | ||
| BeginInspector(); | ||
| if (mChildList == null) | ||
| SetupChildList(); | ||
|
|
||
| m_ColliderState = GetColliderState(); | ||
| switch (m_ColliderState) | ||
| { | ||
| case ColliderState.ColliderOnParent: | ||
| case ColliderState.ColliderOnAllChildren: | ||
| break; | ||
| case ColliderState.NoCollider: | ||
| EditorGUILayout.HelpBox( | ||
| "ClearShot requires a Collider extension to rank the shots. Either add one to the ClearShot itself, or to each of the child cameras.", | ||
| MessageType.Warning); | ||
| break; | ||
| case ColliderState.ColliderOnSomeChildren: | ||
| EditorGUILayout.HelpBox( | ||
| "Some child cameras do not have a Collider extension. ClearShot requires a Collider on all the child cameras, or alternatively on the ClearShot iself.", | ||
| MessageType.Warning); | ||
| break; | ||
| case ColliderState.ColliderOnChildrenAndParent: | ||
| EditorGUILayout.HelpBox( | ||
| "There is a Collider extention on the ClearShot camera, and also on some of its child cameras. You can't have both.", | ||
| MessageType.Error); | ||
| break; | ||
| } | ||
|
|
||
| DrawHeaderInInspector(); | ||
| DrawPropertyInInspector(FindProperty(x => x.m_Priority)); | ||
| DrawTargetsInInspector(FindProperty(x => x.m_Follow), FindProperty(x => x.m_LookAt)); | ||
| DrawRemainingPropertiesInInspector(); | ||
|
|
||
| // Blends | ||
| m_BlendsEditor.DrawEditorCombo( | ||
| "Create New Blender Asset", | ||
| Target.gameObject.name + " Blends", "asset", string.Empty, | ||
| "Custom Blends", false); | ||
|
|
||
| // vcam children | ||
| EditorGUILayout.Separator(); | ||
| EditorGUI.BeginChangeCheck(); | ||
| mChildList.DoLayoutList(); | ||
| if (EditorGUI.EndChangeCheck()) | ||
| serializedObject.ApplyModifiedProperties(); | ||
|
|
||
| // Extensions | ||
| DrawExtensionsWidgetInInspector(); | ||
| } | ||
|
|
||
| enum ColliderState | ||
| { | ||
| NoCollider, | ||
| ColliderOnAllChildren, | ||
| ColliderOnSomeChildren, | ||
| ColliderOnParent, | ||
| ColliderOnChildrenAndParent | ||
| } | ||
|
|
||
| ColliderState GetColliderState() | ||
| { | ||
| int numChildren = 0; | ||
| int numColliderChildren = 0; | ||
| bool colliderOnParent = ObjectHasCollider(Target); | ||
|
|
||
| var children = Target.m_ChildCameras; | ||
| numChildren = children == null ? 0 : children.Length; | ||
| for (int i = 0; i < numChildren; ++i) | ||
| if (ObjectHasCollider(children[i])) | ||
| ++numColliderChildren; | ||
| if (colliderOnParent) | ||
| return (numColliderChildren > 0) | ||
| ? ColliderState.ColliderOnChildrenAndParent : ColliderState.ColliderOnParent; | ||
| if (numColliderChildren > 0) | ||
| return (numColliderChildren == numChildren) | ||
| ? ColliderState.ColliderOnAllChildren : ColliderState.ColliderOnSomeChildren; | ||
| return ColliderState.NoCollider; | ||
| } | ||
|
|
||
| bool ObjectHasCollider(object obj) | ||
| { | ||
| CinemachineVirtualCameraBase vcam = obj as CinemachineVirtualCameraBase; | ||
| var collider = (vcam == null) ? null : vcam.GetComponent<CinemachineCollider>(); | ||
| return (collider != null && collider.enabled); | ||
| } | ||
|
|
||
| void SetupChildList() | ||
| { | ||
| float vSpace = 2; | ||
| float hSpace = 3; | ||
| float floatFieldWidth = EditorGUIUtility.singleLineHeight * 2.5f; | ||
|
|
||
| mChildList = new UnityEditorInternal.ReorderableList( | ||
| serializedObject, FindProperty(x => x.m_ChildCameras), true, true, true, true); | ||
|
|
||
| mChildList.drawHeaderCallback = (Rect rect) => | ||
| { | ||
| EditorGUI.LabelField(rect, "Virtual Camera Children"); | ||
| GUIContent priorityText = new GUIContent("Priority"); | ||
| var textDimensions = GUI.skin.label.CalcSize(priorityText); | ||
| rect.x += rect.width - textDimensions.x; | ||
| rect.width = textDimensions.x; | ||
| EditorGUI.LabelField(rect, priorityText); | ||
| }; | ||
| mChildList.drawElementCallback | ||
| = (Rect rect, int index, bool isActive, bool isFocused) => | ||
| { | ||
| rect.y += vSpace; | ||
| rect.width -= floatFieldWidth + hSpace; | ||
| rect.height = EditorGUIUtility.singleLineHeight; | ||
| SerializedProperty element = mChildList.serializedProperty.GetArrayElementAtIndex(index); | ||
| if (m_ColliderState == ColliderState.ColliderOnSomeChildren | ||
| || m_ColliderState == ColliderState.ColliderOnChildrenAndParent) | ||
| { | ||
| bool hasCollider = ObjectHasCollider(element.objectReferenceValue); | ||
| if ((m_ColliderState == ColliderState.ColliderOnSomeChildren && !hasCollider) | ||
| || (m_ColliderState == ColliderState.ColliderOnChildrenAndParent && hasCollider)) | ||
| { | ||
| float width = rect.width; | ||
| rect.width = rect.height; | ||
| GUIContent label = new GUIContent(""); | ||
| label.image = EditorGUIUtility.IconContent("console.warnicon.sml").image; | ||
| EditorGUI.LabelField(rect, label); | ||
| width -= rect.width; rect.x += rect.width; rect.width = width; | ||
| } | ||
| } | ||
| EditorGUI.PropertyField(rect, element, GUIContent.none); | ||
|
|
||
| SerializedObject obj = new SerializedObject(element.objectReferenceValue); | ||
| rect.x += rect.width + hSpace; rect.width = floatFieldWidth; | ||
| SerializedProperty priorityProp = obj.FindProperty(() => Target.m_Priority); | ||
| float oldWidth = EditorGUIUtility.labelWidth; | ||
| EditorGUIUtility.labelWidth = hSpace * 2; | ||
| EditorGUI.PropertyField(rect, priorityProp, new GUIContent(" ")); | ||
| EditorGUIUtility.labelWidth = oldWidth; | ||
| obj.ApplyModifiedProperties(); | ||
| }; | ||
| mChildList.onChangedCallback = (UnityEditorInternal.ReorderableList l) => | ||
| { | ||
| if (l.index < 0 || l.index >= l.serializedProperty.arraySize) | ||
| return; | ||
| Object o = l.serializedProperty.GetArrayElementAtIndex( | ||
| l.index).objectReferenceValue; | ||
| CinemachineVirtualCameraBase vcam = (o != null) | ||
| ? (o as CinemachineVirtualCameraBase) : null; | ||
| if (vcam != null) | ||
| vcam.transform.SetSiblingIndex(l.index); | ||
| }; | ||
| mChildList.onAddCallback = (UnityEditorInternal.ReorderableList l) => | ||
| { | ||
| var index = l.serializedProperty.arraySize; | ||
| var vcam = CinemachineMenu.CreateDefaultVirtualCamera(); | ||
| Undo.SetTransformParent(vcam.transform, Target.transform, ""); | ||
| var collider = Undo.AddComponent<CinemachineCollider>(vcam.gameObject); | ||
| collider.m_AvoidObstacles = false; | ||
| Undo.RecordObject(collider, "create ClearShot child"); | ||
| vcam.transform.SetSiblingIndex(index); | ||
| }; | ||
| mChildList.onRemoveCallback = (UnityEditorInternal.ReorderableList l) => | ||
| { | ||
| Object o = l.serializedProperty.GetArrayElementAtIndex( | ||
| l.index).objectReferenceValue; | ||
| CinemachineVirtualCameraBase vcam = (o != null) | ||
| ? (o as CinemachineVirtualCameraBase) : null; | ||
| if (vcam != null) | ||
| Undo.DestroyObjectImmediate(vcam.gameObject); | ||
| }; | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,76 @@ | ||
| using UnityEngine; | ||
| using UnityEditor; | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Cinemachine.Editor | ||
| { | ||
| [CustomEditor(typeof(CinemachineCollider))] | ||
| public sealed class CinemachineColliderEditor : BaseEditor<CinemachineCollider> | ||
| { | ||
| protected override List<string> GetExcludedPropertiesInInspector() | ||
| { | ||
| List<string> excluded = base.GetExcludedPropertiesInInspector(); | ||
| if (!Target.m_AvoidObstacles) | ||
| { | ||
| excluded.Add(FieldPath(x => x.m_DistanceLimit)); | ||
| excluded.Add(FieldPath(x => x.m_CameraRadius)); | ||
| excluded.Add(FieldPath(x => x.m_Strategy)); | ||
| excluded.Add(FieldPath(x => x.m_MaximumEffort)); | ||
| excluded.Add(FieldPath(x => x.m_Damping)); | ||
| } | ||
| else if (Target.m_Strategy == CinemachineCollider.ResolutionStrategy.PullCameraForward) | ||
| { | ||
| excluded.Add(FieldPath(x => x.m_MaximumEffort)); | ||
| } | ||
| return excluded; | ||
| } | ||
|
|
||
| public override void OnInspectorGUI() | ||
| { | ||
| BeginInspector(); | ||
|
|
||
| if (Target.m_AvoidObstacles && !Target.VirtualCamera.State.HasLookAt) | ||
| EditorGUILayout.HelpBox( | ||
| "Preserve Line Of Sight requires a LookAt target.", | ||
| MessageType.Warning); | ||
|
|
||
| DrawRemainingPropertiesInInspector(); | ||
| } | ||
|
|
||
| [DrawGizmo(GizmoType.Active | GizmoType.Selected, typeof(CinemachineCollider))] | ||
| private static void DrawColliderGizmos(CinemachineCollider collider, GizmoType type) | ||
| { | ||
| CinemachineVirtualCameraBase vcam = (collider != null) ? collider.VirtualCamera : null; | ||
| if (vcam != null && collider.enabled) | ||
| { | ||
| Color oldColor = Gizmos.color; | ||
| Vector3 pos = vcam.State.FinalPosition; | ||
| if (collider.m_AvoidObstacles && vcam.State.HasLookAt) | ||
| { | ||
| Gizmos.color = CinemachineColliderPrefs.FeelerColor; | ||
| if (collider.m_CameraRadius > 0) | ||
| Gizmos.DrawWireSphere(pos, collider.m_CameraRadius); | ||
|
|
||
| Vector3 forwardFeelerVector = (vcam.State.ReferenceLookAt - pos).normalized; | ||
| float distance = collider.m_DistanceLimit; | ||
| Gizmos.DrawLine(pos, pos + forwardFeelerVector * distance); | ||
|
|
||
| // Show the avoidance path, for debugging | ||
| List<List<Vector3>> debugPaths = collider.DebugPaths; | ||
| foreach (var path in debugPaths) | ||
| { | ||
| Gizmos.color = CinemachineColliderPrefs.FeelerHitColor; | ||
| Vector3 p0 = vcam.State.ReferenceLookAt; | ||
| foreach (var p in path) | ||
| { | ||
| Gizmos.DrawLine(p0, p); | ||
| p0 = p; | ||
| } | ||
| Gizmos.DrawLine(p0, pos); | ||
| } | ||
| } | ||
| Gizmos.color = oldColor; | ||
| } | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,89 @@ | ||
| using UnityEngine; | ||
| using UnityEditor; | ||
| using Cinemachine.Utility; | ||
|
|
||
| namespace Cinemachine.Editor | ||
| { | ||
| [CustomEditor(typeof(CinemachineComposer))] | ||
| internal class CinemachineComposerEditor : BaseEditor<CinemachineComposer> | ||
| { | ||
| CinemachineScreenComposerGuides mScreenGuideEditor; | ||
|
|
||
| protected virtual void OnEnable() | ||
| { | ||
| mScreenGuideEditor = new CinemachineScreenComposerGuides(); | ||
| mScreenGuideEditor.GetHardGuide = () => { return Target.HardGuideRect; }; | ||
| mScreenGuideEditor.GetSoftGuide = () => { return Target.SoftGuideRect; }; | ||
| mScreenGuideEditor.SetHardGuide = (Rect r) => { Target.HardGuideRect = r; }; | ||
| mScreenGuideEditor.SetSoftGuide = (Rect r) => { Target.SoftGuideRect = r; }; | ||
| mScreenGuideEditor.Target = () => { return serializedObject; }; | ||
|
|
||
| Target.OnGUICallback += OnGUI; | ||
| UnityEditorInternal.InternalEditorUtility.RepaintAllViews(); | ||
| } | ||
|
|
||
| protected virtual void OnDisable() | ||
| { | ||
| if (Target != null) | ||
| Target.OnGUICallback -= OnGUI; | ||
| UnityEditorInternal.InternalEditorUtility.RepaintAllViews(); | ||
| } | ||
|
|
||
| public override void OnInspectorGUI() | ||
| { | ||
| BeginInspector(); | ||
| if (Target.LookAtTarget == null) | ||
| EditorGUILayout.HelpBox( | ||
| "A LookAt target is required. Change Aim to Do Nothing if you don't want a LookAt target.", | ||
| MessageType.Warning); | ||
|
|
||
| // First snapshot some settings | ||
| Rect oldHard = Target.HardGuideRect; | ||
| Rect oldSoft = Target.SoftGuideRect; | ||
|
|
||
| // Draw the properties | ||
| DrawRemainingPropertiesInInspector(); | ||
| mScreenGuideEditor.SetNewBounds(oldHard, oldSoft, Target.HardGuideRect, Target.SoftGuideRect); | ||
| } | ||
|
|
||
| protected virtual void OnGUI() | ||
| { | ||
| // Draw the camera guides | ||
| if (!Target.IsValid || !CinemachineSettings.CinemachineCoreSettings.ShowInGameGuides) | ||
| return; | ||
|
|
||
| CinemachineBrain brain = CinemachineCore.Instance.FindPotentialTargetBrain(Target.VirtualCamera); | ||
| if (brain == null || brain.OutputCamera.activeTexture != null) | ||
| return; | ||
|
|
||
| bool isLive = CinemachineCore.Instance.IsLive(Target.VirtualCamera); | ||
|
|
||
| // Screen guides | ||
| mScreenGuideEditor.OnGUI_DrawGuides(isLive, brain.OutputCamera, Target.VcamState.Lens, true); | ||
|
|
||
| // Draw an on-screen gizmo for the target | ||
| if (Target.LookAtTarget != null && isLive) | ||
| { | ||
| Vector3 targetScreenPosition = brain.OutputCamera.WorldToScreenPoint(Target.TrackedPoint); | ||
| if (targetScreenPosition.z > 0) | ||
| { | ||
| targetScreenPosition.y = Screen.height - targetScreenPosition.y; | ||
|
|
||
| GUI.color = CinemachineSettings.ComposerSettings.TargetColour; | ||
| Rect r = new Rect(targetScreenPosition, Vector2.zero); | ||
| float size = (CinemachineSettings.ComposerSettings.TargetSize | ||
| + CinemachineScreenComposerGuides.kGuideBarWidthPx) / 2; | ||
| GUI.DrawTexture(r.Inflated(new Vector2(size, size)), Texture2D.whiteTexture); | ||
| size -= CinemachineScreenComposerGuides.kGuideBarWidthPx; | ||
| if (size > 0) | ||
| { | ||
| Vector4 overlayOpacityScalar | ||
| = new Vector4(1f, 1f, 1f, CinemachineSettings.ComposerSettings.OverlayOpacity); | ||
| GUI.color = Color.black * overlayOpacityScalar; | ||
| GUI.DrawTexture(r.Inflated(new Vector2(size, size)), Texture2D.whiteTexture); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,161 @@ | ||
| using UnityEngine; | ||
| using UnityEditor; | ||
| using System; | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Cinemachine.Editor | ||
| { | ||
| [CustomEditor(typeof(CinemachineConfiner))] | ||
| public sealed class CinemachineConfinerEditor : BaseEditor<CinemachineConfiner> | ||
| { | ||
| protected override List<string> GetExcludedPropertiesInInspector() | ||
| { | ||
| List<string> excluded = base.GetExcludedPropertiesInInspector(); | ||
| CinemachineBrain brain = CinemachineCore.Instance.FindPotentialTargetBrain(Target.VirtualCamera); | ||
| bool ortho = brain != null ? brain.OutputCamera.orthographic : false; | ||
| if (!ortho) | ||
| excluded.Add(FieldPath(x => x.m_ConfineScreenEdges)); | ||
| if (Target.m_ConfineMode == CinemachineConfiner.Mode.Confine2D) | ||
| excluded.Add(FieldPath(x => x.m_BoundingVolume)); | ||
| else | ||
| excluded.Add(FieldPath(x => x.m_BoundingShape2D)); | ||
| return excluded; | ||
| } | ||
|
|
||
| public override void OnInspectorGUI() | ||
| { | ||
| BeginInspector(); | ||
| if (Target.m_ConfineMode == CinemachineConfiner.Mode.Confine2D) | ||
| { | ||
| if (Target.m_BoundingShape2D == null) | ||
| EditorGUILayout.HelpBox("A Bounding Shape is required.", MessageType.Warning); | ||
| else if (Target.m_BoundingShape2D.GetType() != typeof(PolygonCollider2D) | ||
| && Target.m_BoundingShape2D.GetType() != typeof(CompositeCollider2D)) | ||
| { | ||
| EditorGUILayout.HelpBox( | ||
| "Must be a PolygonCollider2D or CompositeCollider2D.", | ||
| MessageType.Warning); | ||
| } | ||
| else if (Target.m_BoundingShape2D.GetType() == typeof(CompositeCollider2D)) | ||
| { | ||
| CompositeCollider2D poly = Target.m_BoundingShape2D as CompositeCollider2D; | ||
| if (poly.geometryType != CompositeCollider2D.GeometryType.Polygons) | ||
| { | ||
| EditorGUILayout.HelpBox( | ||
| "CompositeCollider2D geometry type must be Polygons", | ||
| MessageType.Warning); | ||
| } | ||
| } | ||
| } | ||
| else | ||
| { | ||
| if (Target.m_BoundingVolume == null) | ||
| EditorGUILayout.HelpBox("A Bounding Volume is required.", MessageType.Warning); | ||
| else if (Target.m_BoundingVolume.GetType() != typeof(BoxCollider) | ||
| && Target.m_BoundingVolume.GetType() != typeof(SphereCollider) | ||
| && Target.m_BoundingVolume.GetType() != typeof(CapsuleCollider)) | ||
| { | ||
| EditorGUILayout.HelpBox( | ||
| "Must be a BoxCollider, SphereCollider, or CapsuleCollider.", | ||
| MessageType.Warning); | ||
| } | ||
| } | ||
| DrawRemainingPropertiesInInspector(); | ||
| } | ||
|
|
||
| [DrawGizmo(GizmoType.Active | GizmoType.Selected, typeof(CinemachineConfiner))] | ||
| private static void DrawColliderGizmos(CinemachineConfiner confiner, GizmoType type) | ||
| { | ||
| CinemachineVirtualCameraBase vcam = (confiner != null) ? confiner.VirtualCamera : null; | ||
| if (vcam != null && confiner.IsValid) | ||
| { | ||
| Matrix4x4 oldMatrix = Gizmos.matrix; | ||
| Color oldColor = Gizmos.color; | ||
| Gizmos.color = Color.yellow; | ||
|
|
||
| if (confiner.m_ConfineMode == CinemachineConfiner.Mode.Confine3D) | ||
| { | ||
| Transform t = confiner.m_BoundingVolume.transform; | ||
| Gizmos.matrix = Matrix4x4.TRS(t.position, t.rotation, t.lossyScale); | ||
|
|
||
| Type colliderType = confiner.m_BoundingVolume.GetType(); | ||
| if (colliderType == typeof(BoxCollider)) | ||
| { | ||
| BoxCollider c = confiner.m_BoundingVolume as BoxCollider; | ||
| Gizmos.DrawWireCube(c.center, c.size); | ||
| } | ||
| else if (colliderType == typeof(SphereCollider)) | ||
| { | ||
| SphereCollider c = confiner.m_BoundingVolume as SphereCollider; | ||
| Gizmos.DrawWireSphere(c.center, c.radius); | ||
| } | ||
| else if (colliderType == typeof(CapsuleCollider)) | ||
| { | ||
| CapsuleCollider c = confiner.m_BoundingVolume as CapsuleCollider; | ||
| Vector3 size = Vector3.one * c.radius * 2; | ||
| switch (c.direction) | ||
| { | ||
| case 0: size.x = c.height; break; | ||
| case 1: size.y = c.height; break; | ||
| case 2: size.z = c.height; break; | ||
| } | ||
| Gizmos.DrawWireCube(c.center, size); | ||
| } | ||
| else if (colliderType == typeof(MeshCollider)) | ||
| { | ||
| MeshCollider c = confiner.m_BoundingVolume as MeshCollider; | ||
| Gizmos.DrawWireMesh(c.sharedMesh); | ||
| } | ||
| else | ||
| { | ||
| // Just draw an AABB - not very nice! | ||
| Gizmos.matrix = oldMatrix; | ||
| Bounds bounds = confiner.m_BoundingVolume.bounds; | ||
| Gizmos.DrawWireCube(t.position, bounds.extents * 2); | ||
| } | ||
| } | ||
| else | ||
| { | ||
| Transform t = confiner.m_BoundingShape2D.transform; | ||
| Gizmos.matrix = Matrix4x4.TRS(t.position, t.rotation, t.lossyScale); | ||
|
|
||
| Type colliderType = confiner.m_BoundingShape2D.GetType(); | ||
| if (colliderType == typeof(PolygonCollider2D)) | ||
| { | ||
| PolygonCollider2D poly = confiner.m_BoundingShape2D as PolygonCollider2D; | ||
| for (int i = 0; i < poly.pathCount; ++i) | ||
| DrawPath(poly.GetPath(i), -1); | ||
| } | ||
| else if (colliderType == typeof(CompositeCollider2D)) | ||
| { | ||
| CompositeCollider2D poly = confiner.m_BoundingShape2D as CompositeCollider2D; | ||
| Vector2[] path = new Vector2[poly.pointCount]; | ||
| for (int i = 0; i < poly.pathCount; ++i) | ||
| { | ||
| int numPoints = poly.GetPath(i, path); | ||
| DrawPath(path, numPoints); | ||
| } | ||
| } | ||
| } | ||
| Gizmos.color = oldColor; | ||
| Gizmos.matrix = oldMatrix; | ||
| } | ||
| } | ||
|
|
||
| static void DrawPath(Vector2[] path, int numPoints) | ||
| { | ||
| if (numPoints < 0) | ||
| numPoints = path.Length; | ||
| if (numPoints > 0) | ||
| { | ||
| Vector2 v0 = path[numPoints-1]; | ||
| for (int j = 0; j < numPoints; ++j) | ||
| { | ||
| Vector2 v = path[j]; | ||
| Gizmos.DrawLine(v0, v); | ||
| v0 = v; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,17 @@ | ||
| using System.Collections.Generic; | ||
| using UnityEditor; | ||
|
|
||
| namespace Cinemachine.Editor | ||
| { | ||
| [CustomEditor(typeof(CinemachineExternalCamera))] | ||
| internal class CinemachineExternalCameraEditor | ||
| : CinemachineVirtualCameraBaseEditor<CinemachineExternalCamera> | ||
| { | ||
| protected override List<string> GetExcludedPropertiesInInspector() | ||
| { | ||
| List<string> excluded = base.GetExcludedPropertiesInInspector(); | ||
| excluded.Add("Extensions"); | ||
| return excluded; | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,174 @@ | ||
| using UnityEngine; | ||
| using UnityEditor; | ||
| using Cinemachine.Utility; | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Cinemachine.Editor | ||
| { | ||
| [CustomEditor(typeof(CinemachineFramingTransposer))] | ||
| internal class CinemachineFramingTransposerEditor : BaseEditor<CinemachineFramingTransposer> | ||
| { | ||
| CinemachineScreenComposerGuides mScreenGuideEditor; | ||
|
|
||
| protected override List<string> GetExcludedPropertiesInInspector() | ||
| { | ||
| List<string> excluded = base.GetExcludedPropertiesInInspector(); | ||
| if (Target.m_UnlimitedSoftZone) | ||
| { | ||
| excluded.Add(FieldPath(x => x.m_SoftZoneWidth)); | ||
| excluded.Add(FieldPath(x => x.m_SoftZoneHeight)); | ||
| excluded.Add(FieldPath(x => x.m_BiasX)); | ||
| excluded.Add(FieldPath(x => x.m_BiasY)); | ||
| } | ||
| CinemachineTargetGroup group = Target.TargetGroup; | ||
| if (group == null || Target.m_GroupFramingMode == CinemachineFramingTransposer.FramingMode.None) | ||
| { | ||
| excluded.Add(FieldPath(x => x.m_GroupFramingSize)); | ||
| excluded.Add(FieldPath(x => x.m_AdjustmentMode)); | ||
| excluded.Add(FieldPath(x => x.m_MaxDollyIn)); | ||
| excluded.Add(FieldPath(x => x.m_MaxDollyOut)); | ||
| excluded.Add(FieldPath(x => x.m_MinimumDistance)); | ||
| excluded.Add(FieldPath(x => x.m_MaximumDistance)); | ||
| excluded.Add(FieldPath(x => x.m_MinimumFOV)); | ||
| excluded.Add(FieldPath(x => x.m_MaximumFOV)); | ||
| excluded.Add(FieldPath(x => x.m_MinimumOrthoSize)); | ||
| excluded.Add(FieldPath(x => x.m_MaximumOrthoSize)); | ||
| if (group == null) | ||
| excluded.Add(FieldPath(x => x.m_GroupFramingMode)); | ||
| } | ||
| else | ||
| { | ||
| CinemachineBrain brain = CinemachineCore.Instance.FindPotentialTargetBrain(Target.VirtualCamera); | ||
| bool ortho = brain != null ? brain.OutputCamera.orthographic : false; | ||
| if (ortho) | ||
| { | ||
| excluded.Add(FieldPath(x => x.m_AdjustmentMode)); | ||
| excluded.Add(FieldPath(x => x.m_MaxDollyIn)); | ||
| excluded.Add(FieldPath(x => x.m_MaxDollyOut)); | ||
| excluded.Add(FieldPath(x => x.m_MinimumDistance)); | ||
| excluded.Add(FieldPath(x => x.m_MaximumDistance)); | ||
| excluded.Add(FieldPath(x => x.m_MinimumFOV)); | ||
| excluded.Add(FieldPath(x => x.m_MaximumFOV)); | ||
| } | ||
| else | ||
| { | ||
| excluded.Add(FieldPath(x => x.m_MinimumOrthoSize)); | ||
| excluded.Add(FieldPath(x => x.m_MaximumOrthoSize)); | ||
| switch (Target.m_AdjustmentMode) | ||
| { | ||
| case CinemachineFramingTransposer.AdjustmentMode.DollyOnly: | ||
| excluded.Add(FieldPath(x => x.m_MinimumFOV)); | ||
| excluded.Add(FieldPath(x => x.m_MaximumFOV)); | ||
| break; | ||
| case CinemachineFramingTransposer.AdjustmentMode.ZoomOnly: | ||
| excluded.Add(FieldPath(x => x.m_MaxDollyIn)); | ||
| excluded.Add(FieldPath(x => x.m_MaxDollyOut)); | ||
| excluded.Add(FieldPath(x => x.m_MinimumDistance)); | ||
| excluded.Add(FieldPath(x => x.m_MaximumDistance)); | ||
| break; | ||
| default: | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| return excluded; | ||
| } | ||
|
|
||
| protected virtual void OnEnable() | ||
| { | ||
| mScreenGuideEditor = new CinemachineScreenComposerGuides(); | ||
| mScreenGuideEditor.GetHardGuide = () => { return Target.HardGuideRect; }; | ||
| mScreenGuideEditor.GetSoftGuide = () => { return Target.SoftGuideRect; }; | ||
| mScreenGuideEditor.SetHardGuide = (Rect r) => { Target.HardGuideRect = r; }; | ||
| mScreenGuideEditor.SetSoftGuide = (Rect r) => { Target.SoftGuideRect = r; }; | ||
| mScreenGuideEditor.Target = () => { return serializedObject; }; | ||
|
|
||
| Target.OnGUICallback += OnGUI; | ||
| UnityEditorInternal.InternalEditorUtility.RepaintAllViews(); | ||
| } | ||
|
|
||
| protected virtual void OnDisable() | ||
| { | ||
| if (Target != null) | ||
| Target.OnGUICallback -= OnGUI; | ||
| UnityEditorInternal.InternalEditorUtility.RepaintAllViews(); | ||
| } | ||
|
|
||
| public override void OnInspectorGUI() | ||
| { | ||
| BeginInspector(); | ||
| if (Target.FollowTarget == null) | ||
| EditorGUILayout.HelpBox( | ||
| "Framing Transposer requires a Follow target. Change Body to Do Nothing if you don't want a Follow target.", | ||
| MessageType.Warning); | ||
| if (Target.LookAtTarget != null) | ||
| EditorGUILayout.HelpBox( | ||
| "The LookAt target must be null. The Follow target will be used in place of the LookAt target.", | ||
| MessageType.Warning); | ||
|
|
||
| // First snapshot some settings | ||
| Rect oldHard = Target.HardGuideRect; | ||
| Rect oldSoft = Target.SoftGuideRect; | ||
|
|
||
| // Draw the properties | ||
| DrawRemainingPropertiesInInspector(); | ||
| mScreenGuideEditor.SetNewBounds(oldHard, oldSoft, Target.HardGuideRect, Target.SoftGuideRect); | ||
| } | ||
|
|
||
| protected virtual void OnGUI() | ||
| { | ||
| // Draw the camera guides | ||
| if (!Target.IsValid || !CinemachineSettings.CinemachineCoreSettings.ShowInGameGuides) | ||
| return; | ||
|
|
||
| CinemachineBrain brain = CinemachineCore.Instance.FindPotentialTargetBrain(Target.VirtualCamera); | ||
| if (brain == null || brain.OutputCamera.activeTexture != null) | ||
| return; | ||
|
|
||
| bool isLive = CinemachineCore.Instance.IsLive(Target.VirtualCamera); | ||
|
|
||
| // Screen guides | ||
| mScreenGuideEditor.OnGUI_DrawGuides(isLive, brain.OutputCamera, Target.VcamState.Lens, !Target.m_UnlimitedSoftZone); | ||
|
|
||
| // Draw an on-screen gizmo for the target | ||
| if (Target.FollowTarget != null && isLive) | ||
| { | ||
| Vector3 targetScreenPosition = brain.OutputCamera.WorldToScreenPoint(Target.TrackedPoint); | ||
| if (targetScreenPosition.z > 0) | ||
| { | ||
| targetScreenPosition.y = Screen.height - targetScreenPosition.y; | ||
|
|
||
| GUI.color = CinemachineSettings.ComposerSettings.TargetColour; | ||
| Rect r = new Rect(targetScreenPosition, Vector2.zero); | ||
| float size = (CinemachineSettings.ComposerSettings.TargetSize | ||
| + CinemachineScreenComposerGuides.kGuideBarWidthPx) / 2; | ||
| GUI.DrawTexture(r.Inflated(new Vector2(size, size)), Texture2D.whiteTexture); | ||
| size -= CinemachineScreenComposerGuides.kGuideBarWidthPx; | ||
| if (size > 0) | ||
| { | ||
| Vector4 overlayOpacityScalar | ||
| = new Vector4(1f, 1f, 1f, CinemachineSettings.ComposerSettings.OverlayOpacity); | ||
| GUI.color = Color.black * overlayOpacityScalar; | ||
| GUI.DrawTexture(r.Inflated(new Vector2(size, size)), Texture2D.whiteTexture); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| [DrawGizmo(GizmoType.Active | GizmoType.InSelectionHierarchy, typeof(CinemachineFramingTransposer))] | ||
| private static void DrawGroupComposerGizmos(CinemachineFramingTransposer target, GizmoType selectionType) | ||
| { | ||
| // Show the group bounding box, as viewed from the camera position | ||
| CinemachineTargetGroup group = target.TargetGroup; | ||
| if (group != null) | ||
| { | ||
| Matrix4x4 m = Gizmos.matrix; | ||
| Bounds b = target.m_LastBounds; | ||
| Gizmos.matrix = target.m_lastBoundsMatrix; | ||
| Gizmos.color = Color.yellow; | ||
| Gizmos.DrawWireCube(b.center, b.size); | ||
| Gizmos.matrix = m; | ||
| } | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,206 @@ | ||
| using UnityEngine; | ||
| using UnityEditor; | ||
| using Cinemachine.Editor; | ||
| using System.Collections.Generic; | ||
| using Cinemachine.Utility; | ||
|
|
||
| namespace Cinemachine | ||
| { | ||
| [CustomEditor(typeof(CinemachineFreeLook))] | ||
| internal sealed class CinemachineFreeLookEditor | ||
| : CinemachineVirtualCameraBaseEditor<CinemachineFreeLook> | ||
| { | ||
| protected override List<string> GetExcludedPropertiesInInspector() | ||
| { | ||
| List<string> excluded = base.GetExcludedPropertiesInInspector(); | ||
| excluded.Add(FieldPath(x => x.m_Orbits)); | ||
| if (!Target.m_CommonLens) | ||
| excluded.Add(FieldPath(x => x.m_Lens)); | ||
| if (Target.m_BindingMode == CinemachineTransposer.BindingMode.SimpleFollowWithWorldUp) | ||
| { | ||
| excluded.Add(FieldPath(x => x.m_Heading)); | ||
| excluded.Add(FieldPath(x => x.m_RecenterToTargetHeading)); | ||
| } | ||
| return excluded; | ||
| } | ||
|
|
||
| protected override void OnDisable() | ||
| { | ||
| base.OnDisable(); | ||
|
|
||
| // Must destroy child editors or we get exceptions | ||
| if (m_editors != null) | ||
| foreach (UnityEditor.Editor e in m_editors) | ||
| if (e != null) | ||
| UnityEngine.Object.DestroyImmediate(e); | ||
| } | ||
|
|
||
| public override void OnInspectorGUI() | ||
| { | ||
| // Ordinary properties | ||
| BeginInspector(); | ||
| DrawHeaderInInspector(); | ||
| DrawPropertyInInspector(FindProperty(x => x.m_Priority)); | ||
| DrawTargetsInInspector(FindProperty(x => x.m_Follow), FindProperty(x => x.m_LookAt)); | ||
| DrawRemainingPropertiesInInspector(); | ||
|
|
||
| // Orbits | ||
| EditorGUI.BeginChangeCheck(); | ||
| SerializedProperty orbits = FindProperty(x => x.m_Orbits); | ||
| for (int i = 0; i < CinemachineFreeLook.RigNames.Length; ++i) | ||
| { | ||
| float hSpace = 3; | ||
| SerializedProperty orbit = orbits.GetArrayElementAtIndex(i); | ||
| Rect rect = EditorGUILayout.GetControlRect(true); | ||
| rect = EditorGUI.PrefixLabel(rect, new GUIContent(CinemachineFreeLook.RigNames[i])); | ||
| rect.height = EditorGUIUtility.singleLineHeight; | ||
| rect.width = rect.width / 2 - hSpace; | ||
|
|
||
| float oldWidth = EditorGUIUtility.labelWidth; | ||
| EditorGUIUtility.labelWidth = rect.width / 2; | ||
| SerializedProperty heightProp = orbit.FindPropertyRelative(() => Target.m_Orbits[i].m_Height); | ||
| EditorGUI.PropertyField(rect, heightProp, new GUIContent("Height")); | ||
| rect.x += rect.width + hSpace; | ||
| SerializedProperty radiusProp = orbit.FindPropertyRelative(() => Target.m_Orbits[i].m_Radius); | ||
| EditorGUI.PropertyField(rect, radiusProp, new GUIContent("Radius")); | ||
| EditorGUIUtility.labelWidth = oldWidth; | ||
| } | ||
| if (EditorGUI.EndChangeCheck()) | ||
| serializedObject.ApplyModifiedProperties(); | ||
|
|
||
| // Rigs | ||
| UpdateRigEditors(); | ||
| for (int i = 0; i < m_editors.Length; ++i) | ||
| { | ||
| if (m_editors[i] == null) | ||
| continue; | ||
| EditorGUILayout.Separator(); | ||
| EditorGUILayout.BeginVertical(GUI.skin.box); | ||
| EditorGUILayout.LabelField(RigNames[i], EditorStyles.boldLabel); | ||
| ++EditorGUI.indentLevel; | ||
| m_editors[i].OnInspectorGUI(); | ||
| --EditorGUI.indentLevel; | ||
| EditorGUILayout.EndVertical(); | ||
| } | ||
|
|
||
| // Extensions | ||
| DrawExtensionsWidgetInInspector(); | ||
| } | ||
|
|
||
| string[] RigNames; | ||
| CinemachineVirtualCameraBase[] m_rigs; | ||
| UnityEditor.Editor[] m_editors; | ||
| void UpdateRigEditors() | ||
| { | ||
| RigNames = CinemachineFreeLook.RigNames; | ||
| if (m_rigs == null) | ||
| m_rigs = new CinemachineVirtualCameraBase[RigNames.Length]; | ||
| if (m_editors == null) | ||
| m_editors = new UnityEditor.Editor[RigNames.Length]; | ||
| for (int i = 0; i < RigNames.Length; ++i) | ||
| { | ||
| CinemachineVirtualCamera rig = Target.GetRig(i); | ||
| if (rig == null || rig != m_rigs[i]) | ||
| { | ||
| m_rigs[i] = rig; | ||
| if (m_editors[i] != null) | ||
| UnityEngine.Object.DestroyImmediate(m_editors[i]); | ||
| m_editors[i] = null; | ||
| if (rig != null) | ||
| CreateCachedEditor(rig, null, ref m_editors[i]); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Register with CinemachineFreeLook to create the pipeline in an undo-friendly manner | ||
| /// </summary> | ||
| [InitializeOnLoad] | ||
| class CreateRigWithUndo | ||
| { | ||
| static CreateRigWithUndo() | ||
| { | ||
| CinemachineFreeLook.CreateRigOverride | ||
| = (CinemachineFreeLook vcam, string name, CinemachineVirtualCamera copyFrom) => | ||
| { | ||
| // Create a new rig with default components | ||
| GameObject go = new GameObject(name); | ||
| Undo.RegisterCreatedObjectUndo(go, "created rig"); | ||
| Undo.SetTransformParent(go.transform, vcam.transform, "parenting rig"); | ||
| CinemachineVirtualCamera rig = Undo.AddComponent<CinemachineVirtualCamera>(go); | ||
| Undo.RecordObject(rig, "creating rig"); | ||
| if (copyFrom != null) | ||
| ReflectionHelpers.CopyFields(copyFrom, rig); | ||
| else | ||
| { | ||
| go = rig.GetComponentOwner().gameObject; | ||
| Undo.RecordObject(Undo.AddComponent<CinemachineOrbitalTransposer>(go), "creating rig"); | ||
| Undo.RecordObject(Undo.AddComponent<CinemachineComposer>(go), "creating rig"); | ||
| } | ||
| return rig; | ||
| }; | ||
| CinemachineFreeLook.DestroyRigOverride = (GameObject rig) => | ||
| { | ||
| Undo.DestroyObjectImmediate(rig); | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| [DrawGizmo(GizmoType.Active | GizmoType.Selected, typeof(CinemachineFreeLook))] | ||
| private static void DrawFreeLookGizmos(CinemachineFreeLook vcam, GizmoType selectionType) | ||
| { | ||
| // Standard frustum and logo | ||
| CinemachineBrainEditor.DrawVirtualCameraBaseGizmos(vcam, selectionType); | ||
|
|
||
| Color originalGizmoColour = Gizmos.color; | ||
| bool isActiveVirtualCam = CinemachineCore.Instance.IsLive(vcam); | ||
| Gizmos.color = isActiveVirtualCam | ||
| ? CinemachineSettings.CinemachineCoreSettings.ActiveGizmoColour | ||
| : CinemachineSettings.CinemachineCoreSettings.InactiveGizmoColour; | ||
|
|
||
| if (vcam.Follow != null) | ||
| { | ||
| Vector3 pos = vcam.Follow.position; | ||
| Vector3 up = Vector3.up; | ||
| CinemachineBrain brain = CinemachineCore.Instance.FindPotentialTargetBrain(vcam); | ||
| if (brain != null) | ||
| up = brain.DefaultWorldUp; | ||
|
|
||
| var MiddleRig = vcam.GetRig(1).GetCinemachineComponent<CinemachineOrbitalTransposer>(); | ||
| Quaternion orient = MiddleRig.GetReferenceOrientation(up); | ||
| up = orient * Vector3.up; | ||
| float rotation = vcam.m_XAxis.Value + vcam.m_Heading.m_HeadingBias; | ||
| orient = Quaternion.AngleAxis(rotation, up) * orient; | ||
|
|
||
| CinemachineOrbitalTransposerEditor.DrawCircleAtPointWithRadius( | ||
| pos + up * vcam.m_Orbits[0].m_Height, orient, vcam.m_Orbits[0].m_Radius); | ||
| CinemachineOrbitalTransposerEditor.DrawCircleAtPointWithRadius( | ||
| pos + up * vcam.m_Orbits[1].m_Height, orient, vcam.m_Orbits[1].m_Radius); | ||
| CinemachineOrbitalTransposerEditor.DrawCircleAtPointWithRadius( | ||
| pos + up * vcam.m_Orbits[2].m_Height, orient, vcam.m_Orbits[2].m_Radius); | ||
|
|
||
| DrawCameraPath(pos, orient, vcam); | ||
| } | ||
|
|
||
| Gizmos.color = originalGizmoColour; | ||
| } | ||
|
|
||
| private static void DrawCameraPath(Vector3 atPos, Quaternion orient, CinemachineFreeLook vcam) | ||
| { | ||
| Matrix4x4 prevMatrix = Gizmos.matrix; | ||
| Gizmos.matrix = Matrix4x4.TRS(atPos, orient, Vector3.one); | ||
|
|
||
| const int kNumStepsPerPair = 30; | ||
| Vector3 currPos = vcam.GetLocalPositionForCameraFromInput(0f); | ||
| for (int i = 1; i < kNumStepsPerPair + 1; ++i) | ||
| { | ||
| float t = (float)i / (float)kNumStepsPerPair; | ||
| Vector3 nextPos = vcam.GetLocalPositionForCameraFromInput(t); | ||
| Gizmos.DrawLine(currPos, nextPos); | ||
| Gizmos.DrawWireSphere(nextPos, 0.02f); | ||
| currPos = nextPos; | ||
| } | ||
| Gizmos.matrix = prevMatrix; | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,83 @@ | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Linq.Expressions; | ||
| using UnityEditor; | ||
| using UnityEngine; | ||
| using Cinemachine.Utility; | ||
|
|
||
| namespace Cinemachine.Editor | ||
| { | ||
| [CustomEditor(typeof(CinemachineGroupComposer))] | ||
| internal class CinemachineGroupComposerEditor : CinemachineComposerEditor | ||
| { | ||
| // Specialization | ||
| private CinemachineGroupComposer MyTarget { get { return target as CinemachineGroupComposer; } } | ||
| protected string FieldPath<TValue>(Expression<Func<CinemachineGroupComposer, TValue>> expr) | ||
| { | ||
| return ReflectionHelpers.GetFieldPath(expr); | ||
| } | ||
|
|
||
| protected override List<string> GetExcludedPropertiesInInspector() | ||
| { | ||
| List<string> excluded = base.GetExcludedPropertiesInInspector(); | ||
| CinemachineBrain brain = CinemachineCore.Instance.FindPotentialTargetBrain(MyTarget.VirtualCamera); | ||
| bool ortho = brain != null ? brain.OutputCamera.orthographic : false; | ||
| if (ortho) | ||
| { | ||
| excluded.Add(FieldPath(x => x.m_AdjustmentMode)); | ||
| excluded.Add(FieldPath(x => x.m_MinimumFOV)); | ||
| excluded.Add(FieldPath(x => x.m_MaximumFOV)); | ||
| excluded.Add(FieldPath(x => x.m_MaxDollyIn)); | ||
| excluded.Add(FieldPath(x => x.m_MaxDollyOut)); | ||
| excluded.Add(FieldPath(x => x.m_MinimumDistance)); | ||
| excluded.Add(FieldPath(x => x.m_MaximumDistance)); | ||
| } | ||
| else | ||
| { | ||
| excluded.Add(FieldPath(x => x.m_MinimumOrthoSize)); | ||
| excluded.Add(FieldPath(x => x.m_MaximumOrthoSize)); | ||
| switch (MyTarget.m_AdjustmentMode) | ||
| { | ||
| case CinemachineGroupComposer.AdjustmentMode.DollyOnly: | ||
| excluded.Add(FieldPath(x => x.m_MinimumFOV)); | ||
| excluded.Add(FieldPath(x => x.m_MaximumFOV)); | ||
| break; | ||
| case CinemachineGroupComposer.AdjustmentMode.ZoomOnly: | ||
| excluded.Add(FieldPath(x => x.m_MaxDollyIn)); | ||
| excluded.Add(FieldPath(x => x.m_MaxDollyOut)); | ||
| excluded.Add(FieldPath(x => x.m_MinimumDistance)); | ||
| excluded.Add(FieldPath(x => x.m_MaximumDistance)); | ||
| break; | ||
| default: | ||
| break; | ||
| } | ||
| } | ||
| return excluded; | ||
| } | ||
|
|
||
| public override void OnInspectorGUI() | ||
| { | ||
| if (MyTarget.IsValid && MyTarget.TargetGroup == null) | ||
| EditorGUILayout.HelpBox( | ||
| "The Framing settings will be ignored because the LookAt target is not a kind of CinemachineTargetGroup", | ||
| MessageType.Info); | ||
|
|
||
| base.OnInspectorGUI(); | ||
| } | ||
|
|
||
| [DrawGizmo(GizmoType.Active | GizmoType.InSelectionHierarchy, typeof(CinemachineGroupComposer))] | ||
| private static void DrawGroupComposerGizmos(CinemachineGroupComposer target, GizmoType selectionType) | ||
| { | ||
| // Show the group bounding box, as viewed from the camera position | ||
| if (target.TargetGroup != null) | ||
| { | ||
| Matrix4x4 m = Gizmos.matrix; | ||
| Bounds b = target.m_LastBounds; | ||
| Gizmos.matrix = target.m_lastBoundsMatrix; | ||
| Gizmos.color = Color.yellow; | ||
| Gizmos.DrawWireCube(b.center, b.size); | ||
| Gizmos.matrix = m; | ||
| } | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,23 @@ | ||
| using UnityEditor; | ||
| using UnityEngine; | ||
|
|
||
| namespace Cinemachine.Editor | ||
| { | ||
| [CustomEditor(typeof(CinemachineHardLockToTarget))] | ||
| public sealed class CinemachineHardLockToTargetEditor : BaseEditor<CinemachineHardLockToTarget> | ||
| { | ||
| public override void OnInspectorGUI() | ||
| { | ||
| BeginInspector(); | ||
| if (Target.FollowTarget == null) | ||
| EditorGUILayout.HelpBox( | ||
| "Hard Lock requires a Follow Target. Change Body to Do Nothing if you don't want a Follow target.", | ||
| MessageType.Warning); | ||
| EditorGUI.BeginChangeCheck(); | ||
| GUI.enabled = false; | ||
| EditorGUILayout.LabelField(" ", "Hard Lock has no settings", EditorStyles.miniLabel); | ||
| GUI.enabled = true; | ||
| DrawRemainingPropertiesInInspector(); | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,23 @@ | ||
| using UnityEditor; | ||
| using UnityEngine; | ||
|
|
||
| namespace Cinemachine.Editor | ||
| { | ||
| [CustomEditor(typeof(CinemachineHardLookAt))] | ||
| public sealed class CinemachineHardLookAtEditor : BaseEditor<CinemachineHardLookAt> | ||
| { | ||
| public override void OnInspectorGUI() | ||
| { | ||
| BeginInspector(); | ||
| if (Target.LookAtTarget == null) | ||
| EditorGUILayout.HelpBox( | ||
| "Hard Look At requires a LookAt target. Change Aim to Do Nothing if you don't want a LookAt target.", | ||
| MessageType.Warning); | ||
| EditorGUI.BeginChangeCheck(); | ||
| GUI.enabled = false; | ||
| EditorGUILayout.LabelField(" ", "Hard Look At has no settings", EditorStyles.miniLabel); | ||
| GUI.enabled = true; | ||
| DrawRemainingPropertiesInInspector(); | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,104 @@ | ||
| using UnityEditor; | ||
| using UnityEngine; | ||
| using Cinemachine.Utility; | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Cinemachine.Editor | ||
| { | ||
| [CustomEditor(typeof(CinemachineMixingCamera))] | ||
| internal sealed class CinemachineMixingCameraEditor | ||
| : CinemachineVirtualCameraBaseEditor<CinemachineMixingCamera> | ||
| { | ||
| protected override List<string> GetExcludedPropertiesInInspector() | ||
| { | ||
| List<string> excluded = base.GetExcludedPropertiesInInspector(); | ||
| for (int i = 0; i < CinemachineMixingCamera.MaxCameras; ++i) | ||
| excluded.Add(WeightPropertyName(i)); | ||
| return excluded; | ||
| } | ||
|
|
||
| static string WeightPropertyName(int i) { return "m_Weight" + i; } | ||
|
|
||
| public override void OnInspectorGUI() | ||
| { | ||
| BeginInspector(); | ||
| DrawHeaderInInspector(); | ||
| DrawRemainingPropertiesInInspector(); | ||
|
|
||
| float totalWeight = 0; | ||
| CinemachineVirtualCameraBase[] children = Target.ChildCameras; | ||
| int numCameras = Mathf.Min(CinemachineMixingCamera.MaxCameras, children.Length); | ||
| for (int i = 0; i < numCameras; ++i) | ||
| if (children[i].isActiveAndEnabled) | ||
| totalWeight += Target.GetWeight(i); | ||
|
|
||
| if (numCameras == 0) | ||
| EditorGUILayout.HelpBox("There are no Virtual Camera children", MessageType.Warning); | ||
| else | ||
| { | ||
| EditorGUILayout.Separator(); | ||
| EditorGUILayout.LabelField("Child Camera Weights", EditorStyles.boldLabel); | ||
| for (int i = 0; i < numCameras; ++i) | ||
| { | ||
| SerializedProperty prop = serializedObject.FindProperty(WeightPropertyName(i)); | ||
| if (prop != null) | ||
| EditorGUILayout.PropertyField(prop, new GUIContent(children[i].Name)); | ||
| } | ||
| serializedObject.ApplyModifiedProperties(); | ||
|
|
||
| if (totalWeight <= UnityVectorExtensions.Epsilon) | ||
| EditorGUILayout.HelpBox("No input channels are active", MessageType.Warning); | ||
|
|
||
| if (children.Length > numCameras) | ||
| EditorGUILayout.HelpBox( | ||
| "There are " + children.Length | ||
| + " child cameras. A maximum of " + numCameras + " is supported.", | ||
| MessageType.Warning); | ||
|
|
||
| // Camera proportion indicator | ||
| EditorGUILayout.Separator(); | ||
| EditorGUILayout.LabelField("Mix Result", EditorStyles.boldLabel); | ||
| DrawProportionIndicator(children, numCameras, totalWeight); | ||
| } | ||
|
|
||
| // Extensions | ||
| DrawExtensionsWidgetInInspector(); | ||
| } | ||
|
|
||
| void DrawProportionIndicator( | ||
| CinemachineVirtualCameraBase[] children, int numCameras, float totalWeight) | ||
| { | ||
| GUIStyle style = EditorStyles.centeredGreyMiniLabel; | ||
| Color bkg = new Color(0.27f, 0.27f, 0.27f); // ack! no better way than this? | ||
| Color fg = Color.Lerp(CinemachineBrain.GetSoloGUIColor(), bkg, 0.8f); | ||
| float totalHeight = (style.lineHeight + style.margin.vertical) * numCameras; | ||
| Rect r = EditorGUILayout.GetControlRect(true, totalHeight); | ||
| r.height /= numCameras; r.height -= 1; | ||
| float fullWidth = r.width; | ||
| for (int i = 0; i < numCameras; ++i) | ||
| { | ||
| float p = 0; | ||
| string label = children[i].Name; | ||
| if (totalWeight > UnityVectorExtensions.Epsilon) | ||
| { | ||
| if (children[i].isActiveAndEnabled) | ||
| p = Target.GetWeight(i) / totalWeight; | ||
| else | ||
| label += " (disabled)"; | ||
| } | ||
| r.width = fullWidth * p; | ||
| EditorGUI.DrawRect(r, fg); | ||
|
|
||
| Rect r2 = r; | ||
| r2.x += r.width; | ||
| r2.width = fullWidth - r.width; | ||
| EditorGUI.DrawRect(r2, bkg); | ||
|
|
||
| r.width = fullWidth; | ||
| EditorGUI.LabelField(r, label, style); | ||
|
|
||
| r.y += r.height + 1; | ||
| } | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,103 @@ | ||
| using UnityEngine; | ||
| using UnityEditor; | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Cinemachine.Editor | ||
| { | ||
| [CustomEditor(typeof(CinemachineOrbitalTransposer))] | ||
| internal class CinemachineOrbitalTransposerEditor : BaseEditor<CinemachineOrbitalTransposer> | ||
| { | ||
| protected override List<string> GetExcludedPropertiesInInspector() | ||
| { | ||
| List<string> excluded = base.GetExcludedPropertiesInInspector(); | ||
| if (Target.m_HeadingIsSlave) | ||
| { | ||
| excluded.Add(FieldPath(x => x.m_FollowOffset)); | ||
| excluded.Add(FieldPath(x => x.m_BindingMode)); | ||
| excluded.Add(FieldPath(x => x.m_Heading)); | ||
| excluded.Add(FieldPath(x => x.m_XAxis)); | ||
| excluded.Add(FieldPath(x => x.m_RecenterToTargetHeading)); | ||
| } | ||
| switch (Target.m_BindingMode) | ||
| { | ||
| default: | ||
| case CinemachineTransposer.BindingMode.LockToTarget: | ||
| break; | ||
| case CinemachineTransposer.BindingMode.LockToTargetNoRoll: | ||
| excluded.Add(FieldPath(x => x.m_RollDamping)); | ||
| break; | ||
| case CinemachineTransposer.BindingMode.LockToTargetWithWorldUp: | ||
| excluded.Add(FieldPath(x => x.m_PitchDamping)); | ||
| excluded.Add(FieldPath(x => x.m_RollDamping)); | ||
| break; | ||
| case CinemachineTransposer.BindingMode.LockToTargetOnAssign: | ||
| case CinemachineTransposer.BindingMode.WorldSpace: | ||
| excluded.Add(FieldPath(x => x.m_PitchDamping)); | ||
| excluded.Add(FieldPath(x => x.m_YawDamping)); | ||
| excluded.Add(FieldPath(x => x.m_RollDamping)); | ||
| break; | ||
| case CinemachineTransposer.BindingMode.SimpleFollowWithWorldUp: | ||
| excluded.Add(FieldPath(x => x.m_XDamping)); | ||
| excluded.Add(FieldPath(x => x.m_PitchDamping)); | ||
| excluded.Add(FieldPath(x => x.m_YawDamping)); | ||
| excluded.Add(FieldPath(x => x.m_RollDamping)); | ||
| excluded.Add(FieldPath(x => x.m_Heading)); | ||
| excluded.Add(FieldPath(x => x.m_RecenterToTargetHeading)); | ||
| break; | ||
| } | ||
| return excluded; | ||
| } | ||
|
|
||
| public override void OnInspectorGUI() | ||
| { | ||
| BeginInspector(); | ||
| if (Target.FollowTarget == null) | ||
| EditorGUILayout.HelpBox( | ||
| "Orbital Transposer requires a Follow target.", | ||
| MessageType.Warning); | ||
| DrawRemainingPropertiesInInspector(); | ||
| } | ||
|
|
||
| [DrawGizmo(GizmoType.Active | GizmoType.Selected, typeof(CinemachineOrbitalTransposer))] | ||
| static void DrawTransposerGizmos(CinemachineOrbitalTransposer target, GizmoType selectionType) | ||
| { | ||
| if (target.IsValid) | ||
| { | ||
| Color originalGizmoColour = Gizmos.color; | ||
| Gizmos.color = CinemachineCore.Instance.IsLive(target.VirtualCamera) | ||
| ? CinemachineSettings.CinemachineCoreSettings.ActiveGizmoColour | ||
| : CinemachineSettings.CinemachineCoreSettings.InactiveGizmoColour; | ||
|
|
||
| Vector3 up = Vector3.up; | ||
| CinemachineBrain brain = CinemachineCore.Instance.FindPotentialTargetBrain(target.VirtualCamera); | ||
| if (brain != null) | ||
| up = brain.DefaultWorldUp; | ||
| Vector3 pos = target.FollowTarget.position; | ||
|
|
||
| Quaternion orient = target.GetReferenceOrientation(up); | ||
| up = orient * Vector3.up; | ||
| DrawCircleAtPointWithRadius | ||
| (pos + up * target.m_FollowOffset.y, orient, target.m_FollowOffset.z); | ||
|
|
||
| Gizmos.color = originalGizmoColour; | ||
| } | ||
| } | ||
|
|
||
| internal static void DrawCircleAtPointWithRadius(Vector3 point, Quaternion orient, float radius) | ||
| { | ||
| Matrix4x4 prevMatrix = Gizmos.matrix; | ||
| Gizmos.matrix = Matrix4x4.TRS(point, orient, radius * Vector3.one); | ||
|
|
||
| const int kNumPoints = 25; | ||
| Vector3 currPoint = Vector3.forward; | ||
| Quaternion rot = Quaternion.AngleAxis(360f / (float)kNumPoints, Vector3.up); | ||
| for (int i = 0; i < kNumPoints + 1; ++i) | ||
| { | ||
| Vector3 nextPoint = rot * currPoint; | ||
| Gizmos.DrawLine(currPoint, nextPoint); | ||
| currPoint = nextPoint; | ||
| } | ||
| Gizmos.matrix = prevMatrix; | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1,9 @@ | ||
| using UnityEditor; | ||
|
|
||
| namespace Cinemachine.Editor | ||
| { | ||
| [CustomEditor(typeof(CinemachinePOV))] | ||
| public sealed class CinemachinePOVEditor : BaseEditor<CinemachinePOV> | ||
| { | ||
| } | ||
| } |
| @@ -0,0 +1,191 @@ | ||
| using UnityEngine; | ||
| using UnityEditor; | ||
| using Cinemachine.Utility; | ||
|
|
||
| namespace Cinemachine.Editor | ||
| { | ||
| internal class CinemachineScreenComposerGuides | ||
| { | ||
| public delegate Rect RectGetter(); | ||
| public delegate void RectSetter(Rect r); | ||
| public delegate SerializedObject ObjectGetter(); | ||
|
|
||
| // Clients MUST implement all of these | ||
| public RectGetter GetHardGuide; | ||
| public RectGetter GetSoftGuide; | ||
| public RectSetter SetHardGuide; | ||
| public RectSetter SetSoftGuide; | ||
| public ObjectGetter Target; | ||
|
|
||
| public const float kGuideBarWidthPx = 3f; | ||
|
|
||
| public void SetNewBounds(Rect oldHard, Rect oldSoft, Rect newHard, Rect newSoft) | ||
| { | ||
| if ((oldSoft != newSoft) || (oldHard != newHard)) | ||
| { | ||
| Undo.RecordObject(Target().targetObject, "Composer Bounds"); | ||
| if (oldSoft != newSoft) | ||
| SetSoftGuide(newSoft); | ||
| if (oldHard != newHard) | ||
| SetHardGuide(newHard); | ||
| Target().ApplyModifiedProperties(); | ||
| } | ||
| } | ||
|
|
||
| public void OnGUI_DrawGuides(bool isLive, Camera outputCamera, LensSettings lens, bool showHardGuides) | ||
| { | ||
| Rect cameraRect = outputCamera.pixelRect; | ||
| float screenWidth = cameraRect.width; | ||
| float screenHeight = cameraRect.height; | ||
| cameraRect.yMax = Screen.height - cameraRect.yMin; | ||
| cameraRect.yMin = cameraRect.yMax - screenHeight; | ||
|
|
||
| // Rotate the guides along with the dutch | ||
| Matrix4x4 oldMatrix = GUI.matrix; | ||
| GUI.matrix = Matrix4x4.Translate(cameraRect.min); | ||
| GUIUtility.RotateAroundPivot(lens.Dutch, cameraRect.center); | ||
|
|
||
| Color hardBarsColour = CinemachineSettings.ComposerSettings.HardBoundsOverlayColour; | ||
| Color softBarsColour = CinemachineSettings.ComposerSettings.SoftBoundsOverlayColour; | ||
| float overlayOpacity = CinemachineSettings.ComposerSettings.OverlayOpacity; | ||
| if (!isLive) | ||
| { | ||
| softBarsColour = CinemachineSettings.CinemachineCoreSettings.InactiveGizmoColour; | ||
| hardBarsColour = Color.Lerp(softBarsColour, Color.black, 0.5f); | ||
| overlayOpacity /= 2; | ||
| } | ||
| hardBarsColour.a *= overlayOpacity; | ||
| softBarsColour.a *= overlayOpacity; | ||
|
|
||
| Rect r = showHardGuides ? GetHardGuide() : new Rect(-2, -2, 4, 4); | ||
| float hardEdgeLeft = r.xMin * screenWidth; | ||
| float hardEdgeTop = r.yMin * screenHeight; | ||
| float hardEdgeRight = r.xMax * screenWidth; | ||
| float hardEdgeBottom = r.yMax * screenHeight; | ||
|
|
||
| mDragBars[(int)DragBar.HardBarLineLeft] = new Rect(hardEdgeLeft - kGuideBarWidthPx / 2f, 0f, kGuideBarWidthPx, screenHeight); | ||
| mDragBars[(int)DragBar.HardBarLineTop] = new Rect(0f, hardEdgeTop - kGuideBarWidthPx / 2f, screenWidth, kGuideBarWidthPx); | ||
| mDragBars[(int)DragBar.HardBarLineRight] = new Rect(hardEdgeRight - kGuideBarWidthPx / 2f, 0f, kGuideBarWidthPx, screenHeight); | ||
| mDragBars[(int)DragBar.HardBarLineBottom] = new Rect(0f, hardEdgeBottom - kGuideBarWidthPx / 2f, screenWidth, kGuideBarWidthPx); | ||
|
|
||
| r = GetSoftGuide(); | ||
| float softEdgeLeft = r.xMin * screenWidth; | ||
| float softEdgeTop = r.yMin * screenHeight; | ||
| float softEdgeRight = r.xMax * screenWidth; | ||
| float softEdgeBottom = r.yMax * screenHeight; | ||
|
|
||
| mDragBars[(int)DragBar.SoftBarLineLeft] = new Rect(softEdgeLeft - kGuideBarWidthPx / 2f, 0f, kGuideBarWidthPx, screenHeight); | ||
| mDragBars[(int)DragBar.SoftBarLineTop] = new Rect(0f, softEdgeTop - kGuideBarWidthPx / 2f, screenWidth, kGuideBarWidthPx); | ||
| mDragBars[(int)DragBar.SoftBarLineRight] = new Rect(softEdgeRight - kGuideBarWidthPx / 2f, 0f, kGuideBarWidthPx, screenHeight); | ||
| mDragBars[(int)DragBar.SoftBarLineBottom] = new Rect(0f, softEdgeBottom - kGuideBarWidthPx / 2f, screenWidth, kGuideBarWidthPx); | ||
|
|
||
| mDragBars[(int)DragBar.Center] = new Rect(softEdgeLeft, softEdgeTop, softEdgeRight - softEdgeLeft, softEdgeBottom - softEdgeTop); | ||
|
|
||
| // Handle dragging bars | ||
| if (isLive) | ||
| OnGuiHandleBarDragging(screenWidth, screenHeight); | ||
|
|
||
| // Draw the masks | ||
| GUI.color = hardBarsColour; | ||
| Rect hardBarLeft = new Rect(0, hardEdgeTop, Mathf.Max(0, hardEdgeLeft), hardEdgeBottom - hardEdgeTop); | ||
| Rect hardBarRight = new Rect(hardEdgeRight, hardEdgeTop, | ||
| Mathf.Max(0, screenWidth - hardEdgeRight), hardEdgeBottom - hardEdgeTop); | ||
| Rect hardBarTop = new Rect(Mathf.Min(0, hardEdgeLeft), 0, | ||
| Mathf.Max(screenWidth, hardEdgeRight) - Mathf.Min(0, hardEdgeLeft), Mathf.Max(0, hardEdgeTop)); | ||
| Rect hardBarBottom = new Rect(Mathf.Min(0, hardEdgeLeft), hardEdgeBottom, | ||
| Mathf.Max(screenWidth, hardEdgeRight) - Mathf.Min(0, hardEdgeLeft), | ||
| Mathf.Max(0, screenHeight - hardEdgeBottom)); | ||
| GUI.DrawTexture(hardBarLeft, Texture2D.whiteTexture, ScaleMode.StretchToFill); | ||
| GUI.DrawTexture(hardBarTop, Texture2D.whiteTexture, ScaleMode.StretchToFill); | ||
| GUI.DrawTexture(hardBarRight, Texture2D.whiteTexture, ScaleMode.StretchToFill); | ||
| GUI.DrawTexture(hardBarBottom, Texture2D.whiteTexture, ScaleMode.StretchToFill); | ||
|
|
||
| GUI.color = softBarsColour; | ||
| Rect softBarLeft = new Rect(hardEdgeLeft, softEdgeTop, softEdgeLeft - hardEdgeLeft, softEdgeBottom - softEdgeTop); | ||
| Rect softBarTop = new Rect(hardEdgeLeft, hardEdgeTop, hardEdgeRight - hardEdgeLeft, softEdgeTop - hardEdgeTop); | ||
| Rect softBarRight = new Rect(softEdgeRight, softEdgeTop, hardEdgeRight - softEdgeRight, softEdgeBottom - softEdgeTop); | ||
| Rect softBarBottom = new Rect(hardEdgeLeft, softEdgeBottom, hardEdgeRight - hardEdgeLeft, hardEdgeBottom - softEdgeBottom); | ||
| GUI.DrawTexture(softBarLeft, Texture2D.whiteTexture, ScaleMode.StretchToFill); | ||
| GUI.DrawTexture(softBarTop, Texture2D.whiteTexture, ScaleMode.StretchToFill); | ||
| GUI.DrawTexture(softBarRight, Texture2D.whiteTexture, ScaleMode.StretchToFill); | ||
| GUI.DrawTexture(softBarBottom, Texture2D.whiteTexture, ScaleMode.StretchToFill); | ||
|
|
||
| // Draw the drag bars | ||
| GUI.DrawTexture(mDragBars[(int)DragBar.SoftBarLineLeft], Texture2D.whiteTexture, ScaleMode.StretchToFill); | ||
| GUI.DrawTexture(mDragBars[(int)DragBar.SoftBarLineTop], Texture2D.whiteTexture, ScaleMode.StretchToFill); | ||
| GUI.DrawTexture(mDragBars[(int)DragBar.SoftBarLineRight], Texture2D.whiteTexture, ScaleMode.StretchToFill); | ||
| GUI.DrawTexture(mDragBars[(int)DragBar.SoftBarLineBottom], Texture2D.whiteTexture, ScaleMode.StretchToFill); | ||
|
|
||
| GUI.color = hardBarsColour; | ||
| GUI.DrawTexture(mDragBars[(int)DragBar.HardBarLineLeft], Texture2D.whiteTexture, ScaleMode.StretchToFill); | ||
| GUI.DrawTexture(mDragBars[(int)DragBar.HardBarLineTop], Texture2D.whiteTexture, ScaleMode.StretchToFill); | ||
| GUI.DrawTexture(mDragBars[(int)DragBar.HardBarLineRight], Texture2D.whiteTexture, ScaleMode.StretchToFill); | ||
| GUI.DrawTexture(mDragBars[(int)DragBar.HardBarLineBottom], Texture2D.whiteTexture, ScaleMode.StretchToFill); | ||
|
|
||
| GUI.matrix = oldMatrix; | ||
| } | ||
|
|
||
| // For dragging the bars - order defines precedence | ||
| private enum DragBar | ||
| { | ||
| Center, | ||
| SoftBarLineLeft, SoftBarLineTop, SoftBarLineRight, SoftBarLineBottom, | ||
| HardBarLineLeft, HardBarLineTop, HardBarLineRight, HardBarLineBottom, | ||
| NONE | ||
| }; | ||
| private DragBar mDragging = DragBar.NONE; | ||
| private Rect[] mDragBars = new Rect[9]; | ||
|
|
||
| private void OnGuiHandleBarDragging(float screenWidth, float screenHeight) | ||
| { | ||
| if (Event.current.type == EventType.MouseUp) | ||
| mDragging = DragBar.NONE; | ||
| if (Event.current.type == EventType.MouseDown) | ||
| { | ||
| mDragging = DragBar.NONE; | ||
| for (DragBar i = DragBar.Center; i < DragBar.NONE && mDragging == DragBar.NONE; ++i) | ||
| { | ||
| Vector2 slop = new Vector2(5f, 5f); | ||
| if (i == DragBar.Center) | ||
| { | ||
| if (mDragBars[(int)i].width > 3f * slop.x) | ||
| slop.x = -slop.x; | ||
| if (mDragBars[(int)i].height > 3f * slop.y) | ||
| slop.y = -slop.y; | ||
| } | ||
| Rect r = mDragBars[(int)i].Inflated(slop); | ||
| if (r.Contains(Event.current.mousePosition)) | ||
| mDragging = i; | ||
| } | ||
| } | ||
|
|
||
| if (mDragging != DragBar.NONE && Event.current.type == EventType.MouseDrag) | ||
| { | ||
| Vector2 d = new Vector2( | ||
| Event.current.delta.x / screenWidth, | ||
| Event.current.delta.y / screenHeight); | ||
|
|
||
| // First snapshot some settings | ||
| Rect newHard = GetHardGuide(); | ||
| Rect newSoft = GetSoftGuide(); | ||
| Vector2 changed = Vector2.zero; | ||
| switch (mDragging) | ||
| { | ||
| case DragBar.Center: newSoft.position += d; break; | ||
| case DragBar.SoftBarLineLeft: newSoft = newSoft.Inflated(new Vector2(-d.x, 0)); break; | ||
| case DragBar.SoftBarLineRight: newSoft = newSoft.Inflated(new Vector2(d.x, 0)); break; | ||
| case DragBar.SoftBarLineTop: newSoft = newSoft.Inflated(new Vector2(0, -d.y)); break; | ||
| case DragBar.SoftBarLineBottom: newSoft = newSoft.Inflated(new Vector2(0, d.y)); break; | ||
| case DragBar.HardBarLineLeft: newHard = newHard.Inflated(new Vector2(-d.x, 0)); break; | ||
| case DragBar.HardBarLineRight: newHard = newHard.Inflated(new Vector2(d.x, 0)); break; | ||
| case DragBar.HardBarLineBottom: newHard = newHard.Inflated(new Vector2(0, d.y)); break; | ||
| case DragBar.HardBarLineTop: newHard = newHard.Inflated(new Vector2(0, -d.y)); break; | ||
| } | ||
|
|
||
| // Apply the changes, enforcing the bounds | ||
| SetNewBounds(GetHardGuide(), GetSoftGuide(), newHard, newSoft); | ||
| UnityEditorInternal.InternalEditorUtility.RepaintAllViews(); | ||
| } | ||
| } | ||
| } | ||
| } |