diff --git a/Source/Editor/Windows/GameWindow.cs b/Source/Editor/Windows/GameWindow.cs index 7b815bc98..46c0f33f4 100644 --- a/Source/Editor/Windows/GameWindow.cs +++ b/Source/Editor/Windows/GameWindow.cs @@ -818,19 +818,21 @@ namespace FlaxEditor.Windows // Selected UI controls outline bool drawAnySelectedControl = false; // TODO: optimize this (eg. cache list of selected UIControl's when selection gets changed) - for (var i = 0; i < Editor.Instance.SceneEditing.Selection.Count; i++) + var selection = Editor.SceneEditing.Selection; + for (var i = 0; i < selection.Count; i++) { - if (Editor.Instance.SceneEditing.Selection[i].EditableObject is UIControl controlActor && controlActor && controlActor.Control != null) + if (selection[i].EditableObject is UIControl controlActor && controlActor && controlActor.Control != null) { if (!drawAnySelectedControl) { drawAnySelectedControl = true; Render2D.PushTransform(ref _viewport._cachedTransform); } + var options = Editor.Options.Options.Visual; var control = controlActor.Control; var bounds = control.EditorBounds; bounds = Rectangle.FromPoints(control.PointToParent(_viewport, bounds.Location), control.PointToParent(_viewport, bounds.Size)); - Render2D.DrawRectangle(bounds, Editor.Instance.Options.Options.Visual.SelectionOutlineColor0, Editor.Instance.Options.Options.Visual.UISelectionOutlineSize); + Render2D.DrawRectangle(bounds, options.SelectionOutlineColor0, options.UISelectionOutlineSize); } } if (drawAnySelectedControl) @@ -863,7 +865,7 @@ namespace FlaxEditor.Windows } // Add overlay during debugger breakpoint hang - if (Editor.Instance.Simulation.IsDuringBreakpointHang) + if (Editor.Simulation.IsDuringBreakpointHang) { var bounds = new Rectangle(Float2.Zero, Size); Render2D.FillRectangle(bounds, new Color(0.0f, 0.0f, 0.0f, 0.2f)); diff --git a/Source/Engine/Graphics/Enums.h b/Source/Engine/Graphics/Enums.h index 7d9b5ceb3..3ef462925 100644 --- a/Source/Engine/Graphics/Enums.h +++ b/Source/Engine/Graphics/Enums.h @@ -360,7 +360,7 @@ API_ENUM() enum class CullMode : byte /// /// Render target blending mode descriptor. /// -API_STRUCT() struct BlendingMode +API_STRUCT() struct FLAXENGINE_API BlendingMode { DECLARE_SCRIPTING_TYPE_MINIMAL(BlendingMode); diff --git a/Source/Engine/Graphics/GPUPipelineState.h b/Source/Engine/Graphics/GPUPipelineState.h index 647d8da04..725b1bb74 100644 --- a/Source/Engine/Graphics/GPUPipelineState.h +++ b/Source/Engine/Graphics/GPUPipelineState.h @@ -20,7 +20,7 @@ public: /// /// Pipeline state description /// - API_STRUCT() struct Description + API_STRUCT() struct FLAXENGINE_API Description { DECLARE_SCRIPTING_TYPE_NO_SPAWN(Description); diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp index 1f833933a..10e60aebc 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp @@ -221,15 +221,6 @@ GPUDevice* GPUDeviceDX11::Create() Delete(device); return nullptr; } - -#if PLATFORM_WINDOWS - if (dxgiFactory6 != nullptr) - dxgiFactory6->Release(); - else -#endif - { - dxgiFactory->Release(); - } return device; } diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp index ce6016b33..047b69bb5 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp @@ -202,15 +202,6 @@ GPUDevice* GPUDeviceDX12::Create() return nullptr; } -#if !(PLATFORM_XBOX_SCARLETT || PLATFORM_XBOX_ONE) - if (dxgiFactory6 != nullptr) - dxgiFactory6->Release(); - else -#endif - { - dxgiFactory->Release(); - } - return device; } diff --git a/Source/Engine/Level/Actors/Camera.cpp b/Source/Engine/Level/Actors/Camera.cpp index ea161c38a..f2625ca3b 100644 --- a/Source/Engine/Level/Actors/Camera.cpp +++ b/Source/Engine/Level/Actors/Camera.cpp @@ -46,6 +46,11 @@ Camera::Camera(const SpawnParams& params) #endif } +bool Camera::GetUsePerspective() const +{ + return _usePerspective; +} + void Camera::SetUsePerspective(bool value) { if (_usePerspective != value) @@ -55,6 +60,11 @@ void Camera::SetUsePerspective(bool value) } } +float Camera::GetFieldOfView() const +{ + return _fov; +} + void Camera::SetFieldOfView(float value) { value = Math::Clamp(value, 1.0f, 179.9f); @@ -65,16 +75,26 @@ void Camera::SetFieldOfView(float value) } } +float Camera::GetCustomAspectRatio() const +{ + return _customAspectRatio; +} + void Camera::SetCustomAspectRatio(float value) { value = Math::Clamp(value, 0.0f, 100.0f); - if (_customAspectRatio != value) + if (Math::NotNearEqual(_customAspectRatio, value)) { _customAspectRatio = value; UpdateCache(); } } +float Camera::GetNearPlane() const +{ + return _near; +} + void Camera::SetNearPlane(float value) { value = Math::Clamp(value, 0.001f, _far - 1.0f); @@ -85,6 +105,11 @@ void Camera::SetNearPlane(float value) } } +float Camera::GetFarPlane() const +{ + return _far; +} + void Camera::SetFarPlane(float value) { value = Math::Max(value, _near + 1.0f); @@ -95,6 +120,11 @@ void Camera::SetFarPlane(float value) } } +float Camera::GetOrthographicScale() const +{ + return _orthoScale; +} + void Camera::SetOrthographicScale(float value) { value = Math::Clamp(value, 0.0001f, 1000000.0f); @@ -121,6 +151,20 @@ void Camera::ProjectPoint(const Vector3& worldSpaceLocation, Float2& cameraViewp cameraViewportSpaceLocation = Float2(clipSpaceLocation); } +void Camera::UnprojectPoint(const Float2& gameWindowSpaceLocation, float depth, Vector3& worldSpaceLocation) const +{ + UnprojectPoint(gameWindowSpaceLocation, depth, worldSpaceLocation, GetViewport()); +} + +void Camera::UnprojectPoint(const Float2& cameraViewportSpaceLocation, float depth, Vector3& worldSpaceLocation, const Viewport& viewport) const +{ + Matrix v, p, ivp; + GetMatrices(v, p, viewport); + Matrix::Multiply(v, p, ivp); + ivp.Invert(); + viewport.Unproject(Vector3(cameraViewportSpaceLocation, depth), ivp, worldSpaceLocation); +} + bool Camera::IsPointOnView(const Vector3& worldSpaceLocation) const { Vector3 cameraUp = GetTransform().GetUp(); @@ -191,7 +235,7 @@ Viewport Camera::GetViewport() const if (Editor::Managed) result.Size = Editor::Managed->GetGameWindowSize(); #else - // game + // Game auto mainWin = Engine::MainWindow; if (mainWin) { @@ -201,7 +245,7 @@ Viewport Camera::GetViewport() const #endif // Fallback to the default value - if (result.Width <= ZeroTolerance) + if (result.Size.MinValue() <= ZeroTolerance) result.Size = Float2(1280, 720); return result; diff --git a/Source/Engine/Level/Actors/Camera.h b/Source/Engine/Level/Actors/Camera.h index 806cdcfbb..5a0bece33 100644 --- a/Source/Engine/Level/Actors/Camera.h +++ b/Source/Engine/Level/Actors/Camera.h @@ -66,10 +66,7 @@ public: /// Gets the value indicating if camera should use perspective rendering mode, otherwise it will use orthographic projection. /// API_PROPERTY(Attributes="EditorOrder(20), DefaultValue(true), EditorDisplay(\"Camera\"), Tooltip(\"Enables perspective projection mode, otherwise uses orthographic.\")") - FORCE_INLINE bool GetUsePerspective() const - { - return _usePerspective; - } + bool GetUsePerspective() const; /// /// Sets the value indicating if camera should use perspective rendering mode, otherwise it will use orthographic projection. @@ -80,10 +77,7 @@ public: /// Gets the camera's field of view (in degrees). /// API_PROPERTY(Attributes="EditorOrder(10), DefaultValue(60.0f), Limit(0, 179), EditorDisplay(\"Camera\", \"Field Of View\"), Tooltip(\"Field of view angle in degrees.\")") - FORCE_INLINE float GetFieldOfView() const - { - return _fov; - } + float GetFieldOfView() const; /// /// Sets camera's field of view (in degrees). @@ -94,10 +88,7 @@ public: /// Gets the custom aspect ratio. 0 if not use custom value. /// API_PROPERTY(Attributes="EditorOrder(50), DefaultValue(0.0f), Limit(0, 10, 0.01f), EditorDisplay(\"Camera\"), Tooltip(\"Custom aspect ratio to use. Set to 0 to disable.\")") - FORCE_INLINE float GetCustomAspectRatio() const - { - return _customAspectRatio; - } + float GetCustomAspectRatio() const; /// /// Sets the custom aspect ratio. 0 if not use custom value. @@ -108,10 +99,7 @@ public: /// Gets camera's near plane distance. /// API_PROPERTY(Attributes="EditorOrder(30), DefaultValue(10.0f), Limit(0, 1000, 0.05f), EditorDisplay(\"Camera\"), Tooltip(\"Near clipping plane distance\")") - FORCE_INLINE float GetNearPlane() const - { - return _near; - } + float GetNearPlane() const; /// /// Sets camera's near plane distance. @@ -122,10 +110,7 @@ public: /// Gets camera's far plane distance. /// API_PROPERTY(Attributes="EditorOrder(40), DefaultValue(40000.0f), Limit(0, float.MaxValue, 5), EditorDisplay(\"Camera\"), Tooltip(\"Far clipping plane distance\")") - FORCE_INLINE float GetFarPlane() const - { - return _far; - } + float GetFarPlane() const; /// /// Sets camera's far plane distance. @@ -136,10 +121,7 @@ public: /// Gets the orthographic projection scale. /// API_PROPERTY(Attributes="EditorOrder(60), DefaultValue(1.0f), Limit(0.0001f, 1000, 0.01f), EditorDisplay(\"Camera\"), Tooltip(\"Orthographic projection scale\")") - FORCE_INLINE float GetOrthographicScale() const - { - return _orthoScale; - } + float GetOrthographicScale() const; /// /// Sets the orthographic projection scale. @@ -168,6 +150,23 @@ public: /// The viewport. API_FUNCTION() void ProjectPoint(const Vector3& worldSpaceLocation, API_PARAM(Out) Float2& cameraViewportSpaceLocation, API_PARAM(Ref) const Viewport& viewport) const; + /// + /// Converts a game window-space point into a corresponding point in world space. + /// + /// The input game window coordinates (XY in screen pixels). + /// The input camera-relative depth position (eg. clipping plane). + /// The output world-space location (XYZ in world). + API_FUNCTION() void UnprojectPoint(const Float2& gameWindowSpaceLocation, float depth, API_PARAM(Out) Vector3& worldSpaceLocation) const; + + /// + /// Converts a camera viewport-space point into a corresponding point in world space. + /// + /// The input camera viewport-space location (XY in screen pixels). + /// The input camera-relative depth position (eg. clipping plane). + /// The output world-space location (XYZ in world). + /// The viewport. + API_FUNCTION() void UnprojectPoint(const Float2& cameraViewportSpaceLocation, float depth, API_PARAM(Out) Vector3& worldSpaceLocation, API_PARAM(Ref) const Viewport& viewport) const; + /// /// Checks if the 3d point of the world is in the camera's field of view. /// diff --git a/Source/Engine/Profiler/ProfilingTools.h b/Source/Engine/Profiler/ProfilingTools.h index 55e35e29c..e1c010d77 100644 --- a/Source/Engine/Profiler/ProfilingTools.h +++ b/Source/Engine/Profiler/ProfilingTools.h @@ -12,7 +12,7 @@ /// /// Profiler tools for development. Allows to gather profiling data and events from the engine. /// -API_CLASS(Static) class ProfilingTools +API_CLASS(Static) class FLAXENGINE_API ProfilingTools { DECLARE_SCRIPTING_TYPE_NO_SPAWN(ProfilingTools); public: 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) { diff --git a/Source/Engine/UI/GUI/CanvasScaler.cs b/Source/Engine/UI/GUI/CanvasScaler.cs index d86c868fc..94936c0e2 100644 --- a/Source/Engine/UI/GUI/CanvasScaler.cs +++ b/Source/Engine/UI/GUI/CanvasScaler.cs @@ -433,7 +433,7 @@ namespace FlaxEngine.GUI public override Float2 PointToParent(ref Float2 location) { var result = base.PointToParent(ref location); - result *= _scaleFactor; + result *= _scale; return result; } @@ -441,7 +441,7 @@ namespace FlaxEngine.GUI public override Float2 PointFromParent(ref Float2 location) { var result = base.PointFromParent(ref location); - result /= _scaleFactor; + result /= _scale; return result; } diff --git a/Source/Engine/UI/GUI/Control.Bounds.cs b/Source/Engine/UI/GUI/Control.Bounds.cs index 9d0dafeb7..428e485d8 100644 --- a/Source/Engine/UI/GUI/Control.Bounds.cs +++ b/Source/Engine/UI/GUI/Control.Bounds.cs @@ -105,7 +105,7 @@ namespace FlaxEngine.GUI /// /// Helper for Editor UI (see UIControlControlEditor). /// - [NoSerialize, HideInEditor] + [NoSerialize, HideInEditor, NoAnimate] internal float Proxy_Offset_Left { get => _offsets.Left; @@ -115,7 +115,7 @@ namespace FlaxEngine.GUI /// /// Helper for Editor UI (see UIControlControlEditor). /// - [NoSerialize, HideInEditor] + [NoSerialize, HideInEditor, NoAnimate] internal float Proxy_Offset_Right { get => _offsets.Right; @@ -125,7 +125,7 @@ namespace FlaxEngine.GUI /// /// Helper for Editor UI (see UIControlControlEditor). /// - [NoSerialize, HideInEditor] + [NoSerialize, HideInEditor, NoAnimate] internal float Proxy_Offset_Top { get => _offsets.Top; @@ -135,7 +135,7 @@ namespace FlaxEngine.GUI /// /// Helper for Editor UI (see UIControlControlEditor). /// - [NoSerialize, HideInEditor] + [NoSerialize, HideInEditor, NoAnimate] internal float Proxy_Offset_Bottom { get => _offsets.Bottom;