@@ -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>
{
}
}

Large diffs are not rendered by default.

@@ -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();
}
}
}
}