From 85ab871d486da9729b13759dfbbb22996dcb909f Mon Sep 17 00:00:00 2001 From: stefnotch Date: Mon, 15 Mar 2021 15:40:32 +0100 Subject: [PATCH 01/76] Call the correct DPI getter See also https://github.com/FlaxEngine/FlaxEngine/pull/267 --- Source/Engine/UI/GUI/Common/RichTextBoxBase.cs | 12 ++++++------ Source/Engine/UI/GUI/Common/TextBox.cs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs index 5dcb25419..4844cc880 100644 --- a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs +++ b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs @@ -124,7 +124,7 @@ namespace FlaxEngine.GUI var font = textBlock.Style.Font.GetFont(); if (font) { - height = font.Height / Platform.DpiScale; + height = font.Height / RootWindow.DpiScale; return textBlock.Bounds.UpperLeft; } } @@ -136,7 +136,7 @@ namespace FlaxEngine.GUI var font = textBlock.Style.Font.GetFont(); if (font) { - height = font.Height / Platform.DpiScale; + height = font.Height / RootWindow.DpiScale; return textBlock.Bounds.UpperRight; } } @@ -151,7 +151,7 @@ namespace FlaxEngine.GUI var font = textBlock.Style.Font.GetFont(); if (!font) break; - height = font.Height / Platform.DpiScale; + height = font.Height / RootWindow.DpiScale; return textBlock.Bounds.Location + font.GetCharPosition(_text, ref textBlock.Range, index - textBlock.Range.StartIndex); } } @@ -166,7 +166,7 @@ namespace FlaxEngine.GUI var font = textBlock.Style.Font.GetFont(); if (!font) break; - height = font.Height / Platform.DpiScale; + height = font.Height / RootWindow.DpiScale; return textBlock.Bounds.UpperRight; } } @@ -280,7 +280,7 @@ namespace FlaxEngine.GUI { Vector2 leftEdge = selection.StartIndex <= textBlock.Range.StartIndex ? textBlock.Bounds.UpperLeft : font.GetCharPosition(_text, selection.StartIndex); Vector2 rightEdge = selection.EndIndex >= textBlock.Range.EndIndex ? textBlock.Bounds.UpperRight : font.GetCharPosition(_text, selection.EndIndex); - float height = font.Height / Platform.DpiScale; + float height = font.Height / RootWindow.DpiScale; float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f); alpha *= alpha; Color selectionColor = Color.White * alpha; @@ -330,7 +330,7 @@ namespace FlaxEngine.GUI if (textBlock.Style.UnderlineBrush != null) { var underLineHeight = 2.0f; - var height = font.Height / Platform.DpiScale; + var height = font.Height / RootWindow.DpiScale; var underlineRect = new Rectangle(textBlock.Bounds.Location.X, textBlock.Bounds.Location.Y + height - underLineHeight * 0.5f, textBlock.Bounds.Width, underLineHeight); textBlock.Style.UnderlineBrush.Draw(underlineRect, textBlock.Style.Color); } diff --git a/Source/Engine/UI/GUI/Common/TextBox.cs b/Source/Engine/UI/GUI/Common/TextBox.cs index b1b873f34..f454159ec 100644 --- a/Source/Engine/UI/GUI/Common/TextBox.cs +++ b/Source/Engine/UI/GUI/Common/TextBox.cs @@ -107,7 +107,7 @@ namespace FlaxEngine.GUI return Vector2.Zero; } - height = font.Height / Platform.DpiScale; + height = font.Height / RootWindow.DpiScale; return font.GetCharPosition(_text, index, ref _layout); } @@ -159,7 +159,7 @@ namespace FlaxEngine.GUI { Vector2 leftEdge = font.GetCharPosition(_text, SelectionLeft, ref _layout); Vector2 rightEdge = font.GetCharPosition(_text, SelectionRight, ref _layout); - float fontHeight = font.Height / Platform.DpiScale; + float fontHeight = font.Height / RootWindow.DpiScale; // Draw selection background float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f); From b151ab497f61b7cfaf6091f476a10ffb93474c40 Mon Sep 17 00:00:00 2001 From: stefnotch Date: Mon, 15 Mar 2021 17:30:35 +0100 Subject: [PATCH 02/76] Fix UICanvas high DPI issues --- Source/Engine/UI/UICanvas.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/UI/UICanvas.cs b/Source/Engine/UI/UICanvas.cs index 99bc35672..81b3e09dc 100644 --- a/Source/Engine/UI/UICanvas.cs +++ b/Source/Engine/UI/UICanvas.cs @@ -218,7 +218,7 @@ namespace FlaxEngine var camera = Camera.MainCamera; if (camera) { - ray = camera.ConvertMouseToRay(location); + ray = camera.ConvertMouseToRay(location * Platform.DpiScale); } else { From 97ab226d7e3923986588c0fdaf2e96711d84b210 Mon Sep 17 00:00:00 2001 From: stefnotch Date: Mon, 15 Mar 2021 20:18:13 +0100 Subject: [PATCH 03/76] Update Camera.ProjectPoint documentation to be clearer --- Source/Engine/Level/Actors/Camera.cpp | 8 ++++---- Source/Engine/Level/Actors/Camera.h | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Source/Engine/Level/Actors/Camera.cpp b/Source/Engine/Level/Actors/Camera.cpp index 95eebefc1..1f9de6d41 100644 --- a/Source/Engine/Level/Actors/Camera.cpp +++ b/Source/Engine/Level/Actors/Camera.cpp @@ -101,12 +101,12 @@ void Camera::SetOrthographicScale(float value) } } -void Camera::ProjectPoint(const Vector3& worldSpaceLocation, Vector2& screenSpaceLocation) const +void Camera::ProjectPoint(const Vector3& worldSpaceLocation, Vector2& gameWindowSpaceLocation) const { - ProjectPoint(worldSpaceLocation, screenSpaceLocation, GetViewport()); + ProjectPoint(worldSpaceLocation, gameWindowSpaceLocation, GetViewport()); } -void Camera::ProjectPoint(const Vector3& worldSpaceLocation, Vector2& screenSpaceLocation, const Viewport& viewport) const +void Camera::ProjectPoint(const Vector3& worldSpaceLocation, Vector2& cameraViewportSpaceLocation, const Viewport& viewport) const { Matrix v, p, vp; GetMatrices(v, p, viewport); @@ -114,7 +114,7 @@ void Camera::ProjectPoint(const Vector3& worldSpaceLocation, Vector2& screenSpac Vector3 clipSpaceLocation; Vector3::Transform(worldSpaceLocation, vp, clipSpaceLocation); viewport.Project(worldSpaceLocation, vp, clipSpaceLocation); - screenSpaceLocation = Vector2(clipSpaceLocation); + cameraViewportSpaceLocation = Vector2(clipSpaceLocation); } Ray Camera::ConvertMouseToRay(const Vector2& mousePosition) const diff --git a/Source/Engine/Level/Actors/Camera.h b/Source/Engine/Level/Actors/Camera.h index 7f40617dd..4bf277279 100644 --- a/Source/Engine/Level/Actors/Camera.h +++ b/Source/Engine/Level/Actors/Camera.h @@ -174,19 +174,19 @@ public: public: /// - /// Projects the point from 3D world-space to the camera screen-space (in screen pixels for default viewport calculated from ). + /// Projects the point from 3D world-space to game window coordinates (in screen pixels for default viewport calculated from ). /// /// The input world-space location (XYZ in world). - /// The output screen-space location (XY in screen pixels). - API_FUNCTION() void ProjectPoint(const Vector3& worldSpaceLocation, API_PARAM(Out) Vector2& screenSpaceLocation) const; + /// The output game window coordinates (XY in screen pixels). + API_FUNCTION() void ProjectPoint(const Vector3& worldSpaceLocation, API_PARAM(Out) Vector2& gameWindowSpaceLocation) const; /// - /// Projects the point from 3D world-space to the camera screen-space (in screen pixels for given viewport). + /// Projects the point from 3D world-space to the camera viewport-space (in screen pixels for given viewport). /// /// The input world-space location (XYZ in world). - /// The output screen-space location (XY in screen pixels). + /// The output camera viewport-space location (XY in screen pixels). /// The viewport. - API_FUNCTION() void ProjectPoint(const Vector3& worldSpaceLocation, API_PARAM(Out) Vector2& screenSpaceLocation, API_PARAM(Ref) const Viewport& viewport) const; + API_FUNCTION() void ProjectPoint(const Vector3& worldSpaceLocation, API_PARAM(Out) Vector2& cameraViewportSpaceLocation, API_PARAM(Ref) const Viewport& viewport) const; /// /// Converts the mouse position to 3D ray. From fb28cae2b4a4625eb75717efd035483a2dee21a2 Mon Sep 17 00:00:00 2001 From: stefnotch Date: Mon, 15 Mar 2021 20:18:39 +0100 Subject: [PATCH 04/76] Move ScreenToGameViewport from Engine to Screen And make it accessible from the C# side --- Source/Engine/Engine/Engine.cpp | 18 ------------------ Source/Engine/Engine/Engine.h | 14 -------------- Source/Engine/Engine/Screen.cpp | 18 ++++++++++++++++++ Source/Engine/Engine/Screen.h | 14 ++++++++++++++ Source/Engine/Input/Input.cpp | 4 ++-- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Source/Engine/Engine/Engine.cpp b/Source/Engine/Engine/Engine.cpp index 709997eac..979a2547b 100644 --- a/Source/Engine/Engine/Engine.cpp +++ b/Source/Engine/Engine/Engine.cpp @@ -413,24 +413,6 @@ bool Engine::HasGameViewportFocus() #endif } -Vector2 Engine::ScreenToGameViewport(const Vector2& screenPos) -{ -#if USE_EDITOR - return Editor::Managed->ScreenToGameViewport(screenPos); -#else - return MainWindow ? MainWindow->ScreenToClient(screenPos) : Vector2::Minimum; -#endif -} - -Vector2 Engine::GameViewportToScreen(const Vector2& viewportPos) -{ -#if USE_EDITOR - return Editor::Managed->GameViewportToScreen(viewportPos); -#else - return MainWindow ? MainWindow->ClientToScreen(viewportPos) : Vector2::Minimum; -#endif -} - void Engine::OnPause() { LOG(Info, "App paused"); diff --git a/Source/Engine/Engine/Engine.h b/Source/Engine/Engine/Engine.h index 22aeac9f0..13f3e1fe8 100644 --- a/Source/Engine/Engine/Engine.h +++ b/Source/Engine/Engine/Engine.h @@ -153,20 +153,6 @@ public: /// True if game viewport is focused, otherwise false. static bool HasGameViewportFocus(); - /// - /// Converts the screen-space position to the game viewport position. - /// - /// The screen-space position. - /// The game viewport position. - static Vector2 ScreenToGameViewport(const Vector2& screenPos); - - /// - /// Converts the game viewport position to the screen-space position. - /// - /// The game viewport position. - /// The screen-space position. - static Vector2 GameViewportToScreen(const Vector2& viewportPos); - private: static void OnPause(); diff --git a/Source/Engine/Engine/Screen.cpp b/Source/Engine/Engine/Screen.cpp index 999dc28cb..402e5e312 100644 --- a/Source/Engine/Engine/Screen.cpp +++ b/Source/Engine/Engine/Screen.cpp @@ -66,6 +66,24 @@ void Screen::SetSize(const Vector2& value) Size = value; } +Vector2 Screen::ScreenToGameViewport(const Vector2& screenPos) +{ +#if USE_EDITOR + return Editor::Managed->ScreenToGameViewport(screenPos); +#else + return MainWindow ? MainWindow->ScreenToClient(screenPos) : Vector2::Minimum; +#endif +} + +Vector2 Screen::GameViewportToScreen(const Vector2& viewportPos) +{ +#if USE_EDITOR + return Editor::Managed->GameViewportToScreen(viewportPos); +#else + return MainWindow ? MainWindow->ClientToScreen(viewportPos) : Vector2::Minimum; +#endif +} + bool Screen::GetCursorVisible() { #if USE_EDITOR diff --git a/Source/Engine/Engine/Screen.h b/Source/Engine/Engine/Screen.h index 88a44da43..4fa39a324 100644 --- a/Source/Engine/Engine/Screen.h +++ b/Source/Engine/Engine/Screen.h @@ -33,6 +33,20 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(Screen); /// The value API_PROPERTY() static Vector2 GetSize(); + /// + /// Converts the screen-space position to the game viewport position. + /// + /// The screen-space position. + /// The game viewport position. + API_FUNCTION() static Vector2 ScreenToGameViewport(const Vector2& screenPos); + + /// + /// Converts the game viewport position to the screen-space position. + /// + /// The game viewport position. + /// The screen-space position. + API_FUNCTION() static Vector2 GameViewportToScreen(const Vector2& viewportPos); + /// /// Sets the window size. /// diff --git a/Source/Engine/Input/Input.cpp b/Source/Engine/Input/Input.cpp index 485d5a891..d7796691b 100644 --- a/Source/Engine/Input/Input.cpp +++ b/Source/Engine/Input/Input.cpp @@ -339,14 +339,14 @@ bool Input::GetKeyUp(const KeyboardKeys key) Vector2 Input::GetMousePosition() { - return Mouse ? Engine::ScreenToGameViewport(Mouse->GetPosition()) : Vector2::Minimum; + return Mouse ? Screen::ScreenToGameViewport(Mouse->GetPosition()) : Vector2::Minimum; } void Input::SetMousePosition(const Vector2& position) { if (Mouse && Engine::HasGameViewportFocus()) { - const auto pos = Engine::GameViewportToScreen(position); + const auto pos = Screen::GameViewportToScreen(position); if (pos > Vector2::Minimum) Mouse->SetMousePosition(pos); } From 1d0faddd2ab206617844f43f3aabb3c2b1f56c4a Mon Sep 17 00:00:00 2001 From: stefnotch Date: Mon, 15 Mar 2021 21:22:41 +0100 Subject: [PATCH 05/76] Fix game build --- Source/Engine/Engine/Screen.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Engine/Screen.cpp b/Source/Engine/Engine/Screen.cpp index 402e5e312..11db5dd42 100644 --- a/Source/Engine/Engine/Screen.cpp +++ b/Source/Engine/Engine/Screen.cpp @@ -71,7 +71,8 @@ Vector2 Screen::ScreenToGameViewport(const Vector2& screenPos) #if USE_EDITOR return Editor::Managed->ScreenToGameViewport(screenPos); #else - return MainWindow ? MainWindow->ScreenToClient(screenPos) : Vector2::Minimum; + auto win = Engine::MainWindow; + return win ? win->ScreenToClient(screenPos) : Vector2::Minimum; #endif } @@ -80,7 +81,8 @@ Vector2 Screen::GameViewportToScreen(const Vector2& viewportPos) #if USE_EDITOR return Editor::Managed->GameViewportToScreen(viewportPos); #else - return MainWindow ? MainWindow->ClientToScreen(viewportPos) : Vector2::Minimum; + auto win = Engine::MainWindow; + return win ? win->ClientToScreen(viewportPos) : Vector2::Minimum; #endif } From 5cad37fa50f920528e64abf2c07780fc1bce519a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 16 Mar 2021 19:00:15 +0100 Subject: [PATCH 06/76] Fix packaged editor usage --- Source/Tools/Flax.Build/Platforms/UWP/UWPPlatform.cs | 7 +++++++ .../Flax.Build/Platforms/Windows/WindowsPlatformBase.cs | 7 ++++++- .../Projects/VisualStudio/VisualStudioInstance.cs | 6 +++++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Source/Tools/Flax.Build/Platforms/UWP/UWPPlatform.cs b/Source/Tools/Flax.Build/Platforms/UWP/UWPPlatform.cs index 221483536..bec8b583c 100644 --- a/Source/Tools/Flax.Build/Platforms/UWP/UWPPlatform.cs +++ b/Source/Tools/Flax.Build/Platforms/UWP/UWPPlatform.cs @@ -20,6 +20,13 @@ namespace Flax.Build.Platforms /// public UWPPlatform() { + // Skip if running on non-Windows system + if (Platform.BuildTargetPlatform != TargetPlatform.Windows) + { + _hasRequiredSDKsInstalled = false; + return; + } + // Visual Studio 2017+ supported only var visualStudio = VisualStudioInstance.GetInstances().FirstOrDefault(x => x.Version == VisualStudioVersion.VisualStudio2017 || x.Version == VisualStudioVersion.VisualStudio2019); if (visualStudio == null) diff --git a/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatformBase.cs b/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatformBase.cs index fca112e9c..7c1a78c81 100644 --- a/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatformBase.cs +++ b/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatformBase.cs @@ -243,9 +243,14 @@ namespace Flax.Build.Platforms { if (_toolsets != null) return _toolsets; - var vsInstances = VisualStudioInstance.GetInstances(); _toolsets = new Dictionary(); + // Skip if running on non-Windows system + if (BuildTargetPlatform != TargetPlatform.Windows) + return _toolsets; + + var vsInstances = VisualStudioInstance.GetInstances(); + // Visual Studio 2015 - single instance var vs2015 = vsInstances.FirstOrDefault(x => x.Version == VisualStudioVersion.VisualStudio2015); if (vs2015 != null) diff --git a/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioInstance.cs b/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioInstance.cs index 4c4250aab..6d39625f9 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioInstance.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioInstance.cs @@ -97,9 +97,13 @@ namespace Flax.Build.Projects.VisualStudio { _installDirs = new List(); + // Skip if running on non-Windows system + if (Platform.BuildTargetPlatform != TargetPlatform.Windows) + return _installDirs; + if (Environment.OSVersion.Platform == PlatformID.Win32NT) { - // Visual Studio 2017-2020 + // Visual Studio 2017-2019 List preReleaseInstallDirs = null; try { From ec7d892412ef59b9b9ded5ab12b4bdb659becb3a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 16 Mar 2021 19:02:49 +0100 Subject: [PATCH 07/76] Add stripping binaries for editor distribution build --- Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs b/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs index 8164214cc..b98af5dc1 100644 --- a/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs +++ b/Source/Tools/Flax.Build/Deploy/Deployment.Editor.cs @@ -193,9 +193,14 @@ namespace Flax.Deploy DeployFile(src, dst, "Newtonsoft.Json.pdb"); DeployFiles(src, dst, "*.dll"); DeployFiles(src, dst, "*.so"); - DeployFile(src, dst, "libmonosgen-2.0.so.1"); - DeployFile(src, dst, "libmonosgen-2.0.so.1.0.0"); DeployFile(src, dst, "Logo.png"); + + // Optimize package size + Utilities.Run("strip", "FlaxEditor", null, dst, Utilities.RunOptions.None); + Utilities.Run("strip", "libFlaxEditor.so", null, dst, Utilities.RunOptions.None); + Utilities.Run("strip", "libmonosgen-2.0.so", null, dst, Utilities.RunOptions.None); + Utilities.Run("ln", "-s libmonosgen-2.0.so libmonosgen-2.0.so.1", null, dst, Utilities.RunOptions.None); + Utilities.Run("ln", "-s libmonosgen-2.0.so libmonosgen-2.0.so.1.0.0", null, dst, Utilities.RunOptions.None); } else { From bb6bbe97933569f2bef0f2d8d416bc4dafe9af74 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 16 Mar 2021 22:02:36 +0100 Subject: [PATCH 08/76] Tweaks for network impl on Win32 --- Source/Engine/Platform/Base/NetworkBase.h | 6 +- Source/Engine/Platform/Win32/Win32Network.cpp | 57 +++++++++++-------- Source/Engine/Platform/Win32/Win32Network.h | 3 +- 3 files changed, 37 insertions(+), 29 deletions(-) diff --git a/Source/Engine/Platform/Base/NetworkBase.h b/Source/Engine/Platform/Base/NetworkBase.h index 5d382ab02..69580d658 100644 --- a/Source/Engine/Platform/Base/NetworkBase.h +++ b/Source/Engine/Platform/Base/NetworkBase.h @@ -183,11 +183,11 @@ public: /// /// Accepts a pending connection. /// - /// The socket. - /// The newly connected socket. + /// The socket. + /// The newly connected socket. /// The end point of the new socket. /// Returns true on error, otherwise false. - static bool Accept(NetworkSocket& serverSock, NetworkSocket& newSock, NetworkEndPoint& newEndPoint); + static bool Accept(NetworkSocket& serverSocket, NetworkSocket& newSocket, NetworkEndPoint& newEndPoint); /// /// Checks for socket readability. diff --git a/Source/Engine/Platform/Win32/Win32Network.cpp b/Source/Engine/Platform/Win32/Win32Network.cpp index 64e29467e..08edec861 100644 --- a/Source/Engine/Platform/Win32/Win32Network.cpp +++ b/Source/Engine/Platform/Win32/Win32Network.cpp @@ -1,5 +1,7 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +#if PLATFORM_WIN32 + #include "Win32Network.h" #include "Engine/Core/Log.h" #include "Engine/Core/Collections/Array.h" @@ -7,10 +9,8 @@ #include #include -#define SOCKOPT(OPTENUM, OPTLEVEL, OPTNAME) case OPTENUM: *level = OPTLEVEL; *name = OPTNAME; break; - -static_assert(sizeof NetworkSocket::Data >= sizeof SOCKET, "NetworkSocket::Data is not big enough to contains SOCKET !"); -static_assert(sizeof NetworkEndPoint::Data >= sizeof sockaddr_in6, "NetworkEndPoint::Data is not big enough to contains sockaddr_in6 !"); +static_assert(sizeof(NetworkSocket::Data) >= sizeof(SOCKET), "NetworkSocket::Data is not big enough to contains SOCKET !"); +static_assert(sizeof(NetworkEndPoint::Data) >= sizeof(sockaddr_in6), "NetworkEndPoint::Data is not big enough to contains sockaddr_in6 !"); static_assert(SOCKGROUP_ITEMSIZE >= sizeof(pollfd), "SOCKGROUP_ITEMSIZE macro is not big enough to contains pollfd !"); // @formatter:off @@ -44,12 +44,12 @@ static String GetLastErrorMessage() static int GetAddrSize(const sockaddr& addr) { - return addr.sa_family == AF_INET6 ? sizeof sockaddr_in6 : sizeof sockaddr_in; + return addr.sa_family == AF_INET6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in); } static int GetAddrSizeFromEP(NetworkEndPoint& endPoint) { - return endPoint.IPVersion == NetworkIPVersion::IPv6 ? sizeof sockaddr_in6 : sizeof sockaddr_in; + return endPoint.IPVersion == NetworkIPVersion::IPv6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in); } static NetworkIPVersion GetIPVersionFromAddr(const sockaddr& addr) @@ -118,6 +118,7 @@ static void TranslateSockOptToNative(NetworkSocketOption option, int32* level, i { switch (option) { +#define SOCKOPT(OPTENUM, OPTLEVEL, OPTNAME) case OPTENUM: *level = OPTLEVEL; *name = OPTNAME; break; SOCKOPT(NetworkSocketOption::Debug, SOL_SOCKET, SO_DEBUG) SOCKOPT(NetworkSocketOption::ReuseAddr, SOL_SOCKET, SO_REUSEADDR) SOCKOPT(NetworkSocketOption::KeepAlive, SOL_SOCKET, SO_KEEPALIVE) @@ -135,6 +136,11 @@ static void TranslateSockOptToNative(NetworkSocketOption option, int32* level, i SOCKOPT(NetworkSocketOption::IPv6Only, IPPROTO_IPV6, IPV6_V6ONLY) SOCKOPT(NetworkSocketOption::Mtu, IPPROTO_IP, IP_MTU) SOCKOPT(NetworkSocketOption::Type, SOL_SOCKET, SO_TYPE) +#undef SOCKOPT + default: + *level = 0; + *name = 0; + break; } } @@ -152,7 +158,7 @@ bool Win32Network::CreateSocket(NetworkSocket& socket, NetworkProtocol proto, Ne LOG(Error, "Can't create native socket! Error : {0}", GetLastErrorMessage()); return true; } - memcpy(socket.Data, &sock, sizeof sock); + memcpy(socket.Data, &sock, sizeof(sock)); unsigned long value = 1; if (ioctlsocket(sock, FIONBIO, &value) == SOCKET_ERROR) { @@ -187,7 +193,7 @@ bool Win32Network::SetSocketOption(NetworkSocket& socket, NetworkSocketOption op TranslateSockOptToNative(option, &optlvl, &optnme); - if (setsockopt(*(SOCKET*)socket.Data, optlvl, optnme, (char*)&value, sizeof value) == SOCKET_ERROR) + if (setsockopt(*(SOCKET*)socket.Data, optlvl, optnme, (char*)&value, sizeof(value)) == SOCKET_ERROR) { LOG(Warning, "Unable to set socket option ! Socket : {0} Error : {1}", *(SOCKET*)socket.Data, GetLastErrorMessage()); return true; @@ -241,7 +247,7 @@ bool Win32Network::BindSocket(NetworkSocket& socket, NetworkEndPoint& endPoint) return true; } - const uint16 size = endPoint.IPVersion == NetworkIPVersion::IPv6 ? sizeof sockaddr_in6 : sizeof sockaddr_in; + const uint16 size = GetAddrSizeFromEP(endPoint); if (bind(*(SOCKET*)socket.Data, (const sockaddr*)endPoint.Data, size) == SOCKET_ERROR) { LOG(Error, "Unable to bind socket! Socket : {0} Error : {1}", *(SOCKET*)socket.Data, GetLastErrorMessage()); @@ -260,28 +266,28 @@ bool Win32Network::Listen(NetworkSocket& socket, uint16 queueSize) return false; } -bool Win32Network::Accept(NetworkSocket& serverSock, NetworkSocket& newSock, NetworkEndPoint& newEndPoint) +bool Win32Network::Accept(NetworkSocket& serverSocket, NetworkSocket& newSocket, NetworkEndPoint& newEndPoint) { - if (serverSock.Protocol != NetworkProtocol::Tcp) + if (serverSocket.Protocol != NetworkProtocol::Tcp) { LOG(Warning, "Can't accept connection on UDP socket! Socket : {0}", *(SOCKET*)serverSock.Data); return true; } SOCKET sock; sockaddr_in6 addr; - int32 size = sizeof sockaddr_in6; - if ((sock = accept(*(SOCKET*)serverSock.Data, (sockaddr*)&addr, &size)) == INVALID_SOCKET) + int32 size = sizeof(sockaddr_in6); + if ((sock = accept(*(SOCKET*)serverSocket.Data, (sockaddr*)&addr, &size)) == INVALID_SOCKET) { int32 error = WSAGetLastError(); if (error == WSAEWOULDBLOCK) return false; - LOG(Warning, "Unable to accept incoming connection! Socket : {0} Error : {1}", *(SOCKET*)serverSock.Data, GetErrorMessage(error)); + LOG(Warning, "Unable to accept incoming connection! Socket : {0} Error : {1}", *(SOCKET*)serverSocket.Data, GetErrorMessage(error)); return true; } - memcpy(newSock.Data, &sock, sizeof sock); + memcpy(newSocket.Data, &sock, sizeof(sock)); memcpy(newEndPoint.Data, &addr, size); - newSock.Protocol = serverSock.Protocol; - newSock.IPVersion = serverSock.IPVersion; + newSocket.Protocol = serverSocket.Protocol; + newSocket.IPVersion = serverSocket.IPVersion; if (CreateEndPointFromAddr((sockaddr*)&addr, newEndPoint)) return true; return false; @@ -358,7 +364,7 @@ bool Win32Network::GetSocketState(NetworkSocketGroup& group, uint32 index, Netwo if (index >= group.Capacity) return true; pollfd* pollptr = (pollfd*)&group.Data[index * SOCKGROUP_ITEMSIZE]; - memset(&state, 0, sizeof state); + memset(&state, 0, sizeof(state)); if (pollptr->revents & POLLERR) state.Error = true; if (pollptr->revents & POLLHUP) @@ -398,7 +404,7 @@ bool Win32Network::GetSocketFromGroup(NetworkSocketGroup& group, uint32 index, N if (index >= group.Capacity) return true; SOCKET s = ((pollfd*)&group.Data[index * SOCKGROUP_ITEMSIZE])->fd; - memcpy(socket->Data, &s, sizeof s); + memcpy(socket->Data, &s, sizeof(s)); int32 value; if (GetSocketOption(*socket, NetworkSocketOption::Type, &value)) return true; @@ -490,7 +496,7 @@ int32 Win32Network::ReadSocket(NetworkSocket socket, byte* buffer, uint32 buffer } else { - int32 addrsize = sizeof sockaddr_in6; + int32 addrsize = sizeof(sockaddr_in6); sockaddr_in6 addr; if ((size = recvfrom(*(SOCKET*)socket.Data, (char*)buffer, bufferSize, 0, (sockaddr*)&addr, &addrsize)) == SOCKET_ERROR) { @@ -508,7 +514,7 @@ bool Win32Network::CreateEndPoint(NetworkAddress& address, NetworkIPVersion ipv, int status; addrinfoW hints; addrinfoW* info; - memset(&hints, 0, sizeof hints); + memset(&hints, 0, sizeof(hints)); hints.ai_family = ipv == NetworkIPVersion::IPv6 ? AF_INET6 : ipv == NetworkIPVersion::IPv4 ? AF_INET : AF_UNSPEC; hints.ai_flags |= AI_ADDRCONFIG; hints.ai_flags |= AI_V4MAPPED; @@ -518,13 +524,13 @@ bool Win32Network::CreateEndPoint(NetworkAddress& address, NetworkIPVersion ipv, // consider using NUMERICHOST/NUMERICSERV if address is a valid Ipv4 or IPv6 so we can skip some look up ( potentially slow when resolving host names ) if ((status = GetAddrInfoW(address.Address == String::Empty ? nullptr : address.Address.Get(), address.Port == String::Empty ? nullptr : address.Port.Get(), &hints, &info)) != 0) { - LOG(Error, "Unable to query info for address : {0} Error : {1}", address.Address != String::Empty ? address.Address : String("ANY"), gai_strerror(status)); + LOG(Error, "Unable to query info for address : {0} Error : {1}", address.Address != String::Empty ? *address.Address : TEXT("ANY"), gai_strerror(status)); return true; } if (info == nullptr) { - LOG(Error, "Unable to resolve address! Address : {0}", address.Address != String::Empty ? address.Address : String("ANY")); + LOG(Error, "Unable to resolve address! Address : {0}", address.Address != String::Empty ? *address.Address : TEXT("ANY")); return true; } @@ -534,7 +540,6 @@ bool Win32Network::CreateEndPoint(NetworkAddress& address, NetworkIPVersion ipv, return true; } FreeAddrInfoW(info); - return false; } @@ -552,7 +557,7 @@ NetworkEndPoint Win32Network::RemapEndPointToIPv6(NetworkEndPoint endPoint) const SCOPE_ID scope = SCOPEID_UNSPECIFIED_INIT; // Can be replaced by windows built-in macro IN6ADDR_SETV4MAPPED() - memset(addr6, 0, sizeof sockaddr_in6); + memset(addr6, 0, sizeof(sockaddr_in6)); addr6->sin6_family = AF_INET6; addr6->sin6_scope_struct = scope; addr6->sin6_addr = v4MappedPrefix; @@ -562,3 +567,5 @@ NetworkEndPoint Win32Network::RemapEndPointToIPv6(NetworkEndPoint endPoint) return pv6; } + +#endif diff --git a/Source/Engine/Platform/Win32/Win32Network.h b/Source/Engine/Platform/Win32/Win32Network.h index ce4e59718..11bcb1c2d 100644 --- a/Source/Engine/Platform/Win32/Win32Network.h +++ b/Source/Engine/Platform/Win32/Win32Network.h @@ -9,6 +9,7 @@ class FLAXENGINE_API Win32Network : public NetworkBase { public: + // [NetworkBase] static bool CreateSocket(NetworkSocket& socket, NetworkProtocol proto, NetworkIPVersion ipv); static bool DestroySocket(NetworkSocket& socket); @@ -19,7 +20,7 @@ public: static bool ConnectSocket(NetworkSocket& socket, NetworkEndPoint& endPoint); static bool BindSocket(NetworkSocket& socket, NetworkEndPoint& endPoint); static bool Listen(NetworkSocket& socket, uint16 queueSize); - static bool Accept(NetworkSocket& serverSock, NetworkSocket& newSock, NetworkEndPoint& newEndPoint); + static bool Accept(NetworkSocket& serverSocket, NetworkSocket& newSocket, NetworkEndPoint& newEndPoint); static bool IsReadable(NetworkSocket& socket); static bool IsWriteable(NetworkSocket& socket); static bool CreateSocketGroup(uint32 capacity, NetworkSocketGroup& group); From 3e56cd2c70931f31760d878e62283070c7582cd8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 16 Mar 2021 22:15:28 +0100 Subject: [PATCH 09/76] Add Network implementation for Unix --- Source/Engine/Platform/Network.h | 2 +- Source/Engine/Platform/Types.h | 4 +- Source/Engine/Platform/Unix/UnixNetwork.cpp | 404 ++++++++++++++++++++ Source/Engine/Platform/Unix/UnixNetwork.h | 41 ++ 4 files changed, 448 insertions(+), 3 deletions(-) create mode 100644 Source/Engine/Platform/Unix/UnixNetwork.cpp create mode 100644 Source/Engine/Platform/Unix/UnixNetwork.h diff --git a/Source/Engine/Platform/Network.h b/Source/Engine/Platform/Network.h index b8c198770..af9851a0a 100644 --- a/Source/Engine/Platform/Network.h +++ b/Source/Engine/Platform/Network.h @@ -7,7 +7,7 @@ #elif PLATFORM_UWP #include "Win32/Win32Network.h" #elif PLATFORM_LINUX -#include "Base/NetworkBase.h" +#include "Unix/UnixNetwork.h" #elif PLATFORM_PS4 #include "Base/NetworkBase.h" #elif PLATFORM_XBOX_SCARLETT diff --git a/Source/Engine/Platform/Types.h b/Source/Engine/Platform/Types.h index 3f6511241..3cec8ab1a 100644 --- a/Source/Engine/Platform/Types.h +++ b/Source/Engine/Platform/Types.h @@ -68,8 +68,8 @@ class LinuxThread; typedef LinuxThread Thread; class LinuxWindow; typedef LinuxWindow Window; -class NetworkBase; -typedef NetworkBase Network; +class UnixNetwork; +typedef UnixNetwork Network; #elif PLATFORM_PS4 diff --git a/Source/Engine/Platform/Unix/UnixNetwork.cpp b/Source/Engine/Platform/Unix/UnixNetwork.cpp new file mode 100644 index 000000000..ca99df44c --- /dev/null +++ b/Source/Engine/Platform/Unix/UnixNetwork.cpp @@ -0,0 +1,404 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#if PLATFORM_UNIX + +#include "UnixNetwork.h" +#include "Engine/Core/Log.h" +#include "Engine/Core/Collections/Array.h" +#include "Engine/Utilities/StringConverter.h" +#include +#include +#include +#include +#include +#include +#include + +struct UnixSocketData +{ + int sockfd; +}; +static_assert(sizeof(NetworkSocket::Data) >= sizeof(UnixSocketData), "NetworkSocket::Data is not big enough to contains UnixSocketData !"); +static_assert(sizeof(NetworkEndPoint::Data) >= sizeof(sockaddr_in6), "NetworkEndPoint::Data is not big enough to contains sockaddr_in6 !"); + +static int GetAddrSize(const sockaddr& addr) +{ + return addr.sa_family == AF_INET6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in); +} + +static int GetAddrSizeFromEP(NetworkEndPoint& endPoint) +{ + return endPoint.IPVersion == NetworkIPVersion::IPv6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in); +} + +static NetworkIPVersion GetIPVersionFromAddr(const sockaddr& addr) +{ + return addr.sa_family == AF_INET6 ? NetworkIPVersion::IPv6 : NetworkIPVersion::IPv4;; +} + +static void TranslateSockOptToNative(NetworkSocketOption option, int32* level, int32* name) +{ + switch (option) + { +#define SOCKOPT(OPTENUM, OPTLEVEL, OPTNAME) case OPTENUM: *level = OPTLEVEL; *name = OPTNAME; break; + SOCKOPT(NetworkSocketOption::Debug, SOL_SOCKET, SO_DEBUG) + SOCKOPT(NetworkSocketOption::ReuseAddr, SOL_SOCKET, SO_REUSEADDR) + SOCKOPT(NetworkSocketOption::KeepAlive, SOL_SOCKET, SO_KEEPALIVE) + SOCKOPT(NetworkSocketOption::DontRoute, SOL_SOCKET, SO_DONTROUTE) + SOCKOPT(NetworkSocketOption::Broadcast, SOL_SOCKET, SO_BROADCAST) +#ifdef SO_USELOOPBACK + SOCKOPT(NetworkSocketOption::UseLoopback, SOL_SOCKET, SO_USELOOPBACK) +#endif + SOCKOPT(NetworkSocketOption::Linger, SOL_SOCKET, SO_LINGER) + SOCKOPT(NetworkSocketOption::OOBInline, SOL_SOCKET, SO_OOBINLINE) + SOCKOPT(NetworkSocketOption::SendBuffer, SOL_SOCKET, SO_SNDBUF) + SOCKOPT(NetworkSocketOption::RecvBuffer, SOL_SOCKET, SO_RCVBUF) + SOCKOPT(NetworkSocketOption::SendTimeout, SOL_SOCKET, SO_SNDTIMEO) + SOCKOPT(NetworkSocketOption::RecvTimeout, SOL_SOCKET, SO_RCVTIMEO) + SOCKOPT(NetworkSocketOption::Error, SOL_SOCKET, SO_ERROR) +#ifdef TCP_NODELAY + SOCKOPT(NetworkSocketOption::NoDelay, IPPROTO_TCP, TCP_NODELAY) +#endif + SOCKOPT(NetworkSocketOption::IPv6Only, IPPROTO_IPV6, IPV6_V6ONLY) + SOCKOPT(NetworkSocketOption::Mtu, IPPROTO_IP, IP_MTU) + SOCKOPT(NetworkSocketOption::Type, SOL_SOCKET, SO_TYPE) +#undef SOCKOPT + default: + *level = 0; + *name = 0; + break; + } +} +static bool CreateEndPointFromAddr(sockaddr* addr, NetworkEndPoint& endPoint) +{ + uint32 size = GetAddrSize(*addr); + uint16 port; + void* paddr; + if (addr->sa_family == AF_INET6) + { + paddr = &((sockaddr_in6*)addr)->sin6_addr; + port = ntohs(((sockaddr_in6*)addr)->sin6_port); + } + else if (addr->sa_family == AF_INET) + { + paddr = &((sockaddr_in*)addr)->sin_addr; + port = ntohs(((sockaddr_in*)addr)->sin_port); + } + else + { + LOG(Error, "Unable to create endpoint, sockaddr must be INET or INET6! Family : {0}", addr->sa_family); + return true; + } + + char ip[INET6_ADDRSTRLEN]; + if (inet_ntop(addr->sa_family, paddr, ip, INET6_ADDRSTRLEN) == nullptr) + { + LOG(Error, "Unable to extract address from sockaddr!"); + LOG_UNIX_LAST_ERROR; + return true; + } + char strPort[6]; + sprintf(strPort, "%d", port); + endPoint.IPVersion = GetIPVersionFromAddr(*addr); + memcpy(endPoint.Data, addr, size); + return false; +} + +bool UnixNetwork::CreateSocket(NetworkSocket& socket, NetworkProtocol proto, NetworkIPVersion ipv) +{ + socket.Protocol = proto; + socket.IPVersion = ipv; + const int domain = socket.IPVersion == NetworkIPVersion::IPv6 ? AF_INET6 : AF_INET; + const int type = socket.Protocol == NetworkProtocol::Tcp ? SOCK_STREAM : SOCK_DGRAM; + const int protocol = socket.Protocol == NetworkProtocol::Tcp ? IPPROTO_TCP : IPPROTO_UDP; + auto& sock = *(UnixSocketData*)&socket.Data; + sock.sockfd = ::socket(domain, type, protocol); + if (sock.sockfd < 0) + { + LOG(Error, "Can't create native socket"); + LOG_UNIX_LAST_ERROR; + return true; + } + return false; +} + +bool UnixNetwork::DestroySocket(NetworkSocket& socket) +{ + auto& sock = *(UnixSocketData*)&socket.Data; + ::close(sock.sockfd); + return false; +} + +bool UnixNetwork::SetSocketOption(NetworkSocket& socket, NetworkSocketOption option, bool value) +{ + const int32 v = value; + return SetSocketOption(socket, option, v); +} + +bool UnixNetwork::SetSocketOption(NetworkSocket& socket, NetworkSocketOption option, int32 value) +{ + int32 optlvl = 0; + int32 optnme = 0; + TranslateSockOptToNative(option, &optlvl, &optnme); + auto& sock = *(UnixSocketData*)&socket.Data; + if (setsockopt(sock.sockfd, optlvl, optnme, (char*)&value, sizeof(value)) == -1) + { + LOG(Warning, "Unable to set socket option ! Socket : {0}", sock.sockfd); + LOG_UNIX_LAST_ERROR; + return true; + } + return false; +} + +bool UnixNetwork::GetSocketOption(NetworkSocket& socket, NetworkSocketOption option, bool* value) +{ + int32 v; + const bool status = GetSocketOption(socket, option, &v); + *value = v == 1 ? true : false; + return status; +} + +bool UnixNetwork::GetSocketOption(NetworkSocket& socket, NetworkSocketOption option, int32* value) +{ + int32 optlvl = 0; + int32 optnme = 0; + TranslateSockOptToNative(option, &optlvl, &optnme); + socklen_t size; + auto& sock = *(UnixSocketData*)&socket.Data; + if (getsockopt(sock.sockfd, optlvl, optnme, (char*)value, &size) == -1) + { + LOG(Warning, "Unable to get socket option ! Socket : {0}", sock.sockfd); + LOG_UNIX_LAST_ERROR; + return true; + } + return false; +} + +bool UnixNetwork::ConnectSocket(NetworkSocket& socket, NetworkEndPoint& endPoint) +{ + const uint16 size = GetAddrSizeFromEP(endPoint); + auto& sock = *(UnixSocketData*)&socket.Data; + if (connect(sock.sockfd, (const sockaddr*)endPoint.Data, size) == -1) + { + LOG(Error, "Unable to connect socket to address! Socket : {0}", sock.sockfd); + LOG_UNIX_LAST_ERROR; + return true; + } + return false; +} + +bool UnixNetwork::BindSocket(NetworkSocket& socket, NetworkEndPoint& endPoint) +{ + auto& sock = *(UnixSocketData*)&socket.Data; + if (socket.IPVersion != endPoint.IPVersion) + { + LOG(Error, "Can't bind socket to end point, Socket.IPVersion != EndPoint.IPVersion! Socket : {0}", sock.sockfd); + return true; + } + const uint16 size = GetAddrSizeFromEP(endPoint); + if (bind(sock.sockfd, (const sockaddr*)endPoint.Data, size) == -1) + { + LOG(Error, "Unable to bind socket! Socket : {0}", sock.sockfd); + LOG_UNIX_LAST_ERROR; + return true; + } + return false; +} + +bool UnixNetwork::Listen(NetworkSocket& socket, uint16 queueSize) +{ + auto& sock = *(UnixSocketData*)&socket.Data; + if (listen(sock.sockfd, (int32)queueSize) == -1) + { + LOG(Error, "Unable to listen ! Socket : {0}", sock.sockfd); + return true; + } + return false; +} + +bool UnixNetwork::Accept(NetworkSocket& serverSocket, NetworkSocket& newSocket, NetworkEndPoint& newEndPoint) +{ + auto& serverSock = *(UnixSocketData*)&serverSocket.Data; + if (serverSocket.Protocol != NetworkProtocol::Tcp) + { + LOG(Warning, "Can't accept connection on UDP socket! Socket : {0}", serverSock.sockfd); + return true; + } + sockaddr_in6 addr; + socklen_t size = sizeof(sockaddr_in6); + int sock = accept(serverSock.sockfd, (sockaddr*)&addr, &size); + if (sock < 0) + { + LOG(Warning, "Unable to accept incoming connection! Socket : {0}", serverSock.sockfd); + LOG_UNIX_LAST_ERROR; + return true; + } + auto& newSock = *(UnixSocketData*)&newSocket.Data; + newSock.sockfd = sock; + memcpy(newEndPoint.Data, &addr, size); + newSocket.Protocol = serverSocket.Protocol; + newSocket.IPVersion = serverSocket.IPVersion; + if (CreateEndPointFromAddr((sockaddr*)&addr, newEndPoint)) + return true; + return false; +} + +bool UnixNetwork::IsReadable(NetworkSocket& socket) +{ + return NetworkBase::IsReadable(socket); // TODO: impl this +} + +bool UnixNetwork::IsWriteable(NetworkSocket& socket) +{ + return NetworkBase::IsWriteable(socket); // TODO: impl this +} + +bool UnixNetwork::CreateSocketGroup(uint32 capacity, NetworkSocketGroup& group) +{ + return NetworkBase::CreateSocketGroup(capacity, group); // TODO: impl this +} + +bool UnixNetwork::DestroySocketGroup(NetworkSocketGroup& group) +{ + return NetworkBase::DestroySocketGroup(group); // TODO: impl this +} + +int32 UnixNetwork::Poll(NetworkSocketGroup& group) +{ + return NetworkBase::Poll(group); // TODO: impl this +} + +bool UnixNetwork::GetSocketState(NetworkSocketGroup& group, uint32 index, NetworkSocketState& state) +{ + return NetworkBase::GetSocketState(group, index, state); // TODO: impl this +} + +int32 UnixNetwork::AddSocketToGroup(NetworkSocketGroup& group, NetworkSocket& socket) +{ + return NetworkBase::AddSocketToGroup(group, socket); // TODO: impl this +} + +bool UnixNetwork::GetSocketFromGroup(NetworkSocketGroup& group, uint32 index, NetworkSocket* socket) +{ + return NetworkBase::GetSocketFromGroup(group, index, socket); // TODO: impl this +} + +void UnixNetwork::RemoveSocketFromGroup(NetworkSocketGroup& group, uint32 index) +{ + NetworkBase::RemoveSocketFromGroup(group, index); // TODO: impl this +} + +bool UnixNetwork::RemoveSocketFromGroup(NetworkSocketGroup& group, NetworkSocket& socket) +{ + return NetworkBase::RemoveSocketFromGroup(group, socket); // TODO: impl this +} + +void UnixNetwork::ClearGroup(NetworkSocketGroup& group) +{ + NetworkBase::ClearGroup(group); // TODO: impl this +} + +int32 UnixNetwork::WriteSocket(NetworkSocket socket, byte* data, uint32 length, NetworkEndPoint* endPoint) +{ + auto& sock = *(UnixSocketData*)&socket.Data; + if (endPoint != nullptr && socket.IPVersion != endPoint->IPVersion) + { + LOG(Error, "Unable to send data, Socket.IPVersion != EndPoint.IPVersion! Socket : {0}", sock.sockfd); + return -1; + } + uint32 size; + if (endPoint == nullptr && socket.Protocol == NetworkProtocol::Tcp) + { + if ((size = send(sock.sockfd, (const char*)data, length, 0)) == -1) + { + LOG(Error, "Unable to send data! Socket : {0} Data Length : {1}", sock.sockfd, length); + return -1; + } + } + else if (endPoint != nullptr && socket.Protocol == NetworkProtocol::Udp) + { + if ((size = sendto(sock.sockfd, (const char*)data, length, 0, (const sockaddr*)endPoint->Data, GetAddrSizeFromEP(*endPoint))) == -1) + { + LOG(Error, "Unable to send data! Socket : {0} Data Length : {1}", sock.sockfd, length); + return -1; + } + } + else + { + // TODO: better explanation + LOG(Error, "Unable to send data! Socket : {0} Data Length : {1}", sock.sockfd, length); + return -1; + } + return size; +} + +int32 UnixNetwork::ReadSocket(NetworkSocket socket, byte* buffer, uint32 bufferSize, NetworkEndPoint* endPoint) +{ + auto& sock = *(UnixSocketData*)&socket.Data; + uint32 size; + if (endPoint == nullptr) + { + if ((size = recv(sock.sockfd, (char*)buffer, bufferSize, 0)) == -1) + { + LOG(Error, "Unable to read data! Socket : {0} Buffer Size : {1}", sock.sockfd, bufferSize); + LOG_UNIX_LAST_ERROR; + return -1; + } + } + else + { + socklen_t addrsize = sizeof(sockaddr_in6); + sockaddr_in6 addr; + if ((size = recvfrom(sock.sockfd, (void*)buffer, bufferSize, 0, (sockaddr*)&addr, &addrsize)) == -1) + { + LOG(Error, "Unable to read data! Socket : {0} Buffer Size : {1}", sock.sockfd, bufferSize); + return -1; + } + if (CreateEndPointFromAddr((sockaddr*)&addr, *endPoint)) + return true; + } + return size; +} + +bool UnixNetwork::CreateEndPoint(NetworkAddress& address, NetworkIPVersion ipv, NetworkEndPoint& endPoint, bool bindable) +{ + int status; + addrinfo hints; + addrinfo* info; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = ipv == NetworkIPVersion::IPv6 ? AF_INET6 : ipv == NetworkIPVersion::IPv4 ? AF_INET : AF_UNSPEC; + hints.ai_flags |= AI_ADDRCONFIG; + hints.ai_flags |= AI_V4MAPPED; + if (bindable) + hints.ai_flags = AI_PASSIVE; + + // consider using NUMERICHOST/NUMERICSERV if address is a valid Ipv4 or IPv6 so we can skip some look up ( potentially slow when resolving host names ) + const StringAsANSI<60> addressAnsi(*address.Address, address.Address.Length()); + const StringAsANSI<10> portAnsi(*address.Port, address.Port.Length()); + if ((status = getaddrinfo(address.Address == String::Empty ? nullptr : addressAnsi.Get(), address.Port == String::Empty ? nullptr : portAnsi.Get(), &hints, &info)) != 0) + { + LOG(Error, "Unable to query info for address : {0} Error : {1}", address.Address != String::Empty ? *address.Address : TEXT("ANY"), String(gai_strerror(status))); + return true; + } + + if (info == nullptr) + { + LOG(Error, "Unable to resolve address! Address : {0}", address.Address != String::Empty ? *address.Address : TEXT("ANY")); + return true; + } + + if (CreateEndPointFromAddr(info->ai_addr, endPoint)) + { + freeaddrinfo(info); + return true; + } + freeaddrinfo(info); + return false; +} + +NetworkEndPoint UnixNetwork::RemapEndPointToIPv6(NetworkEndPoint endPoint) +{ + return NetworkBase::RemapEndPointToIPv6(endPoint); // TODO: impl this +} + +#endif diff --git a/Source/Engine/Platform/Unix/UnixNetwork.h b/Source/Engine/Platform/Unix/UnixNetwork.h new file mode 100644 index 000000000..28c81ff2d --- /dev/null +++ b/Source/Engine/Platform/Unix/UnixNetwork.h @@ -0,0 +1,41 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#if PLATFORM_UNIX + +#include "Engine/Platform/Base/NetworkBase.h" + +class FLAXENGINE_API UnixNetwork : public NetworkBase +{ +public: + + // [NetworkBase] + static bool CreateSocket(NetworkSocket& socket, NetworkProtocol proto, NetworkIPVersion ipv); + static bool DestroySocket(NetworkSocket& socket); + static bool SetSocketOption(NetworkSocket& socket, NetworkSocketOption option, bool value); + static bool SetSocketOption(NetworkSocket& socket, NetworkSocketOption option, int32 value); + static bool GetSocketOption(NetworkSocket& socket, NetworkSocketOption option, bool* value); + static bool GetSocketOption(NetworkSocket& socket, NetworkSocketOption option, int32* value); + static bool ConnectSocket(NetworkSocket& socket, NetworkEndPoint& endPoint); + static bool BindSocket(NetworkSocket& socket, NetworkEndPoint& endPoint); + static bool Listen(NetworkSocket& socket, uint16 queueSize); + static bool Accept(NetworkSocket& serverSocket, NetworkSocket& newSocket, NetworkEndPoint& newEndPoint); + static bool IsReadable(NetworkSocket& socket); + static bool IsWriteable(NetworkSocket& socket); + static bool CreateSocketGroup(uint32 capacity, NetworkSocketGroup& group); + static bool DestroySocketGroup(NetworkSocketGroup& group); + static int32 Poll(NetworkSocketGroup& group); + static bool GetSocketState(NetworkSocketGroup& group, uint32 index, NetworkSocketState& state); + static int32 AddSocketToGroup(NetworkSocketGroup& group, NetworkSocket& socket); + static bool GetSocketFromGroup(NetworkSocketGroup& group, uint32 index, NetworkSocket* socket); + static void RemoveSocketFromGroup(NetworkSocketGroup& group, uint32 index); + static bool RemoveSocketFromGroup(NetworkSocketGroup& group, NetworkSocket& socket); + static void ClearGroup(NetworkSocketGroup& group); + static int32 WriteSocket(NetworkSocket socket, byte* data, uint32 length, NetworkEndPoint* endPoint = nullptr); + static int32 ReadSocket(NetworkSocket socket, byte* buffer, uint32 bufferSize, NetworkEndPoint* endPoint = nullptr); + static bool CreateEndPoint(NetworkAddress& address, NetworkIPVersion ipv, NetworkEndPoint& endPoint, bool bindable = true); + static NetworkEndPoint RemapEndPointToIPv6(NetworkEndPoint endPoint); +}; + +#endif From 1567f8723df9e492e4170fbe96e32b87e3e38ca2 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 16 Mar 2021 22:31:51 +0100 Subject: [PATCH 10/76] Fix typo --- Source/Engine/Platform/Base/NetworkBase.cpp | 2 +- Source/Engine/Platform/Base/NetworkBase.h | 2 +- Source/Engine/Platform/Win32/Win32Network.cpp | 2 +- Source/Engine/Platform/Win32/Win32Network.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Engine/Platform/Base/NetworkBase.cpp b/Source/Engine/Platform/Base/NetworkBase.cpp index 4060bfee6..7767d68eb 100644 --- a/Source/Engine/Platform/Base/NetworkBase.cpp +++ b/Source/Engine/Platform/Base/NetworkBase.cpp @@ -57,7 +57,7 @@ bool NetworkBase::IsReadable(NetworkSocket& socket) return true; } -bool NetworkBase::IsWriteable(NetworkSocket& socket) +bool NetworkBase::IsWritable(NetworkSocket& socket) { return true; } diff --git a/Source/Engine/Platform/Base/NetworkBase.h b/Source/Engine/Platform/Base/NetworkBase.h index 69580d658..1e65fbe7f 100644 --- a/Source/Engine/Platform/Base/NetworkBase.h +++ b/Source/Engine/Platform/Base/NetworkBase.h @@ -201,7 +201,7 @@ public: /// /// The socket. /// Returns true when data can be written. Otherwise false. - static bool IsWriteable(NetworkSocket& socket); + static bool IsWritable(NetworkSocket& socket); /// /// Creates a socket group. It allocate memory based on the desired capacity. diff --git a/Source/Engine/Platform/Win32/Win32Network.cpp b/Source/Engine/Platform/Win32/Win32Network.cpp index 08edec861..f0d27ec4c 100644 --- a/Source/Engine/Platform/Win32/Win32Network.cpp +++ b/Source/Engine/Platform/Win32/Win32Network.cpp @@ -311,7 +311,7 @@ bool Win32Network::IsReadable(NetworkSocket& socket) return false; } -bool Win32Network::IsWriteable(NetworkSocket& socket) +bool Win32Network::IsWritable(NetworkSocket& socket) { pollfd entry; entry.fd = *(SOCKET*)socket.Data; diff --git a/Source/Engine/Platform/Win32/Win32Network.h b/Source/Engine/Platform/Win32/Win32Network.h index 11bcb1c2d..4949b8a38 100644 --- a/Source/Engine/Platform/Win32/Win32Network.h +++ b/Source/Engine/Platform/Win32/Win32Network.h @@ -22,7 +22,7 @@ public: static bool Listen(NetworkSocket& socket, uint16 queueSize); static bool Accept(NetworkSocket& serverSocket, NetworkSocket& newSocket, NetworkEndPoint& newEndPoint); static bool IsReadable(NetworkSocket& socket); - static bool IsWriteable(NetworkSocket& socket); + static bool IsWritable(NetworkSocket& socket); static bool CreateSocketGroup(uint32 capacity, NetworkSocketGroup& group); static bool DestroySocketGroup(NetworkSocketGroup& group); static int32 Poll(NetworkSocketGroup& group); From b9ca496aff6be3887f84b23f4eac852565988a4f Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 16 Mar 2021 22:32:02 +0100 Subject: [PATCH 11/76] Fix compilation --- Source/Engine/Platform/Unix/UnixNetwork.cpp | 1 + Source/Engine/Platform/Win32/Win32Network.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Platform/Unix/UnixNetwork.cpp b/Source/Engine/Platform/Unix/UnixNetwork.cpp index ca99df44c..bfd6c679d 100644 --- a/Source/Engine/Platform/Unix/UnixNetwork.cpp +++ b/Source/Engine/Platform/Unix/UnixNetwork.cpp @@ -13,6 +13,7 @@ #include #include #include +#include struct UnixSocketData { diff --git a/Source/Engine/Platform/Win32/Win32Network.cpp b/Source/Engine/Platform/Win32/Win32Network.cpp index f0d27ec4c..a5edd68e3 100644 --- a/Source/Engine/Platform/Win32/Win32Network.cpp +++ b/Source/Engine/Platform/Win32/Win32Network.cpp @@ -270,7 +270,7 @@ bool Win32Network::Accept(NetworkSocket& serverSocket, NetworkSocket& newSocket, { if (serverSocket.Protocol != NetworkProtocol::Tcp) { - LOG(Warning, "Can't accept connection on UDP socket! Socket : {0}", *(SOCKET*)serverSock.Data); + LOG(Warning, "Can't accept connection on UDP socket! Socket : {0}", *(SOCKET*)serverSocket.Data); return true; } SOCKET sock; From 1262243af9c3e79a1d2304c20d83b525f2fcf706 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 16 Mar 2021 23:14:29 +0100 Subject: [PATCH 12/76] Fix compilation --- Source/Engine/Platform/Unix/UnixNetwork.cpp | 4 ++-- Source/Engine/Platform/Unix/UnixNetwork.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Engine/Platform/Unix/UnixNetwork.cpp b/Source/Engine/Platform/Unix/UnixNetwork.cpp index bfd6c679d..139695119 100644 --- a/Source/Engine/Platform/Unix/UnixNetwork.cpp +++ b/Source/Engine/Platform/Unix/UnixNetwork.cpp @@ -249,9 +249,9 @@ bool UnixNetwork::IsReadable(NetworkSocket& socket) return NetworkBase::IsReadable(socket); // TODO: impl this } -bool UnixNetwork::IsWriteable(NetworkSocket& socket) +bool UnixNetwork::IsWritable(NetworkSocket& socket) { - return NetworkBase::IsWriteable(socket); // TODO: impl this + return NetworkBase::IsWritable(socket); // TODO: impl this } bool UnixNetwork::CreateSocketGroup(uint32 capacity, NetworkSocketGroup& group) diff --git a/Source/Engine/Platform/Unix/UnixNetwork.h b/Source/Engine/Platform/Unix/UnixNetwork.h index 28c81ff2d..58c27c453 100644 --- a/Source/Engine/Platform/Unix/UnixNetwork.h +++ b/Source/Engine/Platform/Unix/UnixNetwork.h @@ -22,7 +22,7 @@ public: static bool Listen(NetworkSocket& socket, uint16 queueSize); static bool Accept(NetworkSocket& serverSocket, NetworkSocket& newSocket, NetworkEndPoint& newEndPoint); static bool IsReadable(NetworkSocket& socket); - static bool IsWriteable(NetworkSocket& socket); + static bool IsWritable(NetworkSocket& socket); static bool CreateSocketGroup(uint32 capacity, NetworkSocketGroup& group); static bool DestroySocketGroup(NetworkSocketGroup& group); static int32 Poll(NetworkSocketGroup& group); From 878fee505f08c9ee4e0d5b1c9831c17a8c9d562b Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 16 Mar 2021 23:38:56 +0100 Subject: [PATCH 13/76] Fix updating UI layout after changing control order --- Source/Engine/UI/GUI/ContainerControl.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Engine/UI/GUI/ContainerControl.cs b/Source/Engine/UI/GUI/ContainerControl.cs index fb11f2eff..817bc28a5 100644 --- a/Source/Engine/UI/GUI/ContainerControl.cs +++ b/Source/Engine/UI/GUI/ContainerControl.cs @@ -262,6 +262,8 @@ namespace FlaxEngine.GUI // Change order _children.Insert(newIndex, child); } + + PerformLayout(); } /// From 691df4cb8075c26ebbab33b192310a5090c68499 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 17 Mar 2021 00:04:16 +0100 Subject: [PATCH 14/76] Fix Dpi issues when RootWindow is null Fix #344 --- Source/Editor/GUI/Docking/DockPanel.cs | 2 +- Source/Editor/Surface/ContextMenu/ContentFinder.cs | 2 +- Source/Engine/UI/GUI/Common/RichTextBoxBase.cs | 12 ++++++------ Source/Engine/UI/GUI/Common/TextBox.cs | 4 ++-- Source/Engine/UI/GUI/Control.cs | 5 +++++ Source/Engine/UI/GUI/RenderOutputControl.cs | 2 +- 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/Source/Editor/GUI/Docking/DockPanel.cs b/Source/Editor/GUI/Docking/DockPanel.cs index 74f2d5ab0..f968c2501 100644 --- a/Source/Editor/GUI/Docking/DockPanel.cs +++ b/Source/Editor/GUI/Docking/DockPanel.cs @@ -124,7 +124,7 @@ namespace FlaxEditor.GUI.Docking throw new InvalidOperationException("Missing parent window."); var control = _tabsProxy != null ? (Control)_tabsProxy : this; var clientPos = control.PointToWindow(Vector2.Zero); - return new Rectangle(parentWin.PointToScreen(clientPos), control.Size * RootWindow.DpiScale); + return new Rectangle(parentWin.PointToScreen(clientPos), control.Size * DpiScale); } } diff --git a/Source/Editor/Surface/ContextMenu/ContentFinder.cs b/Source/Editor/Surface/ContextMenu/ContentFinder.cs index 6089c2ca7..fc0f43472 100644 --- a/Source/Editor/Surface/ContextMenu/ContentFinder.cs +++ b/Source/Editor/Surface/ContextMenu/ContentFinder.cs @@ -108,7 +108,7 @@ namespace FlaxEditor.Surface.ContextMenu { _resultPanel.DisposeChildren(); - var dpiScale = RootWindow.DpiScale; + var dpiScale = DpiScale; if (items.Count == 0) { diff --git a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs index 4844cc880..0ef44594b 100644 --- a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs +++ b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs @@ -124,7 +124,7 @@ namespace FlaxEngine.GUI var font = textBlock.Style.Font.GetFont(); if (font) { - height = font.Height / RootWindow.DpiScale; + height = font.Height / DpiScale; return textBlock.Bounds.UpperLeft; } } @@ -136,7 +136,7 @@ namespace FlaxEngine.GUI var font = textBlock.Style.Font.GetFont(); if (font) { - height = font.Height / RootWindow.DpiScale; + height = font.Height / DpiScale; return textBlock.Bounds.UpperRight; } } @@ -151,7 +151,7 @@ namespace FlaxEngine.GUI var font = textBlock.Style.Font.GetFont(); if (!font) break; - height = font.Height / RootWindow.DpiScale; + height = font.Height / DpiScale; return textBlock.Bounds.Location + font.GetCharPosition(_text, ref textBlock.Range, index - textBlock.Range.StartIndex); } } @@ -166,7 +166,7 @@ namespace FlaxEngine.GUI var font = textBlock.Style.Font.GetFont(); if (!font) break; - height = font.Height / RootWindow.DpiScale; + height = font.Height / DpiScale; return textBlock.Bounds.UpperRight; } } @@ -280,7 +280,7 @@ namespace FlaxEngine.GUI { Vector2 leftEdge = selection.StartIndex <= textBlock.Range.StartIndex ? textBlock.Bounds.UpperLeft : font.GetCharPosition(_text, selection.StartIndex); Vector2 rightEdge = selection.EndIndex >= textBlock.Range.EndIndex ? textBlock.Bounds.UpperRight : font.GetCharPosition(_text, selection.EndIndex); - float height = font.Height / RootWindow.DpiScale; + float height = font.Height / DpiScale; float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f); alpha *= alpha; Color selectionColor = Color.White * alpha; @@ -330,7 +330,7 @@ namespace FlaxEngine.GUI if (textBlock.Style.UnderlineBrush != null) { var underLineHeight = 2.0f; - var height = font.Height / RootWindow.DpiScale; + var height = font.Height / DpiScale; var underlineRect = new Rectangle(textBlock.Bounds.Location.X, textBlock.Bounds.Location.Y + height - underLineHeight * 0.5f, textBlock.Bounds.Width, underLineHeight); textBlock.Style.UnderlineBrush.Draw(underlineRect, textBlock.Style.Color); } diff --git a/Source/Engine/UI/GUI/Common/TextBox.cs b/Source/Engine/UI/GUI/Common/TextBox.cs index f454159ec..0a6f11660 100644 --- a/Source/Engine/UI/GUI/Common/TextBox.cs +++ b/Source/Engine/UI/GUI/Common/TextBox.cs @@ -107,7 +107,7 @@ namespace FlaxEngine.GUI return Vector2.Zero; } - height = font.Height / RootWindow.DpiScale; + height = font.Height / DpiScale; return font.GetCharPosition(_text, index, ref _layout); } @@ -159,7 +159,7 @@ namespace FlaxEngine.GUI { Vector2 leftEdge = font.GetCharPosition(_text, SelectionLeft, ref _layout); Vector2 rightEdge = font.GetCharPosition(_text, SelectionRight, ref _layout); - float fontHeight = font.Height / RootWindow.DpiScale; + float fontHeight = font.Height / DpiScale; // Draw selection background float alpha = Mathf.Min(1.0f, Mathf.Cos(_animateTime * BackgroundSelectedFlashSpeed) * 0.5f + 1.3f); diff --git a/Source/Engine/UI/GUI/Control.cs b/Source/Engine/UI/GUI/Control.cs index 3062c3088..fb6424b58 100644 --- a/Source/Engine/UI/GUI/Control.cs +++ b/Source/Engine/UI/GUI/Control.cs @@ -312,6 +312,11 @@ namespace FlaxEngine.GUI /// public virtual WindowRootControl RootWindow => _root?.RootWindow; + /// + /// Gets the control DPI scale factor (1 is default). Includes custom DPI scale. + /// + public float DpiScale => _root?.RootWindow?.DpiScale ?? Platform.DpiScale; + /// /// Gets screen position of the control (upper left corner). /// diff --git a/Source/Engine/UI/GUI/RenderOutputControl.cs b/Source/Engine/UI/GUI/RenderOutputControl.cs index c12b1844e..9a7f6dfb1 100644 --- a/Source/Engine/UI/GUI/RenderOutputControl.cs +++ b/Source/Engine/UI/GUI/RenderOutputControl.cs @@ -224,7 +224,7 @@ namespace FlaxEngine.GUI /// public void SyncBackbufferSize() { - float scale = ResolutionScale * (RootWindow?.DpiScale ?? Platform.DpiScale); + float scale = ResolutionScale * DpiScale; int width = Mathf.CeilToInt(Width * scale); int height = Mathf.CeilToInt(Height * scale); if (_customResolution.HasValue) From a479f1daf62983cedbedabb2049643ad0918c455 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 17 Mar 2021 00:24:29 +0100 Subject: [PATCH 15/76] Fix preserving objects order in prefab instances on apply (based on the prefab) Fixes #346 --- Source/Engine/Level/Prefabs/Prefab.Apply.cpp | 25 ++++++++++++++++++++ Source/Engine/Level/SceneObjectsFactory.cpp | 10 ++++++++ Source/Engine/Serialization/JsonTools.cpp | 2 ++ 3 files changed, 37 insertions(+) diff --git a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp index c0029aa93..c9d94dfe8 100644 --- a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp +++ b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp @@ -367,6 +367,17 @@ bool PrefabInstanceData::SynchronizePrefabInstances(Array& p Level::callActorEvent(Level::ActorEventType::OnActorActiveChanged, actor, nullptr); Level::callActorEvent(Level::ActorEventType::OnActorOrderInParentChanged, actor, nullptr); } + + // Preserve order in parent (values from prefab are used) + if (i != 0) + { + auto prefab = Content::Load(prefabId); + const auto defaultInstance = prefab ? prefab->GetDefaultInstance(obj->GetPrefabObjectID()) : nullptr; + if (defaultInstance) + { + obj->SetOrderInParent(defaultInstance->GetOrderInParent()); + } + } } } @@ -784,6 +795,20 @@ bool Prefab::ApplyAllInternal(Actor* targetActor, bool linkTargetActorObjectToPr obj->Deserialize(diffDataDocument[dataIndex], modifier.Value); sceneObjects->Add(obj); + + // Synchronize order of the scene objects with the serialized data (eg. user reordered actors in prefab editor and applied changes) + if (i != 0) + { + for (int32 j = 0; j < targetObjects->Count(); j++) + { + SceneObject* targetObject = targetObjects->At(j); + if (targetObject->GetPrefabObjectID() == obj->GetID()) + { + obj->SetOrderInParent(targetObject->GetOrderInParent()); + break; + } + } + } } else { diff --git a/Source/Engine/Level/SceneObjectsFactory.cpp b/Source/Engine/Level/SceneObjectsFactory.cpp index a5cb27712..a140b103c 100644 --- a/Source/Engine/Level/SceneObjectsFactory.cpp +++ b/Source/Engine/Level/SceneObjectsFactory.cpp @@ -257,6 +257,16 @@ void SceneObjectsFactory::SynchronizePrefabInstances(Array& sceneO // Reparent obj->SetParent(actualParent, false); } + + // Preserve order in parent (values from prefab are used) + if (i != 0) + { + const auto defaultInstance = prefab ? prefab->GetDefaultInstance(obj->GetPrefabObjectID()) : nullptr; + if (defaultInstance) + { + obj->SetOrderInParent(defaultInstance->GetOrderInParent()); + } + } } // Check all actors with prefab linkage for adding missing objects diff --git a/Source/Engine/Serialization/JsonTools.cpp b/Source/Engine/Serialization/JsonTools.cpp index fad907f45..1a8da00eb 100644 --- a/Source/Engine/Serialization/JsonTools.cpp +++ b/Source/Engine/Serialization/JsonTools.cpp @@ -100,6 +100,8 @@ void ChangeIds(rapidjson_flax::Value& obj, rapidjson_flax::Document& document, c void JsonTools::ChangeIds(Document& doc, const Dictionary& mapping) { + if (mapping.IsEmpty()) + return; ::ChangeIds(doc, doc, mapping); } From 4eeadf87fb6c3a13e9cc88053cfcb7448293476c Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 17 Mar 2021 10:28:14 +0100 Subject: [PATCH 16/76] Fix warning --- Source/Engine/UI/GUI/Control.cs | 2 +- Source/Engine/UI/GUI/WindowRootControl.cs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Source/Engine/UI/GUI/Control.cs b/Source/Engine/UI/GUI/Control.cs index fb6424b58..597cc9e41 100644 --- a/Source/Engine/UI/GUI/Control.cs +++ b/Source/Engine/UI/GUI/Control.cs @@ -315,7 +315,7 @@ namespace FlaxEngine.GUI /// /// Gets the control DPI scale factor (1 is default). Includes custom DPI scale. /// - public float DpiScale => _root?.RootWindow?.DpiScale ?? Platform.DpiScale; + public float DpiScale => _root?.RootWindow?.Window.DpiScale ?? Platform.DpiScale; /// /// Gets screen position of the control (upper left corner). diff --git a/Source/Engine/UI/GUI/WindowRootControl.cs b/Source/Engine/UI/GUI/WindowRootControl.cs index a8028ebe8..1e9785195 100644 --- a/Source/Engine/UI/GUI/WindowRootControl.cs +++ b/Source/Engine/UI/GUI/WindowRootControl.cs @@ -55,11 +55,6 @@ namespace FlaxEngine.GUI /// public bool IsMaximized => _window.IsMaximized; - /// - /// Gets the window DPI scale factor (1 is default). Includes custom DPI scale - /// - public float DpiScale => _window.DpiScale; - internal WindowRootControl(Window window) { _window = window; From 8fb27e6f8399904d099f54d398a1b2a2a3752ccf Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 17 Mar 2021 11:12:08 +0100 Subject: [PATCH 17/76] Fix missing UICanvas linkage in prefab preview #218 --- Source/Editor/Viewport/Previews/PrefabPreview.cs | 12 ++++++++++++ Source/Engine/UI/UICanvas.cpp | 10 ++++++++++ Source/Engine/UI/UICanvas.cs | 12 ++++++++++++ Source/Engine/UI/UICanvas.h | 1 + 4 files changed, 35 insertions(+) diff --git a/Source/Editor/Viewport/Previews/PrefabPreview.cs b/Source/Editor/Viewport/Previews/PrefabPreview.cs index 066e98456..09ff34d0d 100644 --- a/Source/Editor/Viewport/Previews/PrefabPreview.cs +++ b/Source/Editor/Viewport/Previews/PrefabPreview.cs @@ -121,6 +121,18 @@ namespace FlaxEditor.Viewport.Previews { } + /// + public override void Update(float deltaTime) + { + base.Update(deltaTime); + + if (_instance != null) + { + // Link UI canvases to the preview (eg. after canvas added to the prefab) + LinkCanvas(_instance); + } + } + /// public override void OnDestroy() { diff --git a/Source/Engine/UI/UICanvas.cpp b/Source/Engine/UI/UICanvas.cpp index ccd0561ad..ab1841acc 100644 --- a/Source/Engine/UI/UICanvas.cpp +++ b/Source/Engine/UI/UICanvas.cpp @@ -15,6 +15,7 @@ MMethod* UICanvas_PostDeserialize = nullptr; MMethod* UICanvas_OnEnable = nullptr; MMethod* UICanvas_OnDisable = nullptr; MMethod* UICanvas_EndPlay = nullptr; +MMethod* UICanvas_ParentChanged = nullptr; #define UICANVAS_INVOKE(event) \ auto instance = GetManagedInstance(); \ @@ -43,6 +44,7 @@ UICanvas::UICanvas(const SpawnParams& params) UICanvas_OnEnable = mclass->GetMethod("OnEnable"); UICanvas_OnDisable = mclass->GetMethod("OnDisable"); UICanvas_EndPlay = mclass->GetMethod("EndPlay"); + UICanvas_ParentChanged = mclass->GetMethod("ParentChanged"); } } @@ -133,6 +135,14 @@ void UICanvas::EndPlay() Actor::EndPlay(); } +void UICanvas::OnParentChanged() +{ + // Base + Actor::OnParentChanged(); + + UICANVAS_INVOKE(ParentChanged); +} + void UICanvas::OnEnable() { UICANVAS_INVOKE(OnEnable); diff --git a/Source/Engine/UI/UICanvas.cs b/Source/Engine/UI/UICanvas.cs index 81b3e09dc..0c5a32def 100644 --- a/Source/Engine/UI/UICanvas.cs +++ b/Source/Engine/UI/UICanvas.cs @@ -539,6 +539,16 @@ namespace FlaxEngine Setup(); } + internal void ParentChanged() + { +#if FLAX_EDITOR + if (RenderMode == CanvasRenderMode.ScreenSpace && _editorRoot != null && _guiRoot != null) + { + _guiRoot.Parent = HasParent ? _editorRoot : null; + } +#endif + } + internal void OnEnable() { #if FLAX_EDITOR @@ -587,6 +597,8 @@ namespace FlaxEngine internal void EditorOverride(SceneRenderTask task, ContainerControl root) { + if (_editorTask == task && _editorRoot == root) + return; if (_editorTask != null && _renderer != null) _editorTask.CustomPostFx.Remove(_renderer); if (_editorRoot != null && _guiRoot != null) diff --git a/Source/Engine/UI/UICanvas.h b/Source/Engine/UI/UICanvas.h index 8e8b9b0d1..cb049c684 100644 --- a/Source/Engine/UI/UICanvas.h +++ b/Source/Engine/UI/UICanvas.h @@ -24,6 +24,7 @@ protected: // [Actor] void BeginPlay(SceneBeginData* data) final override; void EndPlay() final override; + void OnParentChanged() override; void OnEnable() override; void OnDisable() override; void OnTransformChanged() final override; From aa1c200bf8e9ae231f02d89479833356b20c2d75 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 17 Mar 2021 11:12:20 +0100 Subject: [PATCH 18/76] Fix exception on engine closing in some cases --- Source/Editor/Editor.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index 408dddbd6..ce8805af0 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -1166,7 +1166,7 @@ namespace FlaxEditor if (Windows.GameWin != null && Windows.GameWin.ContainsFocus) { var win = Windows.GameWin.Root; - if (win != null && win.RootWindow is WindowRootControl root && root.Window.IsFocused) + if (win?.RootWindow is WindowRootControl root && root.Window && root.Window.IsFocused) { return true; } @@ -1179,7 +1179,7 @@ namespace FlaxEditor if (Windows.GameWin != null && Windows.GameWin.ContainsFocus) { var win = Windows.GameWin.Root; - if (win != null && win.RootWindow is WindowRootControl root && root.Window.IsFocused) + if (win?.RootWindow is WindowRootControl root && root.Window && root.Window.IsFocused) { pos = Vector2.Round(Windows.GameWin.Viewport.PointFromScreen(pos) * root.DpiScale); } @@ -1199,7 +1199,7 @@ namespace FlaxEditor if (Windows.GameWin != null && Windows.GameWin.ContainsFocus) { var win = Windows.GameWin.Root; - if (win != null && win.RootWindow is WindowRootControl root && root.Window.IsFocused) + if (win?.RootWindow is WindowRootControl root && root.Window && root.Window.IsFocused) { pos = Vector2.Round(Windows.GameWin.Viewport.PointToScreen(pos / root.DpiScale)); } From 0122bf68bf5da371b397d324058acf318cbb16e7 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 17 Mar 2021 11:54:36 +0100 Subject: [PATCH 19/76] Fix skipping UICanvas diff serialization for Size property if render mode is ScreenSpace --- Source/Engine/UI/UICanvas.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/UI/UICanvas.cs b/Source/Engine/UI/UICanvas.cs index 0c5a32def..23ff6f87b 100644 --- a/Source/Engine/UI/UICanvas.cs +++ b/Source/Engine/UI/UICanvas.cs @@ -510,7 +510,7 @@ namespace FlaxEngine jsonWriter.WriteValue(Distance); } - if (Size != other.Size) + if ((RenderMode != other.RenderMode || RenderMode != CanvasRenderMode.ScreenSpace) && Size != other.Size) { jsonWriter.WritePropertyName("Size"); jsonWriter.WriteStartObject(); From 2a2d9f54dee7f0d8c3f012e2cec2879a768eddd0 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 17 Mar 2021 11:55:17 +0100 Subject: [PATCH 20/76] Fix UIControl location deserialization when using prefabs and anchors #218 --- Source/Engine/UI/UIControl.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/Engine/UI/UIControl.cs b/Source/Engine/UI/UIControl.cs index 8fd4f8f72..2b239f982 100644 --- a/Source/Engine/UI/UIControl.cs +++ b/Source/Engine/UI/UIControl.cs @@ -296,6 +296,9 @@ namespace FlaxEngine if (_control != null) { Json.JsonSerializer.Deserialize(_control, json); + + // Synchronize actor with control location + OnControlLocationChanged(_control); } } From e6d3242670f1f49791b12d25f0ee44e36c5abe0e Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 17 Mar 2021 11:58:26 +0100 Subject: [PATCH 21/76] Fix invalid UIControl event blocking for prefab editor --- Source/Engine/UI/UIControl.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/Source/Engine/UI/UIControl.cpp b/Source/Engine/UI/UIControl.cpp index 51312ae15..106e51d63 100644 --- a/Source/Engine/UI/UIControl.cpp +++ b/Source/Engine/UI/UIControl.cpp @@ -155,9 +155,6 @@ void UIControl::OnParentChanged() // Base Actor::OnParentChanged(); - if (!IsDuringPlay()) - return; - UICONTROL_INVOKE(ParentChanged); } From 518df5e62b61f491c7996c1f7d4c3fe72ddb2252 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 17 Mar 2021 13:44:38 +0100 Subject: [PATCH 22/76] Add skipping textbox scrolling if it has no selection --- Source/Engine/UI/GUI/Common/TextBoxBase.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Engine/UI/GUI/Common/TextBoxBase.cs b/Source/Engine/UI/GUI/Common/TextBoxBase.cs index 1df079b48..21187f594 100644 --- a/Source/Engine/UI/GUI/Common/TextBoxBase.cs +++ b/Source/Engine/UI/GUI/Common/TextBoxBase.cs @@ -539,6 +539,12 @@ namespace FlaxEngine.GUI return; } + // If it's not selected + if (_selectionStart == -1 && _selectionEnd == -1) + { + return; + } + Rectangle caretBounds = CaretBounds; Rectangle textArea = TextRectangle; From c4d457d7b7ddc7ffba08624ec9cd6b290bf359ec Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 17 Mar 2021 17:01:10 +0100 Subject: [PATCH 23/76] Fix control Offsets margin diff deserialziation --- Source/Engine/Serialization/JsonSerializer.cs | 111 ++++++++++++++++++ Source/Platforms/DotNet/Newtonsoft.Json.dll | 4 +- Source/Platforms/DotNet/Newtonsoft.Json.pdb | 4 +- Source/Platforms/DotNet/Newtonsoft.Json.xml | 15 +++ 4 files changed, 130 insertions(+), 4 deletions(-) diff --git a/Source/Engine/Serialization/JsonSerializer.cs b/Source/Engine/Serialization/JsonSerializer.cs index 127fa4d87..b3bd51d6f 100644 --- a/Source/Engine/Serialization/JsonSerializer.cs +++ b/Source/Engine/Serialization/JsonSerializer.cs @@ -7,6 +7,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading; +using FlaxEngine.GUI; using FlaxEngine.Json.JsonCustomSerializers; using FlaxEngine.Utilities; using Newtonsoft.Json; @@ -119,6 +120,115 @@ namespace FlaxEngine.Json } } + /// + /// Serialize SoftObjectReference as Guid in internal format. + /// + /// + internal class MarginConverter : JsonConverter + { + /// + public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) + { + var valueMargin = (Margin)value; + + writer.WriteStartObject(); + { + writer.WritePropertyName("Left"); + writer.WriteValue(valueMargin.Left); + writer.WritePropertyName("Right"); + writer.WriteValue(valueMargin.Right); + writer.WritePropertyName("Top"); + writer.WriteValue(valueMargin.Top); + writer.WritePropertyName("Bottom"); + writer.WriteValue(valueMargin.Bottom); + } + writer.WriteEndObject(); + } + + /// + public override void WriteJsonDiff(JsonWriter writer, object value, object other, Newtonsoft.Json.JsonSerializer serializer) + { + var valueMargin = (Margin)value; + var otherMargin = (Margin)other; + writer.WriteStartObject(); + if (!Mathf.NearEqual(valueMargin.Left, otherMargin.Left)) + { + writer.WritePropertyName("Left"); + writer.WriteValue(valueMargin.Left); + } + if (!Mathf.NearEqual(valueMargin.Right, otherMargin.Right)) + { + writer.WritePropertyName("Right"); + writer.WriteValue(valueMargin.Right); + } + if (!Mathf.NearEqual(valueMargin.Top, otherMargin.Top)) + { + writer.WritePropertyName("Top"); + writer.WriteValue(valueMargin.Top); + } + if (!Mathf.NearEqual(valueMargin.Bottom, otherMargin.Bottom)) + { + writer.WritePropertyName("Bottom"); + writer.WriteValue(valueMargin.Bottom); + } + writer.WriteEndObject(); + } + + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) + { + var value = (Margin?)existingValue ?? new Margin(); + if (reader.TokenType == JsonToken.StartObject) + { + while (reader.Read()) + { + switch (reader.TokenType) + { + case JsonToken.PropertyName: + { + var propertyName = (string)reader.Value; + var propertyValue = (float)reader.ReadAsDouble(); + switch (propertyName) + { + case "Left": + value.Left = propertyValue; + break; + case "Right": + value.Right = propertyValue; + break; + case "Top": + value.Top = propertyValue; + break; + case "Bottom": + value.Bottom = propertyValue; + break; + } + break; + } + case JsonToken.Comment: break; + default: return value; + } + } + } + return value; + } + + /// + public override bool CanConvert(Type objectType) + { + return objectType == typeof(Margin); + } + + /// + public override bool CanRead => true; + + /// + public override bool CanWrite => true; + + /// + public override bool CanWriteDiff => true; + } + /* /// /// Serialize Guid values using `N` format @@ -219,6 +329,7 @@ namespace FlaxEngine.Json settings.Converters.Add(ObjectConverter); settings.Converters.Add(new SceneReferenceConverter()); settings.Converters.Add(new SoftObjectReferenceConverter()); + settings.Converters.Add(new MarginConverter()); settings.Converters.Add(new VersionConverter()); //settings.Converters.Add(new GuidConverter()); return settings; diff --git a/Source/Platforms/DotNet/Newtonsoft.Json.dll b/Source/Platforms/DotNet/Newtonsoft.Json.dll index 17df31d86..b08068dd3 100644 --- a/Source/Platforms/DotNet/Newtonsoft.Json.dll +++ b/Source/Platforms/DotNet/Newtonsoft.Json.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:616780417730a6371909713a2d8150347870e67ed52803642caef37e8bda1891 -size 630272 +oid sha256:7ed0cb43a692d86f2d47bfc93475e554ee8a70b33187b1e1d2356a7d4f25fffa +size 629760 diff --git a/Source/Platforms/DotNet/Newtonsoft.Json.pdb b/Source/Platforms/DotNet/Newtonsoft.Json.pdb index 68e8489b6..9d8502e2c 100644 --- a/Source/Platforms/DotNet/Newtonsoft.Json.pdb +++ b/Source/Platforms/DotNet/Newtonsoft.Json.pdb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9d4fc76d2ef9b0cd7b88da95f4894d9cc924703af0b02e052f8e78446f75e2d9 -size 239080 +oid sha256:5e5b77e2864fee56c380d85c8d1488713c5ba5deacb9005d125d9e47629014e8 +size 249884 diff --git a/Source/Platforms/DotNet/Newtonsoft.Json.xml b/Source/Platforms/DotNet/Newtonsoft.Json.xml index fb9404249..c1d3cfd3d 100644 --- a/Source/Platforms/DotNet/Newtonsoft.Json.xml +++ b/Source/Platforms/DotNet/Newtonsoft.Json.xml @@ -1691,6 +1691,15 @@ The value. The calling serializer. + + + Writes the JSON representation of the object diff compared to other instance of the object (the same type). + + The to write to. + The value. + The other value (the same type). + The calling serializer. + Reads the JSON representation of the object. @@ -1722,6 +1731,12 @@ true if this can write JSON; otherwise, false. + + + Gets a value indicating whether this can write JSON for object difference. + + true if this can write JSON diff; otherwise, false. + Converts an object to and from JSON. From 30615e842d3e35cb11ccddfb0989439292450440 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 17 Mar 2021 17:14:57 +0100 Subject: [PATCH 24/76] Fix crash on Actor deserialization if parentId is missing but actor already has a parent --- Source/Engine/Level/Actor.cpp | 44 ++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp index 3753f6140..56aa20fa0 100644 --- a/Source/Engine/Level/Actor.cpp +++ b/Source/Engine/Level/Actor.cpp @@ -945,28 +945,34 @@ void Actor::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) DESERIALIZE_MEMBER(Name, _name); DESERIALIZE_MEMBER(Transform, _localTransform); - Guid parentId = Guid::Empty; - DESERIALIZE_MEMBER(ParentID, parentId); - const auto parent = Scripting::FindObject(parentId); - if (_parent != parent) { - if (IsDuringPlay()) + const auto member = SERIALIZE_FIND_MEMBER(stream, "ParentID"); + if (member != stream.MemberEnd()) { - SetParent(parent, false, false); + Guid parentId; + Serialization::Deserialize(member->value, parentId, modifier); + const auto parent = Scripting::FindObject(parentId); + if (_parent != parent) + { + if (IsDuringPlay()) + { + SetParent(parent, false, false); + } + else + { + if (_parent) + _parent->Children.RemoveKeepOrder(this); + _parent = parent; + if (_parent) + _parent->Children.Add(this); + OnParentChanged(); + } + } + else if (!parent && parentId.IsValid()) + { + LOG(Warning, "Missing parent actor {0} for \'{1}\'", parentId, ToString()); + } } - else - { - if (_parent) - _parent->Children.RemoveKeepOrder(this); - _parent = parent; - if (_parent) - _parent->Children.Add(this); - OnParentChanged(); - } - } - else if (!parent && parentId.IsValid()) - { - LOG(Warning, "Missing parent actor {0} for \'{1}\'", parentId, ToString()); } // StaticFlags update - added StaticFlags::Navigation From f194004ebfa73cc73da01f58504fb50c692bbd95 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 17 Mar 2021 17:15:37 +0100 Subject: [PATCH 25/76] Fix synchronizing ActiveInTreeChanged property with event after prefab changes apply --- Source/Engine/Level/Prefabs/Prefab.Apply.cpp | 31 +++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp index c9d94dfe8..1c6c337ce 100644 --- a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp +++ b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp @@ -358,16 +358,6 @@ bool PrefabInstanceData::SynchronizePrefabInstances(Array& p { obj->Deserialize(instance.Data[dataIndex], modifier.Value); - // Send events because some properties may be modified during prefab changes apply - // TODO: maybe send only valid events (need to track changes for before-after state) - Actor* actor = dynamic_cast(obj); - if (actor && actor->IsDuringPlay()) - { - Level::callActorEvent(Level::ActorEventType::OnActorNameChanged, actor, nullptr); - Level::callActorEvent(Level::ActorEventType::OnActorActiveChanged, actor, nullptr); - Level::callActorEvent(Level::ActorEventType::OnActorOrderInParentChanged, actor, nullptr); - } - // Preserve order in parent (values from prefab are used) if (i != 0) { @@ -383,13 +373,32 @@ bool PrefabInstanceData::SynchronizePrefabInstances(Array& p Scripting::ObjectsLookupIdMapping.Set(nullptr); - // Setup objects after deserialization + // Setup new objects after deserialization for (int32 i = existingObjectsCount; i < sceneObjects->Count(); i++) { SceneObject* obj = sceneObjects.Value->At(i); obj->PostLoad(); } + // Synchronize existing objects logic with deserialized state (fire events) + for (int32 i = 0; i < existingObjectsCount; i++) + { + SceneObject* obj = sceneObjects->At(i); + Actor* actor = dynamic_cast(obj); + if (actor && actor->IsDuringPlay()) + { + const bool shouldBeActiveInHierarchy = actor->GetIsActive() && (!actor->GetParent() || actor->GetParent()->IsActiveInHierarchy()); + if (shouldBeActiveInHierarchy != actor->IsActiveInHierarchy()) + { + actor->_isActiveInHierarchy = shouldBeActiveInHierarchy; + actor->OnActiveInTreeChanged(); + Level::callActorEvent(Level::ActorEventType::OnActorActiveChanged, actor, nullptr); + } + Level::callActorEvent(Level::ActorEventType::OnActorNameChanged, actor, nullptr); + Level::callActorEvent(Level::ActorEventType::OnActorOrderInParentChanged, actor, nullptr); + } + } + // Restore order in parent instance.TargetActor->SetOrderInParent(instance.OrderInParent); From 0c74e2ff9d77b5952fff3a3e8f92a6fe9230b898 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 17 Mar 2021 18:29:15 +0100 Subject: [PATCH 26/76] Fix crash on prefab sync on instance with missing objects --- Source/Engine/Level/Prefabs/Prefab.Apply.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp index 1c6c337ce..45ec036bd 100644 --- a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp +++ b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp @@ -895,7 +895,10 @@ bool Prefab::ApplyAllInternal(Actor* targetActor, bool linkTargetActorObjectToPr for (int32 i = 0; i < sceneObjects->Count(); i++) { auto obj = sceneObjects.Value->At(i); - obj->PostLoad(); + if (obj) + { + obj->PostLoad(); + } } // Update transformations From 92cfcbff8c2eaf09a3f2a9a554e86a67a4aafda6 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 17 Mar 2021 18:29:53 +0100 Subject: [PATCH 27/76] Fix actor layer editor setup --- Source/Editor/CustomEditors/Editors/ActorLayerEditor.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Source/Editor/CustomEditors/Editors/ActorLayerEditor.cs b/Source/Editor/CustomEditors/Editors/ActorLayerEditor.cs index a6aa34880..555ebc870 100644 --- a/Source/Editor/CustomEditors/Editors/ActorLayerEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ActorLayerEditor.cs @@ -22,10 +22,9 @@ namespace FlaxEditor.CustomEditors.Editors public override void Initialize(LayoutElementsContainer layout) { element = layout.ComboBox(); - element.ComboBox.SelectedIndexChanged += OnSelectedIndexChanged; - - // Set layer names element.ComboBox.SetItems(LayersAndTagsSettings.GetCurrentLayers()); + element.ComboBox.SelectedIndex = (int)Values[0]; + element.ComboBox.SelectedIndexChanged += OnSelectedIndexChanged; } private void GetActorsTree(List list, Actor a) From 960268f75667cdeec1f62cfec1472b21790a2501 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 17 Mar 2021 19:23:54 +0100 Subject: [PATCH 28/76] Fix UICanvas state synchronization when working with prefabs --- Source/Engine/UI/UICanvas.cs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/Source/Engine/UI/UICanvas.cs b/Source/Engine/UI/UICanvas.cs index 23ff6f87b..0a9e7531f 100644 --- a/Source/Engine/UI/UICanvas.cs +++ b/Source/Engine/UI/UICanvas.cs @@ -101,7 +101,7 @@ namespace FlaxEngine Setup(); // Reset size - if (previous == CanvasRenderMode.ScreenSpace && _renderMode == CanvasRenderMode.WorldSpace) + if (previous == CanvasRenderMode.ScreenSpace || _renderMode == CanvasRenderMode.WorldSpace) Size = new Vector2(500, 500); } } @@ -145,7 +145,7 @@ namespace FlaxEngine private bool Editor_IsCameraSpace => _renderMode == CanvasRenderMode.CameraSpace; /// - /// Gets or sets the size of the canvas. Used only in or . + /// Gets or sets the size of the canvas. Used only in . /// [EditorOrder(20), EditorDisplay("Canvas"), VisibleIf(nameof(Editor_IsWorldSpace)), Tooltip("Canvas size.")] public Vector2 Size @@ -368,7 +368,7 @@ namespace FlaxEngine _renderer = null; } #if FLAX_EDITOR - if (_editorRoot != null) + if (_editorRoot != null && IsActiveInHierarchy) _guiRoot.Parent = _editorRoot; #endif break; @@ -442,13 +442,16 @@ namespace FlaxEngine jsonWriter.WritePropertyName("Distance"); jsonWriter.WriteValue(Distance); - jsonWriter.WritePropertyName("Size"); - jsonWriter.WriteStartObject(); - jsonWriter.WritePropertyName("X"); - jsonWriter.WriteValue(Size.X); - jsonWriter.WritePropertyName("Y"); - jsonWriter.WriteValue(Size.Y); - jsonWriter.WriteEndObject(); + if (RenderMode == CanvasRenderMode.WorldSpace) + { + jsonWriter.WritePropertyName("Size"); + jsonWriter.WriteStartObject(); + jsonWriter.WritePropertyName("X"); + jsonWriter.WriteValue(Size.X); + jsonWriter.WritePropertyName("Y"); + jsonWriter.WriteValue(Size.Y); + jsonWriter.WriteEndObject(); + } jsonWriter.WriteEndObject(); } @@ -510,7 +513,7 @@ namespace FlaxEngine jsonWriter.WriteValue(Distance); } - if ((RenderMode != other.RenderMode || RenderMode != CanvasRenderMode.ScreenSpace) && Size != other.Size) + if ((RenderMode == CanvasRenderMode.WorldSpace || other.RenderMode == CanvasRenderMode.WorldSpace) && Size != other.Size) { jsonWriter.WritePropertyName("Size"); jsonWriter.WriteStartObject(); @@ -544,7 +547,7 @@ namespace FlaxEngine #if FLAX_EDITOR if (RenderMode == CanvasRenderMode.ScreenSpace && _editorRoot != null && _guiRoot != null) { - _guiRoot.Parent = HasParent ? _editorRoot : null; + _guiRoot.Parent = HasParent && IsActiveInHierarchy ? _editorRoot : null; } #endif } @@ -608,7 +611,7 @@ namespace FlaxEngine _editorRoot = root; Setup(); - if (RenderMode == CanvasRenderMode.ScreenSpace && _editorRoot != null && _guiRoot != null) + if (RenderMode == CanvasRenderMode.ScreenSpace && _editorRoot != null && _guiRoot != null && IsActiveInHierarchy) _guiRoot.Parent = _editorRoot; } #endif From 675bb93fd503384dc78f25ec1e6fa88685b80c79 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 17 Mar 2021 19:24:29 +0100 Subject: [PATCH 29/76] Fix missing prefab instanced actors events sending on changes apply (regression) --- Source/Engine/Level/Prefabs/Prefab.Apply.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp index 45ec036bd..f65c9fbe9 100644 --- a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp +++ b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp @@ -385,7 +385,7 @@ bool PrefabInstanceData::SynchronizePrefabInstances(Array& p { SceneObject* obj = sceneObjects->At(i); Actor* actor = dynamic_cast(obj); - if (actor && actor->IsDuringPlay()) + if (actor) { const bool shouldBeActiveInHierarchy = actor->GetIsActive() && (!actor->GetParent() || actor->GetParent()->IsActiveInHierarchy()); if (shouldBeActiveInHierarchy != actor->IsActiveInHierarchy()) From df497bf68426cc7e4ab35252fabed417310b4e38 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 17 Mar 2021 19:25:12 +0100 Subject: [PATCH 30/76] Fix UIControl invalid showing in prefab window using nested prefab with UI --- Source/Engine/UI/UIControl.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Source/Engine/UI/UIControl.cs b/Source/Engine/UI/UIControl.cs index 2b239f982..04194cf69 100644 --- a/Source/Engine/UI/UIControl.cs +++ b/Source/Engine/UI/UIControl.cs @@ -199,6 +199,11 @@ namespace FlaxEngine // Don't link disabled actors if (!IsActiveInHierarchy) return null; +#if FLAX_EDITOR + // Prefab editor doesn't fire BeginPlay so for disabled actors we don't unlink them so do it here + if (!IsActive) + return null; +#endif var parent = Parent; if (parent is UIControl uiControl && uiControl.Control is ContainerControl uiContainerControl) From 5af3a22fd01f4b32809cfbf5690992a8388edfec Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Perrier Date: Wed, 17 Mar 2021 20:22:06 +0100 Subject: [PATCH 31/76] Add DrawSelf. --- Source/Engine/UI/GUI/ContainerControl.cs | 43 ++++++++++++++---------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/Source/Engine/UI/GUI/ContainerControl.cs b/Source/Engine/UI/GUI/ContainerControl.cs index 817bc28a5..8e046ecde 100644 --- a/Source/Engine/UI/GUI/ContainerControl.cs +++ b/Source/Engine/UI/GUI/ContainerControl.cs @@ -616,32 +616,35 @@ namespace FlaxEngine.GUI } } - /// + /// + /// Draw the control and the children. + /// public override void Draw() { - base.Draw(); + DrawSelf(); + DrawChildren(); + } + /// + /// Draws the control. + /// + public virtual void DrawSelf() + { + base.Draw(); + } + + /// + /// Draws the children. Can be overridden to provide some customizations. Draw is performed with applied clipping mask for the client area. + /// + protected virtual void DrawChildren() + { // Push clipping mask if (ClipChildren) { GetDesireClientArea(out var clientArea); Render2D.PushClip(ref clientArea); } - - DrawChildren(); - - // Pop clipping mask - if (ClipChildren) - { - Render2D.PopClip(); - } - } - - /// - /// Draws the children. Can be overridden to provide some customizations. Draw is performed with applied clipping mask for the client area. - /// - protected virtual void DrawChildren() - { + // Draw all visible child controls if (CullChildren) { @@ -676,6 +679,12 @@ namespace FlaxEngine.GUI } } } + + // Pop clipping mask + if (ClipChildren) + { + Render2D.PopClip(); + } } /// From fb70368c8d94b07d233caa243ae24aee97d78878 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Perrier Date: Wed, 17 Mar 2021 20:22:27 +0100 Subject: [PATCH 32/76] Fix image ordering. --- Source/Engine/UI/GUI/Common/Image.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Engine/UI/GUI/Common/Image.cs b/Source/Engine/UI/GUI/Common/Image.cs index b94b285b6..adeddce6b 100644 --- a/Source/Engine/UI/GUI/Common/Image.cs +++ b/Source/Engine/UI/GUI/Common/Image.cs @@ -80,10 +80,10 @@ namespace FlaxEngine.GUI } /// - public override void Draw() + public override void DrawSelf() { - base.Draw(); - + base.DrawSelf(); + if (Brush == null) return; From c8b57d417c9dc3ffd5b5fc43ca8105b9115a5f36 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Perrier Date: Wed, 17 Mar 2021 20:53:42 +0100 Subject: [PATCH 33/76] Convert Control to ContainerControl. --- Source/Engine/UI/GUI/Common/Border.cs | 6 +++--- Source/Engine/UI/GUI/Common/Button.cs | 4 ++-- Source/Engine/UI/GUI/Common/ProgressBar.cs | 6 +++--- Source/Engine/UI/GUI/Common/RenderToTextureControl.cs | 4 ++-- Source/Engine/UI/GUI/Common/RichTextBoxBase.cs | 2 +- Source/Engine/UI/GUI/Common/TextBox.cs | 2 +- Source/Engine/UI/GUI/Common/TextBoxBase.cs | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Source/Engine/UI/GUI/Common/Border.cs b/Source/Engine/UI/GUI/Common/Border.cs index 543735e99..fb699b132 100644 --- a/Source/Engine/UI/GUI/Common/Border.cs +++ b/Source/Engine/UI/GUI/Common/Border.cs @@ -5,7 +5,7 @@ namespace FlaxEngine.GUI /// /// Border control that draws the border around the control edges (inner and outer sides). /// - public class Border : Control + public class Border : ContainerControl { /// /// Gets or sets the color used to draw border lines. @@ -30,9 +30,9 @@ namespace FlaxEngine.GUI } /// - public override void Draw() + public override void DrawSelf() { - base.Draw(); + base.DrawSelf(); Render2D.DrawRectangle(new Rectangle(Vector2.Zero, Size), BorderColor, BorderWidth); } diff --git a/Source/Engine/UI/GUI/Common/Button.cs b/Source/Engine/UI/GUI/Common/Button.cs index 9d56a4a36..639552ec3 100644 --- a/Source/Engine/UI/GUI/Common/Button.cs +++ b/Source/Engine/UI/GUI/Common/Button.cs @@ -7,7 +7,7 @@ namespace FlaxEngine.GUI /// /// Button control /// - public class Button : Control + public class Button : ContainerControl { /// /// The default height fro the buttons. @@ -171,7 +171,7 @@ namespace FlaxEngine.GUI } /// - public override void Draw() + public override void DrawSelf() { // Cache data Rectangle clientRect = new Rectangle(Vector2.Zero, Size); diff --git a/Source/Engine/UI/GUI/Common/ProgressBar.cs b/Source/Engine/UI/GUI/Common/ProgressBar.cs index f68336d24..21cce7faa 100644 --- a/Source/Engine/UI/GUI/Common/ProgressBar.cs +++ b/Source/Engine/UI/GUI/Common/ProgressBar.cs @@ -8,7 +8,7 @@ namespace FlaxEngine.GUI /// Progress bar control shows visual progress of the action or set of actions. /// /// - public class ProgressBar : Control + public class ProgressBar : ContainerControl { /// /// The value. @@ -160,9 +160,9 @@ namespace FlaxEngine.GUI } /// - public override void Draw() + public override void DrawSelf() { - base.Draw(); + base.DrawSelf(); float progressNormalized = (_current - _minimum) / _maximum; if (progressNormalized > 0.001f) diff --git a/Source/Engine/UI/GUI/Common/RenderToTextureControl.cs b/Source/Engine/UI/GUI/Common/RenderToTextureControl.cs index 526390dac..3894c3027 100644 --- a/Source/Engine/UI/GUI/Common/RenderToTextureControl.cs +++ b/Source/Engine/UI/GUI/Common/RenderToTextureControl.cs @@ -105,7 +105,7 @@ namespace FlaxEngine.GUI } /// - public override void Draw() + public override void DrawSelf() { // Draw cached texture if (_texture && !_invalid && !_isDuringTextureDraw) @@ -119,7 +119,7 @@ namespace FlaxEngine.GUI } // Draw default UI directly - base.Draw(); + base.DrawSelf(); } /// diff --git a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs index 0ef44594b..1a57061e1 100644 --- a/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs +++ b/Source/Engine/UI/GUI/Common/RichTextBoxBase.cs @@ -220,7 +220,7 @@ namespace FlaxEngine.GUI } /// - public override void Draw() + public override void DrawSelf() { // Cache data var rect = new Rectangle(Vector2.Zero, Size); diff --git a/Source/Engine/UI/GUI/Common/TextBox.cs b/Source/Engine/UI/GUI/Common/TextBox.cs index 0a6f11660..0ed5c731c 100644 --- a/Source/Engine/UI/GUI/Common/TextBox.cs +++ b/Source/Engine/UI/GUI/Common/TextBox.cs @@ -132,7 +132,7 @@ namespace FlaxEngine.GUI } /// - public override void Draw() + public override void DrawSelf() { // Cache data var rect = new Rectangle(Vector2.Zero, Size); diff --git a/Source/Engine/UI/GUI/Common/TextBoxBase.cs b/Source/Engine/UI/GUI/Common/TextBoxBase.cs index 1df079b48..c05790308 100644 --- a/Source/Engine/UI/GUI/Common/TextBoxBase.cs +++ b/Source/Engine/UI/GUI/Common/TextBoxBase.cs @@ -9,7 +9,7 @@ namespace FlaxEngine.GUI /// /// Base class for all text box controls which can gather text input from the user. /// - public abstract class TextBoxBase : Control + public abstract class TextBoxBase : ContainerControl { /// /// The text separators (used for words skipping). From 1940707b06902944174c30450f89b0e15fbf88c5 Mon Sep 17 00:00:00 2001 From: stefnotch Date: Wed, 17 Mar 2021 22:27:15 +0100 Subject: [PATCH 34/76] Update documentation comment for ClosestPointPointLine --- Source/Engine/Core/Math/CollisionsHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/Core/Math/CollisionsHelper.cs b/Source/Engine/Core/Math/CollisionsHelper.cs index 7dd660587..d6e0392c8 100644 --- a/Source/Engine/Core/Math/CollisionsHelper.cs +++ b/Source/Engine/Core/Math/CollisionsHelper.cs @@ -125,7 +125,7 @@ namespace FlaxEngine public static class CollisionsHelper { /// - /// Determines the closest point between a point and a line. + /// Determines the closest point between a point and a line segment. /// /// The point to test. /// The line first point. From 42366ee66aa352b8c92fefb8622b79a156996432 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Mar 2021 00:04:58 +0100 Subject: [PATCH 35/76] Fix synchronizing nested prefabs when adding new ObjectsLookupIdMapping #351 --- .../Editor/Viewport/PrefabWindowViewport.cs | 2 +- Source/Editor/Windows/GameWindow.cs | 2 +- Source/Engine/Level/Level.cpp | 2 - Source/Engine/Level/Prefabs/PrefabManager.cpp | 45 +++++++++++++++++-- Source/Engine/Level/SceneObjectsFactory.cpp | 8 +++- 5 files changed, 50 insertions(+), 9 deletions(-) diff --git a/Source/Editor/Viewport/PrefabWindowViewport.cs b/Source/Editor/Viewport/PrefabWindowViewport.cs index 89c42dc95..8cf69f974 100644 --- a/Source/Editor/Viewport/PrefabWindowViewport.cs +++ b/Source/Editor/Viewport/PrefabWindowViewport.cs @@ -576,7 +576,7 @@ namespace FlaxEditor.Viewport // Selected UI controls outline for (var i = 0; i < _window.Selection.Count; i++) { - if (_window.Selection[i].EditableObject is UIControl controlActor && controlActor.Control != null) + if (_window.Selection[i].EditableObject is UIControl controlActor && controlActor && controlActor.Control != null) { var control = controlActor.Control; var bounds = Rectangle.FromPoints(control.PointToParent(this, Vector2.Zero), control.PointToParent(this, control.Size)); diff --git a/Source/Editor/Windows/GameWindow.cs b/Source/Editor/Windows/GameWindow.cs index 2968b0645..5478cfbef 100644 --- a/Source/Editor/Windows/GameWindow.cs +++ b/Source/Editor/Windows/GameWindow.cs @@ -296,7 +296,7 @@ namespace FlaxEditor.Windows // Selected UI controls outline for (var i = 0; i < Editor.Instance.SceneEditing.Selection.Count; i++) { - if (Editor.Instance.SceneEditing.Selection[i].EditableObject is UIControl controlActor && controlActor.Control != null) + if (Editor.Instance.SceneEditing.Selection[i].EditableObject is UIControl controlActor && controlActor && controlActor.Control != null) { var control = controlActor.Control; var bounds = Rectangle.FromPoints(control.PointToParent(_viewport, Vector2.Zero), control.PointToParent(_viewport, control.Size)); diff --git a/Source/Engine/Level/Level.cpp b/Source/Engine/Level/Level.cpp index 049e9ebf3..8b8d4ae07 100644 --- a/Source/Engine/Level/Level.cpp +++ b/Source/Engine/Level/Level.cpp @@ -1037,9 +1037,7 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, bool autoI // Synchronize prefab instances (prefab may have new objects added or some removed so deserialized instances need to synchronize with it) // TODO: resave and force sync scenes during game cooking so this step could be skipped in game - Scripting::ObjectsLookupIdMapping.Set(&modifier.Value->IdsMapping); SceneObjectsFactory::SynchronizePrefabInstances(*sceneObjects.Value, actorToRemovedObjectsData, modifier.Value); - Scripting::ObjectsLookupIdMapping.Set(nullptr); // Delete objects without parent for (int32 i = 1; i < objectsCount; i++) diff --git a/Source/Engine/Level/Prefabs/PrefabManager.cpp b/Source/Engine/Level/Prefabs/PrefabManager.cpp index 512d6e9b7..77698e739 100644 --- a/Source/Engine/Level/Prefabs/PrefabManager.cpp +++ b/Source/Engine/Level/Prefabs/PrefabManager.cpp @@ -16,6 +16,7 @@ #include "Engine/Core/Cache.h" #include "Engine/Debug/Exceptions/ArgumentException.h" #include "Engine/Engine/EngineService.h" +#include "Engine/Scripting/Script.h" #include "Engine/Scripting/Scripting.h" #if USE_EDITOR @@ -216,21 +217,57 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, DictionaryIdsMapping); SceneObjectsFactory::SynchronizePrefabInstances(*sceneObjects.Value, actorToRemovedObjectsData, modifier.Value); - Scripting::ObjectsLookupIdMapping.Set(nullptr); } - // Delete objects without parent + // Delete objects without parent or with invalid linkage to the prefab for (int32 i = 1; i < sceneObjects->Count(); i++) { SceneObject* obj = sceneObjects->At(i); - if (obj && obj->GetParent() == nullptr) + if (!obj) + continue; + + // Check for missing parent (eg. parent object has been deleted) + if (obj->GetParent() == nullptr) { sceneObjects->At(i) = nullptr; LOG(Warning, "Scene object {0} {1} has missing parent object after load. Removing it.", obj->GetID(), obj->ToString()); obj->DeleteObject(); + continue; } + +#if USE_EDITOR && !BUILD_RELEASE + // Check for not being added to the parent (eg. invalid setup events fault on registration) + auto actor = dynamic_cast(obj); + auto script = dynamic_cast(obj); + if (obj->GetParent() == obj || (actor && !actor->GetParent()->Children.Contains(actor)) || (script && !script->GetParent()->Scripts.Contains(script))) + { + sceneObjects->At(i) = nullptr; + LOG(Warning, "Scene object {0} {1} has invalid parent object linkage after load. Removing it.", obj->GetID(), obj->ToString()); + obj->DeleteObject(); + continue; + } +#endif + +#if USE_EDITOR && BUILD_DEBUG + // Check for being added to parent not from spawned prefab (eg. invalid parentId linkage fault) + bool hasParentInInstance = false; + for (int32 j = 0; j < sceneObjects->Count(); j++) + { + if (sceneObjects->At(j) == obj->GetParent()) + { + hasParentInInstance = true; + break; + } + } + if (!hasParentInInstance) + { + sceneObjects->At(i) = nullptr; + LOG(Warning, "Scene object {0} {1} has invalid parent object after load. Removing it.", obj->GetID(), obj->ToString()); + obj->DeleteObject(); + continue; + } +#endif } // Link objects to prefab (only deserialized from prefab data) diff --git a/Source/Engine/Level/SceneObjectsFactory.cpp b/Source/Engine/Level/SceneObjectsFactory.cpp index a140b103c..e366a2f37 100644 --- a/Source/Engine/Level/SceneObjectsFactory.cpp +++ b/Source/Engine/Level/SceneObjectsFactory.cpp @@ -204,6 +204,8 @@ void SceneObjectsFactory::SynchronizePrefabInstances(Array& sceneO { PROFILE_CPU_NAMED("SynchronizePrefabInstances"); + Scripting::ObjectsLookupIdMapping.Set(&modifier->IdsMapping); + // Check all objects with prefab linkage for moving to a proper parent const int32 objectsToCheckCount = sceneObjects.Count(); for (int32 i = 0; i < objectsToCheckCount; i++) @@ -261,7 +263,7 @@ void SceneObjectsFactory::SynchronizePrefabInstances(Array& sceneO // Preserve order in parent (values from prefab are used) if (i != 0) { - const auto defaultInstance = prefab ? prefab->GetDefaultInstance(obj->GetPrefabObjectID()) : nullptr; + const auto defaultInstance = prefab->GetDefaultInstance(obj->GetPrefabObjectID()); if (defaultInstance) { obj->SetOrderInParent(defaultInstance->GetOrderInParent()); @@ -315,6 +317,7 @@ void SceneObjectsFactory::SynchronizePrefabInstances(Array& sceneO continue; // Create instance (including all children) + Scripting::ObjectsLookupIdMapping.Set(&modifier->IdsMapping); SynchronizeNewPrefabInstance(prefab, actor, prefabObjectId, sceneObjects, modifier); } } @@ -325,6 +328,8 @@ void SceneObjectsFactory::SynchronizePrefabInstances(Array& sceneO SceneObject* obj = sceneObjects[i]; obj->PostLoad(); } + + Scripting::ObjectsLookupIdMapping.Set(nullptr); } void SceneObjectsFactory::HandleObjectDeserializationError(const ISerializable::DeserializeStream& value) @@ -424,6 +429,7 @@ void SceneObjectsFactory::SynchronizeNewPrefabInstance(Prefab* prefab, Actor* ac // Map prefab object ID to the new prefab object instance modifier->IdsMapping[prefabObjectId] = Guid::New(); + Scripting::ObjectsLookupIdMapping.Set(&modifier->IdsMapping); // Create prefab instance (recursive prefab loading to support nested prefabs) auto child = Spawn(*(ISerializable::DeserializeStream*)prefabData, modifier); From a21f6d1b9fbb4b7cd27848c7e61d966d4cde3ca9 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Mar 2021 09:20:47 +0100 Subject: [PATCH 36/76] Fix order of new objects in Prefab after apply #357 --- Source/Engine/Level/Prefabs/Prefab.Apply.cpp | 24 +++++++++++++++++--- Source/Engine/Level/SceneObjectsFactory.cpp | 9 ++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp index f65c9fbe9..a6a0edd4b 100644 --- a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp +++ b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp @@ -834,7 +834,7 @@ bool Prefab::ApplyAllInternal(Actor* targetActor, bool linkTargetActorObjectToPr sceneObjects->RemoveAtKeepOrder(i); } - // Deserialize new prefab objects (add new objects) + // Deserialize new prefab objects int32 newPrefabInstanceIdToDataIndexCounter = 0; int32 newPrefabInstanceIdToDataIndexStart = sceneObjects->Count(); sceneObjects->Resize(sceneObjects->Count() + newPrefabInstanceIdToDataIndex.Count()); @@ -856,9 +856,27 @@ bool Prefab::ApplyAllInternal(Actor* targetActor, bool linkTargetActorObjectToPr { const int32 dataIndex = i->Value; SceneObject* obj = sceneObjects->At(newPrefabInstanceIdToDataIndexStart + newPrefabInstanceIdToDataIndexCounter++); - if (obj) + if (!obj) + continue; + SceneObjectsFactory::Deserialize(obj, diffDataDocument[dataIndex], modifier.Value); + } + for (int32 j = 0; j < targetObjects->Count(); j++) + { + auto obj = targetObjects->At(j); + Guid prefabObjectId; + if (newPrefabInstanceIdToPrefabObjectId.TryGet(obj->GetSceneObjectId(), prefabObjectId)) { - SceneObjectsFactory::Deserialize(obj, diffDataDocument[dataIndex], modifier.Value); + newPrefabInstanceIdToDataIndexCounter = 0; + for (auto i = newPrefabInstanceIdToDataIndex.Begin(); i.IsNotEnd(); ++i) + { + SceneObject* e = sceneObjects->At(newPrefabInstanceIdToDataIndexStart + newPrefabInstanceIdToDataIndexCounter++); + if (e->GetID() == prefabObjectId) + { + // Synchronize order of new objects with the order in target instance + e->SetOrderInParent(obj->GetOrderInParent()); + break; + } + } } } Scripting::ObjectsLookupIdMapping.Set(nullptr); diff --git a/Source/Engine/Level/SceneObjectsFactory.cpp b/Source/Engine/Level/SceneObjectsFactory.cpp index e366a2f37..5eca3230e 100644 --- a/Source/Engine/Level/SceneObjectsFactory.cpp +++ b/Source/Engine/Level/SceneObjectsFactory.cpp @@ -326,6 +326,15 @@ void SceneObjectsFactory::SynchronizePrefabInstances(Array& sceneO for (int32 i = objectsToCheckCount; i < sceneObjects.Count(); i++) { SceneObject* obj = sceneObjects[i]; + + // Preserve order in parent (values from prefab are used) + auto prefab = Content::LoadAsync(obj->GetPrefabID()); + const auto defaultInstance = prefab && prefab->IsLoaded() ? prefab->GetDefaultInstance(obj->GetPrefabObjectID()) : nullptr; + if (defaultInstance) + { + obj->SetOrderInParent(defaultInstance->GetOrderInParent()); + } + obj->PostLoad(); } From 845da14e6aabd6641dbd0fce5e137ae885996dd4 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Mar 2021 10:56:48 +0100 Subject: [PATCH 37/76] Fix UIControl setup on IsActive changes #326 --- Source/Engine/UI/UIControl.cpp | 4 ++-- Source/Engine/UI/UIControl.cs | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Source/Engine/UI/UIControl.cpp b/Source/Engine/UI/UIControl.cpp index 106e51d63..6c24be02f 100644 --- a/Source/Engine/UI/UIControl.cpp +++ b/Source/Engine/UI/UIControl.cpp @@ -195,8 +195,8 @@ void UIControl::OnOrderInParentChanged() void UIControl::OnActiveInTreeChanged() { + UICONTROL_INVOKE(ActiveInTreeChanged); + // Base Actor::OnActiveInTreeChanged(); - - UICONTROL_INVOKE(ActiveInTreeChanged); } diff --git a/Source/Engine/UI/UIControl.cs b/Source/Engine/UI/UIControl.cs index 04194cf69..b8f8b00dd 100644 --- a/Source/Engine/UI/UIControl.cs +++ b/Source/Engine/UI/UIControl.cs @@ -328,6 +328,12 @@ namespace FlaxEngine { if (_control != null && !_blockEvents) { + // Skip if this control is inactive and it's parent too (parent will unlink from hierarchy but children will stay connected while being inactive) + if (!IsActiveInHierarchy && Parent && !Parent.IsActive) + { + return; + } + // Link or unlink control (won't modify Enable/Visible state) _control.Parent = GetParent(); _control.IndexInParent = OrderInParent; From 6a6eb96793c05f8199f625665ca20f6414cf5011 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Mar 2021 11:15:27 +0100 Subject: [PATCH 38/76] Fix code style --- Source/Engine/UI/GUI/Common/Image.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/UI/GUI/Common/Image.cs b/Source/Engine/UI/GUI/Common/Image.cs index adeddce6b..264fdf306 100644 --- a/Source/Engine/UI/GUI/Common/Image.cs +++ b/Source/Engine/UI/GUI/Common/Image.cs @@ -83,7 +83,7 @@ namespace FlaxEngine.GUI public override void DrawSelf() { base.DrawSelf(); - + if (Brush == null) return; From 5c171c8b585580b34a304242d0163407b1948b16 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Mar 2021 13:16:17 +0100 Subject: [PATCH 39/76] Fix control Offsets updating for control bounds when changing anchors #312 --- Source/Engine/UI/GUI/Control.Bounds.cs | 93 +++++++++++++------------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/Source/Engine/UI/GUI/Control.Bounds.cs b/Source/Engine/UI/GUI/Control.Bounds.cs index 11b5e677a..6da2cf8cf 100644 --- a/Source/Engine/UI/GUI/Control.Bounds.cs +++ b/Source/Engine/UI/GUI/Control.Bounds.cs @@ -223,53 +223,56 @@ namespace FlaxEngine.GUI set { if (!_bounds.Equals(ref value)) - { - // Calculate anchors based on the parent container client area - Margin anchors; - if (_parent != null) - { - _parent.GetDesireClientArea(out var parentBounds); - anchors = new Margin - ( - _anchorMin.X * parentBounds.Size.X + parentBounds.Location.X, - _anchorMax.X * parentBounds.Size.X, - _anchorMin.Y * parentBounds.Size.Y + parentBounds.Location.Y, - _anchorMax.Y * parentBounds.Size.Y - ); - } - else - { - anchors = Margin.Zero; - } - - // Calculate offsets on X axis - _offsets.Left = value.Location.X - anchors.Left; - if (_anchorMin.X != _anchorMax.X) - { - _offsets.Right = anchors.Right - value.Location.X - value.Size.X; - } - else - { - _offsets.Right = value.Size.X; - } - - // Calculate offsets on Y axis - _offsets.Top = value.Location.Y - anchors.Top; - if (_anchorMin.Y != _anchorMax.Y) - { - _offsets.Bottom = anchors.Bottom - value.Location.Y - value.Size.Y; - } - else - { - _offsets.Bottom = value.Size.Y; - } - - // Flush the control bounds - UpdateBounds(); - } + SetBounds(ref value); } } + private void SetBounds(ref Rectangle value) + { + // Calculate anchors based on the parent container client area + Margin anchors; + if (_parent != null) + { + _parent.GetDesireClientArea(out var parentBounds); + anchors = new Margin + ( + _anchorMin.X * parentBounds.Size.X + parentBounds.Location.X, + _anchorMax.X * parentBounds.Size.X, + _anchorMin.Y * parentBounds.Size.Y + parentBounds.Location.Y, + _anchorMax.Y * parentBounds.Size.Y + ); + } + else + { + anchors = Margin.Zero; + } + + // Calculate offsets on X axis + _offsets.Left = value.Location.X - anchors.Left; + if (_anchorMin.X != _anchorMax.X) + { + _offsets.Right = anchors.Right - value.Location.X - value.Size.X; + } + else + { + _offsets.Right = value.Size.X; + } + + // Calculate offsets on Y axis + _offsets.Top = value.Location.Y - anchors.Top; + if (_anchorMin.Y != _anchorMax.Y) + { + _offsets.Bottom = anchors.Bottom - value.Location.Y - value.Size.Y; + } + else + { + _offsets.Bottom = value.Size.Y; + } + + // Flush the control bounds + UpdateBounds(); + } + /// /// Gets or sets the scale. /// @@ -553,7 +556,7 @@ namespace FlaxEngine.GUI } bounds.Location += parentBounds.Location; } - Bounds = bounds; + SetBounds(ref bounds); } return; } From 922201d1c03f9b96f6a334a4a5e73fa0b349ac47 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Mar 2021 14:18:40 +0100 Subject: [PATCH 40/76] Fix bug with Vector Parameters in Animation Graph #272 --- .../Animations/Graph/AnimGroup.Animation.cpp | 64 ++++++++++++++++++- .../ParticleEmitterGraph.CPU.Particles.cpp | 2 +- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp index 1a26318a1..2497dfe3e 100644 --- a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp +++ b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp @@ -451,7 +451,69 @@ void AnimGraphExecutor::ProcessGroupParameters(Box* box, Node* node, Value& valu // Get parameter int32 paramIndex; const auto param = _graph.GetParameter((Guid)node->Values[0], paramIndex); - value = param ? _data->Parameters[paramIndex].Value : Value::Null; + if (param) + { + value = _data->Parameters[paramIndex].Value; + switch (param->Type.Type) + { + case VariantType::Vector2: + switch (box->ID) + { + case 1: + case 2: + value = value.AsVector2().Raw[box->ID - 1]; + break; + } + break; + case VariantType::Vector3: + switch (box->ID) + { + case 1: + case 2: + case 3: + value = value.AsVector3().Raw[box->ID - 1]; + break; + } + break; + case VariantType::Vector4: + case VariantType::Color: + switch (box->ID) + { + case 1: + case 2: + case 3: + case 4: + value = value.AsVector4().Raw[box->ID - 1]; + break; + } + break; + case VariantType::Matrix: + { + auto& matrix = value.Type.Type == VariantType::Matrix && value.AsBlob.Data ? *(Matrix*)value.AsBlob.Data : Matrix::Identity; + switch (box->ID) + { + case 0: + value = matrix.GetRow1(); + break; + case 1: + value = matrix.GetRow2(); + break; + case 2: + value = matrix.GetRow3(); + break; + case 3: + value = matrix.GetRow4(); + break; + } + break; + } + } + } + else + { + // TODO: add warning that no parameter selected + value = Value::Zero; + } break; } default: diff --git a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.Particles.cpp b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.Particles.cpp index 9a7f92080..019dc41f3 100644 --- a/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.Particles.cpp +++ b/Source/Engine/Particles/Graph/CPU/ParticleEmitterGraph.CPU.Particles.cpp @@ -72,7 +72,7 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupParameters(Box* box, Node* nod case 3: value = matrix.GetRow4(); break; - default: CRASH; + default: break; } break; From 960a122550523ce7c02d71392c03cbe13dab6bf1 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Mar 2021 14:26:00 +0100 Subject: [PATCH 41/76] Revert children clipping to be called outside DrawChildren (regression from #355) --- Source/Engine/UI/GUI/ContainerControl.cs | 30 +++++++++++------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/Source/Engine/UI/GUI/ContainerControl.cs b/Source/Engine/UI/GUI/ContainerControl.cs index 8e046ecde..0a4114205 100644 --- a/Source/Engine/UI/GUI/ContainerControl.cs +++ b/Source/Engine/UI/GUI/ContainerControl.cs @@ -622,7 +622,18 @@ namespace FlaxEngine.GUI public override void Draw() { DrawSelf(); - DrawChildren(); + + if (ClipChildren) + { + GetDesireClientArea(out var clientArea); + Render2D.PushClip(ref clientArea); + DrawChildren(); + Render2D.PopClip(); + } + else + { + DrawChildren(); + } } /// @@ -630,21 +641,14 @@ namespace FlaxEngine.GUI /// public virtual void DrawSelf() { - base.Draw(); + base.Draw(); } - + /// /// Draws the children. Can be overridden to provide some customizations. Draw is performed with applied clipping mask for the client area. /// protected virtual void DrawChildren() { - // Push clipping mask - if (ClipChildren) - { - GetDesireClientArea(out var clientArea); - Render2D.PushClip(ref clientArea); - } - // Draw all visible child controls if (CullChildren) { @@ -679,12 +683,6 @@ namespace FlaxEngine.GUI } } } - - // Pop clipping mask - if (ClipChildren) - { - Render2D.PopClip(); - } } /// From abe635ad9b2cc0bd8156386848ff3f2141ba7916 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Mar 2021 15:12:25 +0100 Subject: [PATCH 42/76] Fix exception in Custom Editors UI due to invalid reference value processing #325 --- Source/Editor/CustomEditors/Values/ValueContainer.cs | 4 ++++ Source/Engine/UI/GUI/Control.cs | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/Editor/CustomEditors/Values/ValueContainer.cs b/Source/Editor/CustomEditors/Values/ValueContainer.cs index f8cecb801..b7131630e 100644 --- a/Source/Editor/CustomEditors/Values/ValueContainer.cs +++ b/Source/Editor/CustomEditors/Values/ValueContainer.cs @@ -251,6 +251,10 @@ namespace FlaxEditor.CustomEditors } if (instanceValues._hasReferenceValue) { + // If the reference value is set for the parent values but it's null object then skip it + if (instanceValues._referenceValue == null && !instanceValues.Type.IsValueType) + return; + _referenceValue = Info.GetValue(instanceValues._referenceValue); _hasReferenceValue = true; } diff --git a/Source/Engine/UI/GUI/Control.cs b/Source/Engine/UI/GUI/Control.cs index 597cc9e41..96b7bf22b 100644 --- a/Source/Engine/UI/GUI/Control.cs +++ b/Source/Engine/UI/GUI/Control.cs @@ -209,7 +209,6 @@ namespace FlaxEngine.GUI public bool Enabled { get => _isEnabled; - set { if (_isEnabled != value) @@ -255,7 +254,6 @@ namespace FlaxEngine.GUI public bool Visible { get => _isVisible; - set { if (_isVisible != value) From 7a12a6c2805a5990a1792792cad5fae26a2af5ab Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Mar 2021 15:59:01 +0100 Subject: [PATCH 43/76] Fix updating UICanvas when using World/Camera Space #361 --- Source/Engine/UI/UICanvas.cs | 46 +++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/Source/Engine/UI/UICanvas.cs b/Source/Engine/UI/UICanvas.cs index 0a9e7531f..6dfe6958d 100644 --- a/Source/Engine/UI/UICanvas.cs +++ b/Source/Engine/UI/UICanvas.cs @@ -81,7 +81,7 @@ namespace FlaxEngine private CanvasRenderMode _renderMode; private readonly CanvasRootControl _guiRoot; private CanvasRenderer _renderer; - private bool _isLoading; + private bool _isLoading, _isRegisteredForTick; /// /// Gets or sets the canvas rendering mode. @@ -237,6 +237,18 @@ namespace FlaxEngine }; } + /// + /// Finalizes an instance of the class. + /// + ~UICanvas() + { + if (_isRegisteredForTick) + { + _isRegisteredForTick = false; + Scripting.Update -= OnUpdate; + } + } + /// /// Gets the world-space oriented bounding box that contains a 3D canvas. /// @@ -371,6 +383,11 @@ namespace FlaxEngine if (_editorRoot != null && IsActiveInHierarchy) _guiRoot.Parent = _editorRoot; #endif + if (_isRegisteredForTick) + { + _isRegisteredForTick = false; + Scripting.Update -= OnUpdate; + } break; } case CanvasRenderMode.CameraSpace: @@ -404,11 +421,32 @@ namespace FlaxEngine } #endif } + if (!_isRegisteredForTick) + { + _isRegisteredForTick = true; + Scripting.Update += OnUpdate; + } break; } } } + private void OnUpdate() + { + if (this && IsActiveInHierarchy && _renderMode != CanvasRenderMode.ScreenSpace) + { + try + { + Profiler.BeginEvent(Name); + _guiRoot.Update(Time.UnscaledDeltaTime); + } + finally + { + Profiler.EndEvent(); + } + } + } + internal string Serialize() { StringBuilder sb = new StringBuilder(256); @@ -585,6 +623,12 @@ namespace FlaxEngine internal void EndPlay() { + if (_isRegisteredForTick) + { + _isRegisteredForTick = false; + Scripting.Update -= OnUpdate; + } + if (_renderer) { SceneRenderTask.GlobalCustomPostFx.Remove(_renderer); From ac511cbadc7d7a729e9f2f15ca6cebbf1fd14e5f Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Mar 2021 16:34:54 +0100 Subject: [PATCH 44/76] Improve documentation comments for Control properties that are based on Pivot property --- Source/Engine/UI/GUI/Control.Bounds.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Engine/UI/GUI/Control.Bounds.cs b/Source/Engine/UI/GUI/Control.Bounds.cs index 6da2cf8cf..06bd0499d 100644 --- a/Source/Engine/UI/GUI/Control.Bounds.cs +++ b/Source/Engine/UI/GUI/Control.Bounds.cs @@ -274,9 +274,9 @@ namespace FlaxEngine.GUI } /// - /// Gets or sets the scale. + /// Gets or sets the scale. Scales control according to its Pivot which by default is (0.5,0.5) (middle of the control). If you set pivot to (0,0) it will scale the control based on it's upper-left corner. /// - [ExpandGroups, EditorDisplay("Transform"), Limit(float.MinValue, float.MaxValue, 0.1f), EditorOrder(1020), Tooltip("The control scale parameter.")] + [ExpandGroups, EditorDisplay("Transform"), Limit(float.MinValue, float.MaxValue, 0.1f), EditorOrder(1020), Tooltip("The control scale parameter. Scales control according to its Pivot which by default is (0.5,0.5) (middle of the control). If you set pivot to (0,0) it will scale the control based on it's upper-left corner.")] public Vector2 Scale { get => _scale; @@ -306,9 +306,9 @@ namespace FlaxEngine.GUI } /// - /// Gets or sets the shear transform angles (x, y). Defined in degrees. + /// Gets or sets the shear transform angles (x, y). Defined in degrees. Shearing happens relative to the control pivot point. /// - [ExpandGroups, EditorDisplay("Transform"), EditorOrder(1040), Tooltip("The shear transform angles (x, y). Defined in degrees.")] + [ExpandGroups, EditorDisplay("Transform"), EditorOrder(1040), Tooltip("The shear transform angles (x, y). Defined in degrees. Shearing happens relative to the control pivot point.")] public Vector2 Shear { get => _shear; @@ -322,9 +322,9 @@ namespace FlaxEngine.GUI } /// - /// Gets or sets the rotation angle (in degrees). + /// Gets or sets the rotation angle (in degrees). Control is rotated around it's pivot point (middle of the control by default). /// - [ExpandGroups, EditorDisplay("Transform"), EditorOrder(1050), Tooltip("The control rotation angle (in degrees).")] + [ExpandGroups, EditorDisplay("Transform"), EditorOrder(1050), Tooltip("The control rotation angle (in degrees). Control is rotated around it's pivot point (middle of the control by default).")] public float Rotation { get => _rotation; From 759dc98737fab5cd29d58d68b2933311b00459b7 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Mar 2021 16:48:07 +0100 Subject: [PATCH 45/76] Fix Rename Popup direction near screen edges #317 --- .../Editor/GUI/ContextMenu/ContextMenuBase.cs | 34 ++++++++++++------- Source/Editor/GUI/Popups/RenamePopup.cs | 9 ++--- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs b/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs index 247844659..402374a8e 100644 --- a/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs +++ b/Source/Editor/GUI/ContextMenu/ContextMenuBase.cs @@ -47,6 +47,11 @@ namespace FlaxEditor.GUI.ContextMenu private Window _window; private Control _previouslyFocused; + /// + /// Gets a value indicating whether use automatic popup direction fix based on the screen dimensions. + /// + protected virtual bool UseAutomaticDirectionFix => true; + /// /// Returns true if context menu is opened /// @@ -132,21 +137,24 @@ namespace FlaxEditor.GUI.ContextMenu Rectangle monitorBounds = Platform.GetMonitorBounds(locationSS); Vector2 rightBottomLocationSS = locationSS + dpiSize; bool isUp = false, isLeft = false; - if (monitorBounds.Bottom < rightBottomLocationSS.Y) + if (UseAutomaticDirectionFix) { - // Direction: up - isUp = true; - locationSS.Y -= dpiSize.Y; + if (monitorBounds.Bottom < rightBottomLocationSS.Y) + { + // Direction: up + isUp = true; + locationSS.Y -= dpiSize.Y; - // Offset to fix sub-menu location - if (parent is ContextMenu menu && menu._childCM != null) - locationSS.Y += 30.0f * dpiScale; - } - if (monitorBounds.Right < rightBottomLocationSS.X) - { - // Direction: left - isLeft = true; - locationSS.X -= dpiSize.X; + // Offset to fix sub-menu location + if (parent is ContextMenu menu && menu._childCM != null) + locationSS.Y += 30.0f * dpiScale; + } + if (monitorBounds.Right < rightBottomLocationSS.X) + { + // Direction: left + isLeft = true; + locationSS.X -= dpiSize.X; + } } // Update direction flag diff --git a/Source/Editor/GUI/Popups/RenamePopup.cs b/Source/Editor/GUI/Popups/RenamePopup.cs index 834e620d9..c1da5dc3e 100644 --- a/Source/Editor/GUI/Popups/RenamePopup.cs +++ b/Source/Editor/GUI/Popups/RenamePopup.cs @@ -42,9 +42,6 @@ namespace FlaxEditor.GUI /// /// Gets or sets the initial value. /// - /// - /// The initial value. - /// public string InitialValue { get => _startValue; @@ -54,9 +51,6 @@ namespace FlaxEditor.GUI /// /// Gets or sets the input field text. /// - /// - /// The text. - /// public string Text { get => _inputField.Text; @@ -138,6 +132,9 @@ namespace FlaxEditor.GUI Hide(); } + /// + protected override bool UseAutomaticDirectionFix => false; + /// public override bool OnKeyDown(KeyboardKeys key) { From 66c1b736351fae0595c7fc23467e60c09601dd8a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Mar 2021 17:55:07 +0100 Subject: [PATCH 46/76] Add `F` to focus camera view in asset previews --- Source/Editor/Viewport/Cameras/ArcBallCamera.cs | 9 +++++++++ Source/Editor/Viewport/Cameras/FPSCamera.cs | 8 ++++++++ Source/Editor/Viewport/Cameras/ViewportCamera.cs | 2 +- .../Viewport/Previews/AnimatedModelPreview.cs | 13 +++++++++++++ Source/Editor/Viewport/Previews/ModelPreview.cs | 13 +++++++++++++ 5 files changed, 44 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Viewport/Cameras/ArcBallCamera.cs b/Source/Editor/Viewport/Cameras/ArcBallCamera.cs index 876adc796..e6a72c8b4 100644 --- a/Source/Editor/Viewport/Cameras/ArcBallCamera.cs +++ b/Source/Editor/Viewport/Cameras/ArcBallCamera.cs @@ -94,6 +94,15 @@ namespace FlaxEditor.Viewport.Cameras Viewport.ViewPosition = _orbitCenter + localPosition; } + /// + public override void SetArcBallView(Quaternion orientation, Vector3 orbitCenter, float orbitRadius) + { + base.SetArcBallView(orientation, orbitCenter, orbitRadius); + + _orbitCenter = orbitCenter; + _orbitRadius = orbitRadius; + } + /// public override void UpdateView(float dt, ref Vector3 moveDelta, ref Vector2 mouseDelta, out bool centerMouse) { diff --git a/Source/Editor/Viewport/Cameras/FPSCamera.cs b/Source/Editor/Viewport/Cameras/FPSCamera.cs index e60def838..1079b7560 100644 --- a/Source/Editor/Viewport/Cameras/FPSCamera.cs +++ b/Source/Editor/Viewport/Cameras/FPSCamera.cs @@ -166,6 +166,14 @@ namespace FlaxEditor.Viewport.Cameras MoveViewport(position, orientation); } + /// + public override void SetArcBallView(Quaternion orientation, Vector3 orbitCenter, float orbitRadius) + { + base.SetArcBallView(orientation, orbitCenter, orbitRadius); + + TargetPoint = orbitCenter; + } + /// public override void Update(float deltaTime) { diff --git a/Source/Editor/Viewport/Cameras/ViewportCamera.cs b/Source/Editor/Viewport/Cameras/ViewportCamera.cs index 85b7a917c..6564d16d0 100644 --- a/Source/Editor/Viewport/Cameras/ViewportCamera.cs +++ b/Source/Editor/Viewport/Cameras/ViewportCamera.cs @@ -62,7 +62,7 @@ namespace FlaxEditor.Viewport.Cameras /// The view rotation. /// The orbit center location. /// The orbit radius. - public void SetArcBallView(Quaternion orientation, Vector3 orbitCenter, float orbitRadius) + public virtual void SetArcBallView(Quaternion orientation, Vector3 orbitCenter, float orbitRadius) { // Rotate Viewport.ViewOrientation = orientation; diff --git a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs index 6f6103a5d..697a7c1c1 100644 --- a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs +++ b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs @@ -249,6 +249,19 @@ namespace FlaxEditor.Viewport.Previews } } + /// + public override bool OnKeyDown(KeyboardKeys key) + { + switch (key) + { + case KeyboardKeys.F: + // Pay respect.. + ViewportCamera.SetArcBallView(_previewModel.Box); + break; + } + return base.OnKeyDown(key); + } + /// public override void OnDestroy() { diff --git a/Source/Editor/Viewport/Previews/ModelPreview.cs b/Source/Editor/Viewport/Previews/ModelPreview.cs index 7055edbe9..3f285ddcd 100644 --- a/Source/Editor/Viewport/Previews/ModelPreview.cs +++ b/Source/Editor/Viewport/Previews/ModelPreview.cs @@ -85,6 +85,19 @@ namespace FlaxEditor.Viewport.Previews } } + /// + public override bool OnKeyDown(KeyboardKeys key) + { + switch (key) + { + case KeyboardKeys.F: + // Pay respect.. + ViewportCamera.SetArcBallView(_previewModel.Box); + break; + } + return base.OnKeyDown(key); + } + /// public override void OnDestroy() { From f32ea923364bb289fc1d633ab82ff8533db016c0 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Mar 2021 18:23:11 +0100 Subject: [PATCH 47/76] Fix editor viewport camera orbiting issues #354 --- Source/Editor/Viewport/Cameras/FPSCamera.cs | 25 +++---- Source/Editor/Viewport/EditorGizmoViewport.cs | 2 +- Source/Editor/Viewport/EditorViewport.cs | 65 ++++++++----------- .../Editor/Viewport/PrefabWindowViewport.cs | 2 +- 4 files changed, 43 insertions(+), 51 deletions(-) diff --git a/Source/Editor/Viewport/Cameras/FPSCamera.cs b/Source/Editor/Viewport/Cameras/FPSCamera.cs index 1079b7560..374d01ccc 100644 --- a/Source/Editor/Viewport/Cameras/FPSCamera.cs +++ b/Source/Editor/Viewport/Cameras/FPSCamera.cs @@ -88,7 +88,7 @@ namespace FlaxEditor.Viewport.Cameras Editor.GetActorEditorSphere(actor, out BoundingSphere sphere); ShowSphere(ref sphere); } - + /// /// Moves the viewport to visualize selected actors. /// @@ -144,7 +144,7 @@ namespace FlaxEditor.Viewport.Cameras ShowSphere(ref mergesSphere, ref orientation); } - + private void ShowSphere(ref BoundingSphere sphere) { var q = new Quaternion(0.424461186f, -0.0940724313f, 0.0443938486f, 0.899451137f); @@ -154,18 +154,19 @@ namespace FlaxEditor.Viewport.Cameras private void ShowSphere(ref BoundingSphere sphere, ref Quaternion orientation) { Vector3 position; - if (Viewport.UseOrthographicProjection) { position = sphere.Center + Vector3.Backward * orientation * (sphere.Radius * 5.0f); Viewport.OrthographicScale = Vector3.Distance(position, sphere.Center) / 1000; } else + { position = sphere.Center - Vector3.Forward * orientation * (sphere.Radius * 2.5f); - TargetPoint = position; + } + TargetPoint = sphere.Center; MoveViewport(position, orientation); } - + /// public override void SetArcBallView(Quaternion orientation, Vector3 orbitCenter, float orbitRadius) { @@ -212,12 +213,12 @@ namespace FlaxEditor.Viewport.Cameras Viewport.GetInput(out var input); Viewport.GetPrevInput(out var prevInput); - var mainViewport = Viewport as MainEditorGizmoViewport; - bool isUsingGizmo = mainViewport != null && mainViewport.TransformGizmo.ActiveAxis != TransformGizmoBase.Axis.None; + var transformGizmo = (Viewport as EditorGizmoViewport)?.Gizmos.Active as TransformGizmoBase; + var isUsingGizmo = transformGizmo != null && transformGizmo.ActiveAxis != TransformGizmoBase.Axis.None; // Get current view properties - float yaw = Viewport.Yaw; - float pitch = Viewport.Pitch; + var yaw = Viewport.Yaw; + var pitch = Viewport.Pitch; var position = Viewport.ViewPosition; var rotation = Viewport.ViewOrientation; @@ -271,7 +272,7 @@ namespace FlaxEditor.Viewport.Cameras position += forward * (Viewport.MouseWheelZoomSpeedFactor * input.MouseWheelDelta * 25.0f); if (input.IsAltDown) { - position += forward * (Viewport.MouseSpeed * 40 * Viewport.MouseDeltaRight.ValuesSum); + position += forward * (Viewport.MouseSpeed * 40 * Viewport.MousePositionDelta.ValuesSum); } } @@ -279,7 +280,7 @@ namespace FlaxEditor.Viewport.Cameras if (input.IsOrbiting && isUsingGizmo) { centerMouse = false; - Viewport.ViewPosition += mainViewport.TransformGizmo.LastDelta.Translation; + Viewport.ViewPosition += transformGizmo.LastDelta.Translation; return; } @@ -288,7 +289,7 @@ namespace FlaxEditor.Viewport.Cameras Viewport.Pitch = pitch; if (input.IsOrbiting) { - float orbitRadius = Vector3.Distance(ref position, ref TargetPoint); + float orbitRadius = Mathf.Max(Vector3.Distance(ref position, ref TargetPoint), 0.0001f); Vector3 localPosition = Viewport.ViewDirection * (-1 * orbitRadius); Viewport.ViewPosition = TargetPoint + localPosition; } diff --git a/Source/Editor/Viewport/EditorGizmoViewport.cs b/Source/Editor/Viewport/EditorGizmoViewport.cs index ae2db1e9b..93b2c7fbe 100644 --- a/Source/Editor/Viewport/EditorGizmoViewport.cs +++ b/Source/Editor/Viewport/EditorGizmoViewport.cs @@ -62,7 +62,7 @@ namespace FlaxEditor.Viewport public bool SnapToGround => Editor.Instance.Options.Options.Input.SnapToGround.Process(Root); /// - public Vector2 MouseDelta => _mouseDeltaLeft * 1000; + public Vector2 MouseDelta => _mouseDelta * 1000; /// public bool UseSnapping => Root.GetKey(KeyboardKeys.Control); diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs index 562381805..c4e2ddce2 100644 --- a/Source/Editor/Viewport/EditorViewport.cs +++ b/Source/Editor/Viewport/EditorViewport.cs @@ -140,7 +140,7 @@ namespace FlaxEditor.Viewport private bool _isControllingMouse; private int _deltaFilteringStep; private Vector2 _startPos; - private Vector2 _mouseDeltaRightLast; + private Vector2 _mouseDeltaLast; private Vector2[] _deltaFilteringBuffer = new Vector2[FpsCameraFilteringFrames]; /// @@ -159,14 +159,9 @@ namespace FlaxEditor.Viewport protected Vector2 _viewMousePos; /// - /// The mouse delta (right button down). + /// The mouse position delta. /// - protected Vector2 _mouseDeltaRight; - - /// - /// The mouse delta (left button down). - /// - protected Vector2 _mouseDeltaLeft; + protected Vector2 _mouseDelta; // Camera @@ -213,14 +208,9 @@ namespace FlaxEditor.Viewport } /// - /// Gets the mouse movement delta for the right button (user press and move). + /// Gets the mouse movement position delta (user press and move). /// - public Vector2 MouseDeltaRight => _mouseDeltaRight; - - /// - /// Gets the mouse movement delta for the left button (user press and move). - /// - public Vector2 MouseDeltaLeft => _mouseDeltaLeft; + public Vector2 MousePositionDelta => _mouseDelta; /// /// Camera's pitch angle clamp range (in degrees). @@ -1018,6 +1008,7 @@ namespace FlaxEditor.Viewport if (_isControllingMouse) { var rmbWheel = false; + // Gather input { bool isAltDown = _input.IsAltDown; @@ -1099,23 +1090,21 @@ namespace FlaxEditor.Viewport moveDelta *= 0.3f; // Calculate smooth mouse delta not dependant on viewport size - Vector2 offset = _viewMousePos - _startPos; if (_input.IsZooming && !_input.IsMouseRightDown && !_input.IsMouseLeftDown && !_input.IsMouseMiddleDown && !_isOrtho && !rmbWheel) { offset = Vector2.Zero; } - offset.X = offset.X > 0 ? Mathf.Floor(offset.X) : Mathf.Ceil(offset.X); offset.Y = offset.Y > 0 ? Mathf.Floor(offset.Y) : Mathf.Ceil(offset.Y); - _mouseDeltaRight = offset / size; - _mouseDeltaRight.Y *= size.Y / size.X; + _mouseDelta = offset / size; + _mouseDelta.Y *= size.Y / size.X; Vector2 mouseDelta = Vector2.Zero; if (_useMouseFiltering) { // Update delta filtering buffer - _deltaFilteringBuffer[_deltaFilteringStep] = _mouseDeltaRight; + _deltaFilteringBuffer[_deltaFilteringStep] = _mouseDelta; _deltaFilteringStep++; // If the step is too far, zero @@ -1129,14 +1118,16 @@ namespace FlaxEditor.Viewport mouseDelta /= FpsCameraFilteringFrames; } else - mouseDelta = _mouseDeltaRight; + { + mouseDelta = _mouseDelta; + } if (_useMouseAcceleration) { // Accelerate the delta var currentDelta = mouseDelta; - mouseDelta += _mouseDeltaRightLast * _mouseAccelerationScale; - _mouseDeltaRightLast = currentDelta; + mouseDelta += _mouseDeltaLast * _mouseAccelerationScale; + _mouseDeltaLast = currentDelta; } // Update @@ -1161,7 +1152,20 @@ namespace FlaxEditor.Viewport } else { - _mouseDeltaRight = _mouseDeltaRightLast = Vector2.Zero; + if (_input.IsMouseLeftDown || _input.IsMouseRightDown) + { + // Calculate smooth mouse delta not dependant on viewport size + Vector2 offset = _viewMousePos - _startPos; + offset.X = offset.X > 0 ? Mathf.Floor(offset.X) : Mathf.Ceil(offset.X); + offset.Y = offset.Y > 0 ? Mathf.Floor(offset.Y) : Mathf.Ceil(offset.Y); + _mouseDelta = offset / size; + _startPos = _viewMousePos; + } + else + { + _mouseDelta = Vector2.Zero; + } + _mouseDeltaLast = Vector2.Zero; if (ContainsFocus) { @@ -1198,19 +1202,6 @@ namespace FlaxEditor.Viewport UpdateView(dt, ref moveDelta, ref mouseDelta, out _); } } - if (_input.IsMouseLeftDown) - { - // Calculate smooth mouse delta not dependant on viewport size - Vector2 offset = _viewMousePos - _startPos; - offset.X = offset.X > 0 ? Mathf.Floor(offset.X) : Mathf.Ceil(offset.X); - offset.Y = offset.Y > 0 ? Mathf.Floor(offset.Y) : Mathf.Ceil(offset.Y); - _mouseDeltaLeft = offset / size; - _startPos = _viewMousePos; - } - else - { - _mouseDeltaLeft = Vector2.Zero; - } _input.MouseWheelDelta = 0; } diff --git a/Source/Editor/Viewport/PrefabWindowViewport.cs b/Source/Editor/Viewport/PrefabWindowViewport.cs index 8cf69f974..30a58c4a2 100644 --- a/Source/Editor/Viewport/PrefabWindowViewport.cs +++ b/Source/Editor/Viewport/PrefabWindowViewport.cs @@ -342,7 +342,7 @@ namespace FlaxEditor.Viewport public bool SnapToGround => false; /// - public Vector2 MouseDelta => _mouseDeltaLeft * 1000; + public Vector2 MouseDelta => _mouseDelta * 1000; /// public bool UseSnapping => Root.GetKey(KeyboardKeys.Control); From f688cd0c69be3b299979db93b741921bc7d1d01a Mon Sep 17 00:00:00 2001 From: honzapatCZ Date: Thu, 18 Mar 2021 18:23:17 +0100 Subject: [PATCH 48/76] prefab first --- Source/Editor/Gizmo/TransformGizmo.cs | 48 +++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/Source/Editor/Gizmo/TransformGizmo.cs b/Source/Editor/Gizmo/TransformGizmo.cs index afda8484e..08dbaaf3e 100644 --- a/Source/Editor/Gizmo/TransformGizmo.cs +++ b/Source/Editor/Gizmo/TransformGizmo.cs @@ -50,6 +50,44 @@ namespace FlaxEditor.Gizmo { } + /// + /// Helper function, recursivily finds the Prefab Root of node or null + /// + /// The node from which to start + /// + public ActorNode GetPrefabRootInParent(ActorNode node) + { + if (!node.HasPrefabLink) + return null; + if (node.Actor.IsPrefabRoot) + return node; + else if (node.ParentNode is ActorNode parAct) + return GetPrefabRootInParent(parAct); + else + return null; + } + + /// + /// Recursively walks up from the node up to ceiling node(inclusive) or selection(exclusive) + /// + /// The node from which to start + /// The ceiling(inclusive) + /// + public ActorNode RecursiveWalkUpAndFindSomethingBeforeSelectedOrSupplied(ActorNode node, ActorNode ceiling) + { + if (node == ceiling) + return node; + if (node.ParentNode is ActorNode parAct) + { + if (Editor.Instance.SceneEditing.Selection.Contains(node.ParentNode)) + return node; + else + return RecursiveWalkUpAndFindSomethingBeforeSelectedOrSupplied(parAct, ceiling); + } + else + return null; + } + /// public override void Pick() { @@ -100,6 +138,16 @@ namespace FlaxEditor.Gizmo } } + //select prefab root and then go down until you find the actual item in which case select the prefab root again + if(hit is ActorNode act) + { + ActorNode prefabRoot = GetPrefabRootInParent(act); + if (prefabRoot != null && act != prefabRoot) + { + hit = RecursiveWalkUpAndFindSomethingBeforeSelectedOrSupplied(act, prefabRoot); + } + } + bool addRemove = Owner.IsControlDown; bool isSelected = sceneEditing.Selection.Contains(hit); From 544a11562c8f5cfe7b82b5b5df7c2267b8845384 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Mar 2021 18:23:58 +0100 Subject: [PATCH 49/76] Add mouse centering in Editor Viewport if initial location is too close to the edge --- Source/Editor/Viewport/EditorViewport.cs | 11 ++++++++--- Source/Engine/Core/Math/Vector2.cs | 10 ++++++++++ Source/Engine/Core/Math/Vector4.cs | 10 ++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs index c4e2ddce2..7e1c3d887 100644 --- a/Source/Editor/Viewport/EditorViewport.cs +++ b/Source/Editor/Viewport/EditorViewport.cs @@ -865,9 +865,14 @@ namespace FlaxEditor.Viewport win.StartTrackingMouse(false); win.Cursor = CursorType.Hidden; - // Center mouse position - //_viewMousePos = Center; - //win.MousePosition = PointToWindow(_viewMousePos); + // Center mouse position if it's too close to the edge + var size = Size; + var center = size * 0.5f; + if (Mathf.Abs(_viewMousePos.X - center.X) > center.X * 0.8f || Mathf.Abs(_viewMousePos.Y - center.Y) > center.Y * 0.8f) + { + _viewMousePos = center; + win.MousePosition = PointToWindow(_viewMousePos); + } } /// diff --git a/Source/Engine/Core/Math/Vector2.cs b/Source/Engine/Core/Math/Vector2.cs index c0b84ca04..bc193a034 100644 --- a/Source/Engine/Core/Math/Vector2.cs +++ b/Source/Engine/Core/Math/Vector2.cs @@ -197,6 +197,16 @@ namespace FlaxEngine /// public float ValuesSum => X + Y; + /// + /// Gets a vector with values being absolute values of that vector. + /// + public Vector2 Absolute => new Vector2(Mathf.Abs(X), Mathf.Abs(Y)); + + /// + /// Gets a vector with values being opposite to values of that vector. + /// + public Vector2 Negative => new Vector2(-X, -Y); + /// /// Gets or sets the component at the specified index. /// diff --git a/Source/Engine/Core/Math/Vector4.cs b/Source/Engine/Core/Math/Vector4.cs index 99430072d..2a62df067 100644 --- a/Source/Engine/Core/Math/Vector4.cs +++ b/Source/Engine/Core/Math/Vector4.cs @@ -227,6 +227,16 @@ namespace FlaxEngine /// public float ValuesSum => X + Y + Z + W; + /// + /// Gets a vector with values being absolute values of that vector. + /// + public Vector4 Absolute => new Vector4(Mathf.Abs(X), Mathf.Abs(Y), Mathf.Abs(Z), Mathf.Abs(W)); + + /// + /// Gets a vector with values being opposite to values of that vector. + /// + public Vector4 Negative => new Vector4(-X, -Y, -Z, -W); + /// /// Gets or sets the component at the specified index. /// From e0ae2984ae8875e761e55189861bc28789d77121 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Perrier Date: Thu, 18 Mar 2021 18:59:32 +0100 Subject: [PATCH 50/76] UICanvas frustum culling. --- Source/Engine/UI/UICanvas.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Engine/UI/UICanvas.cs b/Source/Engine/UI/UICanvas.cs index 6dfe6958d..5e9d340d2 100644 --- a/Source/Engine/UI/UICanvas.cs +++ b/Source/Engine/UI/UICanvas.cs @@ -57,7 +57,8 @@ namespace FlaxEngine /// public override void Render(GPUContext context, ref RenderContext renderContext, GPUTexture input, GPUTexture output) { - // TODO: apply frustum culling to skip rendering if canvas is not in a viewport + if (renderContext.View.Frustum.Contains(Canvas.Bounds.GetBoundingBox()) == ContainmentType.Disjoint) + return; Profiler.BeginEventGPU("UI Canvas"); From f70b116fcbda87ad3b468e547370228d7566e3b2 Mon Sep 17 00:00:00 2001 From: honzapatCZ Date: Thu, 18 Mar 2021 19:18:59 +0100 Subject: [PATCH 51/76] renamed --- Source/Editor/Gizmo/TransformGizmo.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Editor/Gizmo/TransformGizmo.cs b/Source/Editor/Gizmo/TransformGizmo.cs index 08dbaaf3e..6040f0485 100644 --- a/Source/Editor/Gizmo/TransformGizmo.cs +++ b/Source/Editor/Gizmo/TransformGizmo.cs @@ -73,7 +73,7 @@ namespace FlaxEditor.Gizmo /// The node from which to start /// The ceiling(inclusive) /// - public ActorNode RecursiveWalkUpAndFindSomethingBeforeSelectedOrSupplied(ActorNode node, ActorNode ceiling) + public ActorNode WalkUpAndFindActorNodeBeforeSelection(ActorNode node, ActorNode ceiling) { if (node == ceiling) return node; @@ -82,7 +82,7 @@ namespace FlaxEditor.Gizmo if (Editor.Instance.SceneEditing.Selection.Contains(node.ParentNode)) return node; else - return RecursiveWalkUpAndFindSomethingBeforeSelectedOrSupplied(parAct, ceiling); + return WalkUpAndFindActorNodeBeforeSelection(parAct, ceiling); } else return null; @@ -144,7 +144,7 @@ namespace FlaxEditor.Gizmo ActorNode prefabRoot = GetPrefabRootInParent(act); if (prefabRoot != null && act != prefabRoot) { - hit = RecursiveWalkUpAndFindSomethingBeforeSelectedOrSupplied(act, prefabRoot); + hit = WalkUpAndFindActorNodeBeforeSelection(act, prefabRoot); } } From 8ef8b89fd5346d0caa7d050dce8083cad669157e Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Mar 2021 21:50:05 +0100 Subject: [PATCH 52/76] Add constructor to BoundingBox for single point empty box construction --- .../SceneAnimations/SceneAnimationPlayer.cpp | 2 +- Source/Engine/Audio/AudioListener.cpp | 2 +- Source/Engine/Audio/AudioSource.cpp | 2 +- Source/Engine/Core/Math/BoundingBox.cpp | 2 +- Source/Engine/Core/Math/BoundingBox.h | 10 ++++++++++ Source/Engine/Level/Actors/AnimatedModel.cpp | 2 +- Source/Engine/Level/Actors/BoneSocket.cpp | 2 +- Source/Engine/Level/Actors/DirectionalLight.cpp | 2 +- Source/Engine/Level/Actors/EmptyActor.cpp | 2 +- Source/Engine/Level/Actors/ExponentialHeightFog.cpp | 2 +- Source/Engine/Level/Actors/Sky.cpp | 2 +- Source/Engine/Level/Actors/Skybox.cpp | 2 +- Source/Engine/Level/Actors/SplineModel.cpp | 2 +- Source/Engine/Level/Actors/StaticModel.cpp | 2 +- Source/Engine/Level/Scene/Scene.cpp | 2 +- Source/Engine/Particles/ParticleEffect.cpp | 2 +- Source/Engine/Physics/Actors/PhysicsActor.cpp | 4 ++-- Source/Engine/Physics/Actors/SplineRopeBody.cpp | 2 +- .../Engine/Physics/Colliders/CharacterController.cpp | 4 ++-- Source/Engine/Physics/Colliders/SplineCollider.cpp | 4 ++-- Source/Engine/Physics/Joints/Joint.cpp | 2 +- Source/Engine/Terrain/Terrain.cpp | 2 +- Source/Engine/UI/TextRender.cpp | 6 +++--- Source/Engine/UI/UICanvas.cpp | 2 +- Source/Engine/UI/UIControl.cpp | 2 +- 25 files changed, 39 insertions(+), 29 deletions(-) diff --git a/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.cpp b/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.cpp index ea24d126f..784eebb28 100644 --- a/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.cpp +++ b/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.cpp @@ -1132,6 +1132,6 @@ void SceneAnimationPlayer::OnTransformChanged() // Base Actor::OnTransformChanged(); - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); _sphere = BoundingSphere(_transform.Translation, 0.0f); } diff --git a/Source/Engine/Audio/AudioListener.cpp b/Source/Engine/Audio/AudioListener.cpp index 40e7bac3e..e9b1a11ab 100644 --- a/Source/Engine/Audio/AudioListener.cpp +++ b/Source/Engine/Audio/AudioListener.cpp @@ -63,7 +63,7 @@ void AudioListener::OnTransformChanged() // Base Actor::OnTransformChanged(); - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); _sphere = BoundingSphere(_transform.Translation, 0.0f); if (IsActiveInHierarchy()) diff --git a/Source/Engine/Audio/AudioSource.cpp b/Source/Engine/Audio/AudioSource.cpp index b07ea95ee..8969bc4d3 100644 --- a/Source/Engine/Audio/AudioSource.cpp +++ b/Source/Engine/Audio/AudioSource.cpp @@ -461,7 +461,7 @@ void AudioSource::OnTransformChanged() // Base Actor::OnTransformChanged(); - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); _sphere = BoundingSphere(_transform.Translation, 0.0f); if (IsActiveInHierarchy() && SourceIDs.HasItems()) diff --git a/Source/Engine/Core/Math/BoundingBox.cpp b/Source/Engine/Core/Math/BoundingBox.cpp index d7932e1b1..439b4341f 100644 --- a/Source/Engine/Core/Math/BoundingBox.cpp +++ b/Source/Engine/Core/Math/BoundingBox.cpp @@ -6,7 +6,7 @@ #include "../Types/String.h" const BoundingBox BoundingBox::Empty(Vector3(MAX_float), Vector3(MIN_float)); -const BoundingBox BoundingBox::Zero(Vector3(0.0f), Vector3(0.0f)); +const BoundingBox BoundingBox::Zero(Vector3(0.0f)); String BoundingBox::ToString() const { diff --git a/Source/Engine/Core/Math/BoundingBox.h b/Source/Engine/Core/Math/BoundingBox.h index f669370ff..8a349e022 100644 --- a/Source/Engine/Core/Math/BoundingBox.h +++ b/Source/Engine/Core/Math/BoundingBox.h @@ -45,6 +45,16 @@ public: { } + /// + /// Initializes a new instance of the struct. + /// + /// The location of the empty bounding box. + BoundingBox(const Vector3& point) + : Minimum(point) + , Maximum(point) + { + } + /// /// Initializes a new instance of the struct. /// diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index 85ee6d333..f0ae7017e 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -383,7 +383,7 @@ void AnimatedModel::UpdateLocalBounds() } else { - box = BoundingBox(Vector3::Zero, Vector3::Zero); + box = BoundingBox(Vector3::Zero); } // Scale bounds diff --git a/Source/Engine/Level/Actors/BoneSocket.cpp b/Source/Engine/Level/Actors/BoneSocket.cpp index 028b1c507..5efe8deed 100644 --- a/Source/Engine/Level/Actors/BoneSocket.cpp +++ b/Source/Engine/Level/Actors/BoneSocket.cpp @@ -96,7 +96,7 @@ void BoneSocket::OnTransformChanged() // Base Actor::OnTransformChanged(); - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); _sphere = BoundingSphere(_transform.Translation, 0.0f); } diff --git a/Source/Engine/Level/Actors/DirectionalLight.cpp b/Source/Engine/Level/Actors/DirectionalLight.cpp index 240344fc6..8810b0de6 100644 --- a/Source/Engine/Level/Actors/DirectionalLight.cpp +++ b/Source/Engine/Level/Actors/DirectionalLight.cpp @@ -92,6 +92,6 @@ void DirectionalLight::OnTransformChanged() // Base LightWithShadow::OnTransformChanged(); - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); _sphere = BoundingSphere(_transform.Translation, 0.0f); } diff --git a/Source/Engine/Level/Actors/EmptyActor.cpp b/Source/Engine/Level/Actors/EmptyActor.cpp index 309f63652..dfb64824d 100644 --- a/Source/Engine/Level/Actors/EmptyActor.cpp +++ b/Source/Engine/Level/Actors/EmptyActor.cpp @@ -22,6 +22,6 @@ void EmptyActor::OnTransformChanged() // Base Actor::OnTransformChanged(); - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); _sphere = BoundingSphere(_transform.Translation, 0.0f); } diff --git a/Source/Engine/Level/Actors/ExponentialHeightFog.cpp b/Source/Engine/Level/Actors/ExponentialHeightFog.cpp index 77f8e16e7..366ab7de4 100644 --- a/Source/Engine/Level/Actors/ExponentialHeightFog.cpp +++ b/Source/Engine/Level/Actors/ExponentialHeightFog.cpp @@ -228,6 +228,6 @@ void ExponentialHeightFog::OnTransformChanged() // Base Actor::OnTransformChanged(); - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); _sphere = BoundingSphere(_transform.Translation, 0.0f); } diff --git a/Source/Engine/Level/Actors/Sky.cpp b/Source/Engine/Level/Actors/Sky.cpp index 8aaf5fdd3..49f46e9b9 100644 --- a/Source/Engine/Level/Actors/Sky.cpp +++ b/Source/Engine/Level/Actors/Sky.cpp @@ -259,6 +259,6 @@ void Sky::OnTransformChanged() // Base Actor::OnTransformChanged(); - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); _sphere = BoundingSphere(_transform.Translation, 0.0f); } diff --git a/Source/Engine/Level/Actors/Skybox.cpp b/Source/Engine/Level/Actors/Skybox.cpp index e8ea08c89..4edd596b7 100644 --- a/Source/Engine/Level/Actors/Skybox.cpp +++ b/Source/Engine/Level/Actors/Skybox.cpp @@ -146,6 +146,6 @@ void Skybox::OnTransformChanged() // Base Actor::OnTransformChanged(); - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); _sphere = BoundingSphere(_transform.Translation, 0.0f); } diff --git a/Source/Engine/Level/Actors/SplineModel.cpp b/Source/Engine/Level/Actors/SplineModel.cpp index 84306716b..794658afb 100644 --- a/Source/Engine/Level/Actors/SplineModel.cpp +++ b/Source/Engine/Level/Actors/SplineModel.cpp @@ -110,7 +110,7 @@ void SplineModel::OnSplineUpdated() // Skip updates when actor is disabled or something is missing if (!_spline || !Model || !Model->IsLoaded() || !IsActiveInHierarchy() || _spline->GetSplinePointsCount() < 2) { - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); BoundingSphere::FromBox(_box, _sphere); return; } diff --git a/Source/Engine/Level/Actors/StaticModel.cpp b/Source/Engine/Level/Actors/StaticModel.cpp index a884c9707..3f81b22c3 100644 --- a/Source/Engine/Level/Actors/StaticModel.cpp +++ b/Source/Engine/Level/Actors/StaticModel.cpp @@ -187,7 +187,7 @@ void StaticModel::UpdateBounds() } else { - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); } BoundingSphere::FromBox(_box, _sphere); } diff --git a/Source/Engine/Level/Scene/Scene.cpp b/Source/Engine/Level/Scene/Scene.cpp index d38bd4225..94de9d713 100644 --- a/Source/Engine/Level/Scene/Scene.cpp +++ b/Source/Engine/Level/Scene/Scene.cpp @@ -362,6 +362,6 @@ void Scene::OnTransformChanged() // Base Actor::OnTransformChanged(); - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); _sphere = BoundingSphere(_transform.Translation, 0.0f); } diff --git a/Source/Engine/Particles/ParticleEffect.cpp b/Source/Engine/Particles/ParticleEffect.cpp index 40594904d..f23aff28c 100644 --- a/Source/Engine/Particles/ParticleEffect.cpp +++ b/Source/Engine/Particles/ParticleEffect.cpp @@ -306,7 +306,7 @@ void ParticleEffect::UpdateBounds() // Empty bounds if there is no particle system to play or it has been never played if (bounds == BoundingBox::Empty) { - bounds = BoundingBox(_transform.Translation, _transform.Translation); + bounds = BoundingBox(_transform.Translation); } _box = bounds; diff --git a/Source/Engine/Physics/Actors/PhysicsActor.cpp b/Source/Engine/Physics/Actors/PhysicsActor.cpp index 79c4ccf7f..8e92ea902 100644 --- a/Source/Engine/Physics/Actors/PhysicsActor.cpp +++ b/Source/Engine/Physics/Actors/PhysicsActor.cpp @@ -61,7 +61,7 @@ void PhysicsActor::UpdateBounds() } else { - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); } } else @@ -71,7 +71,7 @@ void PhysicsActor::UpdateBounds() } else { - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); } BoundingSphere::FromBox(_box, _sphere); } diff --git a/Source/Engine/Physics/Actors/SplineRopeBody.cpp b/Source/Engine/Physics/Actors/SplineRopeBody.cpp index a610e76ce..b341f7008 100644 --- a/Source/Engine/Physics/Actors/SplineRopeBody.cpp +++ b/Source/Engine/Physics/Actors/SplineRopeBody.cpp @@ -178,6 +178,6 @@ void SplineRopeBody::OnTransformChanged() { Actor::OnTransformChanged(); - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); _sphere = BoundingSphere(_transform.Translation, 0.0f); } diff --git a/Source/Engine/Physics/Colliders/CharacterController.cpp b/Source/Engine/Physics/Colliders/CharacterController.cpp index 7657c7594..4315ce8ba 100644 --- a/Source/Engine/Physics/Colliders/CharacterController.cpp +++ b/Source/Engine/Physics/Colliders/CharacterController.cpp @@ -220,7 +220,7 @@ void CharacterController::UpdateBounds() if (actor) _box = P2C(actor->getWorldBounds(boundsScale)); else - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); BoundingSphere::FromBox(_box, _sphere); } @@ -345,7 +345,7 @@ void CharacterController::OnTransformChanged() } else if (!_controller) { - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); BoundingSphere::FromBox(_box, _sphere); } } diff --git a/Source/Engine/Physics/Colliders/SplineCollider.cpp b/Source/Engine/Physics/Colliders/SplineCollider.cpp index e44d986cc..7bff077e0 100644 --- a/Source/Engine/Physics/Colliders/SplineCollider.cpp +++ b/Source/Engine/Physics/Colliders/SplineCollider.cpp @@ -64,7 +64,7 @@ void SplineCollider::OnSplineUpdated() { if (!_spline || !IsActiveInHierarchy() || _spline->GetSplinePointsCount() < 2 || !CollisionData || !CollisionData->IsLoaded()) { - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); BoundingSphere::FromBox(_box, _sphere); return; } @@ -178,7 +178,7 @@ void SplineCollider::UpdateBounds() void SplineCollider::GetGeometry(PxGeometryHolder& geometry) { // Reset bounds - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); BoundingSphere::FromBox(_box, _sphere); // Skip if sth is missing diff --git a/Source/Engine/Physics/Joints/Joint.cpp b/Source/Engine/Physics/Joints/Joint.cpp index 56c5c1b32..2a8cc57ca 100644 --- a/Source/Engine/Physics/Joints/Joint.cpp +++ b/Source/Engine/Physics/Joints/Joint.cpp @@ -327,7 +327,7 @@ void Joint::OnTransformChanged() // TODO: this could track only local transform changed - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); _sphere = BoundingSphere(_transform.Translation, 0.0f); if (_joint) diff --git a/Source/Engine/Terrain/Terrain.cpp b/Source/Engine/Terrain/Terrain.cpp index e87de12a3..502b5c4a5 100644 --- a/Source/Engine/Terrain/Terrain.cpp +++ b/Source/Engine/Terrain/Terrain.cpp @@ -37,7 +37,7 @@ Terrain::~Terrain() void Terrain::UpdateBounds() { PROFILE_CPU(); - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); for (int32 i = 0; i < _patches.Count(); i++) { auto patch = _patches[i]; diff --git a/Source/Engine/UI/TextRender.cpp b/Source/Engine/UI/TextRender.cpp index a26d3d169..df75bbb87 100644 --- a/Source/Engine/UI/TextRender.cpp +++ b/Source/Engine/UI/TextRender.cpp @@ -31,7 +31,7 @@ TextRender::TextRender(const SpawnParams& params) { _world = Matrix::Identity; _color = Color::White; - _localBox = BoundingBox(Vector3::Zero, Vector3::Zero); + _localBox = BoundingBox(Vector3::Zero); _layoutOptions.Bounds = Rectangle(-100, -100, 200, 200); _layoutOptions.HorizontalAlignment = TextAlignment::Center; _layoutOptions.VerticalAlignment = TextAlignment::Center; @@ -92,7 +92,7 @@ void TextRender::UpdateLayout() _vb0.Clear(); _vb1.Clear(); _vb2.Clear(); - _localBox = BoundingBox(Vector3::Zero, Vector3::Zero); + _localBox = BoundingBox(Vector3::Zero); BoundingBox::Transform(_localBox, _world, _box); BoundingSphere::FromBox(_box, _sphere); #if USE_PRECISE_MESH_INTERSECTS @@ -291,7 +291,7 @@ void TextRender::UpdateLayout() if (_ib.Data.IsEmpty()) { // Empty - box = BoundingBox(_transform.Translation, _transform.Translation); + box = BoundingBox(_transform.Translation); } _localBox = box; BoundingBox::Transform(_localBox, _world, _box); diff --git a/Source/Engine/UI/UICanvas.cpp b/Source/Engine/UI/UICanvas.cpp index ab1841acc..c21281c67 100644 --- a/Source/Engine/UI/UICanvas.cpp +++ b/Source/Engine/UI/UICanvas.cpp @@ -164,6 +164,6 @@ void UICanvas::OnTransformChanged() // Base Actor::OnTransformChanged(); - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); _sphere = BoundingSphere(_transform.Translation, 0.0f); } diff --git a/Source/Engine/UI/UIControl.cpp b/Source/Engine/UI/UIControl.cpp index 6c24be02f..b9fef02f8 100644 --- a/Source/Engine/UI/UIControl.cpp +++ b/Source/Engine/UI/UIControl.cpp @@ -163,7 +163,7 @@ void UIControl::OnTransformChanged() // Base Actor::OnTransformChanged(); - _box = BoundingBox(_transform.Translation, _transform.Translation); + _box = BoundingBox(_transform.Translation); _sphere = BoundingSphere(_transform.Translation, 0.0f); UICONTROL_INVOKE(TransformChanged); From 255b2c85c82af41c2cc60edc27c1094848a6e28e Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Mar 2021 21:51:15 +0100 Subject: [PATCH 53/76] Add bounds calculation for Spline --- Source/Engine/Level/Actors/Spline.cpp | 46 +++++++++++++++++++++++++-- Source/Engine/Level/Actors/Spline.h | 3 ++ 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/Source/Engine/Level/Actors/Spline.cpp b/Source/Engine/Level/Actors/Spline.cpp index 76ecb9653..4c0d21cd7 100644 --- a/Source/Engine/Level/Actors/Spline.cpp +++ b/Source/Engine/Level/Actors/Spline.cpp @@ -3,10 +3,12 @@ #include "Spline.h" #include "Engine/Serialization/Serialization.h" #include "Engine/Animations/CurveSerialization.h" +#include "Engine/Core/Math/Matrix.h" #include Spline::Spline(const SpawnParams& params) : Actor(params) + , _localBounds(Vector3::Zero, Vector3::Zero) { } @@ -411,17 +413,27 @@ void Spline::SetTangentsSmooth() void Spline::UpdateSpline() { + auto& keyframes = Curve.GetKeyframes(); + const int32 count = keyframes.Count(); + // Always keep last point in the loop - const int32 count = Curve.GetKeyframes().Count(); if (_loop && count > 1) { - auto& first = Curve[0]; - auto& last = Curve[count - 1]; + auto& first = keyframes[0]; + auto& last = keyframes[count - 1]; last.Value = first.Value; last.TangentIn = first.TangentIn; last.TangentOut = first.TangentOut; } + // Update bounds + _localBounds = BoundingBox(count != 0 ? keyframes[0].Value.Translation : Vector3::Zero); + for (int32 i = 1; i < count; i++) + _localBounds.Merge(keyframes[i].Value.Translation); + Matrix world; + _transform.GetWorld(world); + BoundingBox::Transform(_localBounds, world, _box); + SplineUpdated(); } @@ -485,6 +497,34 @@ void Spline::OnDebugDrawSelected() #endif +void Spline::OnTransformChanged() +{ + // Base + Actor::OnTransformChanged(); + + Matrix world; + _transform.GetWorld(world); + BoundingBox::Transform(_localBounds, world, _box); + BoundingSphere::FromBox(_box, _sphere); +} + +void Spline::PostLoad() +{ + // Base + Actor::PostLoad(); + + auto& keyframes = Curve.GetKeyframes(); + const int32 count = keyframes.Count(); + + // Update bounds + _localBounds = BoundingBox(count != 0 ? keyframes[0].Value.Translation : Vector3::Zero); + for (int32 i = 1; i < count; i++) + _localBounds.Merge(keyframes[i].Value.Translation); + Matrix world; + _transform.GetWorld(world); + BoundingBox::Transform(_localBounds, world, _box); +} + void Spline::Serialize(SerializeStream& stream, const void* otherObj) { // Base diff --git a/Source/Engine/Level/Actors/Spline.h b/Source/Engine/Level/Actors/Spline.h index f19f9a443..79fce685d 100644 --- a/Source/Engine/Level/Actors/Spline.h +++ b/Source/Engine/Level/Actors/Spline.h @@ -15,6 +15,7 @@ DECLARE_SCENE_OBJECT(Spline); private: bool _loop = false; + BoundingBox _localBounds; public: @@ -377,6 +378,8 @@ public: void OnDebugDraw() override; void OnDebugDrawSelected() override; #endif + void OnTransformChanged() override; + void PostLoad() override; void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; }; From 4ae3fccfd9c2c8550b60a7a1861471f4d5deca73 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 18 Mar 2021 22:20:27 +0100 Subject: [PATCH 54/76] Improve focusing on selected object in Editor #328 --- Source/Editor/SceneGraph/ActorNode.cs | 6 ++++ Source/Editor/SceneGraph/SceneGraphNode.cs | 14 +++++++++ Source/Editor/Viewport/Cameras/FPSCamera.cs | 34 ++++++++++----------- Source/Engine/Level/Actor.cpp | 16 ++++++++-- Source/Engine/Level/Actor.h | 14 ++------- 5 files changed, 53 insertions(+), 31 deletions(-) diff --git a/Source/Editor/SceneGraph/ActorNode.cs b/Source/Editor/SceneGraph/ActorNode.cs index 318d8379b..9543c8d58 100644 --- a/Source/Editor/SceneGraph/ActorNode.cs +++ b/Source/Editor/SceneGraph/ActorNode.cs @@ -263,6 +263,12 @@ namespace FlaxEditor.SceneGraph return _actor.IntersectsItself(ray.Ray, out distance, out normal); } + /// + public override void GetEditorSphere(out BoundingSphere sphere) + { + Editor.GetActorEditorSphere(_actor, out sphere); + } + /// public override void OnDebugDraw(ViewportDebugDrawData data) { diff --git a/Source/Editor/SceneGraph/SceneGraphNode.cs b/Source/Editor/SceneGraph/SceneGraphNode.cs index 01a832c5a..11c3b7709 100644 --- a/Source/Editor/SceneGraph/SceneGraphNode.cs +++ b/Source/Editor/SceneGraph/SceneGraphNode.cs @@ -309,6 +309,20 @@ namespace FlaxEditor.SceneGraph return false; } + /// + /// Gets the object bounding sphere (including child actors). + /// + /// The bounding sphere. + public virtual void GetEditorSphere(out BoundingSphere sphere) + { + sphere = new BoundingSphere(Transform.Translation, 15.0f); + for (int i = 0; i < ChildNodes.Count; i++) + { + ChildNodes[i].GetEditorSphere(out var childSphere); + BoundingSphere.Merge(ref sphere, ref childSphere, out sphere); + } + } + /// /// Called when selected nodes should draw debug shapes using interface. /// diff --git a/Source/Editor/Viewport/Cameras/FPSCamera.cs b/Source/Editor/Viewport/Cameras/FPSCamera.cs index 374d01ccc..22abccf69 100644 --- a/Source/Editor/Viewport/Cameras/FPSCamera.cs +++ b/Source/Editor/Viewport/Cameras/FPSCamera.cs @@ -103,45 +103,43 @@ namespace FlaxEditor.Viewport.Cameras /// /// Moves the viewport to visualize selected actors. /// - /// The actors to show. - public void ShowActors(List actors) + /// The actors to show. + public void ShowActors(List selection) { - if (actors.Count == 0) + if (selection.Count == 0) return; BoundingSphere mergesSphere = BoundingSphere.Empty; - for (int i = 0; i < actors.Count; i++) + for (int i = 0; i < selection.Count; i++) { - if (actors[i] is ActorNode actor) - { - Editor.GetActorEditorSphere(actor.Actor, out BoundingSphere sphere); - BoundingSphere.Merge(ref mergesSphere, ref sphere, out mergesSphere); - } + selection[i].GetEditorSphere(out var sphere); + BoundingSphere.Merge(ref mergesSphere, ref sphere, out mergesSphere); } + if (mergesSphere == BoundingSphere.Empty) + return; ShowSphere(ref mergesSphere); } /// /// Moves the viewport to visualize selected actors. /// - /// The actors to show. + /// The actors to show. /// The used orientation. - public void ShowActors(List actors, ref Quaternion orientation) + public void ShowActors(List selection, ref Quaternion orientation) { - if (actors.Count == 0) + if (selection.Count == 0) return; BoundingSphere mergesSphere = BoundingSphere.Empty; - for (int i = 0; i < actors.Count; i++) + for (int i = 0; i < selection.Count; i++) { - if (actors[i] is ActorNode actor) - { - Editor.GetActorEditorSphere(actor.Actor, out BoundingSphere sphere); - BoundingSphere.Merge(ref mergesSphere, ref sphere, out mergesSphere); - } + selection[i].GetEditorSphere(out var sphere); + BoundingSphere.Merge(ref mergesSphere, ref sphere, out mergesSphere); } + if (mergesSphere == BoundingSphere.Empty) + return; ShowSphere(ref mergesSphere, ref orientation); } diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp index 56aa20fa0..fa5bce1ff 100644 --- a/Source/Engine/Level/Actor.cpp +++ b/Source/Engine/Level/Actor.cpp @@ -1139,20 +1139,28 @@ BoundingBox Actor::GetBoxWithChildren() const #if USE_EDITOR +BoundingBox Actor::GetEditorBox() const +{ + return GetBox(); +} + BoundingBox Actor::GetEditorBoxChildren() const { BoundingBox result = GetEditorBox(); - for (int32 i = 0; i < Children.Count(); i++) { BoundingBox::Merge(result, Children[i]->GetEditorBoxChildren(), result); } - return result; } #endif +bool Actor::HasContentLoaded() const +{ + return true; +} + void Actor::UnregisterObjectHierarchy() { if (IsRegistered()) @@ -1170,6 +1178,10 @@ void Actor::UnregisterObjectHierarchy() } } +void Actor::Draw(RenderContext& renderContext) +{ +} + void Actor::DrawGeneric(RenderContext& renderContext) { // Generic drawing uses only GBuffer Fill Pass and simple frustum culling (see SceneRendering for more optimized drawing) diff --git a/Source/Engine/Level/Actor.h b/Source/Engine/Level/Actor.h index 69d4c8681..233ebe04c 100644 --- a/Source/Engine/Level/Actor.h +++ b/Source/Engine/Level/Actor.h @@ -629,10 +629,7 @@ public: /// /// Gets actor bounding box (single actor, no children included) for editor tools. /// - API_PROPERTY() virtual BoundingBox GetEditorBox() const - { - return GetBox(); - } + API_PROPERTY() virtual BoundingBox GetEditorBox() const; /// /// Gets actor bounding box of the actor including all child actors for editor tools. @@ -644,10 +641,7 @@ public: /// /// Returns true if actor has loaded content. /// - API_PROPERTY() virtual bool HasContentLoaded() const - { - return true; - } + API_PROPERTY() virtual bool HasContentLoaded() const; /// /// Calls UnregisterObject for all objects in the actor hierarchy. @@ -660,9 +654,7 @@ public: /// Draws this actor. Called by Scene Rendering service. This call is more optimized than generic Draw (eg. models are rendered during all passed but other actors are invoked only during GBufferFill pass). /// /// The rendering context. - virtual void Draw(RenderContext& renderContext) - { - } + virtual void Draw(RenderContext& renderContext); /// /// Draws this actor. Called during custom actor rendering or any other generic rendering from code. From 8626350e5f0faf23f5a39fea360f1e3c71166036 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 19 Mar 2021 10:14:58 +0100 Subject: [PATCH 55/76] Fix possible issue for prefab reference value for default value object that might be deleted on prefab apply --- Source/Editor/CustomEditors/Values/ValueContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Editor/CustomEditors/Values/ValueContainer.cs b/Source/Editor/CustomEditors/Values/ValueContainer.cs index b7131630e..84542e591 100644 --- a/Source/Editor/CustomEditors/Values/ValueContainer.cs +++ b/Source/Editor/CustomEditors/Values/ValueContainer.cs @@ -167,14 +167,14 @@ namespace FlaxEditor.CustomEditors { if (_hasReferenceValue) { - if (_referenceValue is SceneObject referenceSceneObject && referenceSceneObject.HasPrefabLink) + if (_referenceValue is SceneObject referenceSceneObject && referenceSceneObject && referenceSceneObject.HasPrefabLink) { for (int i = 0; i < Count; i++) { if (this[i] == referenceSceneObject) continue; - if (this[i] == null || (this[i] is SceneObject valueSceneObject && valueSceneObject.PrefabObjectID != referenceSceneObject.PrefabObjectID)) + if (this[i] == null || (this[i] is SceneObject valueSceneObject && valueSceneObject && valueSceneObject.PrefabObjectID != referenceSceneObject.PrefabObjectID)) return true; } } From 4efd411045439dbc92ee39c6be43de0a5d039a70 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 19 Mar 2021 12:15:13 +0100 Subject: [PATCH 56/76] Add improvements for objects spawning in editor viewport #367 --- .../Viewport/MainEditorGizmoViewport.cs | 28 +++++++++---------- .../Windows/WindowsWindow.DragDrop.cpp | 6 ++++ 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index a0f2eb044..df94759d1 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -860,6 +860,13 @@ namespace FlaxEditor.Viewport return location; } + private void Spawn(Actor actor, ref Vector3 hitLocation) + { + actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); + Editor.Instance.SceneEditing.Spawn(actor); + Focus(); + } + private void Spawn(AssetItem item, SceneGraphNode hit, ref Vector2 location, ref Vector3 hitLocation) { if (item is AssetItem assetItem) @@ -872,8 +879,7 @@ namespace FlaxEditor.Viewport Name = item.ShortName, ParticleSystem = asset }; - actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); - Editor.Instance.SceneEditing.Spawn(actor); + Spawn(actor, ref hitLocation); return; } if (assetItem.IsOfType()) @@ -884,8 +890,7 @@ namespace FlaxEditor.Viewport Name = item.ShortName, Animation = asset }; - actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); - Editor.Instance.SceneEditing.Spawn(actor); + Spawn(actor, ref hitLocation); return; } if (assetItem.IsOfType()) @@ -921,8 +926,7 @@ namespace FlaxEditor.Viewport Name = item.ShortName, SkinnedModel = model }; - actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); - Editor.Instance.SceneEditing.Spawn(actor); + Spawn(actor, ref hitLocation); return; } if (assetItem.IsOfType()) @@ -933,8 +937,7 @@ namespace FlaxEditor.Viewport Name = item.ShortName, Model = model }; - actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); - Editor.Instance.SceneEditing.Spawn(actor); + Spawn(actor, ref hitLocation); return; } if (assetItem.IsOfType()) @@ -945,8 +948,7 @@ namespace FlaxEditor.Viewport Name = item.ShortName, Clip = clip }; - actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); - Editor.Instance.SceneEditing.Spawn(actor); + Spawn(actor, ref hitLocation); return; } if (assetItem.IsOfType()) @@ -954,8 +956,7 @@ namespace FlaxEditor.Viewport var prefab = FlaxEngine.Content.LoadAsync(item.ID); var actor = PrefabManager.SpawnPrefab(prefab, null); actor.Name = item.ShortName; - actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); - Editor.Instance.SceneEditing.Spawn(actor); + Spawn(actor, ref hitLocation); return; } if (assetItem.IsOfType()) @@ -967,8 +968,7 @@ namespace FlaxEditor.Viewport { var actor = (Actor)visualScriptItem.ScriptType.CreateInstance(); actor.Name = item.ShortName; - actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); - Editor.Instance.SceneEditing.Spawn(actor); + Spawn(actor, ref hitLocation); return; } } diff --git a/Source/Engine/Platform/Windows/WindowsWindow.DragDrop.cpp b/Source/Engine/Platform/Windows/WindowsWindow.DragDrop.cpp index 1bec8868a..a6dc90a1f 100644 --- a/Source/Engine/Platform/Windows/WindowsWindow.DragDrop.cpp +++ b/Source/Engine/Platform/Windows/WindowsWindow.DragDrop.cpp @@ -10,6 +10,8 @@ #include "Engine/Core/Collections/Array.h" #include "Engine/Engine/Engine.h" #include "Engine/Platform/IGuiData.h" +#include "Engine/Input/Input.h" +#include "Engine/Input/Mouse.h" #include "Engine/Threading/ThreadPoolTask.h" #include "Engine/Threading/ThreadPool.h" #include "Engine/Scripting/Scripting.h" @@ -630,6 +632,10 @@ DragDropEffect WindowsWindow::DoDragDrop(const StringView& data) dropSource->Release(); ReleaseStgMedium(&stgmed); + // Fix hanging mouse state (Windows doesn't send WM_LBUTTONUP when we end the drag and drop) + if (Input::GetMouseButton(MouseButton::Left)) + Input::Mouse->OnMouseUp(Input::Mouse->GetPosition(), MouseButton::Left, this); + return SUCCEEDED(result) ? dropEffectFromOleEnum(dwEffect) : DragDropEffect::None; } From 54753a49edc7d44423b2580b03b00ba13ded3132 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 19 Mar 2021 12:15:50 +0100 Subject: [PATCH 57/76] Add support for spawning Collision Data as Mesh Collider in viewport drag&drop --- .../Viewport/MainEditorGizmoViewport.cs | 16 ++++++- .../Editor/Viewport/PrefabWindowViewport.cs | 44 +++++++++++++------ 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs index df94759d1..e79b01313 100644 --- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs +++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs @@ -797,6 +797,8 @@ namespace FlaxEditor.Viewport return true; if (assetItem.IsOfType()) return true; + if (assetItem.IsOfType()) + return true; if (assetItem.IsOfType()) return true; if (assetItem.IsOfType()) @@ -940,6 +942,17 @@ namespace FlaxEditor.Viewport Spawn(actor, ref hitLocation); return; } + if (assetItem.IsOfType()) + { + var collisionData = FlaxEngine.Content.LoadAsync(item.ID); + var actor = new MeshCollider + { + Name = item.ShortName, + CollisionData = collisionData + }; + Spawn(actor, ref hitLocation); + return; + } if (assetItem.IsOfType()) { var clip = FlaxEngine.Content.LoadAsync(item.ID); @@ -983,8 +996,7 @@ namespace FlaxEditor.Viewport return; } actor.Name = item.Name; - actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); - Editor.Instance.SceneEditing.Spawn(actor); + Spawn(actor, ref hitLocation); } /// diff --git a/Source/Editor/Viewport/PrefabWindowViewport.cs b/Source/Editor/Viewport/PrefabWindowViewport.cs index 30a58c4a2..a9ee39b8c 100644 --- a/Source/Editor/Viewport/PrefabWindowViewport.cs +++ b/Source/Editor/Viewport/PrefabWindowViewport.cs @@ -682,10 +682,14 @@ namespace FlaxEditor.Viewport return true; if (assetItem.IsOfType()) return true; + if (assetItem.IsOfType()) + return true; if (assetItem.IsOfType()) return true; if (assetItem.IsOfType()) return true; + if (assetItem is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance) + return true; } return false; @@ -746,8 +750,7 @@ namespace FlaxEditor.Viewport Name = item.ShortName, ParticleSystem = particleSystem }; - actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); - Spawn(actor); + Spawn(actor, ref hitLocation); return; } if (typeof(MaterialBase).IsAssignableFrom(binaryAssetItem.Type)) @@ -773,8 +776,7 @@ namespace FlaxEditor.Viewport Name = item.ShortName, SkinnedModel = model }; - actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); - Spawn(actor); + Spawn(actor, ref hitLocation); return; } if (typeof(Model).IsAssignableFrom(binaryAssetItem.Type)) @@ -785,8 +787,18 @@ namespace FlaxEditor.Viewport Name = item.ShortName, Model = model }; - actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); - Spawn(actor); + Spawn(actor, ref hitLocation); + return; + } + if (binaryAssetItem.IsOfType()) + { + var collisionData = FlaxEngine.Content.LoadAsync(item.ID); + var actor = new MeshCollider + { + Name = item.ShortName, + CollisionData = collisionData + }; + Spawn(actor, ref hitLocation); return; } if (typeof(AudioClip).IsAssignableFrom(binaryAssetItem.Type)) @@ -797,8 +809,7 @@ namespace FlaxEditor.Viewport Name = item.ShortName, Clip = clip }; - actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); - Spawn(actor); + Spawn(actor, ref hitLocation); return; } if (typeof(Prefab).IsAssignableFrom(binaryAssetItem.Type)) @@ -806,16 +817,24 @@ namespace FlaxEditor.Viewport var prefab = FlaxEngine.Content.LoadAsync(item.ID); var actor = PrefabManager.SpawnPrefab(prefab, null); actor.Name = item.ShortName; - actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); - Spawn(actor); + Spawn(actor, ref hitLocation); return; } } + if (item is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance) + { + var actor = (Actor)visualScriptItem.ScriptType.CreateInstance(); + actor.Name = item.ShortName; + Spawn(actor, ref hitLocation); + return; + } } - private void Spawn(Actor actor) + private void Spawn(Actor actor, ref Vector3 hitLocation) { + actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); _window.Spawn(actor); + Focus(); } private void Spawn(ScriptType item, SceneGraphNode hit, ref Vector3 hitLocation) @@ -827,8 +846,7 @@ namespace FlaxEditor.Viewport return; } actor.Name = item.Name; - actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation); - Spawn(actor); + Spawn(actor, ref hitLocation); } /// From 7ff5ebb45da81d4ff0669123ddcdd967b923b8c4 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 19 Mar 2021 12:21:09 +0100 Subject: [PATCH 58/76] Fix using scale mode Gizmo --- .../Gizmo/TransformGizmoBase.Selection.cs | 60 +++++++++---------- Source/Editor/Gizmo/TransformGizmoBase.cs | 25 +------- 2 files changed, 31 insertions(+), 54 deletions(-) diff --git a/Source/Editor/Gizmo/TransformGizmoBase.Selection.cs b/Source/Editor/Gizmo/TransformGizmoBase.Selection.cs index c1f7d1d0d..f8277999e 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.Selection.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.Selection.cs @@ -26,7 +26,7 @@ namespace FlaxEditor.Gizmo // Return arithmetic average or whatever it means return center / count; } - + private bool IntersectsRotateCircle(Vector3 normal, ref Ray ray, out float distance) { var plane = new Plane(Vector3.Zero, normal); @@ -51,7 +51,7 @@ namespace FlaxEditor.Gizmo Vector3.Transform(ref ray.Position, ref invGizmoWorld, out localRay.Position); // Find gizmo collisions with mouse - float closestintersection = float.MaxValue; + float closestIntersection = float.MaxValue; float intersection; _activeAxis = Axis.None; switch (_activeMode) @@ -59,42 +59,42 @@ namespace FlaxEditor.Gizmo case Mode.Translate: { // Axis boxes collision - if (XAxisBox.Intersects(ref localRay, out intersection) && intersection < closestintersection) + if (XAxisBox.Intersects(ref localRay, out intersection) && intersection < closestIntersection) { _activeAxis = Axis.X; - closestintersection = intersection; + closestIntersection = intersection; } - if (YAxisBox.Intersects(ref localRay, out intersection) && intersection < closestintersection) + if (YAxisBox.Intersects(ref localRay, out intersection) && intersection < closestIntersection) { _activeAxis = Axis.Y; - closestintersection = intersection; + closestIntersection = intersection; } - if (ZAxisBox.Intersects(ref localRay, out intersection) && intersection < closestintersection) + if (ZAxisBox.Intersects(ref localRay, out intersection) && intersection < closestIntersection) { _activeAxis = Axis.Z; - closestintersection = intersection; + closestIntersection = intersection; } // Quad planes collision - if (closestintersection >= float.MaxValue) - closestintersection = float.MinValue; - if (XYBox.Intersects(ref localRay, out intersection) && intersection > closestintersection) + if (closestIntersection >= float.MaxValue) + closestIntersection = float.MinValue; + if (XYBox.Intersects(ref localRay, out intersection) && intersection > closestIntersection) { _activeAxis = Axis.XY; - closestintersection = intersection; + closestIntersection = intersection; } - if (XZBox.Intersects(ref localRay, out intersection) && intersection > closestintersection) + if (XZBox.Intersects(ref localRay, out intersection) && intersection > closestIntersection) { _activeAxis = Axis.ZX; - closestintersection = intersection; + closestIntersection = intersection; } - if (YZBox.Intersects(ref localRay, out intersection) && intersection > closestintersection) + if (YZBox.Intersects(ref localRay, out intersection) && intersection > closestIntersection) { _activeAxis = Axis.YZ; - closestintersection = intersection; + closestIntersection = intersection; } break; @@ -103,20 +103,20 @@ namespace FlaxEditor.Gizmo case Mode.Rotate: { // Circles - if (IntersectsRotateCircle(Vector3.UnitX, ref localRay, out intersection) && intersection < closestintersection) + if (IntersectsRotateCircle(Vector3.UnitX, ref localRay, out intersection) && intersection < closestIntersection) { _activeAxis = Axis.X; - closestintersection = intersection; + closestIntersection = intersection; } - if (IntersectsRotateCircle(Vector3.UnitY, ref localRay, out intersection) && intersection < closestintersection) + if (IntersectsRotateCircle(Vector3.UnitY, ref localRay, out intersection) && intersection < closestIntersection) { _activeAxis = Axis.Y; - closestintersection = intersection; + closestIntersection = intersection; } - if (IntersectsRotateCircle(Vector3.UnitZ, ref localRay, out intersection) && intersection < closestintersection) + if (IntersectsRotateCircle(Vector3.UnitZ, ref localRay, out intersection) && intersection < closestIntersection) { _activeAxis = Axis.Z; - closestintersection = intersection; + closestIntersection = intersection; } // Center @@ -132,27 +132,27 @@ namespace FlaxEditor.Gizmo case Mode.Scale: { // Spheres collision - if (ScaleXSphere.Intersects(ref ray, out intersection) && intersection < closestintersection) + if (ScaleXSphere.Intersects(ref ray, out intersection) && intersection < closestIntersection) { _activeAxis = Axis.X; - closestintersection = intersection; + closestIntersection = intersection; } - if (ScaleYSphere.Intersects(ref ray, out intersection) && intersection < closestintersection) + if (ScaleYSphere.Intersects(ref ray, out intersection) && intersection < closestIntersection) { _activeAxis = Axis.Y; - closestintersection = intersection; + closestIntersection = intersection; } - if (ScaleZSphere.Intersects(ref ray, out intersection) && intersection < closestintersection) + if (ScaleZSphere.Intersects(ref ray, out intersection) && intersection < closestIntersection) { _activeAxis = Axis.Z; - closestintersection = intersection; + closestIntersection = intersection; } // Center - if (CenterBox.Intersects(ref ray, out intersection) && intersection < closestintersection) + if (CenterBox.Intersects(ref ray, out intersection) && intersection < closestIntersection) { _activeAxis = Axis.Center; - closestintersection = intersection; + closestIntersection = intersection; } break; diff --git a/Source/Editor/Gizmo/TransformGizmoBase.cs b/Source/Editor/Gizmo/TransformGizmoBase.cs index 8c997bc2c..e123bd3f6 100644 --- a/Source/Editor/Gizmo/TransformGizmoBase.cs +++ b/Source/Editor/Gizmo/TransformGizmoBase.cs @@ -174,7 +174,7 @@ namespace FlaxEditor.Gizmo _axisAlignedWorld = _screenScaleMatrix * Matrix.CreateWorld(Position, Vector3.Backward, Vector3.Up); // Assign world - if (_activeTransformSpace == TransformSpace.World) + if (_activeTransformSpace == TransformSpace.World && _activeMode != Mode.Scale) { _gizmoWorld = _axisAlignedWorld; @@ -297,29 +297,6 @@ namespace FlaxEditor.Gizmo else if (_activeMode == Mode.Scale) { // Scale - if (_activeTransformSpace == TransformSpace.World && _activeAxis != Axis.Center) - { - var deltaLocal = delta; - Quaternion orientation = GetSelectedObject(0).Orientation; - delta = Vector3.Transform(delta, orientation); - - // Fix axis sign of delta movement for rotated object in some cases (eg. rotated object by 90 deg on Y axis and scale in world space with Red/X axis) - switch (_activeAxis) - { - case Axis.X: - if (deltaLocal.X < 0) - delta *= -1; - break; - case Axis.Y: - if (deltaLocal.Y < 0) - delta *= -1; - break; - case Axis.Z: - if (deltaLocal.Z < 0) - delta *= -1; - break; - } - } _scaleDelta = delta; } } From 29e06eb6963dfefe74d9019765bd531184fb3e0b Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 19 Mar 2021 15:46:33 +0100 Subject: [PATCH 59/76] Add `WorldSpaceFaceCamera` mode to UICanvas #359 --- Source/Engine/UI/UICanvas.cs | 134 ++++++++++++++++++++++++----------- 1 file changed, 94 insertions(+), 40 deletions(-) diff --git a/Source/Engine/UI/UICanvas.cs b/Source/Engine/UI/UICanvas.cs index 5e9d340d2..591b91c07 100644 --- a/Source/Engine/UI/UICanvas.cs +++ b/Source/Engine/UI/UICanvas.cs @@ -31,6 +31,12 @@ namespace FlaxEngine /// [Tooltip("The world space rendering mode that places Canvas as any other object in the scene. The size of the Canvas can be set manually using its Transform, and UI elements will render in front of or behind other objects in the scene based on 3D placement. This is useful for UIs that are meant to be a part of the world. This is also known as a 'diegetic interface'.")] WorldSpace = 2, + + /// + /// The world space rendering mode that places Canvas as any other object in the scene and orients it to face the camera. The size of the Canvas can be set manually using its Transform, and UI elements will render in front of or behind other objects in the scene based on 3D placement. This is useful for UIs that are meant to be a part of the world. This is also known as a 'diegetic interface'. + /// + [Tooltip("The world space rendering mode that places Canvas as any other object in the scene and orients canvas to face the camera. The size of the Canvas can be set manually using its Transform, and UI elements will render in front of or behind other objects in the scene based on 3D placement. This is useful for UIs that are meant to be a part of the world. This is also known as a 'diegetic interface'.")] + WorldSpaceFaceCamera = 3, } /// @@ -102,14 +108,14 @@ namespace FlaxEngine Setup(); // Reset size - if (previous == CanvasRenderMode.ScreenSpace || _renderMode == CanvasRenderMode.WorldSpace) + if (previous == CanvasRenderMode.ScreenSpace || (_renderMode == CanvasRenderMode.WorldSpace || _renderMode == CanvasRenderMode.WorldSpaceFaceCamera)) Size = new Vector2(500, 500); } } } /// - /// Gets or sets the canvas rendering location within rendering pipeline. Used only in or . + /// Gets or sets the canvas rendering location within rendering pipeline. Used only in or or . /// [EditorOrder(13), EditorDisplay("Canvas"), VisibleIf(nameof(Editor_Is3D)), Tooltip("Canvas rendering location within the rendering pipeline. Change this if you want GUI to affect the lighting or post processing effects like bloom.")] public PostProcessEffectLocation RenderLocation { get; set; } = PostProcessEffectLocation.Default; @@ -139,22 +145,26 @@ namespace FlaxEngine [EditorOrder(15), EditorDisplay("Canvas"), Tooltip("If checked, canvas can receive the input events.")] public bool ReceivesEvents { get; set; } = true; +#if FLAX_EDITOR private bool Editor_Is3D => _renderMode != CanvasRenderMode.ScreenSpace; - private bool Editor_IsWorldSpace => _renderMode == CanvasRenderMode.WorldSpace; + private bool Editor_IsWorldSpace => _renderMode == CanvasRenderMode.WorldSpace || _renderMode == CanvasRenderMode.WorldSpaceFaceCamera; private bool Editor_IsCameraSpace => _renderMode == CanvasRenderMode.CameraSpace; + private bool Editor_UseRenderCamera => _renderMode == CanvasRenderMode.CameraSpace || _renderMode == CanvasRenderMode.WorldSpaceFaceCamera; +#endif + /// - /// Gets or sets the size of the canvas. Used only in . + /// Gets or sets the size of the canvas. Used only in or . /// - [EditorOrder(20), EditorDisplay("Canvas"), VisibleIf(nameof(Editor_IsWorldSpace)), Tooltip("Canvas size.")] + [EditorOrder(20), EditorDisplay("Canvas"), VisibleIf("Editor_IsWorldSpace"), Tooltip("Canvas size.")] public Vector2 Size { get => _guiRoot.Size; set { - if (_renderMode == CanvasRenderMode.WorldSpace || _isLoading) + if (_renderMode == CanvasRenderMode.WorldSpace || _renderMode == CanvasRenderMode.WorldSpaceFaceCamera || _isLoading) { _guiRoot.Size = value; } @@ -164,19 +174,19 @@ namespace FlaxEngine /// /// Gets or sets a value indicating whether ignore scene depth when rendering the GUI (scene objects won't cover the interface). /// - [EditorOrder(30), EditorDisplay("Canvas"), VisibleIf(nameof(Editor_Is3D)), Tooltip("If checked, scene depth will be ignored when rendering the GUI (scene objects won't cover the interface).")] + [EditorOrder(30), EditorDisplay("Canvas"), VisibleIf("Editor_Is3D"), Tooltip("If checked, scene depth will be ignored when rendering the GUI (scene objects won't cover the interface).")] public bool IgnoreDepth { get; set; } = false; /// - /// Gets or sets the camera used to place the GUI when render mode is set to . + /// Gets or sets the camera used to place the GUI when render mode is set to or . /// - [EditorOrder(50), EditorDisplay("Canvas"), VisibleIf(nameof(Editor_IsCameraSpace)), Tooltip("Camera used to place the GUI when RenderMode is set to CameraSpace")] + [EditorOrder(50), EditorDisplay("Canvas"), VisibleIf("Editor_UseRenderCamera"), Tooltip("Camera used to place the GUI when RenderMode is set to CameraSpace or WorldSpaceFaceCamera.")] public Camera RenderCamera { get; set; } /// /// Gets or sets the distance from the to place the plane with GUI. If the screen is resized, changes resolution, or the camera frustum changes, the Canvas will automatically change size to match as well. /// - [EditorOrder(60), Limit(0.01f), EditorDisplay("Canvas"), VisibleIf(nameof(Editor_IsCameraSpace)), Tooltip("Distance from the RenderCamera to place the plane with GUI. If the screen is resized, changes resolution, or the camera frustum changes, the Canvas will automatically change size to match as well.")] + [EditorOrder(60), Limit(0.01f), EditorDisplay("Canvas"), VisibleIf("Editor_IsCameraSpace"), Tooltip("Distance from the RenderCamera to place the plane with GUI. If the screen is resized, changes resolution, or the camera frustum changes, the Canvas will automatically change size to match as well.")] public float Distance { get; set; } = 500; /// @@ -284,24 +294,31 @@ namespace FlaxEngine /// The world. public void GetWorldMatrix(out Matrix world) { - if (_renderMode == CanvasRenderMode.WorldSpace) - { - // In 3D world - GetLocalToWorldMatrix(out world); - } - else if (_renderMode == CanvasRenderMode.CameraSpace) - { - Matrix tmp1, tmp2; - Vector3 viewPos, viewUp, viewForward, pos; - Quaternion viewRot; - - // Use default camera is not specified - var camera = RenderCamera ?? Camera.MainCamera; - #if FLAX_EDITOR - if (_editorTask) + // Override projection for editor preview + if (_editorTask) + { + if (_renderMode == CanvasRenderMode.WorldSpace) + { + GetLocalToWorldMatrix(out world); + } + else if (_renderMode == CanvasRenderMode.WorldSpaceFaceCamera) + { + var view = _editorTask.View; + var transform = Transform; + var cameraPosition = view.Position; + var cameraDirection = view.Direction; + var up = Vector3.Up; + Matrix.Translation(_guiRoot.Width * -0.5f, _guiRoot.Height * -0.5f, 0, out var m1); + Matrix.Scaling(ref transform.Scale, out var m2); + Matrix.Multiply(ref m1, ref m2, out var m3); + Matrix.RotationY(Mathf.Pi, out m2); + Matrix.Multiply(ref m3, ref m2, out m1); + Matrix.Billboard(ref transform.Translation, ref cameraPosition, ref up, ref cameraDirection, out m2); + Matrix.Multiply(ref m1, ref m2, out world); + } + else if (_renderMode == CanvasRenderMode.CameraSpace) { - // Use editor viewport task to override Camera Space placement var view = _editorTask.View; var frustum = view.Frustum; if (!frustum.IsOrthographic) @@ -309,19 +326,52 @@ namespace FlaxEngine else _guiRoot.Size = _editorTask.Viewport.Size; Matrix.Translation(_guiRoot.Width / -2.0f, _guiRoot.Height / -2.0f, 0, out world); - Matrix.RotationYawPitchRoll(Mathf.Pi, Mathf.Pi, 0, out tmp2); - Matrix.Multiply(ref world, ref tmp2, out tmp1); - viewPos = view.Position; - viewRot = view.Direction != Vector3.Up ? Quaternion.LookRotation(view.Direction, Vector3.Up) : Quaternion.LookRotation(view.Direction, Vector3.Right); - viewUp = Vector3.Up * viewRot; - viewForward = view.Direction; - pos = view.Position + view.Direction * Distance; + Matrix.RotationYawPitchRoll(Mathf.Pi, Mathf.Pi, 0, out var tmp2); + Matrix.Multiply(ref world, ref tmp2, out var tmp1); + var viewPos = view.Position; + var viewRot = view.Direction != Vector3.Up ? Quaternion.LookRotation(view.Direction, Vector3.Up) : Quaternion.LookRotation(view.Direction, Vector3.Right); + var viewUp = Vector3.Up * viewRot; + var viewForward = view.Direction; + var pos = view.Position + view.Direction * Distance; Matrix.Billboard(ref pos, ref viewPos, ref viewUp, ref viewForward, out tmp2); Matrix.Multiply(ref tmp1, ref tmp2, out world); return; } + else + { + world = Matrix.Identity; + } + return; + } #endif + // Use default camera is not specified + var camera = RenderCamera ?? Camera.MainCamera; + + if (_renderMode == CanvasRenderMode.WorldSpace || (_renderMode == CanvasRenderMode.WorldSpaceFaceCamera && !camera)) + { + // In 3D world + GetLocalToWorldMatrix(out world); + } + else if (_renderMode == CanvasRenderMode.WorldSpaceFaceCamera) + { + // In 3D world face camera + var transform = Transform; + var cameraPosition = camera.Position; + var cameraDirection = camera.Direction; + var up = Vector3.Up; + Matrix.Translation(_guiRoot.Width * -0.5f, _guiRoot.Height * -0.5f, 0, out var m1); + Matrix.Scaling(ref transform.Scale, out var m2); + Matrix.Multiply(ref m1, ref m2, out var m3); + Matrix.RotationY(Mathf.Pi, out m2); + Matrix.Multiply(ref m3, ref m2, out m1); + Matrix.Billboard(ref transform.Translation, ref cameraPosition, ref up, ref cameraDirection, out m2); + Matrix.Multiply(ref m1, ref m2, out world); + } + else if (_renderMode == CanvasRenderMode.CameraSpace && camera) + { + Matrix tmp1, tmp2; + // Adjust GUI size to the viewport size at the given distance form the camera var viewport = camera.Viewport; if (camera.UsePerspective) @@ -342,11 +392,11 @@ namespace FlaxEngine Matrix.Multiply(ref world, ref tmp2, out tmp1); // In front of the camera - viewPos = camera.Position; - viewRot = camera.Orientation; - viewUp = Vector3.Up * viewRot; - viewForward = Vector3.Forward * viewRot; - pos = viewPos + viewForward * Distance; + var viewPos = camera.Position; + var viewRot = camera.Orientation; + var viewUp = Vector3.Up * viewRot; + var viewForward = Vector3.Forward * viewRot; + var pos = viewPos + viewForward * Distance; Matrix.Billboard(ref pos, ref viewPos, ref viewUp, ref viewForward, out tmp2); Matrix.Multiply(ref tmp1, ref tmp2, out world); @@ -393,6 +443,7 @@ namespace FlaxEngine } case CanvasRenderMode.CameraSpace: case CanvasRenderMode.WorldSpace: + case CanvasRenderMode.WorldSpaceFaceCamera: { // Render canvas manually _guiRoot.AnchorPreset = AnchorPresets.TopLeft; @@ -481,7 +532,7 @@ namespace FlaxEngine jsonWriter.WritePropertyName("Distance"); jsonWriter.WriteValue(Distance); - if (RenderMode == CanvasRenderMode.WorldSpace) + if (RenderMode == CanvasRenderMode.WorldSpace || RenderMode == CanvasRenderMode.WorldSpaceFaceCamera) { jsonWriter.WritePropertyName("Size"); jsonWriter.WriteStartObject(); @@ -552,7 +603,10 @@ namespace FlaxEngine jsonWriter.WriteValue(Distance); } - if ((RenderMode == CanvasRenderMode.WorldSpace || other.RenderMode == CanvasRenderMode.WorldSpace) && Size != other.Size) + if ((RenderMode == CanvasRenderMode.WorldSpace || + RenderMode == CanvasRenderMode.WorldSpaceFaceCamera || + other.RenderMode == CanvasRenderMode.WorldSpace || + other.RenderMode == CanvasRenderMode.WorldSpaceFaceCamera) && Size != other.Size) { jsonWriter.WritePropertyName("Size"); jsonWriter.WriteStartObject(); From 7010c52af3fd22ed28896e86988698ff3b1947ea Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Fri, 19 Mar 2021 17:15:18 +0100 Subject: [PATCH 60/76] Fix missing selection type in CustomEditorPresenter --- Source/Editor/CustomEditors/CustomEditorPresenter.cs | 3 +++ Source/Editor/CustomEditors/Values/ValueContainer.cs | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Source/Editor/CustomEditors/CustomEditorPresenter.cs b/Source/Editor/CustomEditors/CustomEditorPresenter.cs index 2cea89f08..7f19de195 100644 --- a/Source/Editor/CustomEditors/CustomEditorPresenter.cs +++ b/Source/Editor/CustomEditors/CustomEditorPresenter.cs @@ -250,6 +250,7 @@ namespace FlaxEditor.CustomEditors Selection.Clear(); Selection.Add(obj); + Selection.SetType(new ScriptType(obj.GetType())); OnSelectionChanged(); } @@ -271,6 +272,7 @@ namespace FlaxEditor.CustomEditors Selection.Clear(); Selection.AddRange(objectsArray); + Selection.SetType(new ScriptType(objectsArray.GetType())); OnSelectionChanged(); } @@ -284,6 +286,7 @@ namespace FlaxEditor.CustomEditors return; Selection.Clear(); + Selection.SetType(ScriptType.Null); OnSelectionChanged(); } diff --git a/Source/Editor/CustomEditors/Values/ValueContainer.cs b/Source/Editor/CustomEditors/Values/ValueContainer.cs index 84542e591..49d3b5591 100644 --- a/Source/Editor/CustomEditors/Values/ValueContainer.cs +++ b/Source/Editor/CustomEditors/Values/ValueContainer.cs @@ -43,7 +43,7 @@ namespace FlaxEditor.CustomEditors /// /// Gets the values type. /// - public ScriptType Type { get; } + public ScriptType Type { get; private set; } /// /// Gets a value indicating whether single object is selected. @@ -284,6 +284,15 @@ namespace FlaxEditor.CustomEditors Type = type; } + /// + /// Sets the type. Use with caution. + /// + /// The type. + public void SetType(ScriptType type) + { + Type = type; + } + /// /// Gets the custom attributes defined for the values source member. /// From 59b975499fccbfd9f8a968b0903980c0b2281e30 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 20 Mar 2021 12:15:50 +0100 Subject: [PATCH 61/76] Fix WorldSpaceFaceCamera bug #370 --- Source/Engine/UI/UICanvas.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/Engine/UI/UICanvas.cs b/Source/Engine/UI/UICanvas.cs index 591b91c07..6f1687f31 100644 --- a/Source/Engine/UI/UICanvas.cs +++ b/Source/Engine/UI/UICanvas.cs @@ -312,7 +312,8 @@ namespace FlaxEngine Matrix.Translation(_guiRoot.Width * -0.5f, _guiRoot.Height * -0.5f, 0, out var m1); Matrix.Scaling(ref transform.Scale, out var m2); Matrix.Multiply(ref m1, ref m2, out var m3); - Matrix.RotationY(Mathf.Pi, out m2); + Quaternion.Euler(180, 180, 0, out var quat); + Matrix.RotationQuaternion(ref quat, out m2); Matrix.Multiply(ref m3, ref m2, out m1); Matrix.Billboard(ref transform.Translation, ref cameraPosition, ref up, ref cameraDirection, out m2); Matrix.Multiply(ref m1, ref m2, out world); @@ -363,7 +364,8 @@ namespace FlaxEngine Matrix.Translation(_guiRoot.Width * -0.5f, _guiRoot.Height * -0.5f, 0, out var m1); Matrix.Scaling(ref transform.Scale, out var m2); Matrix.Multiply(ref m1, ref m2, out var m3); - Matrix.RotationY(Mathf.Pi, out m2); + Quaternion.Euler(180, 180, 0, out var quat); + Matrix.RotationQuaternion(ref quat, out m2); Matrix.Multiply(ref m3, ref m2, out m1); Matrix.Billboard(ref transform.Translation, ref cameraPosition, ref up, ref cameraDirection, out m2); Matrix.Multiply(ref m1, ref m2, out world); From 7dd67b5ae3db897c122213238b15b9991b9162da Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 20 Mar 2021 13:06:35 +0100 Subject: [PATCH 62/76] Fix Label auto-height and auto-width when text overflows the lines and it's wrapped #358 --- Source/Engine/UI/GUI/Common/Label.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Source/Engine/UI/GUI/Common/Label.cs b/Source/Engine/UI/GUI/Common/Label.cs index 0889bad9d..7ef433eca 100644 --- a/Source/Engine/UI/GUI/Common/Label.cs +++ b/Source/Engine/UI/GUI/Common/Label.cs @@ -239,7 +239,13 @@ namespace FlaxEngine.GUI if (font) { // Calculate text size - _textSize = font.MeasureText(_text); + var layout = TextLayoutOptions.Default; + layout.TextWrapping = Wrapping; + if (_autoHeight && !_autoWidth) + layout.Bounds.Size.X = Width - Margin.Width; + else if (_autoWidth && !_autoHeight) + layout.Bounds.Size.Y = Height - Margin.Height; + _textSize = font.MeasureText(_text, ref layout); // Check if size is controlled via text if (_autoWidth || _autoHeight) From fac7c8aa6a1a677f97071061bb27d1a13dad3c49 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 20 Mar 2021 17:56:55 +0100 Subject: [PATCH 63/76] Fix possible exception in actor editor bounds getters #286 --- Source/Editor/Editor.cs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index ce8805af0..5cada5d87 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -816,9 +816,16 @@ namespace FlaxEditor /// The bounding sphere. public static void GetActorEditorSphere(Actor actor, out BoundingSphere sphere) { - Internal_GetEditorBoxWithChildren(FlaxEngine.Object.GetUnmanagedPtr(actor), out var box); - BoundingSphere.FromBox(ref box, out sphere); - sphere.Radius = Math.Max(sphere.Radius, 15.0f); + if (actor) + { + Internal_GetEditorBoxWithChildren(FlaxEngine.Object.GetUnmanagedPtr(actor), out var box); + BoundingSphere.FromBox(ref box, out sphere); + sphere.Radius = Math.Max(sphere.Radius, 15.0f); + } + else + { + sphere = BoundingSphere.Empty; + } } /// @@ -828,7 +835,14 @@ namespace FlaxEditor /// The bounding box. public static void GetActorEditorBox(Actor actor, out BoundingBox box) { - Internal_GetEditorBoxWithChildren(FlaxEngine.Object.GetUnmanagedPtr(actor), out box); + if (actor) + { + Internal_GetEditorBoxWithChildren(FlaxEngine.Object.GetUnmanagedPtr(actor), out box); + } + else + { + box = BoundingBox.Zero; + } } /// From 40a3fb96a20bc13a3459de455a50df5c8e36c114 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 20 Mar 2021 18:40:06 +0100 Subject: [PATCH 64/76] Fix ParticleSystemWindow overlapping text bug #239 --- .../Windows/Assets/ParticleSystemWindow.cs | 53 ++++++++----------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/Source/Editor/Windows/Assets/ParticleSystemWindow.cs b/Source/Editor/Windows/Assets/ParticleSystemWindow.cs index 929e81b61..b601f3786 100644 --- a/Source/Editor/Windows/Assets/ParticleSystemWindow.cs +++ b/Source/Editor/Windows/Assets/ParticleSystemWindow.cs @@ -107,7 +107,7 @@ namespace FlaxEditor.Windows.Assets { private readonly ParticleSystemWindow _window; - [EditorDisplay("Particle System"), EditorOrder(100), Limit(1), Tooltip("The timeline animation duration in frames.")] + [EditorDisplay("Particle System"), EditorOrder(-100), Limit(1), Tooltip("The timeline animation duration in frames.")] public int TimelineDurationFrames { get => _window.Timeline.DurationFrames; @@ -124,7 +124,7 @@ namespace FlaxEditor.Windows.Assets /// The proxy object for editing particle system track properties. /// [CustomEditor(typeof(EmitterTrackProxyEditor))] - private class EmitterTrackProxy + private class EmitterTrackProxy : GeneralProxy { private readonly ParticleSystemWindow _window; private readonly ParticleEffect _effect; @@ -171,6 +171,7 @@ namespace FlaxEditor.Windows.Assets } public EmitterTrackProxy(ParticleSystemWindow window, ParticleEffect effect, ParticleEmitterTrack track, int emitterIndex) + : base(window) { _window = window; _effect = effect; @@ -238,7 +239,7 @@ namespace FlaxEditor.Windows.Assets /// /// The proxy object for editing folder track properties. /// - private class FolderTrackProxy + private class FolderTrackProxy : GeneralProxy { private readonly FolderTrack _track; @@ -265,7 +266,8 @@ namespace FlaxEditor.Windows.Assets set => _track.IconColor = value; } - public FolderTrackProxy(FolderTrack track) + public FolderTrackProxy(ParticleSystemWindow window, FolderTrack track) + : base(window) { _track = track; } @@ -275,8 +277,7 @@ namespace FlaxEditor.Windows.Assets private readonly SplitPanel _split2; private ParticleSystemTimeline _timeline; private readonly ParticleSystemPreview _preview; - private readonly CustomEditorPresenter _propertiesEditor1; - private readonly CustomEditorPresenter _propertiesEditor2; + private readonly CustomEditorPresenter _propertiesEditor; private ToolStripButton _saveButton; private ToolStripButton _undoButton; private ToolStripButton _redoButton; @@ -347,18 +348,12 @@ namespace FlaxEditor.Windows.Assets _timeline.Modified += OnTimelineModified; _timeline.SelectionChanged += OnTimelineSelectionChanged; - // Properties editor (general) - var propertiesEditor1 = new CustomEditorPresenter(null, string.Empty); - propertiesEditor1.Panel.Parent = _split2.Panel2; - propertiesEditor1.Modified += OnParticleSystemPropertyEdited; - _propertiesEditor1 = propertiesEditor1; - propertiesEditor1.Select(new GeneralProxy(this)); - - // Properties editor (selection) - var propertiesEditor2 = new CustomEditorPresenter(null, string.Empty); - propertiesEditor2.Panel.Parent = _split2.Panel2; - propertiesEditor2.Modified += OnParticleSystemPropertyEdited; - _propertiesEditor2 = propertiesEditor2; + // Properties editor + var propertiesEditor = new CustomEditorPresenter(_undo, string.Empty); + propertiesEditor.Panel.Parent = _split2.Panel2; + propertiesEditor.Modified += OnParticleSystemPropertyEdited; + _propertiesEditor = propertiesEditor; + propertiesEditor.Select(new GeneralProxy(this)); // Toolstrip _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save32, Save).LinkTooltip("Save"); @@ -380,8 +375,7 @@ namespace FlaxEditor.Windows.Assets if (!_isEditingInstancedParameterValue) { - _propertiesEditor1.BuildLayoutOnUpdate(); - _propertiesEditor2.BuildLayoutOnUpdate(); + _propertiesEditor.BuildLayoutOnUpdate(); } } @@ -399,7 +393,7 @@ namespace FlaxEditor.Windows.Assets { if (_timeline.SelectedTracks.Count == 0) { - _propertiesEditor2.Deselect(); + _propertiesEditor.Select(new GeneralProxy(this)); return; } @@ -414,14 +408,14 @@ namespace FlaxEditor.Windows.Assets } else if (track is FolderTrack folderTrack) { - tracks[i] = new FolderTrackProxy(folderTrack); + tracks[i] = new FolderTrackProxy(this, folderTrack); } else { throw new NotImplementedException("Invalid track type."); } } - _propertiesEditor2.Select(tracks); + _propertiesEditor.Select(tracks); } private void OnParticleSystemPropertyEdited() @@ -443,8 +437,7 @@ namespace FlaxEditor.Windows.Assets if (_timeline.IsModified) { - _propertiesEditor1.BuildLayoutOnUpdate(); - _propertiesEditor2.BuildLayoutOnUpdate(); + _propertiesEditor.BuildLayoutOnUpdate(); _timeline.Save(_asset); } @@ -484,7 +477,7 @@ namespace FlaxEditor.Windows.Assets /// protected override void UnlinkItem() { - _propertiesEditor2.Deselect(); + _propertiesEditor.Deselect(); _preview.System = null; _isWaitingForTimelineLoad = false; @@ -507,7 +500,7 @@ namespace FlaxEditor.Windows.Assets if (_parametersVersion != _preview.PreviewActor.ParametersVersion) { _parametersVersion = _preview.PreviewActor.ParametersVersion; - _propertiesEditor2.BuildLayoutOnUpdate(); + _propertiesEditor.BuildLayoutOnUpdate(); } base.Update(deltaTime); @@ -534,8 +527,7 @@ namespace FlaxEditor.Windows.Assets // Setup _undo.Clear(); _timeline.Enabled = true; - _propertiesEditor1.BuildLayout(); - _propertiesEditor2.Deselect(); + _propertiesEditor.Select(new GeneralProxy(this)); ClearEditedFlag(); } @@ -580,8 +572,7 @@ namespace FlaxEditor.Windows.Assets { if (_undo != null) _undo.Enabled = false; - _propertiesEditor1?.Deselect(); - _propertiesEditor2?.Deselect(); + _propertiesEditor?.Deselect(); _undo?.Clear(); _undo = null; From 0d12ccef64529218279824d7f87b72397ee2e6aa Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 20 Mar 2021 18:43:31 +0100 Subject: [PATCH 65/76] Fix invalid Timeline layout UI when opening timeline data --- Source/Editor/GUI/Timeline/Timeline.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Editor/GUI/Timeline/Timeline.cs b/Source/Editor/GUI/Timeline/Timeline.cs index e0e4083c1..56f8620c6 100644 --- a/Source/Editor/GUI/Timeline/Timeline.cs +++ b/Source/Editor/GUI/Timeline/Timeline.cs @@ -1438,6 +1438,7 @@ namespace FlaxEditor.GUI.Timeline ArrangeTracks(); PerformLayout(true); UnlockChildrenRecursive(); + PerformLayout(true); Profiler.EndEvent(); ClearEditedFlag(); From 160dfa5dc7a0bd24a325e95c607ea9e079f2ee91 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sat, 20 Mar 2021 18:49:31 +0100 Subject: [PATCH 66/76] Fix Label text alignment in auto size text #308 --- Source/Engine/UI/GUI/Common/Label.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Engine/UI/GUI/Common/Label.cs b/Source/Engine/UI/GUI/Common/Label.cs index 7ef433eca..d549a9d85 100644 --- a/Source/Engine/UI/GUI/Common/Label.cs +++ b/Source/Engine/UI/GUI/Common/Label.cs @@ -200,8 +200,8 @@ namespace FlaxEngine.GUI color *= 0.6f; var scale = 1.0f; - var hAlignment = _autoWidth ? TextAlignment.Near : HorizontalAlignment; - var wAlignment = _autoHeight ? TextAlignment.Near : VerticalAlignment; + var hAlignment = HorizontalAlignment; + var wAlignment = VerticalAlignment; if (_autoFitText) { hAlignment = TextAlignment.Center; From f4134316677a449e50d26cca5459bd09ea1c898c Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 21 Mar 2021 13:27:45 +0100 Subject: [PATCH 67/76] Add error check to prevent changing parent of the Scene actor --- Source/Engine/Level/Actor.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp index fa5bce1ff..8ab195ef1 100644 --- a/Source/Engine/Level/Actor.cpp +++ b/Source/Engine/Level/Actor.cpp @@ -203,6 +203,13 @@ void Actor::SetParent(Actor* value, bool worldPositionsStays, bool canBreakPrefa LOG(Error, "Editing scene hierarchy is only allowed on a main thread."); return; } +#if USE_EDITOR || !BUILD_RELEASE + if (Is()) + { + LOG(Error, "Cannot change parent of the Scene. Use Level to manage scenes."); + return; + } +#endif // Peek the previous state const Transform prevTransform = _transform; From 1c140a5b0e934097afb38809d4db45ac6a241d9d Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 21 Mar 2021 13:44:30 +0100 Subject: [PATCH 68/76] Fix crash in navmesh builder when scene gets unloaded after navmesh tile gets dirty --- Source/Engine/Navigation/NavMeshBuilder.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Engine/Navigation/NavMeshBuilder.cpp b/Source/Engine/Navigation/NavMeshBuilder.cpp index 55319bb9e..755f4179b 100644 --- a/Source/Engine/Navigation/NavMeshBuilder.cpp +++ b/Source/Engine/Navigation/NavMeshBuilder.cpp @@ -1016,6 +1016,8 @@ void NavMeshBuilder::Update() { NavBuildQueue.RemoveAt(i--); const auto scene = req.Scene.Get(); + if (!scene) + continue; // Early out if scene has no bounds volumes to define nav mesh area if (scene->NavigationVolumes.IsEmpty()) From 851fd1a6d046847938e564049a12313460772c1d Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 21 Mar 2021 14:00:23 +0100 Subject: [PATCH 69/76] Tweaks for prefabs first selection --- Source/Editor/Gizmo/TransformGizmo.cs | 37 ++++++++++++--------------- Source/Editor/SceneGraph/ActorNode.cs | 6 +++++ 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/Source/Editor/Gizmo/TransformGizmo.cs b/Source/Editor/Gizmo/TransformGizmo.cs index 6040f0485..f490de430 100644 --- a/Source/Editor/Gizmo/TransformGizmo.cs +++ b/Source/Editor/Gizmo/TransformGizmo.cs @@ -51,41 +51,38 @@ namespace FlaxEditor.Gizmo } /// - /// Helper function, recursivily finds the Prefab Root of node or null + /// Helper function, recursively finds the Prefab Root of node or null. /// - /// The node from which to start - /// + /// The node from which to start. + /// The prefab root or null. public ActorNode GetPrefabRootInParent(ActorNode node) { if (!node.HasPrefabLink) return null; if (node.Actor.IsPrefabRoot) return node; - else if (node.ParentNode is ActorNode parAct) + if (node.ParentNode is ActorNode parAct) return GetPrefabRootInParent(parAct); - else - return null; + return null; } /// - /// Recursively walks up from the node up to ceiling node(inclusive) or selection(exclusive) + /// Recursively walks up from the node up to ceiling node(inclusive) or selection(exclusive). /// /// The node from which to start /// The ceiling(inclusive) - /// + /// The node to select. public ActorNode WalkUpAndFindActorNodeBeforeSelection(ActorNode node, ActorNode ceiling) { - if (node == ceiling) + if (node == ceiling || _selection.Contains(node)) return node; - if (node.ParentNode is ActorNode parAct) + if (node.ParentNode is ActorNode parentNode) { - if (Editor.Instance.SceneEditing.Selection.Contains(node.ParentNode)) + if (_selection.Contains(node.ParentNode)) return node; - else - return WalkUpAndFindActorNodeBeforeSelection(parAct, ceiling); + return WalkUpAndFindActorNodeBeforeSelection(parentNode, ceiling); } - else - return null; + return node; } /// @@ -138,13 +135,13 @@ namespace FlaxEditor.Gizmo } } - //select prefab root and then go down until you find the actual item in which case select the prefab root again - if(hit is ActorNode act) + // Select prefab root and then go down until you find the actual item in which case select the prefab root again + if (hit is ActorNode actorNode) { - ActorNode prefabRoot = GetPrefabRootInParent(act); - if (prefabRoot != null && act != prefabRoot) + ActorNode prefabRoot = GetPrefabRootInParent(actorNode); + if (prefabRoot != null && actorNode != prefabRoot) { - hit = WalkUpAndFindActorNodeBeforeSelection(act, prefabRoot); + hit = WalkUpAndFindActorNodeBeforeSelection(actorNode, prefabRoot); } } diff --git a/Source/Editor/SceneGraph/ActorNode.cs b/Source/Editor/SceneGraph/ActorNode.cs index 9543c8d58..017cff3bf 100644 --- a/Source/Editor/SceneGraph/ActorNode.cs +++ b/Source/Editor/SceneGraph/ActorNode.cs @@ -321,5 +321,11 @@ namespace FlaxEditor.SceneGraph base.Dispose(); } + + /// + public override string ToString() + { + return _actor ? _actor.ToString() : base.ToString(); + } } } From e095b610fde6afa6f3d3b047e221648ac6bfcc1d Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 21 Mar 2021 14:19:14 +0100 Subject: [PATCH 70/76] Bump the version number --- Flax.flaxproj | 4 ++-- Source/FlaxEngine.Gen.cs | 4 ++-- Source/FlaxEngine.Gen.h | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Flax.flaxproj b/Flax.flaxproj index 0c2683afb..cc643346f 100644 --- a/Flax.flaxproj +++ b/Flax.flaxproj @@ -2,8 +2,8 @@ "Name": "Flax", "Version": { "Major": 1, - "Minor": 0, - "Build": 6216 + "Minor": 1, + "Build": 6217 }, "Company": "Flax", "Copyright": "Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.", diff --git a/Source/FlaxEngine.Gen.cs b/Source/FlaxEngine.Gen.cs index 3a9feca06..6f8878d25 100644 --- a/Source/FlaxEngine.Gen.cs +++ b/Source/FlaxEngine.Gen.cs @@ -13,5 +13,5 @@ using System.Runtime.InteropServices; [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("b8442186-4a70-7c85-704a-857c262d00f6")] -[assembly: AssemblyVersion("1.0.6216")] -[assembly: AssemblyFileVersion("1.0.6216")] +[assembly: AssemblyVersion("1.1.6217")] +[assembly: AssemblyFileVersion("1.1.6217")] diff --git a/Source/FlaxEngine.Gen.h b/Source/FlaxEngine.Gen.h index 94eb7c467..7a888ae1f 100644 --- a/Source/FlaxEngine.Gen.h +++ b/Source/FlaxEngine.Gen.h @@ -3,11 +3,11 @@ #pragma once #define FLAXENGINE_NAME "FlaxEngine" -#define FLAXENGINE_VERSION Version(1, 0, 6216) -#define FLAXENGINE_VERSION_TEXT "1.0.6216" +#define FLAXENGINE_VERSION Version(1, 1, 6217) +#define FLAXENGINE_VERSION_TEXT "1.1.6217" #define FLAXENGINE_VERSION_MAJOR 1 -#define FLAXENGINE_VERSION_MINOR 0 -#define FLAXENGINE_VERSION_BUILD 6216 +#define FLAXENGINE_VERSION_MINOR 1 +#define FLAXENGINE_VERSION_BUILD 6217 #define FLAXENGINE_COMPANY "Flax" #define FLAXENGINE_COPYRIGHT "Copyright (c) 2012-2021 Wojciech Figat. All rights reserved." From a3eddd5b3b97b2c8993417a2e5adf58c2114d586 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 21 Mar 2021 14:19:34 +0100 Subject: [PATCH 71/76] Fix bindings cache to rely on project name and version --- .../Bindings/BindingsGenerator.CSharp.cs | 2 +- .../Bindings/BindingsGenerator.Cache.cs | 15 ++++++++------- Source/Tools/Flax.Build/Bindings/ModuleInfo.cs | 6 +++++- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs index 84236cfd2..44d3b457c 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.CSharp.cs @@ -1092,7 +1092,7 @@ namespace Flax.Build.Bindings private static unsafe void GenerateCSharp(BuildData buildData, IGrouping binaryModule) { // Skip generating C# bindings code for native-only modules - if (binaryModule.Any(x => !x.BuildCSharp)) + if (binaryModule.All(x => !x.BuildCSharp)) return; var contents = new StringBuilder(); diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs index 8413917bb..27dedb6b4 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs @@ -18,7 +18,8 @@ namespace Flax.Build.Bindings partial class BindingsGenerator { - private static readonly Dictionary _typeCache = new Dictionary(); + private static readonly Dictionary TypeCache = new Dictionary(); + private const int CacheVersion = 7; internal static void Write(BinaryWriter writer, string e) { @@ -160,7 +161,7 @@ namespace Flax.Build.Bindings var typename = reader.ReadString(); if (string.IsNullOrEmpty(typename)) return e; - if (!_typeCache.TryGetValue(typename, out var type)) + if (!TypeCache.TryGetValue(typename, out var type)) { type = Builder.BuildTypes.FirstOrDefault(x => x.FullName == typename); if (type == null) @@ -169,7 +170,7 @@ namespace Flax.Build.Bindings Log.Error(msg); throw new Exception(msg); } - _typeCache.Add(typename, type); + TypeCache.Add(typename, type); } e = (T)Activator.CreateInstance(type); e.Read(reader); @@ -185,7 +186,7 @@ namespace Flax.Build.Bindings for (int i = 0; i < count; i++) { var typename = reader.ReadString(); - if (!_typeCache.TryGetValue(typename, out var type)) + if (!TypeCache.TryGetValue(typename, out var type)) { type = Builder.BuildTypes.FirstOrDefault(x => x.FullName == typename); if (type == null) @@ -194,7 +195,7 @@ namespace Flax.Build.Bindings Log.Error(msg); throw new Exception(msg); } - _typeCache.Add(typename, type); + TypeCache.Add(typename, type); } var e = (T)Activator.CreateInstance(type); e.Read(reader); @@ -218,7 +219,7 @@ namespace Flax.Build.Bindings using (var writer = new BinaryWriter(stream, Encoding.UTF8)) { // Version - writer.Write(5); + writer.Write(CacheVersion); writer.Write(File.GetLastWriteTime(Assembly.GetExecutingAssembly().Location).Ticks); // Build options @@ -254,7 +255,7 @@ namespace Flax.Build.Bindings { // Version var version = reader.ReadInt32(); - if (version != 5) + if (version != CacheVersion) return false; if (File.GetLastWriteTime(Assembly.GetExecutingAssembly().Location).Ticks != reader.ReadInt64()) return false; diff --git a/Source/Tools/Flax.Build/Bindings/ModuleInfo.cs b/Source/Tools/Flax.Build/Bindings/ModuleInfo.cs index 75ff73720..0769d6ce6 100644 --- a/Source/Tools/Flax.Build/Bindings/ModuleInfo.cs +++ b/Source/Tools/Flax.Build/Bindings/ModuleInfo.cs @@ -34,6 +34,8 @@ namespace Flax.Build.Bindings BindingsGenerator.Write(writer, Module.BinaryModuleName); writer.Write(Module.BuildNativeCode); writer.Write(Module.BuildCSharp); + writer.Write(Globals.Project.Name); + writer.Write(Globals.Project.Version.ToString()); base.Write(writer); } @@ -44,7 +46,9 @@ namespace Flax.Build.Bindings reader.ReadString() != Module.FilePath || BindingsGenerator.Read(reader, Module.BinaryModuleName) != Module.BinaryModuleName || reader.ReadBoolean() != Module.BuildNativeCode || - reader.ReadBoolean() != Module.BuildCSharp + reader.ReadBoolean() != Module.BuildCSharp || + reader.ReadString() != Globals.Project.Name || + reader.ReadString() != Globals.Project.Version.ToString() ) throw new Exception(); From 22812ad21e1745f7eb1e7a38a4d72d52a59ea80e Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 21 Mar 2021 15:34:15 +0100 Subject: [PATCH 72/76] Fix game build --- Source/Engine/UI/UICanvas.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Engine/UI/UICanvas.cs b/Source/Engine/UI/UICanvas.cs index 6f1687f31..cbd554775 100644 --- a/Source/Engine/UI/UICanvas.cs +++ b/Source/Engine/UI/UICanvas.cs @@ -117,7 +117,7 @@ namespace FlaxEngine /// /// Gets or sets the canvas rendering location within rendering pipeline. Used only in or or . /// - [EditorOrder(13), EditorDisplay("Canvas"), VisibleIf(nameof(Editor_Is3D)), Tooltip("Canvas rendering location within the rendering pipeline. Change this if you want GUI to affect the lighting or post processing effects like bloom.")] + [EditorOrder(13), EditorDisplay("Canvas"), VisibleIf("Editor_Is3D"), Tooltip("Canvas rendering location within the rendering pipeline. Change this if you want GUI to affect the lighting or post processing effects like bloom.")] public PostProcessEffectLocation RenderLocation { get; set; } = PostProcessEffectLocation.Default; private int _order; From cb96a8765941eb0491d7685768a21739ca8b57a8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 21 Mar 2021 20:25:25 +0100 Subject: [PATCH 73/76] Fix crash when material is generated at 2 threads at once --- Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp index b6b5306e2..fa0ae58c5 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp @@ -54,6 +54,7 @@ namespace { // Loaded and parsed features data cache Dictionary Features; + CriticalSection FeaturesLock; } bool FeatureData::Init() @@ -174,6 +175,7 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo features.Add(typeName); \ if (!Features.ContainsKey(typeName)) \ { \ + ScopeLock lock(FeaturesLock); \ auto& feature = Features[typeName]; \ type::Generate(feature.Data); \ if (feature.Init()) \ @@ -388,7 +390,7 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo // Update material usage based on material generator outputs materialInfo.UsageFlags = baseLayer->UsageFlags; -#define WRITE_FEATURES(input) for (auto f : features) _writer.Write(Features[f].Inputs[(int32)FeatureTemplateInputsMapping::input]); +#define WRITE_FEATURES(input) FeaturesLock.Lock(); for (auto f : features) _writer.Write(Features[f].Inputs[(int32)FeatureTemplateInputsMapping::input]); FeaturesLock.Unlock(); // Defines { _writer.Write(TEXT("#define MATERIAL_MASK_THRESHOLD ({0})\n"), baseLayer->MaskThreshold); From b3e16a6b66ee5b41ba3891bbe531ff5b491a513a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 22 Mar 2021 10:24:15 +0100 Subject: [PATCH 74/76] Fix material not updating on connection removal #372 --- Source/Editor/Surface/Elements/Box.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Editor/Surface/Elements/Box.cs b/Source/Editor/Surface/Elements/Box.cs index 2a460013c..6a8745fa6 100644 --- a/Source/Editor/Surface/Elements/Box.cs +++ b/Source/Editor/Surface/Elements/Box.cs @@ -578,6 +578,7 @@ namespace FlaxEditor.Surface.Elements BreakConnection(connectedBox); action.End(); Surface.Undo.AddAction(action); + Surface.MarkAsEdited(); } else { From 78f8066d4d7e382ec82d29c5147567980374f947 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 22 Mar 2021 10:24:22 +0100 Subject: [PATCH 75/76] Fix code style --- Source/Editor/Surface/VisjectSurface.Input.cs | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/Source/Editor/Surface/VisjectSurface.Input.cs b/Source/Editor/Surface/VisjectSurface.Input.cs index 996f9d2e0..9b96aa165 100644 --- a/Source/Editor/Surface/VisjectSurface.Input.cs +++ b/Source/Editor/Surface/VisjectSurface.Input.cs @@ -298,7 +298,6 @@ namespace FlaxEditor.Surface rerouteNode.GetBoxes().First(b => b.IsOutput).CreateConnection(inputBox); addConnectionsAction.End(); - Undo.AddAction(new MultiUndoAction(spawnNodeAction, disconnectBoxesAction, addConnectionsAction)); } else @@ -565,11 +564,10 @@ namespace FlaxEditor.Surface if (key == KeyboardKeys.ArrowUp || key == KeyboardKeys.ArrowDown) { Box selectedBox = GetSelectedBox(SelectedNodes); - if (selectedBox == null) return true; + if (selectedBox == null) + return true; - Box toSelect = (key == KeyboardKeys.ArrowUp) ? - selectedBox?.ParentNode.GetPreviousBox(selectedBox) : - selectedBox?.ParentNode.GetNextBox(selectedBox); + Box toSelect = (key == KeyboardKeys.ArrowUp) ? selectedBox?.ParentNode.GetPreviousBox(selectedBox) : selectedBox?.ParentNode.GetNextBox(selectedBox); if (toSelect != null && toSelect.IsOutput == selectedBox.IsOutput) { @@ -581,10 +579,12 @@ namespace FlaxEditor.Surface if (key == KeyboardKeys.Tab) { Box selectedBox = GetSelectedBox(SelectedNodes); - if (selectedBox == null) return true; + if (selectedBox == null) + return true; int connectionCount = selectedBox.Connections.Count; - if (connectionCount == 0) return true; + if (connectionCount == 0) + return true; if (Root.GetKey(KeyboardKeys.Shift)) { @@ -596,11 +596,11 @@ namespace FlaxEditor.Surface } } - if (key == KeyboardKeys.ArrowRight || key == KeyboardKeys.ArrowLeft) { Box selectedBox = GetSelectedBox(SelectedNodes); - if (selectedBox == null) return true; + if (selectedBox == null) + return true; Box toSelect = null; @@ -633,7 +633,6 @@ namespace FlaxEditor.Surface { Select(toSelect.ParentNode); toSelect.ParentNode.SelectBox(toSelect); - } return true; } @@ -825,10 +824,7 @@ namespace FlaxEditor.Surface xLocation += -120 - distanceBetweenNodes.X; } - return new Vector2( - xLocation, - yLocation - ); + return new Vector2(xLocation, yLocation); } private bool IntersectsConnection(Vector2 mousePosition, out InputBox inputBox, out OutputBox outputBox) From 39a6d0d2923de6fdf3df68dea603586a2481dc8a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 22 Mar 2021 11:23:25 +0100 Subject: [PATCH 76/76] Add Unix network impl for Android --- Source/Engine/Platform/Network.h | 4 ++-- Source/Engine/Platform/Types.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Engine/Platform/Network.h b/Source/Engine/Platform/Network.h index af9851a0a..c6c99d1f8 100644 --- a/Source/Engine/Platform/Network.h +++ b/Source/Engine/Platform/Network.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #pragma once @@ -13,7 +13,7 @@ #elif PLATFORM_XBOX_SCARLETT #include "Win32/Win32Network.h" #elif PLATFORM_ANDROID -#include "Base/NetworkBase.h" +#include "Unix/UnixNetwork.h" #else #error Missing Network implementation! #endif diff --git a/Source/Engine/Platform/Types.h b/Source/Engine/Platform/Types.h index 3cec8ab1a..b43bd2bd5 100644 --- a/Source/Engine/Platform/Types.h +++ b/Source/Engine/Platform/Types.h @@ -137,8 +137,8 @@ class AndroidThread; typedef AndroidThread Thread; class AndroidWindow; typedef AndroidWindow Window; -class NetworkBase; -typedef NetworkBase Network; +class UnixNetwork; +typedef UnixNetwork Network; #else