From 88b02105b3ade4fc9c2f3bb2e795f1b029dd8e15 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Mon, 15 Dec 2025 20:36:35 -0600 Subject: [PATCH 1/8] Add direction gizmo. --- Source/Editor/Gizmo/DirectionGizmo.cs | 168 ++++++++++++++++++ .../Viewport/MainEditorGizmoViewport.cs | 3 + 2 files changed, 171 insertions(+) create mode 100644 Source/Editor/Gizmo/DirectionGizmo.cs diff --git a/Source/Editor/Gizmo/DirectionGizmo.cs b/Source/Editor/Gizmo/DirectionGizmo.cs new file mode 100644 index 000000000..17e94564c --- /dev/null +++ b/Source/Editor/Gizmo/DirectionGizmo.cs @@ -0,0 +1,168 @@ +using System.Collections.Generic; +using FlaxEditor.Gizmo; +using FlaxEditor.Viewport; +using FlaxEngine; +using FlaxEngine.GUI; + +namespace FlaxEditor.Gizmo; + +public class DirectionGizmo +{ + private IGizmoOwner _owner; + private ViewportProjection _viewportProjection; + private EditorViewport _viewport; + private Vector3 _gizmoCenter; + private float _axisLength = 70.0f; + private float _textAxisLength = 85.0f; + + private AxisData _xAxisData; + private AxisData _yAxisData; + private AxisData _zAxisData; + private AxisData _negXAxisData; + private AxisData _negYAxisData; + private AxisData _negZAxisData; + + private List _axisData = new List(); + + private SpriteHandle _posHandle; + private SpriteHandle _negHandle; + + private FontReference _fontReference; + + private struct ViewportProjection + { + private Matrix _viewProjection; + private BoundingFrustum _frustum; + private FlaxEngine.Viewport _viewport; + private Vector3 _origin; + + public void Init(EditorViewport editorViewport) + { + // Inline EditorViewport.ProjectPoint to save on calculation for large set of points + _viewport = new FlaxEngine.Viewport(0, 0, editorViewport.Width, editorViewport.Height); + _frustum = editorViewport.ViewFrustum; + _viewProjection = _frustum.Matrix; + _origin = editorViewport.Task.View.Origin; + } + + public void ProjectPoint(Vector3 worldSpaceLocation, out Float2 viewportSpaceLocation) + { + worldSpaceLocation -= _origin; + _viewport.Project(ref worldSpaceLocation, ref _viewProjection, out var projected); + viewportSpaceLocation = new Float2((float)projected.X, (float)projected.Y); + } + } + + private struct AxisData + { + public Float2 Delta; + public float Distance; + public string Label; + public Color AxisColor; + public bool Negative; + } + + /// + /// Constructor of the Direction Gizmo + /// + /// The owner of this object. + public DirectionGizmo(IGizmoOwner owner) + { + _owner = owner; + _viewport = owner.Viewport; + _viewportProjection.Init(owner.Viewport); + + _xAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "X", AxisColor = new Color(1.0f, 0.0f, 0.02745f, 1.0f), Negative = false }; + _yAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "Y", AxisColor = new Color(0.239215f, 1.0f, 0.047058f, 1.0f), Negative = false }; + _zAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "Z", AxisColor = new Color(0.0f, 0.0235294f, 1.0f, 1.0f), Negative = false }; + + _negXAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "-X", AxisColor = new Color(1.0f, 0.0f, 0.02745f, 1.0f), Negative = true }; + _negYAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "-Y", AxisColor = new Color(0.239215f, 1.0f, 0.047058f, 1.0f), Negative = true }; + _negZAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "-Z", AxisColor = new Color(0.0f, 0.0235294f, 1.0f, 1.0f), Negative = true }; + _axisData.EnsureCapacity(6); + + _posHandle = Editor.Instance.Icons.VisjectBoxClosed32; + _negHandle = Editor.Instance.Icons.VisjectBoxOpen32; + + _fontReference = new FontReference(Style.Current.FontSmall); + _fontReference.Size = 8; + } + + /// + /// Used to Draw the gizmo. + /// + public void Draw() + { + _viewportProjection.Init(_owner.Viewport); + _gizmoCenter = _viewport.Task.View.WorldPosition + _viewport.Task.View.Direction * 1500; + _viewportProjection.ProjectPoint(_gizmoCenter, out var gizmoCenterScreen); + var bounds = _viewport.Bounds; + var screenLocation = bounds.Location - new Float2(-bounds.Width * 0.5f + 50, bounds.Height * 0.5f - 50); + var relativeCenter = gizmoCenterScreen - screenLocation; + + // Project unit vectors + _viewportProjection.ProjectPoint(_gizmoCenter + Vector3.Right, out var xProjected); + _viewportProjection.ProjectPoint(_gizmoCenter + Vector3.Up, out var yProjected); + _viewportProjection.ProjectPoint(_gizmoCenter + Vector3.Forward, out var zProjected); + _viewportProjection.ProjectPoint(_gizmoCenter - Vector3.Right, out var negXProjected); + _viewportProjection.ProjectPoint(_gizmoCenter - Vector3.Up, out var negYProjected); + _viewportProjection.ProjectPoint(_gizmoCenter - Vector3.Forward, out var negZProjected); + + // Normalize by viewport height to keep size independent of FOV and viewport dimensions + float heightNormalization = _viewport.Height / 720.0f; // 720 = reference height + + Float2 xDelta = (xProjected - gizmoCenterScreen) / heightNormalization; + Float2 yDelta = (yProjected - gizmoCenterScreen) / heightNormalization; + Float2 zDelta = (zProjected - gizmoCenterScreen) / heightNormalization; + Float2 negXDelta = (negXProjected - gizmoCenterScreen) / heightNormalization; + Float2 negYDelta = (negYProjected - gizmoCenterScreen) / heightNormalization; + Float2 negZDelta = (negZProjected - gizmoCenterScreen) / heightNormalization; + + // Calculate distances from camera to determine draw order + Vector3 cameraPosition = _viewport.Task.View.Position; + float xDistance = Vector3.Distance(cameraPosition, _gizmoCenter + Vector3.Right); + float yDistance = Vector3.Distance(cameraPosition, _gizmoCenter + Vector3.Up); + float zDistance = Vector3.Distance(cameraPosition, _gizmoCenter + Vector3.Forward); + float negXDistance = Vector3.Distance(cameraPosition, _gizmoCenter - Vector3.Right); + float negYDistance = Vector3.Distance(cameraPosition, _gizmoCenter - Vector3.Up); + float negZDistance = Vector3.Distance(cameraPosition, _gizmoCenter - Vector3.Forward); + + _xAxisData.Delta = xDelta; + _xAxisData.Distance = xDistance; + _yAxisData.Delta = yDelta; + _yAxisData.Distance = yDistance; + _zAxisData.Delta = zDelta; + _zAxisData.Distance = zDistance; + _negXAxisData.Delta = negXDelta; + _negXAxisData.Distance = negXDistance; + _negYAxisData.Delta = negYDelta; + _negYAxisData.Distance = negYDistance; + _negZAxisData.Delta = negZDelta; + _negZAxisData.Distance = negZDistance; + + // Sort for correct draw order. + _axisData.Clear(); + _axisData.AddRange([_xAxisData, _yAxisData, _zAxisData, _negXAxisData, _negYAxisData, _negZAxisData]); + _axisData.Sort( (a, b) => -a.Distance.CompareTo(b.Distance)); + + // Draw in order from farthest to closest + foreach (var axis in _axisData) + { + Float2 tipScreen = relativeCenter + axis.Delta * _axisLength; + Float2 tipTextScreen = relativeCenter + axis.Delta * _textAxisLength; + + if (!axis.Negative) + { + Render2D.DrawLine(relativeCenter, tipScreen, axis.AxisColor, 2.0f); + Render2D.DrawSprite(_posHandle, new Rectangle(tipTextScreen - new Float2(12, 12), new Float2(24, 24)), axis.AxisColor); + var font = _fontReference.GetFont(); + Render2D.DrawText(font, axis.Label, Color.Black, tipTextScreen - font.MeasureText(axis.Label) * 0.5f); + } + else + { + Render2D.DrawSprite(_posHandle, new Rectangle(tipTextScreen - new Float2(12, 12), new Float2(24, 24)), axis.AxisColor.RGBMultiplied(0.65f)); + Render2D.DrawSprite(_negHandle, new Rectangle(tipTextScreen - new Float2(12, 12), new Float2(24, 24)), axis.AxisColor); + } + } + } +} diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index 5343a1fe5..cd4b15799 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -107,6 +107,7 @@ namespace FlaxEditor.Viewport private readonly ViewportDebugDrawData _debugDrawData = new ViewportDebugDrawData(32); private EditorSpritesRenderer _editorSpritesRenderer; private ViewportRubberBandSelector _rubberBandSelector; + private DirectionGizmo _directionGizmo; /// /// Drag and drop handlers @@ -216,6 +217,7 @@ namespace FlaxEditor.Viewport // Add rubber band selector _rubberBandSelector = new ViewportRubberBandSelector(this); + _directionGizmo = new DirectionGizmo(this); // Add grid Grid = new GridGizmo(this); @@ -593,6 +595,7 @@ namespace FlaxEditor.Viewport // Draw rubber band for rectangle selection _rubberBandSelector.Draw(); + _directionGizmo.Draw(); } /// From 56e6df261d37c7adb71973d50d6dc7b0632efdc9 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Mon, 15 Dec 2025 21:22:11 -0600 Subject: [PATCH 2/8] Add hovering and selecting. --- Source/Editor/Gizmo/DirectionGizmo.cs | 113 ++++++++++++++++-- .../Viewport/MainEditorGizmoViewport.cs | 5 + 2 files changed, 108 insertions(+), 10 deletions(-) diff --git a/Source/Editor/Gizmo/DirectionGizmo.cs b/Source/Editor/Gizmo/DirectionGizmo.cs index 17e94564c..bfe2ebab9 100644 --- a/Source/Editor/Gizmo/DirectionGizmo.cs +++ b/Source/Editor/Gizmo/DirectionGizmo.cs @@ -12,8 +12,9 @@ public class DirectionGizmo private ViewportProjection _viewportProjection; private EditorViewport _viewport; private Vector3 _gizmoCenter; - private float _axisLength = 70.0f; - private float _textAxisLength = 85.0f; + private float _axisLength = 75.0f; + private float _textAxisLength = 95.0f; + private float _spriteRadius = 12.0f; private AxisData _xAxisData; private AxisData _yAxisData; @@ -23,11 +24,15 @@ public class DirectionGizmo private AxisData _negZAxisData; private List _axisData = new List(); + private int _hoveredAxisIndex = -1; private SpriteHandle _posHandle; private SpriteHandle _negHandle; private FontReference _fontReference; + + // Store sprite positions for hover detection + private List<(Float2 position, AxisDirection direction)> _spritePositions = new List<(Float2, AxisDirection)>(); private struct ViewportProjection { @@ -60,6 +65,17 @@ public class DirectionGizmo public string Label; public Color AxisColor; public bool Negative; + public AxisDirection Direction; + } + + private enum AxisDirection + { + PosX, + PosY, + PosZ, + NegX, + NegY, + NegZ } /// @@ -72,13 +88,13 @@ public class DirectionGizmo _viewport = owner.Viewport; _viewportProjection.Init(owner.Viewport); - _xAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "X", AxisColor = new Color(1.0f, 0.0f, 0.02745f, 1.0f), Negative = false }; - _yAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "Y", AxisColor = new Color(0.239215f, 1.0f, 0.047058f, 1.0f), Negative = false }; - _zAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "Z", AxisColor = new Color(0.0f, 0.0235294f, 1.0f, 1.0f), Negative = false }; + _xAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "X", AxisColor = new Color(1.0f, 0.0f, 0.02745f, 1.0f), Negative = false, Direction = AxisDirection.PosX }; + _yAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "Y", AxisColor = new Color(0.239215f, 1.0f, 0.047058f, 1.0f), Negative = false, Direction = AxisDirection.PosY }; + _zAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "Z", AxisColor = new Color(0.0f, 0.0235294f, 1.0f, 1.0f), Negative = false, Direction = AxisDirection.PosZ }; - _negXAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "-X", AxisColor = new Color(1.0f, 0.0f, 0.02745f, 1.0f), Negative = true }; - _negYAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "-Y", AxisColor = new Color(0.239215f, 1.0f, 0.047058f, 1.0f), Negative = true }; - _negZAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "-Z", AxisColor = new Color(0.0f, 0.0235294f, 1.0f, 1.0f), Negative = true }; + _negXAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "-X", AxisColor = new Color(1.0f, 0.0f, 0.02745f, 1.0f), Negative = true, Direction = AxisDirection.NegX }; + _negYAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "-Y", AxisColor = new Color(0.239215f, 1.0f, 0.047058f, 1.0f), Negative = true, Direction = AxisDirection.NegY }; + _negZAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "-Z", AxisColor = new Color(0.0f, 0.0235294f, 1.0f, 1.0f), Negative = true, Direction = AxisDirection.NegZ }; _axisData.EnsureCapacity(6); _posHandle = Editor.Instance.Icons.VisjectBoxClosed32; @@ -87,6 +103,66 @@ public class DirectionGizmo _fontReference = new FontReference(Style.Current.FontSmall); _fontReference.Size = 8; } + + private bool IsPointInSprite(Float2 point, Float2 spriteCenter) + { + Float2 delta = point - spriteCenter; + float distanceSq = delta.LengthSquared; + float radiusSq = _spriteRadius * _spriteRadius; + return distanceSq <= radiusSq; + } + + /// + /// Updates the gizmo for mouse interactions (hover and click detection). + /// + public void Update(Float2 mousePos) + { + _hoveredAxisIndex = -1; + + // Check which axis is being hovered - check from end (closest) to start (farthest) for proper layering + for (int i = _spritePositions.Count - 1; i >= 0; i--) + { + if (IsPointInSprite(mousePos, _spritePositions[i].position)) + { + _hoveredAxisIndex = i; + break; + } + } + } + + /// + /// Handles mouse click on direction gizmo sprites. + /// + public bool OnMouseDown(Float2 mousePos) + { + // Check which axis is being clicked - check from end (closest) to start (farthest) for proper layering + for (int i = _spritePositions.Count - 1; i >= 0; i--) + { + if (IsPointInSprite(mousePos, _spritePositions[i].position)) + { + OrientViewToAxis(_spritePositions[i].direction); + return true; + } + } + + return false; + } + + private void OrientViewToAxis(AxisDirection direction) + { + Quaternion orientation = direction switch + { + AxisDirection.PosX => Quaternion.Euler(0, 90, 0), + AxisDirection.NegX => Quaternion.Euler(0, -90, 0), + AxisDirection.PosY => Quaternion.Euler(-90, 0, 0), + AxisDirection.NegY => Quaternion.Euler(90, 0, 0), + AxisDirection.PosZ => Quaternion.Euler(0, 0, 0), + AxisDirection.NegZ => Quaternion.Euler(0, 180, 0), + _ => Quaternion.Identity + }; + + _viewport.ViewOrientation = orientation; + } /// /// Used to Draw the gizmo. @@ -144,24 +220,41 @@ public class DirectionGizmo _axisData.Clear(); _axisData.AddRange([_xAxisData, _yAxisData, _zAxisData, _negXAxisData, _negYAxisData, _negZAxisData]); _axisData.Sort( (a, b) => -a.Distance.CompareTo(b.Distance)); + + // Rebuild sprite positions list for hover detection + _spritePositions.Clear(); // Draw in order from farthest to closest - foreach (var axis in _axisData) + for (int i = 0; i < _axisData.Count; i++) { + var axis = _axisData[i]; Float2 tipScreen = relativeCenter + axis.Delta * _axisLength; Float2 tipTextScreen = relativeCenter + axis.Delta * _textAxisLength; + bool isHovered = _hoveredAxisIndex == i; + + // Store sprite position for hover detection + _spritePositions.Add((tipTextScreen, axis.Direction)); if (!axis.Negative) { Render2D.DrawLine(relativeCenter, tipScreen, axis.AxisColor, 2.0f); Render2D.DrawSprite(_posHandle, new Rectangle(tipTextScreen - new Float2(12, 12), new Float2(24, 24)), axis.AxisColor); + var font = _fontReference.GetFont(); - Render2D.DrawText(font, axis.Label, Color.Black, tipTextScreen - font.MeasureText(axis.Label) * 0.5f); + Color textColor = isHovered ? Color.White : Color.Black; + Render2D.DrawText(font, axis.Label, textColor, tipTextScreen - font.MeasureText(axis.Label) * 0.5f); } else { Render2D.DrawSprite(_posHandle, new Rectangle(tipTextScreen - new Float2(12, 12), new Float2(24, 24)), axis.AxisColor.RGBMultiplied(0.65f)); Render2D.DrawSprite(_negHandle, new Rectangle(tipTextScreen - new Float2(12, 12), new Float2(24, 24)), axis.AxisColor); + + // Draw white label text on hover for negative axes + if (isHovered) + { + var font = _fontReference.GetFont(); + Render2D.DrawText(font, axis.Label, Color.White, tipTextScreen - font.MeasureText(axis.Label) * 0.5f); + } } } } diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index cd4b15799..b5232c7e4 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -612,6 +612,8 @@ namespace FlaxEditor.Viewport { base.OnMouseMove(location); + _directionGizmo.Update(location); + // Don't allow rubber band selection when gizmo is controlling mouse, vertex painting mode, or cloth painting is enabled bool canStart = !(IsControllingMouse || IsRightMouseButtonDown || IsAltKeyDown) && Gizmos?.Active is TransformGizmo && !Gizmos.Active.IsControllingMouse; @@ -622,6 +624,9 @@ namespace FlaxEditor.Viewport protected override void OnLeftMouseButtonDown() { base.OnLeftMouseButtonDown(); + + if (_directionGizmo.OnMouseDown(_viewMousePos)) + return; _rubberBandSelector.TryStartingRubberBandSelection(); } From d671f57952ed9279961b0b6fc5ff1a0fec250ea1 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Mon, 15 Dec 2025 21:41:45 -0600 Subject: [PATCH 3/8] Change to container control for anchoring. --- Source/Editor/Gizmo/DirectionGizmo.cs | 43 +++++++++++-------- .../Viewport/MainEditorGizmoViewport.cs | 10 ++--- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/Source/Editor/Gizmo/DirectionGizmo.cs b/Source/Editor/Gizmo/DirectionGizmo.cs index bfe2ebab9..350c3be5c 100644 --- a/Source/Editor/Gizmo/DirectionGizmo.cs +++ b/Source/Editor/Gizmo/DirectionGizmo.cs @@ -6,7 +6,7 @@ using FlaxEngine.GUI; namespace FlaxEditor.Gizmo; -public class DirectionGizmo +public class DirectionGizmo : ContainerControl { private IGizmoOwner _owner; private ViewportProjection _viewportProjection; @@ -33,7 +33,7 @@ public class DirectionGizmo // Store sprite positions for hover detection private List<(Float2 position, AxisDirection direction)> _spritePositions = new List<(Float2, AxisDirection)>(); - + private struct ViewportProjection { private Matrix _viewProjection; @@ -112,33 +112,40 @@ public class DirectionGizmo return distanceSq <= radiusSq; } - /// - /// Updates the gizmo for mouse interactions (hover and click detection). - /// - public void Update(Float2 mousePos) + /// + public override void OnMouseMove(Float2 location) { _hoveredAxisIndex = -1; + // Convert local control space to screen space + Float2 viewportLocation = PointToParent(ref location); + // Check which axis is being hovered - check from end (closest) to start (farthest) for proper layering for (int i = _spritePositions.Count - 1; i >= 0; i--) { - if (IsPointInSprite(mousePos, _spritePositions[i].position)) + if (IsPointInSprite(viewportLocation, _spritePositions[i].position)) { _hoveredAxisIndex = i; break; } } + + base.OnMouseMove(location); } - - /// - /// Handles mouse click on direction gizmo sprites. - /// - public bool OnMouseDown(Float2 mousePos) + + /// + public override bool OnMouseDown(Float2 location, MouseButton button) { + if (base.OnMouseDown(location, button)) + return true; + + // Convert local control space to screen space + Float2 viewportLocation = PointToParent(ref location); + // Check which axis is being clicked - check from end (closest) to start (farthest) for proper layering for (int i = _spritePositions.Count - 1; i >= 0; i--) { - if (IsPointInSprite(mousePos, _spritePositions[i].position)) + if (IsPointInSprite(viewportLocation, _spritePositions[i].position)) { OrientViewToAxis(_spritePositions[i].direction); return true; @@ -167,14 +174,16 @@ public class DirectionGizmo /// /// Used to Draw the gizmo. /// - public void Draw() + public override void DrawSelf() { + base.DrawSelf(); + _viewportProjection.Init(_owner.Viewport); _gizmoCenter = _viewport.Task.View.WorldPosition + _viewport.Task.View.Direction * 1500; _viewportProjection.ProjectPoint(_gizmoCenter, out var gizmoCenterScreen); - var bounds = _viewport.Bounds; - var screenLocation = bounds.Location - new Float2(-bounds.Width * 0.5f + 50, bounds.Height * 0.5f - 50); - var relativeCenter = gizmoCenterScreen - screenLocation; + + // Use the settable bounds instead of hardcoded positioning + var relativeCenter = Bounds.Location + Bounds.Size * 0.5f; // Project unit vectors _viewportProjection.ProjectPoint(_gizmoCenter + Vector3.Right, out var xProjected); diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index b5232c7e4..fccb7a79e 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -218,6 +218,11 @@ namespace FlaxEditor.Viewport // Add rubber band selector _rubberBandSelector = new ViewportRubberBandSelector(this); _directionGizmo = new DirectionGizmo(this); + _directionGizmo.Parent = this; + _directionGizmo.AnchorPreset = AnchorPresets.TopRight; + _directionGizmo.LocalY += 30; + _directionGizmo.LocalX -= 10; + _directionGizmo.Size = new Float2(100, 100); // Add grid Grid = new GridGizmo(this); @@ -612,8 +617,6 @@ namespace FlaxEditor.Viewport { base.OnMouseMove(location); - _directionGizmo.Update(location); - // Don't allow rubber band selection when gizmo is controlling mouse, vertex painting mode, or cloth painting is enabled bool canStart = !(IsControllingMouse || IsRightMouseButtonDown || IsAltKeyDown) && Gizmos?.Active is TransformGizmo && !Gizmos.Active.IsControllingMouse; @@ -624,9 +627,6 @@ namespace FlaxEditor.Viewport protected override void OnLeftMouseButtonDown() { base.OnLeftMouseButtonDown(); - - if (_directionGizmo.OnMouseDown(_viewMousePos)) - return; _rubberBandSelector.TryStartingRubberBandSelection(); } From 9708601d3b6d879e52207b5d71cb35d3951c8a51 Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Mon, 15 Dec 2025 21:46:03 -0600 Subject: [PATCH 4/8] Small cleanup. --- Source/Editor/Gizmo/DirectionGizmo.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/Editor/Gizmo/DirectionGizmo.cs b/Source/Editor/Gizmo/DirectionGizmo.cs index 350c3be5c..bb6823002 100644 --- a/Source/Editor/Gizmo/DirectionGizmo.cs +++ b/Source/Editor/Gizmo/DirectionGizmo.cs @@ -120,7 +120,7 @@ public class DirectionGizmo : ContainerControl // Convert local control space to screen space Float2 viewportLocation = PointToParent(ref location); - // Check which axis is being hovered - check from end (closest) to start (farthest) for proper layering + // Check which axis is being hovered - check from closest to farthest for proper layering for (int i = _spritePositions.Count - 1; i >= 0; i--) { if (IsPointInSprite(viewportLocation, _spritePositions[i].position)) @@ -142,7 +142,7 @@ public class DirectionGizmo : ContainerControl // Convert local control space to screen space Float2 viewportLocation = PointToParent(ref location); - // Check which axis is being clicked - check from end (closest) to start (farthest) for proper layering + // Check which axis is being clicked - check from closest to farthest for proper layering for (int i = _spritePositions.Count - 1; i >= 0; i--) { if (IsPointInSprite(viewportLocation, _spritePositions[i].position)) @@ -247,7 +247,7 @@ public class DirectionGizmo : ContainerControl if (!axis.Negative) { Render2D.DrawLine(relativeCenter, tipScreen, axis.AxisColor, 2.0f); - Render2D.DrawSprite(_posHandle, new Rectangle(tipTextScreen - new Float2(12, 12), new Float2(24, 24)), axis.AxisColor); + Render2D.DrawSprite(_posHandle, new Rectangle(tipTextScreen - new Float2(_spriteRadius), new Float2(_spriteRadius * 2)), axis.AxisColor); var font = _fontReference.GetFont(); Color textColor = isHovered ? Color.White : Color.Black; @@ -255,8 +255,8 @@ public class DirectionGizmo : ContainerControl } else { - Render2D.DrawSprite(_posHandle, new Rectangle(tipTextScreen - new Float2(12, 12), new Float2(24, 24)), axis.AxisColor.RGBMultiplied(0.65f)); - Render2D.DrawSprite(_negHandle, new Rectangle(tipTextScreen - new Float2(12, 12), new Float2(24, 24)), axis.AxisColor); + Render2D.DrawSprite(_posHandle, new Rectangle(tipTextScreen - new Float2(_spriteRadius), new Float2(_spriteRadius * 2)), axis.AxisColor.RGBMultiplied(0.65f)); + Render2D.DrawSprite(_negHandle, new Rectangle(tipTextScreen - new Float2(_spriteRadius), new Float2(_spriteRadius * 2)), axis.AxisColor); // Draw white label text on hover for negative axes if (isHovered) From b9f177d1ab17185f1ebf7ecee0bbcd8daeb1ae1b Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Tue, 16 Dec 2025 17:12:54 -0600 Subject: [PATCH 5/8] Add ensure capacity to lists. --- Source/Editor/Gizmo/DirectionGizmo.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Editor/Gizmo/DirectionGizmo.cs b/Source/Editor/Gizmo/DirectionGizmo.cs index bb6823002..1c0af3d70 100644 --- a/Source/Editor/Gizmo/DirectionGizmo.cs +++ b/Source/Editor/Gizmo/DirectionGizmo.cs @@ -96,6 +96,7 @@ public class DirectionGizmo : ContainerControl _negYAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "-Y", AxisColor = new Color(0.239215f, 1.0f, 0.047058f, 1.0f), Negative = true, Direction = AxisDirection.NegY }; _negZAxisData = new AxisData { Delta = new Float2(0, 0), Distance = 0, Label = "-Z", AxisColor = new Color(0.0f, 0.0235294f, 1.0f, 1.0f), Negative = true, Direction = AxisDirection.NegZ }; _axisData.EnsureCapacity(6); + _spritePositions.EnsureCapacity(6); _posHandle = Editor.Instance.Icons.VisjectBoxClosed32; _negHandle = Editor.Instance.Icons.VisjectBoxOpen32; From 2c5cc7fcc00d83fe165ef7ef09830571ee41cf8e Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Tue, 16 Dec 2025 17:32:35 -0600 Subject: [PATCH 6/8] Fix double drawing. --- Source/Editor/Gizmo/DirectionGizmo.cs | 22 +++++++------------ .../Viewport/MainEditorGizmoViewport.cs | 9 ++++---- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/Source/Editor/Gizmo/DirectionGizmo.cs b/Source/Editor/Gizmo/DirectionGizmo.cs index 1c0af3d70..082ceef0c 100644 --- a/Source/Editor/Gizmo/DirectionGizmo.cs +++ b/Source/Editor/Gizmo/DirectionGizmo.cs @@ -118,13 +118,10 @@ public class DirectionGizmo : ContainerControl { _hoveredAxisIndex = -1; - // Convert local control space to screen space - Float2 viewportLocation = PointToParent(ref location); - // Check which axis is being hovered - check from closest to farthest for proper layering for (int i = _spritePositions.Count - 1; i >= 0; i--) { - if (IsPointInSprite(viewportLocation, _spritePositions[i].position)) + if (IsPointInSprite(location, _spritePositions[i].position)) { _hoveredAxisIndex = i; break; @@ -140,13 +137,10 @@ public class DirectionGizmo : ContainerControl if (base.OnMouseDown(location, button)) return true; - // Convert local control space to screen space - Float2 viewportLocation = PointToParent(ref location); - // Check which axis is being clicked - check from closest to farthest for proper layering for (int i = _spritePositions.Count - 1; i >= 0; i--) { - if (IsPointInSprite(viewportLocation, _spritePositions[i].position)) + if (IsPointInSprite(location, _spritePositions[i].position)) { OrientViewToAxis(_spritePositions[i].direction); return true; @@ -182,9 +176,8 @@ public class DirectionGizmo : ContainerControl _viewportProjection.Init(_owner.Viewport); _gizmoCenter = _viewport.Task.View.WorldPosition + _viewport.Task.View.Direction * 1500; _viewportProjection.ProjectPoint(_gizmoCenter, out var gizmoCenterScreen); - - // Use the settable bounds instead of hardcoded positioning - var relativeCenter = Bounds.Location + Bounds.Size * 0.5f; + + var relativeCenter = Size * 0.5f; // Project unit vectors _viewportProjection.ProjectPoint(_gizmoCenter + Vector3.Right, out var xProjected); @@ -233,7 +226,9 @@ public class DirectionGizmo : ContainerControl // Rebuild sprite positions list for hover detection _spritePositions.Clear(); - + + Render2D.DrawSprite(_posHandle, new Rectangle(0, 0, Size), Color.Black.AlphaMultiplied(0.1f)); + // Draw in order from farthest to closest for (int i = 0; i < _axisData.Count; i++) { @@ -258,8 +253,7 @@ public class DirectionGizmo : ContainerControl { Render2D.DrawSprite(_posHandle, new Rectangle(tipTextScreen - new Float2(_spriteRadius), new Float2(_spriteRadius * 2)), axis.AxisColor.RGBMultiplied(0.65f)); Render2D.DrawSprite(_negHandle, new Rectangle(tipTextScreen - new Float2(_spriteRadius), new Float2(_spriteRadius * 2)), axis.AxisColor); - - // Draw white label text on hover for negative axes + if (isHovered) { var font = _fontReference.GetFont(); diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index fccb7a79e..86dba5947 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -218,11 +218,11 @@ namespace FlaxEditor.Viewport // Add rubber band selector _rubberBandSelector = new ViewportRubberBandSelector(this); _directionGizmo = new DirectionGizmo(this); - _directionGizmo.Parent = this; _directionGizmo.AnchorPreset = AnchorPresets.TopRight; - _directionGizmo.LocalY += 30; - _directionGizmo.LocalX -= 10; - _directionGizmo.Size = new Float2(100, 100); + _directionGizmo.Parent = this; + _directionGizmo.LocalY += 25; + _directionGizmo.LocalX -= 150; + _directionGizmo.Size = new Float2(150, 150); // Add grid Grid = new GridGizmo(this); @@ -600,7 +600,6 @@ namespace FlaxEditor.Viewport // Draw rubber band for rectangle selection _rubberBandSelector.Draw(); - _directionGizmo.Draw(); } /// From 1b9f6ed20f81a9b046336e72acb1e5feaf8efdeb Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Tue, 16 Dec 2025 18:16:58 -0600 Subject: [PATCH 7/8] Fix large world build. --- Source/Editor/Gizmo/DirectionGizmo.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Editor/Gizmo/DirectionGizmo.cs b/Source/Editor/Gizmo/DirectionGizmo.cs index 082ceef0c..c9089e5fc 100644 --- a/Source/Editor/Gizmo/DirectionGizmo.cs +++ b/Source/Editor/Gizmo/DirectionGizmo.cs @@ -199,12 +199,12 @@ public class DirectionGizmo : ContainerControl // Calculate distances from camera to determine draw order Vector3 cameraPosition = _viewport.Task.View.Position; - float xDistance = Vector3.Distance(cameraPosition, _gizmoCenter + Vector3.Right); - float yDistance = Vector3.Distance(cameraPosition, _gizmoCenter + Vector3.Up); - float zDistance = Vector3.Distance(cameraPosition, _gizmoCenter + Vector3.Forward); - float negXDistance = Vector3.Distance(cameraPosition, _gizmoCenter - Vector3.Right); - float negYDistance = Vector3.Distance(cameraPosition, _gizmoCenter - Vector3.Up); - float negZDistance = Vector3.Distance(cameraPosition, _gizmoCenter - Vector3.Forward); + float xDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter + Vector3.Right); + float yDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter + Vector3.Up); + float zDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter + Vector3.Forward); + float negXDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter - Vector3.Right); + float negYDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter - Vector3.Up); + float negZDistance = (float)Vector3.Distance(cameraPosition, _gizmoCenter - Vector3.Forward); _xAxisData.Delta = xDelta; _xAxisData.Distance = xDistance; From 37e776e407dbbe4e05052803bbc5c493a78127ff Mon Sep 17 00:00:00 2001 From: Chandler Cox Date: Fri, 6 Feb 2026 21:56:25 -0600 Subject: [PATCH 8/8] Add HideInEditor attribute to DirectionGizmo --- Source/Editor/Gizmo/DirectionGizmo.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Editor/Gizmo/DirectionGizmo.cs b/Source/Editor/Gizmo/DirectionGizmo.cs index c9089e5fc..176832c5e 100644 --- a/Source/Editor/Gizmo/DirectionGizmo.cs +++ b/Source/Editor/Gizmo/DirectionGizmo.cs @@ -6,6 +6,7 @@ using FlaxEngine.GUI; namespace FlaxEditor.Gizmo; +[HideInEditor] public class DirectionGizmo : ContainerControl { private IGizmoOwner _owner;