From b57e847916d3f3ef03de1b51b9073dec152f7be7 Mon Sep 17 00:00:00 2001 From: Zode Date: Mon, 17 Jun 2024 21:19:31 +0300 Subject: [PATCH] Add absolute snapping --- .../Gizmo/TransformGizmoBase.Settings.cs | 5 +++ Source/Editor/Gizmo/TransformGizmoBase.cs | 42 +++++++++++++++++++ Source/Editor/Viewport/EditorGizmoViewport.cs | 20 ++++++++- 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Gizmo/TransformGizmoBase.Settings.cs b/Source/Editor/Gizmo/TransformGizmoBase.Settings.cs index bbd13f688..c7af85c14 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.Settings.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.Settings.cs @@ -75,6 +75,11 @@ namespace FlaxEditor.Gizmo /// public bool ScaleSnapEnabled = false; + /// + /// True if enable absolute grid snapping + /// + public bool AbsoluteSnapEnabled = false; + /// /// Translation snap value /// diff --git a/Source/Editor/Gizmo/TransformGizmoBase.cs b/Source/Editor/Gizmo/TransformGizmoBase.cs index 81f76d392..2c7580c79 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.cs @@ -40,6 +40,7 @@ namespace FlaxEditor.Gizmo private Vector3 _intersectPosition; private bool _isActive; private bool _isDuplicating; + private bool _hasAbsoluteSnapped; private bool _isTransforming; private Vector3 _lastIntersectionPosition; @@ -316,6 +317,7 @@ namespace FlaxEditor.Gizmo if ((isScaling ? ScaleSnapEnabled : TranslationSnapEnable) || Owner.UseSnapping) { var snapValue = new Vector3(isScaling ? ScaleSnapValue : TranslationSnapValue); + _translationScaleSnapDelta += delta; if (!isScaling && snapValue.X < 0.0f) { @@ -334,11 +336,29 @@ namespace FlaxEditor.Gizmo else snapValue.Z = (Real)b.Minimum.Z - b.Maximum.Z; } + + Vector3 absoluteDelta = Vector3.Zero; + if (!_hasAbsoluteSnapped && AbsoluteSnapEnabled) + { + _hasAbsoluteSnapped = true; + + Vector3 currentTranslationScale = isScaling ? GetSelectedTransform(0).Scale : GetSelectedTransform(0).Translation; + absoluteDelta = currentTranslationScale - new Vector3( + Mathf.Round(currentTranslationScale.X / snapValue.X) * snapValue.X, + Mathf.Round(currentTranslationScale.Y / snapValue.Y) * snapValue.Y, + Mathf.Round(currentTranslationScale.Z / snapValue.Z) * snapValue.Z); + } + delta = new Vector3( (int)(_translationScaleSnapDelta.X / snapValue.X) * snapValue.X, (int)(_translationScaleSnapDelta.Y / snapValue.Y) * snapValue.Y, (int)(_translationScaleSnapDelta.Z / snapValue.Z) * snapValue.Z); _translationScaleSnapDelta -= delta; + delta -= absoluteDelta; + } + else + { + _hasAbsoluteSnapped = false; } if (_activeMode == Mode.Translate) @@ -368,12 +388,34 @@ namespace FlaxEditor.Gizmo if (RotationSnapEnabled || Owner.UseSnapping) { float snapValue = RotationSnapValue * Mathf.DegreesToRadians; + + float absoluteDelta = 0.0f; + if (!_hasAbsoluteSnapped && AbsoluteSnapEnabled) + { + _hasAbsoluteSnapped = true; + + float currentAngle = 0.0f; + switch (_activeAxis) + { + case Axis.X: currentAngle = GetSelectedTransform(0).Orientation.EulerAngles.X; break; + case Axis.Y: currentAngle = GetSelectedTransform(0).Orientation.EulerAngles.Y; break; + case Axis.Z: currentAngle = GetSelectedTransform(0).Orientation.EulerAngles.Z; break; + } + + absoluteDelta = currentAngle - (Mathf.Round(currentAngle / RotationSnapValue) * RotationSnapValue); + } + _rotationSnapDelta += delta; float snapped = Mathf.Round(_rotationSnapDelta / snapValue) * snapValue; _rotationSnapDelta -= snapped; delta = snapped; + delta -= absoluteDelta * Mathf.DegreesToRadians; + } + else + { + _hasAbsoluteSnapped = false; } switch (_activeAxis) diff --git a/Source/Editor/Viewport/EditorGizmoViewport.cs b/Source/Editor/Viewport/EditorGizmoViewport.cs index f0681e48d..e79d3f19e 100644 --- a/Source/Editor/Viewport/EditorGizmoViewport.cs +++ b/Source/Editor/Viewport/EditorGizmoViewport.cs @@ -137,7 +137,9 @@ namespace FlaxEditor.Viewport if (useProjectCache) { // Initialize snapping enabled from cached values - if (editor.ProjectCache.TryGetCustomData("TranslateSnapState", out bool cachedBool)) + if (editor.ProjectCache.TryGetCustomData("AbsoluteSnapState", out bool cachedBool)) + transformGizmo.AbsoluteSnapEnabled = cachedBool; + if (editor.ProjectCache.TryGetCustomData("TranslateSnapState", out cachedBool)) transformGizmo.TranslationSnapEnable = cachedBool; if (editor.ProjectCache.TryGetCustomData("RotationSnapState", out cachedBool)) transformGizmo.RotationSnapEnabled = cachedBool; @@ -169,6 +171,22 @@ namespace FlaxEditor.Viewport }; transformSpaceWidget.Parent = viewport; + // Absolute snapping widget + var absoluteSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); + var enableAbsoluteSnapping = new ViewportWidgetButton("A", SpriteHandle.Default, null, true) + { + Checked = transformGizmo.AbsoluteSnapEnabled, + TooltipText = "Enable absolute snapping", + Parent = absoluteSnappingWidget + }; + enableAbsoluteSnapping.Toggled += _ => + { + transformGizmo.AbsoluteSnapEnabled = !transformGizmo.AbsoluteSnapEnabled; + if (useProjectCache) + editor.ProjectCache.SetCustomData("AbsoluteSnapState", transformGizmo.AbsoluteSnapEnabled); + }; + absoluteSnappingWidget.Parent = viewport; + // Scale snapping widget var scaleSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); var enableScaleSnapping = new ViewportWidgetButton(string.Empty, editor.Icons.ScaleSnap32, null, true)