diff --git a/Source/Engine/UI/GUI/CanvasContainer.cs b/Source/Engine/UI/GUI/CanvasContainer.cs index d85ed37a8..f032a99d3 100644 --- a/Source/Engine/UI/GUI/CanvasContainer.cs +++ b/Source/Engine/UI/GUI/CanvasContainer.cs @@ -29,34 +29,6 @@ namespace FlaxEngine.GUI return ((CanvasRootControl)a).Canvas.Order - ((CanvasRootControl)b).Canvas.Order; } - private bool IntersectsChildContent(CanvasRootControl child, ref Ray ray, out Float2 childSpaceLocation) - { - // Inline bounds calculations (it will reuse world matrix) - var bounds = new OrientedBoundingBox - { - Extents = new Vector3(child.Size * 0.5f, Mathf.Epsilon) - }; - - child.Canvas.GetWorldMatrix(out var world); - Matrix.Translation((float)bounds.Extents.X, (float)bounds.Extents.Y, 0, out var offset); - Matrix.Multiply(ref offset, ref world, out var boxWorld); - boxWorld.Decompose(out bounds.Transformation); - - // Hit test - if (bounds.Intersects(ref ray, out Vector3 hitPoint)) - { - // Transform world-space hit point to canvas local-space - world.Invert(); - Vector3.Transform(ref hitPoint, ref world, out Vector3 localHitPoint); - - childSpaceLocation = new Float2(localHitPoint); - return child.ContainsPoint(ref childSpaceLocation); - } - - childSpaceLocation = Float2.Zero; - return false; - } - /// public override void OnChildrenChanged() { @@ -102,7 +74,7 @@ namespace FlaxEngine.GUI var child = (CanvasRootControl)_children[i]; if (child.Visible && child.Enabled && child.Is3D) { - if (IntersectsChildContent(child, ref ray, out var childLocation)) + if (child.Intersects3D(ref ray, out var childLocation)) { child.OnMouseEnter(childLocation); return; @@ -148,7 +120,7 @@ namespace FlaxEngine.GUI } else { - if (!isFirst3DHandled && IntersectsChildContent(child, ref ray, out var childLocation)) + if (!isFirst3DHandled && child.Intersects3D(ref ray, out var childLocation)) { isFirst3DHandled = true; @@ -189,7 +161,7 @@ namespace FlaxEngine.GUI var child = (CanvasRootControl)_children[i]; if (child.Visible && child.Enabled && child.Is3D) { - if (IntersectsChildContent(child, ref ray, out var childLocation)) + if (child.Intersects3D(ref ray, out var childLocation)) { child.OnMouseWheel(childLocation, delta); return true; @@ -216,7 +188,7 @@ namespace FlaxEngine.GUI var child = (CanvasRootControl)_children[i]; if (child.Visible && child.Enabled && child.Is3D) { - if (IntersectsChildContent(child, ref ray, out var childLocation)) + if (child.Intersects3D(ref ray, out var childLocation)) { child.OnMouseDown(childLocation, button); return true; @@ -243,7 +215,7 @@ namespace FlaxEngine.GUI var child = (CanvasRootControl)_children[i]; if (child.Visible && child.Enabled && child.Is3D) { - if (IntersectsChildContent(child, ref ray, out var childLocation)) + if (child.Intersects3D(ref ray, out var childLocation)) { child.OnMouseUp(childLocation, button); return true; @@ -270,7 +242,7 @@ namespace FlaxEngine.GUI var child = (CanvasRootControl)_children[i]; if (child.Visible && child.Enabled && child.Is3D) { - if (IntersectsChildContent(child, ref ray, out var childLocation)) + if (child.Intersects3D(ref ray, out var childLocation)) { child.OnMouseDoubleClick(childLocation, button); return true; diff --git a/Source/Engine/UI/GUI/CanvasRootControl.cs b/Source/Engine/UI/GUI/CanvasRootControl.cs index a3d099eee..408c46b0f 100644 --- a/Source/Engine/UI/GUI/CanvasRootControl.cs +++ b/Source/Engine/UI/GUI/CanvasRootControl.cs @@ -40,6 +40,40 @@ namespace FlaxEngine.GUI _canvas = canvas; } + /// + /// Checks if the 3D canvas intersects with a given 3D mouse ray. + /// + /// The input ray to test (in world-space). + /// Output canvas-space local position. + /// True if canvas intersects with that point, otherwise false. + public bool Intersects3D(ref Ray ray, out Float2 canvasLocation) + { + // Inline bounds calculations (it will reuse world matrix) + var bounds = new OrientedBoundingBox + { + Extents = new Vector3(Size * 0.5f, Mathf.Epsilon) + }; + + _canvas.GetWorldMatrix(out var world); + Matrix.Translation((float)bounds.Extents.X, (float)bounds.Extents.Y, 0, out var offset); + Matrix.Multiply(ref offset, ref world, out var boxWorld); + boxWorld.Decompose(out bounds.Transformation); + + // Hit test + if (bounds.Intersects(ref ray, out Vector3 hitPoint)) + { + // Transform world-space hit point to canvas local-space + world.Invert(); + Vector3.Transform(ref hitPoint, ref world, out Vector3 localHitPoint); + + canvasLocation = new Float2(localHitPoint); + return ContainsPoint(ref canvasLocation); + } + + canvasLocation = Float2.Zero; + return false; + } + /// public override CursorType Cursor { @@ -136,6 +170,22 @@ namespace FlaxEngine.GUI return location; } + /// + public override Float2 PointFromParent(ref Float2 locationParent) + { + if (Is2D) + return base.PointFromParent(ref locationParent); + + var camera = Camera.MainCamera; + if (!camera) + return locationParent; + + // Use world-space ray to convert it to the local-space of the canvas + UICanvas.CalculateRay(ref locationParent, out Ray ray); + Intersects3D(ref ray, out var location); + return location; + } + /// public override bool ContainsPoint(ref Float2 location) {