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;