diff --git a/Flax.flaxproj b/Flax.flaxproj index cc643346f..681c1dc55 100644 --- a/Flax.flaxproj +++ b/Flax.flaxproj @@ -3,7 +3,7 @@ "Version": { "Major": 1, "Minor": 1, - "Build": 6217 + "Build": 6218 }, "Company": "Flax", "Copyright": "Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.", diff --git a/Source/Editor/Cooker/Platform/UWP/UWPPlatformTools.cpp b/Source/Editor/Cooker/Platform/UWP/UWPPlatformTools.cpp index 6b4c95ffb..e6516bf67 100644 --- a/Source/Editor/Cooker/Platform/UWP/UWPPlatformTools.cpp +++ b/Source/Editor/Cooker/Platform/UWP/UWPPlatformTools.cpp @@ -43,7 +43,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data) const auto uwpDataPath = platformDataPath / (isXboxOne ? TEXT("XboxOne") : TEXT("UWP")) / TEXT("Binaries"); const auto gameSettings = GameSettings::Get(); const auto platformSettings = UWPPlatformSettings::Get(); - Array fileTemplate; + StringAnsi fileTemplate; // Copy binaries const auto binPath = data.GetGameBinariesPath(); @@ -149,12 +149,11 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data) if (!FileSystem::FileExists(dstAssemblyInfoPath)) { // Get template - if (File::ReadAllBytes(srcAssemblyInfoPath, fileTemplate)) + if (File::ReadAllText(srcAssemblyInfoPath, fileTemplate)) { data.Error(TEXT("Failed to load AssemblyInfo.cs template.")); return true; } - fileTemplate[fileTemplate.Count() - 1] = 0; // Write data to file auto file = FileWriteStream::Open(dstAssemblyInfoPath); @@ -163,7 +162,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data) { auto now = DateTime::Now(); file->WriteTextFormatted( - (char*)fileTemplate.Get() + fileTemplate.Get() , gameSettings->ProductName.ToStringAnsi() , gameSettings->CompanyName.ToStringAnsi() , now.GetYear() @@ -182,12 +181,11 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data) if (!FileSystem::FileExists(dstAppPath)) { // Get template - if (File::ReadAllBytes(srcAppPath, fileTemplate)) + if (File::ReadAllText(srcAppPath, fileTemplate)) { data.Error(TEXT("Failed to load App.cs template.")); return true; } - fileTemplate[fileTemplate.Count() - 1] = 0; // Write data to file auto file = FileWriteStream::Open(dstAppPath); @@ -195,7 +193,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data) if (file) { file->WriteTextFormatted( - (char*)fileTemplate.Get() + fileTemplate.Get() , defaultNamespace.ToStringAnsi() // {0} Default Namespace ); hasError = file->HasError(); @@ -211,12 +209,11 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data) const auto srcFlaxGeneratedPath = uwpDataPath / TEXT("FlaxGenerated.cs"); { // Get template - if (File::ReadAllBytes(srcFlaxGeneratedPath, fileTemplate)) + if (File::ReadAllText(srcFlaxGeneratedPath, fileTemplate)) { data.Error(TEXT("Failed to load FlaxGenerated.cs template.")); return true; } - fileTemplate[fileTemplate.Count() - 1] = 0; // Prepare StringAnsi autoRotationPreferences; @@ -252,7 +249,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data) if (file) { file->WriteTextFormatted( - (char*)fileTemplate.Get() + fileTemplate.Get() , autoRotationPreferences.Get() , preferredLaunchWindowingMode.Get() ); @@ -272,12 +269,11 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data) if (!FileSystem::FileExists(dstSolutionPath)) { // Get template - if (File::ReadAllBytes(srcSolutionPath, fileTemplate)) + if (File::ReadAllText(srcSolutionPath, fileTemplate)) { data.Error(TEXT("Failed to load Solution.sln template.")); return true; } - fileTemplate[fileTemplate.Count() - 1] = 0; // Write data to file auto file = FileWriteStream::Open(dstSolutionPath); @@ -285,7 +281,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data) if (file) { file->WriteTextFormatted( - (char*)fileTemplate.Get() + fileTemplate.Get() , projectName.ToStringAnsi() // {0} Project Name , mode // {1} Platform Mode , projectGuid.ToStringAnsi() // {2} Project ID @@ -305,12 +301,11 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data) const auto srcProjectPath = uwpDataPath / TEXT("Project.csproj"); { // Get template - if (File::ReadAllBytes(srcProjectPath, fileTemplate)) + if (File::ReadAllText(srcProjectPath, fileTemplate)) { data.Error(TEXT("Failed to load Project.csproj template.")); return true; } - fileTemplate[fileTemplate.Count() - 1] = 0; // Build included files data StringBuilder filesInclude(2048); @@ -334,7 +329,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data) if (file) { file->WriteTextFormatted( - (char*)fileTemplate.Get() + fileTemplate.Get() , projectName.ToStringAnsi() // {0} Project Name , mode // {1} Platform Mode , projectGuid.Get() // {2} Project ID @@ -357,12 +352,11 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data) if (!FileSystem::FileExists(dstManifestPath)) { // Get template - if (File::ReadAllBytes(srcManifestPath, fileTemplate)) + if (File::ReadAllText(srcManifestPath, fileTemplate)) { data.Error(TEXT("Failed to load Package.appxmanifest template.")); return true; } - fileTemplate[fileTemplate.Count() - 1] = 0; // Build included files data StringBuilder filesInclude(2048); @@ -385,7 +379,7 @@ bool UWPPlatformTools::OnDeployBinaries(CookingData& data) if (file) { file->WriteTextFormatted( - (char*)fileTemplate.Get() + fileTemplate.Get() , projectName.ToStringAnsi() // {0} Display Name , gameSettings->CompanyName.ToStringAnsi() // {1} Company Name , productId.ToStringAnsi() // {2} Product ID diff --git a/Source/Editor/CustomEditors/Values/ListValueContainer.cs b/Source/Editor/CustomEditors/Values/ListValueContainer.cs index f8e5dd26c..416b866cc 100644 --- a/Source/Editor/CustomEditors/Values/ListValueContainer.cs +++ b/Source/Editor/CustomEditors/Values/ListValueContainer.cs @@ -46,10 +46,7 @@ namespace FlaxEditor.CustomEditors if (values.HasReferenceValue) { - var v = (IList)values.ReferenceValue; - - // Get the reference value if collections are the same size - if (v != null && values.Count == v.Count) + if (values.ReferenceValue is IList v && values.Count == v.Count && v.Count > index) { _referenceValue = v[index]; _hasReferenceValue = true; diff --git a/Source/Editor/Options/OptionsModule.cs b/Source/Editor/Options/OptionsModule.cs index 62496823c..06cff713c 100644 --- a/Source/Editor/Options/OptionsModule.cs +++ b/Source/Editor/Options/OptionsModule.cs @@ -150,7 +150,10 @@ namespace FlaxEditor.Options private void Save() { // Update file - Editor.SaveJsonAsset(_optionsFilePath, Options); + if (Editor.SaveJsonAsset(_optionsFilePath, Options)) + { + MessageBox.Show(string.Format("Failed to save editor option to '{0}'. Ensure that directory exists and program has access to it.", _optionsFilePath), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } // Special case for editor analytics var editorAnalyticsTrackingFile = Path.Combine(Editor.LocalCachePath, "noTracking"); diff --git a/Source/Editor/Viewport/PrefabWindowViewport.cs b/Source/Editor/Viewport/PrefabWindowViewport.cs index 1b66b8c95..d59ebb977 100644 --- a/Source/Editor/Viewport/PrefabWindowViewport.cs +++ b/Source/Editor/Viewport/PrefabWindowViewport.cs @@ -26,6 +26,7 @@ namespace FlaxEditor.Viewport /// public class PrefabWindowViewport : PrefabPreview, IEditorPrimitivesOwner { + [HideInEditor] private sealed class PrefabSpritesRenderer : MainEditorGizmoViewport.EditorSpritesRenderer { public PrefabWindowViewport Viewport; diff --git a/Source/Engine/Content/Cache/AssetsCache.h b/Source/Engine/Content/Cache/AssetsCache.h index ba0ee0303..3186b3cfc 100644 --- a/Source/Engine/Content/Cache/AssetsCache.h +++ b/Source/Engine/Content/Cache/AssetsCache.h @@ -31,7 +31,7 @@ DECLARE_ENUM_OPERATORS(AssetsCacheFlags); /// /// Flax Game Engine assets cache container /// -class AssetsCache +class FLAXENGINE_API AssetsCache { public: diff --git a/Source/Engine/ContentImporters/CreateJson.cpp b/Source/Engine/ContentImporters/CreateJson.cpp index 6141cb03e..fb7d3f6e7 100644 --- a/Source/Engine/ContentImporters/CreateJson.cpp +++ b/Source/Engine/ContentImporters/CreateJson.cpp @@ -41,6 +41,18 @@ bool CreateJson::Create(const StringView& path, StringAnsiView& data, StringAnsi LOG(Warning, "Asset will have different type name {0} -> {1}", typeName, String(dataTypename.Get())); } } + else + { + const String directory = StringUtils::GetDirectoryName(path); + if (!FileSystem::DirectoryExists(directory)) + { + if (FileSystem::CreateDirectory(directory)) + { + LOG(Warning, "Failed to create directory"); + return true; + } + } + } rapidjson_flax::StringBuffer buffer; diff --git a/Source/Engine/Core/Types/StringView.cpp b/Source/Engine/Core/Types/StringView.cpp index d6cbb3a6a..e29afe4e8 100644 --- a/Source/Engine/Core/Types/StringView.cpp +++ b/Source/Engine/Core/Types/StringView.cpp @@ -27,6 +27,18 @@ bool StringView::operator!=(const String& other) const return StringUtils::Compare(this->GetText(), *other) != 0; } +String StringView::Left(int32 count) const +{ + const int32 countClamped = count < 0 ? 0 : count < Length() ? count : Length(); + return String(**this, countClamped); +} + +String StringView::Right(int32 count) const +{ + const int32 countClamped = count < 0 ? 0 : count < Length() ? count : Length(); + return String(**this + Length() - countClamped); +} + String StringView::Substring(int32 startIndex) const { ASSERT(startIndex >= 0 && startIndex < Length()); diff --git a/Source/Engine/Core/Types/StringView.h b/Source/Engine/Core/Types/StringView.h index 5d5ad2799..b413ff552 100644 --- a/Source/Engine/Core/Types/StringView.h +++ b/Source/Engine/Core/Types/StringView.h @@ -321,6 +321,20 @@ public: public: + /// + /// Gets the left most given number of characters. + /// + /// The characters count. + /// The substring. + String Left(int32 count) const; + + /// + /// Gets the string of characters from the right (end of the string). + /// + /// The characters count. + /// The substring. + String Right(int32 count) const; + /// /// Retrieves substring created from characters starting from startIndex to the String end. /// diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp index 498fd3491..9126d313b 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp @@ -1040,7 +1040,7 @@ void StagingManagerVulkan::Dispose() ScopeLock lock(_locker); #if !BUILD_RELEASE - LOG(Info, "Vulakn staging buffers peek memory usage: {0}, allocs: {1}, frees: {2}", Utilities::BytesToText(_allBuffersPeekSize), Utilities::BytesToText(_allBuffersAllocSize), Utilities::BytesToText(_allBuffersFreeSize)); + LOG(Info, "Vulkan staging buffers peek memory usage: {0}, allocs: {1}, frees: {2}", Utilities::BytesToText(_allBuffersPeekSize), Utilities::BytesToText(_allBuffersAllocSize), Utilities::BytesToText(_allBuffersFreeSize)); #endif // Release buffers and clear memory diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp index 8ab195ef1..ef5b2a554 100644 --- a/Source/Engine/Level/Actor.cpp +++ b/Source/Engine/Level/Actor.cpp @@ -347,6 +347,12 @@ void Actor::SetOrderInParent(int32 index) } } +Actor* Actor::GetChild(int32 index) const +{ + CHECK_RETURN(index >= 0 && index < Children.Count(), nullptr); + return Children[index]; +} + Actor* Actor::GetChild(const StringView& name) const { for (int32 i = 0; i < Children.Count(); i++) @@ -354,7 +360,6 @@ Actor* Actor::GetChild(const StringView& name) const if (Children[i]->GetName() == name) return Children[i]; } - return nullptr; } @@ -482,6 +487,12 @@ void Actor::SetName(const StringView& value) Level::callActorEvent(Level::ActorEventType::OnActorNameChanged, this, nullptr); } +Script* Actor::GetScript(int32 index) const +{ + CHECK_RETURN(index >= 0 && index < Scripts.Count(), nullptr); + return Scripts[index]; +} + Script* Actor::GetScript(const MClass* type) const { CHECK_RETURN(type, nullptr); diff --git a/Source/Engine/Level/Actor.h b/Source/Engine/Level/Actor.h index 233ebe04c..560403890 100644 --- a/Source/Engine/Level/Actor.h +++ b/Source/Engine/Level/Actor.h @@ -192,10 +192,7 @@ public: /// /// The child actor index. /// The child actor (always valid). - API_FUNCTION() FORCE_INLINE Actor* GetChild(int32 index) const - { - return Children[index]; - } + API_FUNCTION() Actor* GetChild(int32 index) const; /// /// Gets the child actor with the given name. @@ -266,10 +263,7 @@ public: /// /// The script index. /// The script (always valid). - API_FUNCTION() FORCE_INLINE Script* GetScript(int32 index) const - { - return Scripts[index]; - } + API_FUNCTION() Script* GetScript(int32 index) const; /// /// Gets the script of the given type from this actor. diff --git a/Source/Engine/Main/UWP/main.cpp b/Source/Engine/Main/UWP/main.cpp index 08d9cc422..e615a2b38 100644 --- a/Source/Engine/Main/UWP/main.cpp +++ b/Source/Engine/Main/UWP/main.cpp @@ -65,22 +65,6 @@ void Game::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs void Game::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args) { - /* - // Save app state asynchronously after requesting a deferral. Holding a deferral - // indicates that the application is busy performing suspending operations. Be - // aware that a deferral may not be held indefinitely. After about five seconds, - // the app will be forced to exit. - SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral(); - - create_task([this, deferral]() - { - m_deviceResources->Trim(); - - m_main->Suspend(); - - deferral->Complete(); - }); - */ } void Game::OnResuming(Platform::Object^ sender, Platform::Object^ args) @@ -396,9 +380,10 @@ int PlatformImpl::GetSpecialFolderPath(const SpecialFolder type, wchar_t* buffer path = Windows::Storage::ApplicationData::Current->LocalFolder->Path; break; case SpecialFolder::ProgramData: + path = Windows::Storage::ApplicationData::Current->RoamingFolder->Path; break; - //case SpecialFolder::Temporary: path = Windows::Storage::ApplicationData::Current->TemporaryFolder->Path; break; case SpecialFolder::Temporary: + //path = Windows::Storage::ApplicationData::Current->TemporaryFolder->Path; path = Windows::Storage::ApplicationData::Current->LocalFolder->Path; break; } @@ -409,7 +394,7 @@ int PlatformImpl::GetSpecialFolderPath(const SpecialFolder type, wchar_t* buffer if (length >= bufferLength) length = bufferLength - 1; const wchar_t* data = path->Data(); - for (int i = 0; isetSlopeLimit(cosf(value * DegreesToRadians)); + _controller->setSlopeLimit(Math::Cos(value * DegreesToRadians)); +} + +CharacterController::NonWalkableModes CharacterController::GetNonWalkableMode() const +{ + return _nonWalkableMode; } void CharacterController::SetNonWalkableMode(NonWalkableModes value) @@ -72,6 +77,11 @@ void CharacterController::SetNonWalkableMode(NonWalkableModes value) _controller->setNonWalkableMode(static_cast(value)); } +float CharacterController::GetStepOffset() const +{ + return _stepOffset; +} + void CharacterController::SetStepOffset(float value) { if (Math::NearEqual(value, _stepOffset)) diff --git a/Source/Engine/Physics/Colliders/CharacterController.h b/Source/Engine/Physics/Colliders/CharacterController.h index e3f690f8c..5b4dd3f49 100644 --- a/Source/Engine/Physics/Colliders/CharacterController.h +++ b/Source/Engine/Physics/Colliders/CharacterController.h @@ -118,10 +118,7 @@ public: /// Gets the non-walkable mode for the character controller. /// API_PROPERTY(Attributes="EditorOrder(215), DefaultValue(NonWalkableModes.PreventClimbing), EditorDisplay(\"Character Controller\")") - FORCE_INLINE NonWalkableModes GetNonWalkableMode() const - { - return _nonWalkableMode; - } + NonWalkableModes GetNonWalkableMode() const; /// /// Sets the non-walkable mode for the character controller. @@ -132,10 +129,7 @@ public: /// Gets the step height. The character will step up a stair only if it is closer to the ground than the indicated value. This should not be greater than the Character Controller’s height or it will generate an error. /// API_PROPERTY(Attributes="EditorOrder(220), DefaultValue(30.0f), Limit(0), EditorDisplay(\"Character Controller\")") - FORCE_INLINE float GetStepOffset() const - { - return _stepOffset; - } + float GetStepOffset() const; /// /// Sets the step height. The character will step up a stair only if it is closer to the ground than the indicated value. This should not be greater than the Character Controller’s height or it will generate an error. diff --git a/Source/Engine/Platform/Base/StringUtilsBase.cpp b/Source/Engine/Platform/Base/StringUtilsBase.cpp index b492abc9b..e8fe3ebc3 100644 --- a/Source/Engine/Platform/Base/StringUtilsBase.cpp +++ b/Source/Engine/Platform/Base/StringUtilsBase.cpp @@ -289,7 +289,7 @@ void RemoveLongPathPrefix(const String& path, String& result) result.Remove(2, 6); } -String StringUtils::GetDirectoryName(const String& path) +String StringUtils::GetDirectoryName(const StringView& path) { const int32 lastFrontSlash = path.FindLast('\\'); const int32 lastBackSlash = path.FindLast('/'); @@ -297,24 +297,22 @@ String StringUtils::GetDirectoryName(const String& path) return splitIndex != INVALID_INDEX ? path.Left(splitIndex) : String::Empty; } -String StringUtils::GetFileName(const String& path) +String StringUtils::GetFileName(const StringView& path) { Char chr; const int32 length = path.Length(); int32 num = length; - do { num--; if (num < 0) - return path; + return String(path); chr = path[num]; } while (chr != DirectorySeparatorChar && chr != AltDirectorySeparatorChar && chr != VolumeSeparatorChar); - return path.Substring(num + 1, length - num - 1); } -String StringUtils::GetFileNameWithoutExtension(const String& path) +String StringUtils::GetFileNameWithoutExtension(const StringView& path) { String filename = GetFileName(path); const int32 num = filename.FindLast('.'); @@ -325,14 +323,14 @@ String StringUtils::GetFileNameWithoutExtension(const String& path) return filename; } -String StringUtils::GetPathWithoutExtension(const String& path) +String StringUtils::GetPathWithoutExtension(const StringView& path) { const int32 num = path.FindLast('.'); if (num != -1) { return path.Substring(0, num); } - return path; + return String(path); } void StringUtils::PathRemoveRelativeParts(String& path) diff --git a/Source/Engine/Platform/Linux/LinuxPlatform.cpp b/Source/Engine/Platform/Linux/LinuxPlatform.cpp index a49d655dd..59066a2e7 100644 --- a/Source/Engine/Platform/Linux/LinuxPlatform.cpp +++ b/Source/Engine/Platform/Linux/LinuxPlatform.cpp @@ -20,6 +20,7 @@ #include "Engine/Platform/MessageBox.h" #include "Engine/Platform/WindowsManager.h" #include "Engine/Platform/Clipboard.h" +#include "Engine/Platform/IGuiData.h" #include "Engine/Utilities/StringConverter.h" #include "Engine/Threading/Threading.h" #include "Engine/Engine/Engine.h" @@ -58,6 +59,15 @@ X11::Display* xDisplay = nullptr; X11::XIM IM = nullptr; X11::XIC IC = nullptr; X11::Atom xAtomDeleteWindow; +X11::Atom xAtomXdndEnter; +X11::Atom xAtomXdndPosition; +X11::Atom xAtomXdndLeave; +X11::Atom xAtomXdndDrop; +X11::Atom xAtomXdndActionCopy; +X11::Atom xAtomXdndStatus; +X11::Atom xAtomXdndSelection; +X11::Atom xAtomXdndFinished; +X11::Atom xAtomXdndAware; X11::Atom xAtomWmState; X11::Atom xAtomWmStateHidden; X11::Atom xAtomWmStateMaxVert; @@ -65,6 +75,11 @@ X11::Atom xAtomWmStateMaxHorz; X11::Atom xAtomWmWindowOpacity; X11::Atom xAtomWmName; X11::Atom xAtomClipboard; +X11::Atom xDnDRequested = 0; +X11::Window xDndSourceWindow = 0; +DragDropEffect xDndResult; +Vector2 xDndPos; +int32 xDnDVersion = 0; int32 SystemDpi = 96; X11::Cursor Cursors[(int32)CursorType::MAX]; X11::XcursorImage* CursorsImg[(int32)CursorType::MAX]; @@ -1171,6 +1186,13 @@ public: } }; +struct Property +{ + unsigned char* data; + int format, nitems; + X11::Atom type; +}; + namespace Impl { LinuxKeyboard Keyboard; @@ -1222,6 +1244,407 @@ namespace Impl } } } + + Property ReadProperty(X11::Display* display, X11::Window window, X11::Atom property) + { + X11::Atom readType = 0; + int readFormat = 0; + unsigned long nitems = 0; + unsigned long readBytes = 0; + unsigned char* result = nullptr; + int bytesCount = 1024; + if (property != 0) + { + do + { + if (result != nullptr) + X11::XFree(result); + XGetWindowProperty(display, window, property, 0, bytesCount, 0, AnyPropertyType, &readType, &readFormat, &nitems, &readBytes, &result); + bytesCount *= 2; + } while (readBytes != 0); + } + Property p = { result, readFormat, (int)nitems, readType }; + return p; + } + + static X11::Atom SelectTargetFromList(X11::Display* display, const char* targetType, X11::Atom* list, int count) + { + for (int i = 0; i < count; i++) + { + X11::Atom atom = list[i]; + if (atom != 0 && StringAnsi(XGetAtomName(display, atom)) == targetType) + return atom; + } + return 0; + } + + static X11::Atom SelectTargetFromAtoms(X11::Display* display, const char* targetType, X11::Atom t1, X11::Atom t2, X11::Atom t3) + { + if (t1 != 0 && StringAnsi(XGetAtomName(display, t1)) == targetType) + return t1; + if (t2 != 0 && StringAnsi(XGetAtomName(display, t2)) == targetType) + return t2; + if (t3 != 0 && StringAnsi(XGetAtomName(display, t3)) == targetType) + return t3; + return 0; + } + + static X11::Window FindAppWindow(X11::Display* display, X11::Window w) + { + int nprops, i = 0; + X11::Atom* a; + if (w == 0) + return 0; + a = X11::XListProperties(display, w, &nprops); + for (i = 0; i < nprops; i++) + { + if (a[i] == xAtomXdndAware) + break; + } + if (nprops) + X11::XFree(a); + if (i != nprops) + return w; + X11::Window child, wtmp; + int tmp; + unsigned int utmp; + X11::XQueryPointer(display, w, &wtmp, &child, &tmp, &tmp, &tmp, &tmp, &utmp); + return FindAppWindow(display, child); + } +} + +class LinuxDropFilesData : public IGuiData +{ +public: + Array Files; + + Type GetType() const override + { + return Type::Files; + } + String GetAsText() const override + { + return String::Empty; + } + void GetAsFiles(Array* files) const override + { + files->Add(Files); + } +}; + +class LinuxDropTextData : public IGuiData +{ +public: + StringView Text; + + Type GetType() const override + { + return Type::Text; + } + String GetAsText() const override + { + return String(Text); + } + void GetAsFiles(Array* files) const override + { + } +}; + +DragDropEffect LinuxWindow::DoDragDrop(const StringView& data) +{ + auto cursorWrong = X11::XCreateFontCursor(xDisplay, 54); + auto cursorTransient = X11::XCreateFontCursor(xDisplay, 24); + auto cursorGood = X11::XCreateFontCursor(xDisplay, 4); + Array> formats; + formats.Add(X11::XInternAtom(xDisplay, "text/plain", 0)); + formats.Add(X11::XInternAtom(xDisplay, "TEXT", 0)); + formats.Add((X11::Atom)31); + StringAnsi dataAnsi(data); + LinuxDropTextData dropData; + dropData.Text = data; + + // Begin dragging + auto screen = X11::XDefaultScreen(xDisplay); + auto rootWindow = X11::XRootWindow(xDisplay, screen); + if (X11::XGrabPointer(xDisplay, _window, 1, Button1MotionMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, rootWindow, cursorWrong, CurrentTime) != GrabSuccess) + return DragDropEffect::None; + X11::XSetSelectionOwner(xDisplay, xAtomXdndSelection, _window, CurrentTime); + + // Process events + X11::XEvent event; + enum Status + { + Unaware, + Unreceptive, + CanDrop, + }; + int status = Unaware, previousVersion = -1; + X11::Window previousWindow = 0; + DragDropEffect result = DragDropEffect::None; + float lastDraw = Platform::GetTimeSeconds(); + float startTime = lastDraw; + while (true) + { + X11::XNextEvent(xDisplay, &event); + + if (event.type == SelectionClear) + break; + if (event.type == SelectionRequest) + { + // Extract the relavent data + X11::Window owner = event.xselectionrequest.owner; + X11::Atom selection = event.xselectionrequest.selection; + X11::Atom target = event.xselectionrequest.target; + X11::Atom property = event.xselectionrequest.property; + X11::Window requestor = event.xselectionrequest.requestor; + X11::Time timestamp = event.xselectionrequest.time; + X11::Display* disp = event.xselection.display; + X11::XEvent s; + s.xselection.type = SelectionNotify; + s.xselection.requestor = requestor; + s.xselection.selection = selection; + s.xselection.target = target; + s.xselection.property = 0; + s.xselection.time = timestamp; + if (target == X11::XInternAtom(disp, "TARGETS", 0)) + { + Array targets; + targets.Add(target); + targets.Add(X11::XInternAtom(disp, "MULTIPLE", 0)); + targets.Add(formats.Get(), formats.Count()); + X11::XChangeProperty(disp, requestor, property, (X11::Atom)4, 32, PropModeReplace, (unsigned char*)targets.Get(), targets.Count()); + s.xselection.property = property; + } + else if (formats.Contains(target)) + { + s.xselection.property = property; + X11::XChangeProperty(disp, requestor, property, target, 8, PropModeReplace, reinterpret_cast(dataAnsi.Get()), dataAnsi.Length()); + } + X11::XSendEvent(event.xselection.display, event.xselectionrequest.requestor, 1, 0, &s); + } + else if (event.type == MotionNotify) + { + // Find window under mouse + auto window = Impl::FindAppWindow(xDisplay, rootWindow); + int fmt, version = -1; + X11::Atom atmp; + unsigned long nitems, bytesLeft; + unsigned char* data = nullptr; + if (window == previousWindow) + version = previousVersion; + else if(window == 0) + ; + else if (X11::XGetWindowProperty(xDisplay, window, xAtomXdndAware, 0, 2, 0, AnyPropertyType, &atmp, &fmt, &nitems, &bytesLeft, &data) != Success) + continue; + else if (data == 0) + continue; + else if (fmt != 32) + continue; + else if (nitems != 1) + continue; + else + version = data[0]; + if (status == Unaware && version != -1) + status = Unreceptive; + else if(version == -1) + status = Unaware; + xDndPos = Vector2((float)event.xmotion.x_root, (float)event.xmotion.y_root); + + // Update mouse grab + if (status == Unaware) + X11::XChangeActivePointerGrab(xDisplay, Button1MotionMask | ButtonReleaseMask, cursorWrong, CurrentTime); + else if(status == Unreceptive) + X11::XChangeActivePointerGrab(xDisplay, Button1MotionMask | ButtonReleaseMask, cursorTransient, CurrentTime); + else + X11::XChangeActivePointerGrab(xDisplay, Button1MotionMask | ButtonReleaseMask, cursorGood, CurrentTime); + + if (window != previousWindow && previousVersion != -1) + { + // Send drag left event + auto ww = WindowsManager::GetByNativePtr((void*)previousWindow); + if (ww) + { + ww->_dragOver = false; + ww->OnDragLeave(); + } + else + { + X11::XClientMessageEvent m; + memset(&m, 0, sizeof(m)); + m.type = ClientMessage; + m.display = event.xclient.display; + m.window = previousWindow; + m.message_type = xAtomXdndLeave; + m.format = 32; + m.data.l[0] = _window; + m.data.l[1] = 0; + m.data.l[2] = 0; + m.data.l[3] = 0; + m.data.l[4] = 0; + X11::XSendEvent(xDisplay, previousWindow, 0, NoEventMask, (X11::XEvent*)&m); + X11::XFlush(xDisplay); + } + } + + if (window != previousWindow && version != -1) + { + // Send drag enter event + auto ww = WindowsManager::GetByNativePtr((void*)window); + if (ww) + { + xDndPos = ww->ScreenToClient(Platform::GetMousePosition()); + xDndResult = DragDropEffect::None; + ww->OnDragEnter(&dropData, xDndPos, xDndResult); + } + else + { + X11::XClientMessageEvent m; + memset(&m, 0, sizeof(m)); + m.type = ClientMessage; + m.display = event.xclient.display; + m.window = window; + m.message_type = xAtomXdndEnter; + m.format = 32; + m.data.l[0] = _window; + m.data.l[1] = Math::Min(5, version) << 24 | (formats.Count() > 3); + m.data.l[2] = formats.Count() > 0 ? formats[0] : 0; + m.data.l[3] = formats.Count() > 1 ? formats[1] : 0; + m.data.l[4] = formats.Count() > 2 ? formats[2] : 0; + X11::XSendEvent(xDisplay, window, 0, NoEventMask, (X11::XEvent*)&m); + X11::XFlush(xDisplay); + } + } + + if (version != -1) + { + // Send position event + auto ww = WindowsManager::GetByNativePtr((void*)window); + if (ww) + { + xDndPos = ww->ScreenToClient(Platform::GetMousePosition()); + ww->_dragOver = true; + xDndResult = DragDropEffect::None; + ww->OnDragOver(&dropData, xDndPos, xDndResult); + status = CanDrop; + } + else + { + int x, y, tmp; + unsigned int utmp; + X11::Window wtmp; + X11::XQueryPointer(xDisplay, window, &wtmp, &wtmp, &tmp, &tmp, &x, &y, &utmp); + X11::XClientMessageEvent m; + memset(&m, 0, sizeof(m)); + m.type = ClientMessage; + m.display = event.xclient.display; + m.window = window; + m.message_type = xAtomXdndPosition; + m.format = 32; + m.data.l[0] = _window; + m.data.l[1] = 0; + m.data.l[2] = (x << 16) | y; + m.data.l[3] = CurrentTime; + m.data.l[4] = xAtomXdndActionCopy; + X11::XSendEvent(xDisplay, window, 0, NoEventMask, (X11::XEvent*)&m); + X11::XFlush(xDisplay); + } + } + + previousWindow = window; + previousVersion = version; + } + else if (event.type == ClientMessage && event.xclient.message_type == xAtomXdndStatus) + { + if ((event.xclient.data.l[1]&1) && status != Unaware) + status = CanDrop; + if (!(event.xclient.data.l[1]&1) && status != Unaware) + status = Unreceptive; + } + else if (event.type == ButtonRelease && event.xbutton.button == Button1) + { + if (status == CanDrop) + { + // Send drop event + auto ww = WindowsManager::GetByNativePtr((void*)previousWindow); + if (ww) + { + xDndPos = ww->ScreenToClient(Platform::GetMousePosition()); + xDndResult = DragDropEffect::None; + ww->OnDragDrop(&dropData, xDndPos, xDndResult); + ww->Focus(); + result = xDndResult; + } + else + { + X11::XClientMessageEvent m; + memset(&m, 0, sizeof(m)); + m.type = ClientMessage; + m.display = event.xclient.display; + m.window = previousWindow; + m.message_type = xAtomXdndDrop; + m.format = 32; + m.data.l[0] = _window; + m.data.l[1] = 0; + m.data.l[2] = CurrentTime; + m.data.l[3] = 0; + m.data.l[4] = 0; + X11::XSendEvent(xDisplay, previousWindow, 0, NoEventMask, (X11::XEvent*)&m); + X11::XFlush(xDisplay); + result = DragDropEffect::Copy; + } + } + break; + } + + // Redraw + const float time = Platform::GetTimeSeconds(); + if (time - lastDraw >= 1.0f / 20.0f) + { + lastDraw = time; + Engine::OnDraw(); + } + + // Prevent dead-loop + if (time - startTime >= 10.0f) + { + break; + } + } + + // Drag end + if (previousWindow != 0 && previousVersion != -1) + { + // Send drag left event + auto ww = WindowsManager::GetByNativePtr((void*)previousWindow); + if (ww) + { + ww->_dragOver = false; + ww->OnDragLeave(); + } + else + { + X11::XClientMessageEvent m; + memset(&m, 0, sizeof(m)); + m.type = ClientMessage; + m.display = event.xclient.display; + m.window = previousWindow; + m.message_type = xAtomXdndLeave; + m.format = 32; + m.data.l[0] = _window; + m.data.l[1] = 0; + m.data.l[2] = 0; + m.data.l[3] = 0; + m.data.l[4] = 0; + X11::XSendEvent(xDisplay, previousWindow, 0, NoEventMask, (X11::XEvent*)&m); + X11::XFlush(xDisplay); + } + } + + // End grabbing + X11::XChangeActivePointerGrab(xDisplay, Button1MotionMask | ButtonReleaseMask, 0, CurrentTime); + XUngrabPointer(xDisplay, CurrentTime); + + return result; } void LinuxClipboard::Clear() @@ -1651,7 +2074,15 @@ bool LinuxPlatform::Init() } xAtomDeleteWindow = X11::XInternAtom(xDisplay, "WM_DELETE_WINDOW", 0); - xAtomWmState = X11::XInternAtom(xDisplay, "_NET_WM_STATE", 0); + xAtomXdndEnter = X11::XInternAtom(xDisplay, "XdndEnter", 0); + xAtomXdndPosition = X11::XInternAtom(xDisplay, "XdndPosition", 0); + xAtomXdndLeave = X11::XInternAtom(xDisplay, "XdndLeave", 0); + xAtomXdndDrop = X11::XInternAtom(xDisplay, "XdndDrop", 0); + xAtomXdndActionCopy = X11::XInternAtom(xDisplay, "XdndActionCopy", 0); + xAtomXdndStatus = X11::XInternAtom(xDisplay, "XdndStatus", 0); + xAtomXdndSelection = X11::XInternAtom(xDisplay, "XdndSelection", 0); + xAtomXdndFinished = X11::XInternAtom(xDisplay, "XdndFinished", 0); + xAtomXdndAware = X11::XInternAtom(xDisplay, "XdndAware", 0); xAtomWmStateHidden = X11::XInternAtom(xDisplay, "_NET_WM_STATE_HIDDEN", 0); xAtomWmStateMaxHorz = X11::XInternAtom(xDisplay, "_NET_WM_STATE_MAXIMIZED_HORZ", 0); xAtomWmStateMaxVert = X11::XInternAtom(xDisplay, "_NET_WM_STATE_MAXIMIZED_VERT", 0); @@ -1799,6 +2230,93 @@ void LinuxPlatform::Tick() window->Close(ClosingReason::User); } } + else if ((uint32)event.xclient.message_type == (uint32)xAtomXdndEnter) + { + // Drag&drop enter + X11::Window source = event.xclient.data.l[0]; + xDnDVersion = (int32)(event.xclient.data.l[1] >> 24); + const char* targetTypeFiles = "text/uri-list"; + if (event.xclient.data.l[1] & 1) + { + Property p = Impl::ReadProperty(xDisplay, source, XInternAtom(xDisplay, "XdndTypeList", 0)); + xDnDRequested = Impl::SelectTargetFromList(xDisplay, targetTypeFiles, (X11::Atom*)p.data, p.nitems); + X11::XFree(p.data); + } + else + { + xDnDRequested = Impl::SelectTargetFromAtoms(xDisplay, targetTypeFiles, event.xclient.data.l[2], event.xclient.data.l[3], event.xclient.data.l[4]); + } + } + else if ((uint32)event.xclient.message_type == (uint32)xAtomXdndPosition) + { + // Drag&drop move + X11::XClientMessageEvent m; + memset(&m, 0, sizeof(m)); + m.type = ClientMessage; + m.display = event.xclient.display; + m.window = event.xclient.data.l[0]; + m.message_type = xAtomXdndStatus; + m.format = 32; + m.data.l[0] = event.xany.window; + m.data.l[1] = (xDnDRequested != 0); + m.data.l[2] = 0; + m.data.l[3] = 0; + m.data.l[4] = xAtomXdndActionCopy; + X11::XSendEvent(xDisplay, event.xclient.data.l[0], 0, NoEventMask, (X11::XEvent*)&m); + X11::XFlush(xDisplay); + xDndPos = Vector2((float)(event.xclient.data.l[2] >> 16), (float)(event.xclient.data.l[2] & 0xffff)); + window = WindowsManager::GetByNativePtr((void*)event.xany.window); + if (window) + { + LinuxDropFilesData dropData; + xDndResult = DragDropEffect::None; + if (window->_dragOver) + { + window->OnDragEnter(&dropData, xDndPos, xDndResult); + } + else + { + window->_dragOver = true; + window->OnDragOver(&dropData, xDndPos, xDndResult); + } + } + } + else if ((uint32)event.xclient.message_type == (uint32)xAtomXdndLeave) + { + window = WindowsManager::GetByNativePtr((void*)event.xany.window); + if (window && window->_dragOver) + { + window->_dragOver = false; + window->OnDragLeave(); + } + } + else if ((uint32)event.xclient.message_type == (uint32)xAtomXdndDrop) + { + auto w = event.xany.window; + if (xDnDRequested != 0) + { + xDndSourceWindow = event.xclient.data.l[0]; + auto primary = XInternAtom(xDisplay, "PRIMARY", 0); + if (xDnDVersion >= 1) + XConvertSelection(xDisplay, xAtomXdndSelection, xDnDRequested, primary, w, event.xclient.data.l[2]); + else + XConvertSelection(xDisplay, xAtomXdndSelection, xDnDRequested, primary, w, CurrentTime); + } + else + { + X11::XClientMessageEvent m; + memset(&m, 0, sizeof(m)); + m.type = ClientMessage; + m.display = event.xclient.display; + m.window = event.xclient.data.l[0]; + m.message_type = xAtomXdndFinished; + m.format = 32; + m.data.l[0] = w; + m.data.l[1] = 0; + m.data.l[2] = 0; + X11::XSendEvent(xDisplay, event.xclient.data.l[0], 0, NoEventMask, (X11::XEvent*)&m); + } + } break; case MapNotify: // Auto-focus shown windows @@ -1980,6 +2498,41 @@ void LinuxPlatform::Tick() X11::XSendEvent(xDisplay, ev.requestor, 0, 0, (X11::XEvent*)&ev); break; } + case SelectionNotify: + if (event.xselection.target == xDnDRequested) + { + // Drag&drop + window = WindowsManager::GetByNativePtr((void*)event.xany.window); + if (window) + { + Property p = Impl::ReadProperty(xDisplay, event.xany.window, X11::XInternAtom(xDisplay, "PRIMARY", 0)); + if (xDndResult != DragDropEffect::None) + { + LinuxDropFilesData dropData; + const String filesList((const char*)p.data); + filesList.Split('\n', dropData.Files); + for (auto& e : dropData.Files) + { + e.Replace(TEXT("file://"), TEXT("")); + e = e.TrimTrailing(); + } + xDndResult = DragDropEffect::None; + window->OnDragDrop(&dropData, xDndPos, xDndResult); + } + } + X11::XClientMessageEvent m; + memset(&m, 0, sizeof(m)); + m.type = ClientMessage; + m.display = xDisplay; + m.window = xDndSourceWindow; + m.message_type = xAtomXdndFinished; + m.format = 32; + m.data.l[0] = event.xany.window; + m.data.l[1] = 1; + m.data.l[2] = xAtomXdndActionCopy; + XSendEvent(xDisplay, xDndSourceWindow, 0, NoEventMask, (X11::XEvent*)&m); + } + break; default: break; } diff --git a/Source/Engine/Platform/Linux/LinuxWindow.cpp b/Source/Engine/Platform/Linux/LinuxWindow.cpp index 8714a130c..04389eb29 100644 --- a/Source/Engine/Platform/Linux/LinuxWindow.cpp +++ b/Source/Engine/Platform/Linux/LinuxWindow.cpp @@ -103,7 +103,6 @@ LinuxWindow::LinuxWindow(const CreateWindowSettings& settings) bool Fullscreen; bool AllowMinimize; bool AllowMaximize; - bool AllowDragAndDrop; */ const X11::Window window = X11::XCreateWindow( @@ -223,6 +222,15 @@ LinuxWindow::LinuxWindow(const CreateWindowSettings& settings) } X11::XChangeProperty(display, window, wmState, (X11::Atom)4, 32, PropModeReplace, (unsigned char*)states, statesCount); + // Drag&drop support + if (settings.AllowDragAndDrop) + { + auto xdndVersion = 5; + auto xdndAware = XInternAtom(display, "XdndAware", 0); + if (xdndAware != 0) + X11::XChangeProperty(display, window, xdndAware, (X11::Atom)4, 32, PropModeReplace, (unsigned char*)&xdndVersion, 1); + } + // Sync X11::XFlush(display); X11::XSync(display, 0); @@ -725,12 +733,6 @@ void LinuxWindow::SetTitle(const StringView& title) _title = title; } -DragDropEffect LinuxWindow::DoDragDrop(const StringView& data) -{ - // TODO: impl drag and drop on Linux - return DragDropEffect::None; -} - void LinuxWindow::StartTrackingMouse(bool useMouseScreenOffset) { // TODO: impl this diff --git a/Source/Engine/Platform/Linux/LinuxWindow.h b/Source/Engine/Platform/Linux/LinuxWindow.h index 845fd587e..24a3d94a2 100644 --- a/Source/Engine/Platform/Linux/LinuxWindow.h +++ b/Source/Engine/Platform/Linux/LinuxWindow.h @@ -13,14 +13,13 @@ class LinuxWindow : public WindowBase { friend LinuxPlatform; - public: typedef unsigned long HandleType; private: - bool _resizeDisabled, _focusOnMapped = false; + bool _resizeDisabled, _focusOnMapped = false, _dragOver = false; float _opacity = 1.0f; HandleType _window; diff --git a/Source/Engine/Platform/StringUtils.h b/Source/Engine/Platform/StringUtils.h index 7e0b7b422..9d812bc47 100644 --- a/Source/Engine/Platform/StringUtils.h +++ b/Source/Engine/Platform/StringUtils.h @@ -207,19 +207,19 @@ public: // Returns the directory name of the specified path string // @param path The path string from which to obtain the directory name // @returns Directory name - static String GetDirectoryName(const String& path); + static String GetDirectoryName(const StringView& path); // Returns the file name and extension of the specified path string // @param path The path string from which to obtain the file name and extension // @returns File name with extension - static String GetFileName(const String& path); + static String GetFileName(const StringView& path); // Returns the file name without extension of the specified path string // @param path The path string from which to obtain the file name // @returns File name without extension - static String GetFileNameWithoutExtension(const String& path); + static String GetFileNameWithoutExtension(const StringView& path); - static String GetPathWithoutExtension(const String& path); + static String GetPathWithoutExtension(const StringView& path); static void PathRemoveRelativeParts(String& path); diff --git a/Source/Engine/Platform/Win32/Win32Platform.cpp b/Source/Engine/Platform/Win32/Win32Platform.cpp index b4140163f..d80cc6dd7 100644 --- a/Source/Engine/Platform/Win32/Win32Platform.cpp +++ b/Source/Engine/Platform/Win32/Win32Platform.cpp @@ -318,14 +318,15 @@ void Win32Platform::Free(void* ptr) void* Win32Platform::AllocatePages(uint64 numPages, uint64 pageSize) { const uint64 numBytes = numPages * pageSize; - - // Use VirtualAlloc to allocate page-aligned memory +#if PLATFORM_UWP + return VirtualAllocFromApp(nullptr, (SIZE_T)numBytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +#else return VirtualAlloc(nullptr, (SIZE_T)numBytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +#endif } void Win32Platform::FreePages(void* ptr) { - // Free page-aligned memory VirtualFree(ptr, 0, MEM_RELEASE); } diff --git a/Source/Engine/Platform/Windows/WindowsPlatform.cpp b/Source/Engine/Platform/Windows/WindowsPlatform.cpp index 1b8942dec..8bff48f18 100644 --- a/Source/Engine/Platform/Windows/WindowsPlatform.cpp +++ b/Source/Engine/Platform/Windows/WindowsPlatform.cpp @@ -38,7 +38,7 @@ namespace CriticalSection SymLocker; bool SymInitialized = false; bool SymModulesDirty = true; - char* SymPath = nullptr; + Array SymbolsPath; #endif } @@ -617,9 +617,8 @@ void WindowsPlatform::Exit() { SymInitialized = false; SymCleanup(GetCurrentProcess()); - free(SymPath); - SymPath = nullptr; } + SymbolsPath.Resize(0); SymLocker.Unlock(); #endif @@ -1116,7 +1115,13 @@ void* WindowsPlatform::LoadLibrary(const Char* filename) #if CRASH_LOG_ENABLE // Refresh modules info during next stack trace collecting to have valid debug symbols information SymLocker.Lock(); - SymModulesDirty = true; + const auto folder = StringUtils::GetDirectoryName(filename); + if (!SymbolsPath.Contains(folder)) + SymbolsPath.Add(folder); + if (SymInitialized) + { + SymModulesDirty = true; + } SymLocker.Unlock(); #endif @@ -1137,80 +1142,43 @@ Array WindowsPlatform::GetStackFrames(int32 skipCount, SymInitialized = true; // Build search path - const size_t nSymPathLen = 4096; - SymPath = (char*)malloc(nSymPathLen); - SymPath[0] = 0; - strcat_s(SymPath, nSymPathLen, ".;"); - const size_t nTempLen = 1024; - char szTemp[nTempLen]; - - // Current directory path - if (GetCurrentDirectoryA(nTempLen, szTemp) > 0) + String symbolSearchPath; + TCHAR ModulePath[MAX_PATH] = { 0 }; + if (::GetModuleFileName(::GetModuleHandle(nullptr), ModulePath, MAX_PATH)) { - szTemp[nTempLen - 1] = 0; - strcat_s(SymPath, nSymPathLen, szTemp); - strcat_s(SymPath, nSymPathLen, ";"); + symbolSearchPath += StringUtils::GetDirectoryName(ModulePath); + symbolSearchPath += ";"; } - - // Main module path - if (GetModuleFileNameA(nullptr, szTemp, nTempLen) > 0) + for (auto& path : SymbolsPath) { - szTemp[nTempLen - 1] = 0; - for (char* p = (szTemp + strlen(szTemp) - 1); p >= szTemp; --p) - { - // Locate the rightmost path separator - if ((*p == '\\') || (*p == '/') || (*p == ':')) - { - *p = 0; - break; - } - } - if (strlen(szTemp) > 0) - { - strcat_s(SymPath, nSymPathLen, szTemp); - strcat_s(SymPath, nSymPathLen, ";"); - } + symbolSearchPath += path; + symbolSearchPath += ";"; } - - // System symbols paths - if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0) + String _NT_SYMBOL_PATH; + if (!Platform::GetEnvironmentVariable(TEXT("_NT_SYMBOL_PATH"), _NT_SYMBOL_PATH)) { - szTemp[nTempLen - 1] = 0; - strcat_s(SymPath, nSymPathLen, szTemp); - strcat_s(SymPath, nSymPathLen, ";"); + symbolSearchPath += _NT_SYMBOL_PATH; + symbolSearchPath += ";"; } - if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0) - { - szTemp[nTempLen - 1] = 0; - strcat_s(SymPath, nSymPathLen, szTemp); - strcat_s(SymPath, nSymPathLen, ";"); - } - if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0) - { - szTemp[nTempLen - 1] = 0; - strcat_s(SymPath, nSymPathLen, szTemp); - strcat_s(SymPath, nSymPathLen, ";"); - - strcat_s(szTemp, nTempLen, "\\system32"); - strcat_s(SymPath, nSymPathLen, szTemp); - strcat_s(SymPath, nSymPathLen, ";"); - } - - SymInitialize(process, SymPath, FALSE); + symbolSearchPath += Platform::GetWorkingDirectory(); + symbolSearchPath += ";"; DWORD options = SymGetOptions(); options |= SYMOPT_LOAD_LINES; options |= SYMOPT_FAIL_CRITICAL_ERRORS; + options |= SYMOPT_DEFERRED_LOADS; + options |= SYMOPT_EXACT_SYMBOLS; SymSetOptions(options); + + SymInitializeW(process, *symbolSearchPath, TRUE); } - // Load modules + // Refresh modules if needed if (SymModulesDirty) { SymModulesDirty = false; - GetModuleListPSAPI(process); + SymRefreshModuleList(process); } - SymRefreshModuleList(process); // Capture the context if missing /*EXCEPTION_POINTERS exceptionPointers; diff --git a/Source/Engine/Renderer/DepthOfFieldPass.cpp b/Source/Engine/Renderer/DepthOfFieldPass.cpp index 4e4ee7ed1..afa48ad13 100644 --- a/Source/Engine/Renderer/DepthOfFieldPass.cpp +++ b/Source/Engine/Renderer/DepthOfFieldPass.cpp @@ -34,6 +34,8 @@ bool DepthOfFieldPass::Init() _platformSupportsDoF = limits.HasCompute; _platformSupportsBokeh = _platformSupportsDoF && limits.HasGeometryShaders && limits.HasDrawIndirect && limits.HasAppendConsumeBuffers; + _platformSupportsBokeh &= GPUDevice::Instance->GetRendererType() != RendererType::DirectX12; // TODO: fix bokeh crash on d3d12 (driver issue probably - started to happen recently) + // Create pipeline states if (_platformSupportsDoF) { diff --git a/Source/Engine/Scripting/ManagedCLR/MAssembly.Mono.cpp b/Source/Engine/Scripting/ManagedCLR/MAssembly.Mono.cpp index 7d00c1b8c..224565429 100644 --- a/Source/Engine/Scripting/ManagedCLR/MAssembly.Mono.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MAssembly.Mono.cpp @@ -326,6 +326,24 @@ bool MAssembly::LoadWithImage(const String& assemblyPath) mono_debug_open_image_from_memory(assemblyImage, _debugData.Get(), _debugData.Count()); } } + +#if 0 + // Hack to load debug information for Newtonsoft.Json (enable it to debug C# code of json lib) + if (assemblyPath.EndsWith(TEXT("FlaxEngine.CSharp.dll"))) + { + static Array NewtonsoftJsonDebugData; + File::ReadAllBytes(StringUtils::GetDirectoryName(assemblyPath) / TEXT("Newtonsoft.Json.pdb"), NewtonsoftJsonDebugData); + if (NewtonsoftJsonDebugData.HasItems()) + { + StringAnsi tmp(StringUtils::GetDirectoryName(assemblyPath) / TEXT("Newtonsoft.Json.dll")); + MonoAssembly* a = mono_assembly_open(tmp.Get(), &status); + if (a) + { + mono_debug_open_image_from_memory(mono_assembly_get_image(a), NewtonsoftJsonDebugData.Get(), NewtonsoftJsonDebugData.Count()); + } + } + } +#endif #endif // Set state diff --git a/Source/Engine/Scripting/Script.cpp b/Source/Engine/Scripting/Script.cpp index e1d2da73a..98a88975b 100644 --- a/Source/Engine/Scripting/Script.cpp +++ b/Source/Engine/Scripting/Script.cpp @@ -178,13 +178,15 @@ void Script::SetupType() { // Enable tick functions based on the method overriden in C# or Visual Script ScriptingTypeHandle typeHandle = GetTypeHandle(); - _tickUpdate = _tickLateUpdate = _tickFixedUpdate = 0; while (typeHandle != Script::TypeInitializer) { auto& type = typeHandle.GetType(); - _tickUpdate |= type.Script.ScriptVTable[8] != nullptr; - _tickLateUpdate |= type.Script.ScriptVTable[9] != nullptr; - _tickFixedUpdate |= type.Script.ScriptVTable[10] != nullptr; + if (type.Script.ScriptVTable) + { + _tickUpdate |= type.Script.ScriptVTable[8] != nullptr; + _tickLateUpdate |= type.Script.ScriptVTable[9] != nullptr; + _tickFixedUpdate |= type.Script.ScriptVTable[10] != nullptr; + } typeHandle = type.GetBaseType(); } } diff --git a/Source/Engine/Scripting/Scripting.cpp b/Source/Engine/Scripting/Scripting.cpp index 7f87178fd..d53f0a7ab 100644 --- a/Source/Engine/Scripting/Scripting.cpp +++ b/Source/Engine/Scripting/Scripting.cpp @@ -27,7 +27,6 @@ #include "Engine/Engine/EngineService.h" #include "Engine/Graphics/RenderTask.h" #include "Engine/Serialization/JsonTools.h" -#include "Engine/Utilities/StringConverter.h" #include #include diff --git a/Source/Engine/Serialization/WriteStream.h b/Source/Engine/Serialization/WriteStream.h index 6ff65d4ec..06e3b3904 100644 --- a/Source/Engine/Serialization/WriteStream.h +++ b/Source/Engine/Serialization/WriteStream.h @@ -154,8 +154,7 @@ public: // @param length Text length void WriteText(const char* text, int32 length) { - for (int32 i = 0; i < length; i++) - WriteChar(text[i]); + WriteBytes((const void*)text, sizeof(char) * length); } // Writes text to the stream @@ -163,8 +162,7 @@ public: // @param length Text length void WriteText(const Char* text, int32 length) { - for (int32 i = 0; i < length; i++) - WriteChar(text[i]); + WriteBytes((const void*)text, sizeof(Char) * length); } template diff --git a/Source/Engine/UI/GUI/Common/ProgressBar.cs b/Source/Engine/UI/GUI/Common/ProgressBar.cs index 21cce7faa..881bbc161 100644 --- a/Source/Engine/UI/GUI/Common/ProgressBar.cs +++ b/Source/Engine/UI/GUI/Common/ProgressBar.cs @@ -39,9 +39,6 @@ namespace FlaxEngine.GUI /// /// Gets a value indicating whether use progress value smoothing. /// - /// - /// true if use progress value smoothing; otherwise, false. - /// public bool UseSmoothing => !Mathf.IsZero(SmoothingScale); /// @@ -91,8 +88,6 @@ namespace FlaxEngine.GUI if (!Mathf.NearEqual(value, _value)) { _value = value; - - // Check if skip smoothing if (!UseSmoothing) { _current = _value; @@ -138,22 +133,22 @@ namespace FlaxEngine.GUI /// public override void Update(float deltaTime) { - bool isDeltaSlow = deltaTime > (1 / 20.0f); - - // Ensure progress bar is visible if (Visible) { // Value smoothing + var value = _value; if (Mathf.Abs(_current - _value) > 0.01f) { // Lerp or not if running slow - float value; + bool isDeltaSlow = deltaTime > (1 / 20.0f); if (!isDeltaSlow && UseSmoothing) value = Mathf.Lerp(_current, _value, Mathf.Saturate(deltaTime * 5.0f * SmoothingScale)); - else - value = _value; _current = value; } + else + { + _current = _value; + } } base.Update(deltaTime); diff --git a/Source/Engine/UI/GUI/ContainerControl.cs b/Source/Engine/UI/GUI/ContainerControl.cs index 0a4114205..57d2fb528 100644 --- a/Source/Engine/UI/GUI/ContainerControl.cs +++ b/Source/Engine/UI/GUI/ContainerControl.cs @@ -274,7 +274,7 @@ namespace FlaxEngine.GUI public int GetChildIndexAt(Vector2 point) { int result = -1; - for (int i = 0; i < _children.Count; i++) + for (int i = _children.Count - 1; i >= 0; i--) { var child = _children[i]; @@ -296,7 +296,7 @@ namespace FlaxEngine.GUI public Control GetChildAt(Vector2 point) { Control result = null; - for (int i = 0; i < _children.Count; i++) + for (int i = _children.Count - 1; i >= 0; i--) { var child = _children[i]; @@ -322,7 +322,7 @@ namespace FlaxEngine.GUI throw new ArgumentNullException(nameof(isValid)); Control result = null; - for (int i = 0; i < _children.Count; i++) + for (int i = _children.Count - 1; i >= 0; i--) { var child = _children[i]; @@ -344,7 +344,7 @@ namespace FlaxEngine.GUI public Control GetChildAtRecursive(Vector2 point) { Control result = null; - for (int i = 0; i < _children.Count; i++) + for (int i = _children.Count - 1; i >= 0; i--) { var child = _children[i]; diff --git a/Source/Engine/UI/GUI/Tooltip.cs b/Source/Engine/UI/GUI/Tooltip.cs index 1ccf0a5da..4541124e7 100644 --- a/Source/Engine/UI/GUI/Tooltip.cs +++ b/Source/Engine/UI/GUI/Tooltip.cs @@ -73,13 +73,18 @@ namespace FlaxEngine.GUI Vector2 locationWS = target.PointToWindow(location); Vector2 locationSS = parentWin.PointToScreen(locationWS); Vector2 screenSize = Platform.VirtualDesktopSize; + Vector2 parentWinLocationSS = parentWin.PointToScreen(Vector2.Zero); + float parentWinRightSS = parentWinLocationSS.Y + parentWin.Size.Y; + float parentWinBottomSS = parentWinLocationSS.X + parentWin.Size.X; Vector2 rightBottomLocationSS = locationSS + dpiSize; - if (screenSize.Y < rightBottomLocationSS.Y) + + // Prioritize tooltip placement within parent window, fall back to virtual desktop + if (parentWinRightSS < rightBottomLocationSS.Y || screenSize.Y < rightBottomLocationSS.Y) { // Direction: up locationSS.Y -= dpiSize.Y; } - if (screenSize.X < rightBottomLocationSS.X) + if (parentWinBottomSS < rightBottomLocationSS.X || screenSize.X < rightBottomLocationSS.X) { // Direction: left locationSS.X -= dpiSize.X; @@ -155,7 +160,7 @@ namespace FlaxEngine.GUI /// The delta time. public void OnMouseOverControl(Control target, float dt) { - if (!Visible) + if (!Visible && _timeToPopupLeft > 0.0f) { _lastTarget = target; _timeToPopupLeft -= dt; diff --git a/Source/FlaxEngine.Gen.cs b/Source/FlaxEngine.Gen.cs index 6f8878d25..62d40ad9a 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.1.6217")] -[assembly: AssemblyFileVersion("1.1.6217")] +[assembly: AssemblyVersion("1.1.6218")] +[assembly: AssemblyFileVersion("1.1.6218")] diff --git a/Source/FlaxEngine.Gen.h b/Source/FlaxEngine.Gen.h index 7a888ae1f..eff8449cc 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, 1, 6217) -#define FLAXENGINE_VERSION_TEXT "1.1.6217" +#define FLAXENGINE_VERSION Version(1, 1, 6218) +#define FLAXENGINE_VERSION_TEXT "1.1.6218" #define FLAXENGINE_VERSION_MAJOR 1 #define FLAXENGINE_VERSION_MINOR 1 -#define FLAXENGINE_VERSION_BUILD 6217 +#define FLAXENGINE_VERSION_BUILD 6218 #define FLAXENGINE_COMPANY "Flax" #define FLAXENGINE_COPYRIGHT "Copyright (c) 2012-2021 Wojciech Figat. All rights reserved." diff --git a/Source/Platforms/DotNet/Newtonsoft.Json.dll b/Source/Platforms/DotNet/Newtonsoft.Json.dll index 4dfac3f8c..05dcf0c44 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:66ed636b7679286d3689f8469081eaf0dde575ce48266c7b02742cb604967842 +oid sha256:eed043b9e8a7982f4a60ab332e833bd8834d6d43814773d30fda48a22eda1d8e size 641536 diff --git a/Source/Platforms/DotNet/Newtonsoft.Json.pdb b/Source/Platforms/DotNet/Newtonsoft.Json.pdb index fea2e1b56..3848081ec 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:4add026a04737ecd4a6596cfca850653936df6254e33fbf8114c31dd7afd0d41 -size 253736 +oid sha256:882eecaf201c6d6e7c724e24259df9d23a6c7d8be1b9d407ff646fa24da680ca +size 253816 diff --git a/Source/Platforms/UWP/Binaries/Newtonsoft.Json.dll b/Source/Platforms/UWP/Binaries/Newtonsoft.Json.dll index 1fd4728ee..1885aed9a 100644 --- a/Source/Platforms/UWP/Binaries/Newtonsoft.Json.dll +++ b/Source/Platforms/UWP/Binaries/Newtonsoft.Json.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:55c75dbdc210dc74e389090e2f08ac160e12b7a505c6bc1b6fcec5ed5bb08ca9 +oid sha256:c43903a192d31dac91b7744e2b1a2e8cec21983ceed630261fd7b80a433fee20 size 635392 diff --git a/Source/Platforms/UWP/Binaries/Project.csproj b/Source/Platforms/UWP/Binaries/Project.csproj index c6c48c200..1895423a0 100644 --- a/Source/Platforms/UWP/Binaries/Project.csproj +++ b/Source/Platforms/UWP/Binaries/Project.csproj @@ -54,6 +54,7 @@ Designer + {3} @@ -70,7 +71,7 @@ - + diff --git a/Source/Platforms/XboxOne/Binaries/Newtonsoft.Json.dll b/Source/Platforms/XboxOne/Binaries/Newtonsoft.Json.dll index 1fd4728ee..1885aed9a 100644 --- a/Source/Platforms/XboxOne/Binaries/Newtonsoft.Json.dll +++ b/Source/Platforms/XboxOne/Binaries/Newtonsoft.Json.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:55c75dbdc210dc74e389090e2f08ac160e12b7a505c6bc1b6fcec5ed5bb08ca9 +oid sha256:c43903a192d31dac91b7744e2b1a2e8cec21983ceed630261fd7b80a433fee20 size 635392 diff --git a/Source/Platforms/XboxOne/Binaries/Project.csproj b/Source/Platforms/XboxOne/Binaries/Project.csproj index c6c48c200..1895423a0 100644 --- a/Source/Platforms/XboxOne/Binaries/Project.csproj +++ b/Source/Platforms/XboxOne/Binaries/Project.csproj @@ -54,6 +54,7 @@ Designer + {3} @@ -70,7 +71,7 @@ - + diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs index 27dedb6b4..8fc7d18f2 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cache.cs @@ -250,66 +250,66 @@ namespace Flax.Build.Bindings var path = GetCachePath(moduleInfo.Module, moduleOptions); if (!File.Exists(path)) return false; - using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) - using (var reader = new BinaryReader(stream, Encoding.UTF8)) + try { - // Version - var version = reader.ReadInt32(); - if (version != CacheVersion) - return false; - if (File.GetLastWriteTime(Assembly.GetExecutingAssembly().Location).Ticks != reader.ReadInt64()) - return false; - - // Build options - if (reader.ReadString() != moduleOptions.IntermediateFolder || - reader.ReadInt32() != (int)moduleOptions.Platform.Target || - reader.ReadInt32() != (int)moduleOptions.Architecture || - reader.ReadInt32() != (int)moduleOptions.Configuration) - return false; - var publicDefinitions = Read(reader, Utilities.GetEmptyArray()); - if (publicDefinitions.Length != moduleOptions.PublicDefinitions.Count || publicDefinitions.Any(x => !moduleOptions.PublicDefinitions.Contains(x))) - return false; - var privateDefinitions = Read(reader, Utilities.GetEmptyArray()); - if (privateDefinitions.Length != moduleOptions.PrivateDefinitions.Count || privateDefinitions.Any(x => !moduleOptions.PrivateDefinitions.Contains(x))) - return false; - var preprocessorDefinitions = Read(reader, Utilities.GetEmptyArray()); - if (preprocessorDefinitions.Length != moduleOptions.CompileEnv.PreprocessorDefinitions.Count || preprocessorDefinitions.Any(x => !moduleOptions.CompileEnv.PreprocessorDefinitions.Contains(x))) - return false; - - // Header files - var headerFilesCount = reader.ReadInt32(); - if (headerFilesCount != headerFiles.Count) - return false; - for (int i = 0; i < headerFilesCount; i++) + using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (var reader = new BinaryReader(stream, Encoding.UTF8)) { - var headerFile = headerFiles[i]; - if (headerFile != reader.ReadString()) + // Version + var version = reader.ReadInt32(); + if (version != CacheVersion) return false; - if (File.GetLastWriteTime(headerFile).Ticks > reader.ReadInt64()) + if (File.GetLastWriteTime(Assembly.GetExecutingAssembly().Location).Ticks != reader.ReadInt64()) return false; - } - // Info - var newModuleInfo = new ModuleInfo - { - Module = moduleInfo.Module, - Name = moduleInfo.Name, - Namespace = moduleInfo.Namespace, - IsFromCache = true, - }; - try - { + // Build options + if (reader.ReadString() != moduleOptions.IntermediateFolder || + reader.ReadInt32() != (int)moduleOptions.Platform.Target || + reader.ReadInt32() != (int)moduleOptions.Architecture || + reader.ReadInt32() != (int)moduleOptions.Configuration) + return false; + var publicDefinitions = Read(reader, Utilities.GetEmptyArray()); + if (publicDefinitions.Length != moduleOptions.PublicDefinitions.Count || publicDefinitions.Any(x => !moduleOptions.PublicDefinitions.Contains(x))) + return false; + var privateDefinitions = Read(reader, Utilities.GetEmptyArray()); + if (privateDefinitions.Length != moduleOptions.PrivateDefinitions.Count || privateDefinitions.Any(x => !moduleOptions.PrivateDefinitions.Contains(x))) + return false; + var preprocessorDefinitions = Read(reader, Utilities.GetEmptyArray()); + if (preprocessorDefinitions.Length != moduleOptions.CompileEnv.PreprocessorDefinitions.Count || preprocessorDefinitions.Any(x => !moduleOptions.CompileEnv.PreprocessorDefinitions.Contains(x))) + return false; + + // Header files + var headerFilesCount = reader.ReadInt32(); + if (headerFilesCount != headerFiles.Count) + return false; + for (int i = 0; i < headerFilesCount; i++) + { + var headerFile = headerFiles[i]; + if (headerFile != reader.ReadString()) + return false; + if (File.GetLastWriteTime(headerFile).Ticks > reader.ReadInt64()) + return false; + } + + // Info + var newModuleInfo = new ModuleInfo + { + Module = moduleInfo.Module, + Name = moduleInfo.Name, + Namespace = moduleInfo.Namespace, + IsFromCache = true, + }; newModuleInfo.Read(reader); // Skip parsing and use data loaded from cache moduleInfo = newModuleInfo; return true; } - catch - { - // Skip loading cache - return false; - } + } + catch + { + // Skip loading cache + return false; } } } diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs index 424286e0e..6828a8eca 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs @@ -1129,6 +1129,7 @@ namespace Flax.Build.Bindings var paramsCount = eventInfo.Type.GenericArgs?.Count ?? 0; // C# event invoking wrapper (calls C# event from C++ delegate) + CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h"); CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MEvent.h"); contents.Append(" "); if (eventInfo.IsStatic) @@ -1251,7 +1252,13 @@ namespace Flax.Build.Bindings if (fieldInfo.Getter != null) GenerateCppWrapperFunction(buildData, contents, classInfo, fieldInfo.Getter, "{0}"); if (fieldInfo.Setter != null) - GenerateCppWrapperFunction(buildData, contents, classInfo, fieldInfo.Setter, "{0} = {1}"); + { + var callFormat = "{0} = {1}"; + var type = fieldInfo.Setter.Parameters[0].Type; + if (type.IsArray) + callFormat = $"auto __tmp = {{1}}; for (int32 i = 0; i < {type.ArraySize}; i++) {{0}}[i] = __tmp[i]"; + GenerateCppWrapperFunction(buildData, contents, classInfo, fieldInfo.Setter, callFormat); + } } // Properties diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs index 742aa6f63..f8d26314f 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.cs @@ -623,9 +623,6 @@ namespace Flax.Build.Bindings if (!fieldInfo.IsReadOnly) { - if (fieldInfo.Type.IsArray) - throw new NotImplementedException("Use ReadOnly on field. TODO: add support for setter for fixed-array fields."); - fieldInfo.Setter = new FunctionInfo { Name = "Set" + fieldInfo.Name, diff --git a/Source/Tools/Flax.Build/Platforms/UWP/UWPToolchain.cs b/Source/Tools/Flax.Build/Platforms/UWP/UWPToolchain.cs index 7a76d642d..237026b32 100644 --- a/Source/Tools/Flax.Build/Platforms/UWP/UWPToolchain.cs +++ b/Source/Tools/Flax.Build/Platforms/UWP/UWPToolchain.cs @@ -67,10 +67,10 @@ namespace Flax.Build.Platforms options.CompileEnv.PreprocessorDefinitions.Add("PLATFORM_UWP"); options.CompileEnv.PreprocessorDefinitions.Add("WINAPI_FAMILY=WINAPI_FAMILY_PC_APP"); options.CompileEnv.PreprocessorDefinitions.Add("_WINRT_DLL"); + options.CompileEnv.PreprocessorDefinitions.Add("_WINDLL"); options.CompileEnv.PreprocessorDefinitions.Add("__WRL_NO_DEFAULT_LIB__"); options.LinkEnv.InputLibraries.Add("WindowsApp.lib"); - options.LinkEnv.InputLibraries.Add("dloadhelper.lib"); } } } diff --git a/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs b/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs index 38446ee17..b59bcae39 100644 --- a/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs +++ b/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs @@ -680,6 +680,8 @@ namespace Flax.Build.Platforms args.Add("/WINMD"); args.Add(string.Format("/WINMDFILE:\"{0}\"", Path.ChangeExtension(outputFilePath, "winmd"))); args.Add("/APPCONTAINER"); + if (linkEnvironment.Output == LinkerOutput.SharedLibrary) + args.Add("/DYNAMICBASE"); } if (linkEnvironment.LinkTimeCodeGeneration) @@ -937,7 +939,7 @@ namespace Flax.Build.Platforms xmlTextWriter.WriteStartElement("Properties"); // TODO: better logo handling - var logoSrcPath = Path.Combine(Environment.CurrentDirectory, "Source", "Logo.png"); + var logoSrcPath = Path.Combine(Globals.EngineRoot, "Source", "Logo.png"); var logoDstPath = Path.Combine(options.IntermediateFolder, "Logo.png"); if (!File.Exists(logoDstPath)) Utilities.FileCopy(logoSrcPath, logoDstPath);