-
Notifications
You must be signed in to change notification settings - Fork 869
Expand file tree
/
Copy pathComparisonGizmoController.cs
More file actions
244 lines (210 loc) · 10.7 KB
/
ComparisonGizmoController.cs
File metadata and controls
244 lines (210 loc) · 10.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
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 + m_State.length * side * orthoPlaneNormal;
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;
}
}
}