123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- using System;
- using UnityEngine.UIElements;
- using UnityEngine;
- namespace UnityEditor.Rendering.LookDev
- {
- //TODO: clamps to always have both node on screen
- class ComparisonGizmoController : Manipulator
- {
- const float k_DragPadding = 0.05f;
- const float k_ReferenceScale = 1080f;
- ComparisonGizmoState m_State;
- SwitchableCameraController m_Switcher;
- enum Selected
- {
- None,
- NodeFirstView,
- NodeSecondView,
- PlaneSeparator,
- Fader
- }
- Selected m_Selected;
- Vector2 m_SavedRelativePositionOnMouseDown;
- bool m_IsDragging;
- bool isDragging
- {
- get => m_IsDragging;
- set
- {
- //As in scene view, stop dragging as first button is release in case of multiple button down
- if (value ^ m_IsDragging)
- {
- if (value)
- {
- target.RegisterCallback<MouseMoveEvent>(OnMouseDrag);
- target.CaptureMouse();
- }
- else
- {
- target.ReleaseMouse();
- target.UnregisterCallback<MouseMoveEvent>(OnMouseDrag);
- }
- m_IsDragging = value;
- }
- }
- }
- public ComparisonGizmoController(SwitchableCameraController switcher)
- {
- m_Switcher = switcher;
- }
- public void UpdateGizmoState(ComparisonGizmoState state)
- {
- m_State = state;
- }
- protected override void RegisterCallbacksOnTarget()
- {
- target.RegisterCallback<MouseDownEvent>(OnMouseDown);
- target.RegisterCallback<MouseUpEvent>(OnMouseUp);
- target.RegisterCallback<WheelEvent>(OnScrollWheel);
- }
- protected override void UnregisterCallbacksFromTarget()
- {
- target.UnregisterCallback<MouseDownEvent>(OnMouseDown);
- target.UnregisterCallback<MouseUpEvent>(OnMouseUp);
- target.UnregisterCallback<WheelEvent>(OnScrollWheel);
- }
- void OnScrollWheel(WheelEvent evt)
- {
- if (LookDev.currentContext.layout.viewLayout != Layout.CustomSplit)
- return;
- if (GetViewFromComposition(evt.localMousePosition) == ViewIndex.Second)
- m_Switcher.SwitchUntilNextWheelEvent();
- //let event be propagated to views
- }
- void OnMouseDown(MouseDownEvent evt)
- {
- if (LookDev.currentContext.layout.viewLayout != Layout.CustomSplit)
- return;
- Rect displayRect = target.contentRect;
- SelectGizmoZone(GetNormalizedCoordinates(evt.localMousePosition, displayRect));
- if (m_Selected != Selected.None)
- {
- m_SavedRelativePositionOnMouseDown = GetNormalizedCoordinates(evt.localMousePosition, displayRect) - m_State.center;
- isDragging = true;
- //We do not want to move camera and gizmo at the same time.
- evt.StopImmediatePropagation();
- }
- else
- {
- //else let event be propagated to views
- if (GetViewFromComposition(evt.localMousePosition) == ViewIndex.Second)
- m_Switcher.SwitchUntilNextEndOfDrag();
- }
- }
-
- void OnMouseUp(MouseUpEvent evt)
- {
- if (LookDev.currentContext.layout.viewLayout != Layout.CustomSplit
- || m_Selected == Selected.None)
- return;
- // deadzone in fader gizmo
- if (m_Selected == Selected.Fader && Mathf.Abs(m_State.blendFactor) < ComparisonGizmoState.circleRadiusSelected / (m_State.length - ComparisonGizmoState.circleRadius))
- m_State.blendFactor = 0f;
- m_Selected = Selected.None;
- isDragging = false;
- //We do not want to move camera and gizmo at the same time.
- evt.StopImmediatePropagation();
- LookDev.SaveConfig();
- }
- void OnMouseDrag(MouseMoveEvent evt)
- {
- if (m_Selected == Selected.None)
- return;
- switch (m_Selected)
- {
- case Selected.PlaneSeparator: OnDragPlaneSeparator(evt); break;
- case Selected.NodeFirstView:
- case Selected.NodeSecondView: OnDragPlaneNodeExtremity(evt); break;
- case Selected.Fader: OnDragFader(evt); break;
- default: throw new ArgumentException("Unknown kind of Selected");
- }
- }
- void OnDragPlaneSeparator(MouseMoveEvent evt)
- {
- //TODO: handle case when resizing window (clamping)
- Vector2 newPosition = GetNormalizedCoordinates(evt.localMousePosition, target.contentRect) - m_SavedRelativePositionOnMouseDown;
- // We clamp the center of the gizmo to the border of the screen in order to avoid being able to put it out of the screen.
- // The safe band is here to ensure that you always see at least part of the gizmo in order to be able to grab it again.
- //Vector2 extends = GetNormalizedCoordinates(new Vector2(displayRect.width, displayRect.height), displayRect);
- //newPosition.x = Mathf.Clamp(newPosition.x, -extends.x + k_DragPadding, extends.x - k_DragPadding);
- //newPosition.y = Mathf.Clamp(newPosition.y, -extends.y + k_DragPadding, extends.y - k_DragPadding);
- m_State.Update(newPosition, m_State.length, m_State.angle);
- //We do not want to move camera and gizmo at the same time.
- evt.StopImmediatePropagation();
- }
-
- void OnDragPlaneNodeExtremity(MouseMoveEvent evt)
- {
- Vector2 normalizedCoord = GetNormalizedCoordinates(evt.localMousePosition, target.contentRect);
- Vector2 basePoint, newPoint;
- float angleSnapping = Mathf.Deg2Rad * 45.0f * 0.5f;
- newPoint = normalizedCoord;
- basePoint = m_Selected == Selected.NodeFirstView ? m_State.point2 : m_State.point1;
- // Snap to a multiple of "angleSnapping"
- if ((evt.modifiers & EventModifiers.Shift) != 0)
- {
- Vector3 verticalPlane = new Vector3(-1.0f, 0.0f, basePoint.x);
- float side = Vector3.Dot(new Vector3(normalizedCoord.x, normalizedCoord.y, 1.0f), verticalPlane);
- float angle = Mathf.Deg2Rad * Vector2.Angle(new Vector2(0.0f, 1.0f), normalizedCoord - basePoint);
- if (side > 0.0f)
- angle = 2.0f * Mathf.PI - angle;
- angle = (int)(angle / angleSnapping) * angleSnapping;
- Vector2 dir = normalizedCoord - basePoint;
- float length = dir.magnitude;
- newPoint = basePoint + new Vector2(Mathf.Sin(angle), Mathf.Cos(angle)) * length;
- }
- if (m_Selected == Selected.NodeFirstView)
- m_State.Update(newPoint, basePoint);
- else
- m_State.Update(basePoint, newPoint);
- //We do not want to move camera and gizmo at the same time.
- evt.StopImmediatePropagation();
- }
- void OnDragFader(MouseMoveEvent evt)
- {
- Vector2 mousePosition = GetNormalizedCoordinates(evt.localMousePosition, target.contentRect);
- float distanceToOrthoPlane = -Vector3.Dot(new Vector3(mousePosition.x, mousePosition.y, 1.0f), m_State.planeOrtho) / m_State.blendFactorMaxGizmoDistance;
- m_State.blendFactor = Mathf.Clamp(distanceToOrthoPlane, -1.0f, 1.0f);
- //We do not want to move camera and gizmo at the same time.
- evt.StopImmediatePropagation();
- }
- void SelectGizmoZone(Vector2 normalizedMousePosition)
- {
- //TODO: Optimize
- Vector3 normalizedMousePositionZ1 = new Vector3(normalizedMousePosition.x, normalizedMousePosition.y, 1.0f);
- float distanceToPlane = Vector3.Dot(normalizedMousePositionZ1, m_State.plane);
- float absDistanceToPlane = Mathf.Abs(distanceToPlane);
- float distanceFromCenter = Vector2.Distance(normalizedMousePosition, m_State.center);
- float distanceToOrtho = Vector3.Dot(normalizedMousePositionZ1, m_State.planeOrtho);
- float side = (distanceToOrtho > 0.0f) ? 1.0f : -1.0f;
- Vector2 orthoPlaneNormal = new Vector2(m_State.planeOrtho.x, m_State.planeOrtho.y);
- Selected selected = Selected.None;
- if (absDistanceToPlane < ComparisonGizmoState.circleRadiusSelected && (distanceFromCenter < (m_State.length + ComparisonGizmoState.circleRadiusSelected)))
- {
- if (absDistanceToPlane < ComparisonGizmoState.thicknessSelected)
- selected = Selected.PlaneSeparator;
- Vector2 circleCenter = m_State.center + side * orthoPlaneNormal * m_State.length;
- float d = Vector2.Distance(normalizedMousePosition, circleCenter);
- if (d <= ComparisonGizmoState.circleRadiusSelected)
- selected = side > 0.0f ? Selected.NodeFirstView : Selected.NodeSecondView;
- float maxBlendCircleDistanceToCenter = m_State.blendFactorMaxGizmoDistance;
- float blendCircleDistanceToCenter = m_State.blendFactor * maxBlendCircleDistanceToCenter;
- Vector2 blendCircleCenter = m_State.center - orthoPlaneNormal * blendCircleDistanceToCenter;
- float blendCircleSelectionRadius = Mathf.Lerp(ComparisonGizmoState.blendFactorCircleRadius, ComparisonGizmoState.blendFactorCircleRadiusSelected, Mathf.Clamp((maxBlendCircleDistanceToCenter - Mathf.Abs(blendCircleDistanceToCenter)) / (ComparisonGizmoState.blendFactorCircleRadiusSelected - ComparisonGizmoState.blendFactorCircleRadius), 0.0f, 1.0f));
- if ((normalizedMousePosition - blendCircleCenter).magnitude < blendCircleSelectionRadius)
- selected = Selected.Fader;
- }
- m_Selected = selected;
- }
- //normalize in [-1,1]^2 for a 1080^2. Can be above 1 for higher than 1080.
- internal static Vector2 GetNormalizedCoordinates(Vector2 localMousePosition, Rect rect)
- => new Vector2(
- (2f * localMousePosition.x - rect.width) / k_ReferenceScale,
- (-2f * localMousePosition.y + rect.height) / k_ReferenceScale);
- ViewIndex GetViewFromComposition(Vector2 localCoordinate)
- {
- Vector2 normalizedLocalCoordinate = GetNormalizedCoordinates(localCoordinate, target.contentRect);
- return Vector3.Dot(new Vector3(normalizedLocalCoordinate.x, normalizedLocalCoordinate.y, 1), m_State.plane) >= 0
- ? ViewIndex.First
- : ViewIndex.Second;
- }
- }
- }
|