diff --git a/.gitignore b/.gitignore index 1920b3eea..54907892f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ Cache/ Binaries/ Output/ Logs/ +Source/*.Gen.* Source/*.csproj /Package_*/ !Source/Engine/Debug diff --git a/Source/Editor/Content/GUI/ContentView.cs b/Source/Editor/Content/GUI/ContentView.cs index 7eb2e0950..6065ca9f8 100644 --- a/Source/Editor/Content/GUI/ContentView.cs +++ b/Source/Editor/Content/GUI/ContentView.cs @@ -692,10 +692,13 @@ namespace FlaxEditor.Content.GUI c = char.ToLowerInvariant(c); for (int i = 0; i < _items.Count; i++) { - var name = _items[i].ShortName; + var item = _items[i]; + var name = item.ShortName; if (!string.IsNullOrEmpty(name) && char.ToLowerInvariant(name[0]) == c) { - Select(_items[i]); + Select(item); + if (Parent is Panel panel) + panel.ScrollViewTo(item, true); break; } } diff --git a/Source/Editor/Content/Proxy/ScriptProxy.cs b/Source/Editor/Content/Proxy/ScriptProxy.cs index 3196ea833..f688f37df 100644 --- a/Source/Editor/Content/Proxy/ScriptProxy.cs +++ b/Source/Editor/Content/Proxy/ScriptProxy.cs @@ -45,7 +45,7 @@ namespace FlaxEditor.Content } /// - public override string NewItemName => "Script"; + public override string NewItemName => "MyScript"; /// public override bool CanCreate(ContentFolder targetLocation) @@ -72,6 +72,8 @@ namespace FlaxEditor.Content // Scripts cannot start with digit. if (Char.IsDigit(filename[0])) return false; + if (filename.Equals("Script")) + return false; return true; } diff --git a/Source/Editor/GUI/Dialogs/ColorPickerDialog.cs b/Source/Editor/GUI/Dialogs/ColorPickerDialog.cs index 8209b63cf..161b3f4ae 100644 --- a/Source/Editor/GUI/Dialogs/ColorPickerDialog.cs +++ b/Source/Editor/GUI/Dialogs/ColorPickerDialog.cs @@ -25,6 +25,7 @@ namespace FlaxEditor.GUI.Dialogs { private const float ButtonsWidth = 60.0f; private const float PickerMargin = 6.0f; + private const float EyedropperMargin = 8.0f; private const float RGBAMargin = 12.0f; private const float HSVMargin = 0.0f; private const float ChannelsMargin = 4.0f; @@ -34,6 +35,7 @@ namespace FlaxEditor.GUI.Dialogs private Color _value; private bool _disableEvents; private bool _useDynamicEditing; + private bool _activeEyedropper; private ColorValueBox.ColorPickerEvent _onChanged; private ColorValueBox.ColorPickerClosedEvent _onClosed; @@ -48,6 +50,7 @@ namespace FlaxEditor.GUI.Dialogs private TextBox _cHex; private Button _cCancel; private Button _cOK; + private Button _cEyedropper; /// /// Gets the selected color. @@ -192,10 +195,44 @@ namespace FlaxEditor.GUI.Dialogs }; _cOK.Clicked += OnSubmit; + // Eyedropper button + var style = Style.Current; + _cEyedropper = new Button(_cOK.X - EyedropperMargin, _cHex.Bottom + PickerMargin) + { + TooltipText = "Eyedropper tool to pick a color directly from the screen", + BackgroundBrush = new SpriteBrush(Editor.Instance.Icons.Search32), + BackgroundColor = style.Foreground, + BackgroundColorHighlighted = style.Foreground.RGBMultiplied(0.9f), + BorderColor = Color.Transparent, + BorderColorHighlighted = style.BorderSelected, + Parent = this, + }; + _cEyedropper.Clicked += OnEyedropStart; + _cEyedropper.Height = (_cValue.Bottom - _cEyedropper.Y) * 0.5f; + _cEyedropper.Width = _cEyedropper.Height; + _cEyedropper.X -= _cEyedropper.Width; + // Set initial color SelectedColor = initialValue; } + private void OnColorPicked(Color32 colorPicked) + { + if (_activeEyedropper) + { + _activeEyedropper = false; + SelectedColor = colorPicked; + ScreenUtilities.PickColorDone -= OnColorPicked; + } + } + + private void OnEyedropStart() + { + _activeEyedropper = true; + ScreenUtilities.PickColor(); + ScreenUtilities.PickColorDone += OnColorPicked; + } + private void OnRGBAChanged() { if (_disableEvents) @@ -221,6 +258,19 @@ namespace FlaxEditor.GUI.Dialogs SelectedColor = color; } + /// + public override void Update(float deltaTime) + { + base.Update(deltaTime); + + // Update eye dropper tool + if (_activeEyedropper) + { + Float2 mousePosition = Platform.MousePosition; + SelectedColor = ScreenUtilities.GetColorAt(mousePosition); + } + } + /// public override void Draw() { @@ -274,6 +324,20 @@ namespace FlaxEditor.GUI.Dialogs base.OnShow(); } + /// + public override bool OnKeyDown(KeyboardKeys key) + { + if (_activeEyedropper && key == KeyboardKeys.Escape) + { + // Cancel eye dropping + _activeEyedropper = false; + ScreenUtilities.PickColorDone -= OnColorPicked; + return true; + } + + return base.OnKeyDown(key); + } + /// public override void OnSubmit() { diff --git a/Source/Editor/GUI/Input/ColorValueBox.cs b/Source/Editor/GUI/Input/ColorValueBox.cs index bafa27c87..167cc65bb 100644 --- a/Source/Editor/GUI/Input/ColorValueBox.cs +++ b/Source/Editor/GUI/Input/ColorValueBox.cs @@ -57,6 +57,11 @@ namespace FlaxEditor.GUI.Input /// protected Color _value; + /// + /// Enables live preview of the selected value from the picker. Otherwise will update the value only when user confirms it on dialog closing. + /// + public bool UseDynamicEditing = true; + /// /// Occurs when value gets changed. /// @@ -143,7 +148,7 @@ namespace FlaxEditor.GUI.Input base.OnSubmit(); // Show color picker dialog - _currentDialog = ShowPickColorDialog?.Invoke(this, _value, OnColorChanged, OnPickerClosed); + _currentDialog = ShowPickColorDialog?.Invoke(this, _value, OnColorChanged, OnPickerClosed, UseDynamicEditing); } private void OnColorChanged(Color color, bool sliding) diff --git a/Source/Editor/Surface/Elements/ColorValue.cs b/Source/Editor/Surface/Elements/ColorValue.cs index 96069cfeb..19934581d 100644 --- a/Source/Editor/Surface/Elements/ColorValue.cs +++ b/Source/Editor/Surface/Elements/ColorValue.cs @@ -30,7 +30,7 @@ namespace FlaxEditor.Surface.Elements { ParentNode = parentNode; Archetype = archetype; - + UseDynamicEditing = false; ParentNode.ValuesChanged += OnNodeValuesChanged; } diff --git a/Source/Editor/Utilities/ScreenUtilities.cpp b/Source/Editor/Utilities/ScreenUtilities.cpp new file mode 100644 index 000000000..cff41f7bf --- /dev/null +++ b/Source/Editor/Utilities/ScreenUtilities.cpp @@ -0,0 +1,130 @@ +// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. + +#include "ScreenUtilities.h" +#include "Engine/Core/Math/Vector2.h" +#include "Engine/Core/Delegate.h" +#include "Engine/Core/Log.h" +#include "Engine/Profiler/ProfilerCPU.h" + +Delegate ScreenUtilities::PickColorDone; + +#if PLATFORM_WINDOWS + +#include + +#pragma comment(lib, "Gdi32.lib") + +static HHOOK MouseCallbackHook; + +LRESULT CALLBACK OnScreenUtilsMouseCallback(_In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam) +{ + if (nCode >= 0 && wParam == WM_LBUTTONDOWN) + { + UnhookWindowsHookEx(MouseCallbackHook); + + // Push event with the picked color + const Float2 cursorPos = Platform::GetMousePosition(); + const Color32 colorPicked = ScreenUtilities::GetColorAt(cursorPos); + ScreenUtilities::PickColorDone(colorPicked); + return 1; + } + return CallNextHookEx(NULL, nCode, wParam, lParam); +} + +Color32 ScreenUtilities::GetColorAt(const Float2& pos) +{ + PROFILE_CPU(); + HDC deviceContext = GetDC(NULL); + COLORREF color = GetPixel(deviceContext, (int)pos.X, (int)pos.Y); + ReleaseDC(NULL, deviceContext); + return Color32(GetRValue(color), GetGValue(color), GetBValue(color), 255); +} + +void ScreenUtilities::PickColor() +{ + MouseCallbackHook = SetWindowsHookEx(WH_MOUSE_LL, OnScreenUtilsMouseCallback, NULL, NULL); + if (MouseCallbackHook == NULL) + { + LOG(Warning, "Failed to set mouse hook."); + LOG(Warning, "Error: {0}", GetLastError()); + } +} + +#elif PLATFORM_LINUX + +#include "Engine/Platform/Linux/LinuxPlatform.h" +#include "Engine/Platform/Linux/IncludeX11.h" + +Color32 ScreenUtilities::GetColorAt(const Float2& pos) +{ + X11::XColor color; + + X11::Display* display = (X11::Display*) LinuxPlatform::GetXDisplay(); + int defaultScreen = X11::XDefaultScreen(display); + + X11::XImage* image; + image = X11::XGetImage(display, X11::XRootWindow(display, defaultScreen), x, y, 1, 1, AllPlanes, XYPixmap); + color.pixel = XGetPixel(image, 0, 0); + X11::XFree(image); + + X11::XQueryColor(display, X11::XDefaultColormap(display, defaultScreen), &color); + + Color32 outputColor; + outputColor.R = color.red / 256; + outputColor.G = color.green / 256; + outputColor.B = color.blue / 256; + return outputColor; +} + +void OnScreenUtilsXEventCallback(void* eventPtr) +{ + X11::XEvent* event = (X11::XEvent*) eventPtr; + X11::Display* display = (X11::Display*)LinuxPlatform::GetXDisplay(); + if (event->type == ButtonPress) + { + const Float2 cursorPos = Platform::GetMousePosition(); + const Color32 colorPicked = ScreenUtilities::GetColorAt(cursorPos); + X11::XUngrabPointer(display, CurrentTime); + ScreenUtilities::PickColorDone(colorPicked); + LinuxPlatform::xEventRecieved.Unbind(OnScreenUtilsXEventCallback); + } +} + +void ScreenUtilities::PickColor() +{ + PROFILE_CPU(); + X11::Display* display = (X11::Display*) LinuxPlatform::GetXDisplay(); + X11::Window rootWindow = X11::XRootWindow(display, X11::XDefaultScreen(display)); + + X11::Cursor cursor = XCreateFontCursor(display, 130); + int grabbedPointer = X11::XGrabPointer(display, rootWindow, 0, ButtonPressMask, GrabModeAsync, GrabModeAsync, rootWindow, cursor, CurrentTime); + if (grabbedPointer != GrabSuccess) + { + LOG(Error, "Failed to grab cursor for events."); + X11::XFreeCursor(display, cursor); + return; + } + + X11::XFreeCursor(display, cursor); + LinuxPlatform::xEventRecieved.Bind(OnScreenUtilsXEventCallback); +} + +#elif PLATFORM_MAC + +#include +#include + +Color32 ScreenUtilities::GetColorAt(const Float2& pos) +{ + // TODO: implement ScreenUtilities for macOS + return { 0, 0, 0, 255 }; +} + +void ScreenUtilities::PickColor() +{ + // This is what C# calls to start the color picking sequence + // This should stop mouse clicks from working for one click, and that click is on the selected color + // There is a class called NSColorSample that might implement that for you, but maybe not. +} + +#endif diff --git a/Source/Editor/Utilities/ScreenUtilities.h b/Source/Editor/Utilities/ScreenUtilities.h new file mode 100644 index 000000000..506dc8634 --- /dev/null +++ b/Source/Editor/Utilities/ScreenUtilities.h @@ -0,0 +1,33 @@ +// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Core/Types/BaseTypes.h" +#include "Engine/Core/Math/Color32.h" +#include "Engine/Core/Math/Vector2.h" +#include "Engine/Core/Delegate.h" + +/// +/// Platform-dependent screen utilities. +/// +API_CLASS(Static) class FLAXENGINE_API ScreenUtilities +{ + DECLARE_SCRIPTING_TYPE_MINIMAL(ScreenUtilities); + + /// + /// Gets the pixel color at the specified coordinates. + /// + /// Screen-space coordinate to read. + /// Pixel color at the specified coordinates. + API_FUNCTION() static Color32 GetColorAt(const Float2& pos); + + /// + /// Starts async color picking. Color will be returned through PickColorDone event when the actions ends (user selected the final color with a mouse). When action is active, GetColorAt can be used to read the current value. + /// + API_FUNCTION() static void PickColor(); + + /// + /// Called when PickColor action is finished. + /// + API_EVENT() static Delegate PickColorDone; +}; diff --git a/Source/Editor/Windows/ContentWindow.cs b/Source/Editor/Windows/ContentWindow.cs index 7aca2526a..a44c35cb3 100644 --- a/Source/Editor/Windows/ContentWindow.cs +++ b/Source/Editor/Windows/ContentWindow.cs @@ -612,7 +612,16 @@ namespace FlaxEditor.Windows /// The files paths to import. public void Paste(string[] files) { - Editor.ContentImporting.Import(files, CurrentViewFolder); + var importFiles = new List(); + foreach (var sourcePath in files) + { + var item = Editor.ContentDatabase.Find(sourcePath); + if (item != null) + Editor.ContentDatabase.Copy(item, Path.Combine(CurrentViewFolder.Path, item.FileName)); + else + importFiles.Add(sourcePath); + } + Editor.ContentImporting.Import(importFiles, CurrentViewFolder); } /// diff --git a/Source/Engine/Core/ObjectsRemovalService.cpp b/Source/Engine/Core/ObjectsRemovalService.cpp index 77ce686e0..35458595e 100644 --- a/Source/Engine/Core/ObjectsRemovalService.cpp +++ b/Source/Engine/Core/ObjectsRemovalService.cpp @@ -1,6 +1,7 @@ // Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. #include "ObjectsRemovalService.h" +#include "Utilities.h" #include "Collections/Dictionary.h" #include "Engine/Engine/Time.h" #include "Engine/Engine/EngineService.h" @@ -8,6 +9,11 @@ #include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Scripting/ScriptingObject.h" +const Char* BytesSizesData[] = { TEXT("b"), TEXT("Kb"), TEXT("Mb"), TEXT("Gb"), TEXT("Tb"), TEXT("Pb"), TEXT("Eb"), TEXT("Zb"), TEXT("Yb") }; +const Char* HertzSizesData[] = { TEXT("Hz"), TEXT("KHz"), TEXT("MHz"), TEXT("GHz"), TEXT("THz"), TEXT("PHz"), TEXT("EHz"), TEXT("ZHz"), TEXT("YHz") }; +Span Utilities::Private::BytesSizes(BytesSizesData, ARRAY_COUNT(BytesSizesData)); +Span Utilities::Private::HertzSizes(HertzSizesData, ARRAY_COUNT(HertzSizesData)); + namespace ObjectsRemovalServiceImpl { CriticalSection PoolLocker; diff --git a/Source/Engine/Core/Utilities.h b/Source/Engine/Core/Utilities.h index c65200077..36339baf5 100644 --- a/Source/Engine/Core/Utilities.h +++ b/Source/Engine/Core/Utilities.h @@ -4,12 +4,19 @@ #include "Types/BaseTypes.h" #include "Types/String.h" +#include "Types/Span.h" #if _MSC_VER && PLATFORM_SIMD_SSE4_2 #include #endif namespace Utilities { + struct Private + { + static FLAXENGINE_API Span BytesSizes; + static FLAXENGINE_API Span HertzSizes; + }; + // Round floating point value up to 1 decimal place template FORCE_INLINE T RoundTo1DecimalPlace(T value) @@ -31,20 +38,41 @@ namespace Utilities return (T)round((double)value * 1000.0) / (T)1000; } + // Converts units to the best fitting human-readable denominator + // @param units Units count + // @param divider Amount of units required for the next size + // @param sizes Array with human-readable sizes to convert from + // @return The best fitting string of the units + template + String UnitsToText(T units, int32 divider, const Span sizes) + { + if (sizes.Length() == 0) + return String::Format(TEXT("{0}"), units); + int32 i = 0; + double dblSUnits = static_cast(units); + for (; static_cast(units / static_cast(divider)) > 0; i++, units /= divider) + dblSUnits = units / static_cast(divider); + if (i >= sizes.Length()) + i = 0; + return String::Format(TEXT("{0} {1}"), RoundTo2DecimalPlaces(dblSUnits), sizes[i]); + } + // Converts size of the file (in bytes) to the best fitting string // @param bytes Size of the file in bytes // @return The best fitting string of the file size template String BytesToText(T bytes) { - static const Char* sizes[] = { TEXT("B"), TEXT("KB"), TEXT("MB"), TEXT("GB"), TEXT("TB") }; - uint64 i = 0; - double dblSByte = static_cast(bytes); - for (; static_cast(bytes / 1024.0) > 0; i++, bytes /= 1024) - dblSByte = bytes / 1024.0; - if (i >= ARRAY_COUNT(sizes)) - return String::Empty; - return String::Format(TEXT("{0} {1}"), RoundTo2DecimalPlaces(dblSByte), sizes[i]); + return UnitsToText(bytes, 1024, Private::BytesSizes); + } + + // Converts hertz to the best fitting string + // @param hertz Hertz for convertion + // @return The best fitting string + template + String HertzToText(T hertz) + { + return UnitsToText(hertz, 1000, Private::HertzSizes); } // Returns the amount of set bits in 32-bit integer. diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp index 79bb57d16..1f833933a 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp @@ -114,7 +114,15 @@ GPUDevice* GPUDeviceDX11::Create() // Create DXGI factory #if PLATFORM_WINDOWS IDXGIFactory1* dxgiFactory; - HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)); + IDXGIFactory6* dxgiFactory6; + HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory6)); + if (hr == S_OK) + dxgiFactory = dxgiFactory6; + else + { + dxgiFactory6 = nullptr; + hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)); + } #else IDXGIFactory2* dxgiFactory; HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)); @@ -126,16 +134,17 @@ GPUDevice* GPUDeviceDX11::Create() } // Enumerate the DXGIFactory's adapters + int32 selectedAdapterIndex = -1; Array adapters; - IDXGIAdapter* tmpAdapter; - for (uint32 index = 0; dxgiFactory->EnumAdapters(index, &tmpAdapter) != DXGI_ERROR_NOT_FOUND; index++) + IDXGIAdapter* tempAdapter; + for (uint32 index = 0; dxgiFactory->EnumAdapters(index, &tempAdapter) != DXGI_ERROR_NOT_FOUND; index++) { GPUAdapterDX adapter; - if (tmpAdapter && TryCreateDevice(tmpAdapter, maxAllowedFeatureLevel, &adapter.MaxFeatureLevel)) + if (tempAdapter && TryCreateDevice(tempAdapter, maxAllowedFeatureLevel, &adapter.MaxFeatureLevel)) { adapter.Index = index; - VALIDATE_DIRECTX_RESULT(tmpAdapter->GetDesc(&adapter.Description)); - uint32 outputs = RenderToolsDX::CountAdapterOutputs(tmpAdapter); + VALIDATE_DIRECTX_RESULT(tempAdapter->GetDesc(&adapter.Description)); + uint32 outputs = RenderToolsDX::CountAdapterOutputs(tempAdapter); LOG(Info, "Adapter {1}: '{0}', DirectX {2}", adapter.Description.Description, index, RenderToolsDX::GetFeatureLevelString(adapter.MaxFeatureLevel)); LOG(Info, " Dedicated Video Memory: {0}, Dedicated System Memory: {1}, Shared System Memory: {2}, Output(s): {3}", Utilities::BytesToText(adapter.Description.DedicatedVideoMemory), Utilities::BytesToText(adapter.Description.DedicatedSystemMemory), Utilities::BytesToText(adapter.Description.SharedSystemMemory), outputs); @@ -143,14 +152,41 @@ GPUDevice* GPUDeviceDX11::Create() adapters.Add(adapter); } } +#if PLATFORM_WINDOWS + // Find the best performing adapter and prefer using it instead of the first device + const auto gpuPreference = DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE; + if (dxgiFactory6 != nullptr && selectedAdapterIndex == -1) + { + if (dxgiFactory6->EnumAdapterByGpuPreference(0, gpuPreference, IID_PPV_ARGS(&tempAdapter)) != DXGI_ERROR_NOT_FOUND) + { + GPUAdapterDX adapter; + if (tempAdapter && TryCreateDevice(tempAdapter, maxAllowedFeatureLevel, &adapter.MaxFeatureLevel)) + { + DXGI_ADAPTER_DESC desc; + VALIDATE_DIRECTX_RESULT(tempAdapter->GetDesc(&desc)); + for (int i = 0; i < adapters.Count(); i++) + { + if (adapters[i].Description.AdapterLuid.LowPart == desc.AdapterLuid.LowPart && + adapters[i].Description.AdapterLuid.HighPart == desc.AdapterLuid.HighPart) + { + selectedAdapterIndex = i; + break; + } + } + } + } + } +#endif // Select the adapter to use - if (adapters.Count() == 0) + if (selectedAdapterIndex < 0) + selectedAdapterIndex = 0; + if (adapters.Count() == 0 || selectedAdapterIndex >= adapters.Count()) { LOG(Error, "Failed to find valid DirectX adapter!"); return nullptr; } - GPUAdapterDX selectedAdapter = adapters[0]; + GPUAdapterDX selectedAdapter = adapters[selectedAdapterIndex]; uint32 vendorId = 0; if (CommandLine::Options.NVIDIA) vendorId = GPU_VENDOR_ID_NVIDIA; @@ -185,6 +221,15 @@ GPUDevice* GPUDeviceDX11::Create() Delete(device); return nullptr; } + +#if PLATFORM_WINDOWS + if (dxgiFactory6 != nullptr) + dxgiFactory6->Release(); + else +#endif + { + dxgiFactory->Release(); + } return device; } diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp index d54f3f38d..ce6016b33 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp @@ -89,7 +89,15 @@ GPUDevice* GPUDeviceDX12::Create() // Create DXGI factory (CreateDXGIFactory2 is supported on Windows 8.1 or newer) IDXGIFactory4* dxgiFactory; - HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)); + IDXGIFactory6* dxgiFactory6; + HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory6)); + if (hr == S_OK) + dxgiFactory = dxgiFactory6; + else + { + dxgiFactory6 = nullptr; + hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)); + } if (hr != S_OK) { LOG(Error, "Cannot create DXGI adapter. Error code: {0:x}.", hr); @@ -97,6 +105,7 @@ GPUDevice* GPUDeviceDX12::Create() } // Enumerate the DXGIFactory's adapters + int32 selectedAdapterIndex = -1; Array adapters; IDXGIAdapter* tempAdapter; for (uint32 index = 0; dxgiFactory->EnumAdapters(index, &tempAdapter) != DXGI_ERROR_NOT_FOUND; index++) @@ -118,13 +127,39 @@ GPUDevice* GPUDeviceDX12::Create() } } + // Find the best performing adapter and prefer using it instead of the first device + const auto gpuPreference = DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE; + if (dxgiFactory6 != nullptr && selectedAdapterIndex == -1) + { + if (dxgiFactory6->EnumAdapterByGpuPreference(0, gpuPreference, IID_PPV_ARGS(&tempAdapter)) != DXGI_ERROR_NOT_FOUND) + { + GPUAdapterDX adapter; + if (tempAdapter && CheckDX12Support(tempAdapter)) + { + DXGI_ADAPTER_DESC desc; + VALIDATE_DIRECTX_RESULT(tempAdapter->GetDesc(&desc)); + for (int i = 0; i < adapters.Count(); i++) + { + if (adapters[i].Description.AdapterLuid.LowPart == desc.AdapterLuid.LowPart && + adapters[i].Description.AdapterLuid.HighPart == desc.AdapterLuid.HighPart) + { + selectedAdapterIndex = i; + break; + } + } + } + } + } + // Select the adapter to use - if (adapters.Count() == 0) + if (selectedAdapterIndex < 0) + selectedAdapterIndex = 0; + if (adapters.Count() == 0 || selectedAdapterIndex >= adapters.Count()) { LOG(Error, "Failed to find valid DirectX adapter!"); return nullptr; } - GPUAdapterDX selectedAdapter = adapters[0]; + GPUAdapterDX selectedAdapter = adapters[selectedAdapterIndex]; uint32 vendorId = 0; if (CommandLine::Options.NVIDIA) vendorId = GPU_VENDOR_ID_NVIDIA; @@ -167,6 +202,15 @@ GPUDevice* GPUDeviceDX12::Create() return nullptr; } +#if !(PLATFORM_XBOX_SCARLETT || PLATFORM_XBOX_ONE) + if (dxgiFactory6 != nullptr) + dxgiFactory6->Release(); + else +#endif + { + dxgiFactory->Release(); + } + return device; } diff --git a/Source/Engine/GraphicsDevice/DirectX/IncludeDirectXHeaders.h b/Source/Engine/GraphicsDevice/DirectX/IncludeDirectXHeaders.h index 79e8fb7bd..deb0168fb 100644 --- a/Source/Engine/GraphicsDevice/DirectX/IncludeDirectXHeaders.h +++ b/Source/Engine/GraphicsDevice/DirectX/IncludeDirectXHeaders.h @@ -40,9 +40,11 @@ typedef IGraphicsUnknown IDXGISwapChain3; #include #include #include +#include #endif #if GRAPHICS_API_DIRECTX12 #include +#include #endif #pragma comment(lib, "DXGI.lib") diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp index def68a103..f6dac375e 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp @@ -1155,6 +1155,7 @@ GPUDevice* GPUDeviceVulkan::Create() #endif // Enumerate all GPU devices and pick one + int32 selectedAdapterIndex = -1; uint32 gpuCount = 0; VALIDATE_VULKAN_RESULT(vkEnumeratePhysicalDevices(Instance, &gpuCount, nullptr)); if (gpuCount <= 0) @@ -1187,6 +1188,9 @@ GPUDevice* GPUDeviceVulkan::Create() break; case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: type = TEXT("Discrete GPU"); + // Select the first discrete GPU device + if (selectedAdapterIndex == -1) + selectedAdapterIndex = gpuIndex; break; case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: type = TEXT("Virtual GPU"); @@ -1203,12 +1207,13 @@ GPUDevice* GPUDeviceVulkan::Create() } // Select the adapter to use - if (adapters.Count() == 0) + if (selectedAdapterIndex < 0) + selectedAdapterIndex = 0; + if (adapters.Count() == 0 || selectedAdapterIndex >= adapters.Count()) { LOG(Error, "Failed to find valid Vulkan adapter!"); return nullptr; } - int32 selectedAdapter = 0; uint32 vendorId = 0; if (CommandLine::Options.NVIDIA) vendorId = GPU_VENDOR_ID_NVIDIA; @@ -1222,15 +1227,15 @@ GPUDevice* GPUDeviceVulkan::Create() { if (adapters[i].GetVendorId() == vendorId) { - selectedAdapter = i; + selectedAdapterIndex = i; break; } } } - ASSERT(selectedAdapter != -1 && adapters[selectedAdapter].IsValid()); + ASSERT(adapters[selectedAdapterIndex].IsValid()); // Create device - auto device = New(ShaderProfile::Vulkan_SM5, New(adapters[selectedAdapter])); + auto device = New(ShaderProfile::Vulkan_SM5, New(adapters[selectedAdapterIndex])); if (device->Init()) { LOG(Warning, "Graphics Device init failed"); diff --git a/Source/Engine/Input/Keyboard.h b/Source/Engine/Input/Keyboard.h index 45f8e295e..7e238bcf5 100644 --- a/Source/Engine/Input/Keyboard.h +++ b/Source/Engine/Input/Keyboard.h @@ -26,9 +26,8 @@ protected: public: /// - /// Gets the text entered during the current frame. + /// Gets the text entered during the current frame (Unicode format). /// - /// The input text (Unicode). API_PROPERTY() StringView GetInputText() const { return StringView(_state.InputText, _state.InputTextLength); diff --git a/Source/Engine/Input/Mouse.h b/Source/Engine/Input/Mouse.h index 7fc2be75a..0acd31238 100644 --- a/Source/Engine/Input/Mouse.h +++ b/Source/Engine/Input/Mouse.h @@ -58,7 +58,6 @@ public: /// /// Gets the position of the mouse in the screen-space coordinates. /// - /// The mouse position API_PROPERTY() FORCE_INLINE Float2 GetPosition() const { return _state.MousePosition; @@ -72,7 +71,6 @@ public: /// /// Gets the delta position of the mouse in the screen-space coordinates. /// - /// The mouse position delta API_PROPERTY() FORCE_INLINE Float2 GetPositionDelta() const { return _state.MousePosition - _prevState.MousePosition; @@ -81,7 +79,6 @@ public: /// /// Gets the mouse wheel change during the last frame. /// - /// Mouse wheel value delta API_PROPERTY() FORCE_INLINE float GetScrollDelta() const { return _state.MouseWheelDelta; diff --git a/Source/Engine/Networking/INetworkObject.h b/Source/Engine/Networking/INetworkObject.h index 457811557..932c3aa0d 100644 --- a/Source/Engine/Networking/INetworkObject.h +++ b/Source/Engine/Networking/INetworkObject.h @@ -13,22 +13,27 @@ API_INTERFACE(Namespace = "FlaxEngine.Networking") class FLAXENGINE_API INetwork DECLARE_SCRIPTING_TYPE_MINIMAL(INetworkObject); public: /// - /// Event called when network objects gets spawned. + /// Event called when network object gets spawned. /// - API_FUNCTION() virtual void OnNetworkSpawn() = 0; + API_FUNCTION() virtual void OnNetworkSpawn() {}; /// - /// Event called when network objects gets despawned. + /// Event called when network object gets despawned. /// - API_FUNCTION() virtual void OnNetworkDespawn() = 0; + API_FUNCTION() virtual void OnNetworkDespawn() {}; /// /// Event called before network object gets replicated (before reading data). /// - API_FUNCTION() virtual void OnNetworkSerialize() = 0; + API_FUNCTION() virtual void OnNetworkSerialize() {}; /// - /// Event called when network objects gets replicated (after reading data). + /// Event called when network object gets replicated (after reading data). /// - API_FUNCTION() virtual void OnNetworkDeserialize() = 0; + API_FUNCTION() virtual void OnNetworkDeserialize() {}; + + /// + /// Event called when network object gets synced (called only once upon initial sync). + /// + API_FUNCTION() virtual void OnNetworkSync() {}; }; diff --git a/Source/Engine/Networking/NetworkReplicator.cpp b/Source/Engine/Networking/NetworkReplicator.cpp index 6813eeb54..c9a4773f0 100644 --- a/Source/Engine/Networking/NetworkReplicator.cpp +++ b/Source/Engine/Networking/NetworkReplicator.cpp @@ -109,12 +109,14 @@ struct NetworkReplicatedObject uint32 LastOwnerFrame = 0; NetworkObjectRole Role; uint8 Spawned : 1; + uint8 Synced : 1; DataContainer TargetClientIds; INetworkObject* AsNetworkObject; NetworkReplicatedObject() { Spawned = 0; + Synced = 0; } bool operator==(const NetworkReplicatedObject& other) const @@ -637,7 +639,14 @@ void InvokeObjectReplication(NetworkReplicatedObject& item, uint32 ownerFrame, b } if (item.AsNetworkObject) + { item.AsNetworkObject->OnNetworkDeserialize(); + if (!item.Synced) + { + item.Synced = true; + item.AsNetworkObject->OnNetworkSync(); + } + } // Speed up replication of client-owned objects to other clients from server to reduce lag (data has to go from client to server and then to other clients) if (NetworkManager::IsServer()) diff --git a/Source/Engine/Platform/Base/PlatformBase.cpp b/Source/Engine/Platform/Base/PlatformBase.cpp index 08e3bd53e..d9c8b2826 100644 --- a/Source/Engine/Platform/Base/PlatformBase.cpp +++ b/Source/Engine/Platform/Base/PlatformBase.cpp @@ -5,6 +5,7 @@ #include "Engine/Platform/MemoryStats.h" #include "Engine/Platform/MessageBox.h" #include "Engine/Platform/FileSystem.h" +#include "Engine/Platform/Window.h" #include "Engine/Platform/User.h" #include "Engine/Core/Log.h" #include "Engine/Core/Types/DateTime.h" @@ -157,7 +158,7 @@ void PlatformBase::LogInfo() LOG(Info, "CPU package count: {0}, Core count: {1}, Logical processors: {2}", cpuInfo.ProcessorPackageCount, cpuInfo.ProcessorCoreCount, cpuInfo.LogicalProcessorCount); LOG(Info, "CPU Page size: {0}, cache line size: {1} bytes", Utilities::BytesToText(cpuInfo.PageSize), cpuInfo.CacheLineSize); LOG(Info, "L1 cache: {0}, L2 cache: {1}, L3 cache: {2}", Utilities::BytesToText(cpuInfo.L1CacheSize), Utilities::BytesToText(cpuInfo.L2CacheSize), Utilities::BytesToText(cpuInfo.L3CacheSize)); - LOG(Info, "Clock speed: {0} GHz", Utilities::RoundTo2DecimalPlaces(cpuInfo.ClockSpeed * 1e-9f)); + LOG(Info, "Clock speed: {0}", Utilities::HertzToText(cpuInfo.ClockSpeed)); const MemoryStats memStats = Platform::GetMemoryStats(); LOG(Info, "Physical Memory: {0} total, {1} used ({2}%)", Utilities::BytesToText(memStats.TotalPhysicalMemory), Utilities::BytesToText(memStats.UsedPhysicalMemory), Utilities::RoundTo2DecimalPlaces((float)memStats.UsedPhysicalMemory * 100.0f / (float)memStats.TotalPhysicalMemory)); @@ -520,6 +521,21 @@ void PlatformBase::CreateGuid(Guid& result) result = Guid(dateThingHigh, randomThing | (sequentialThing << 16), cyclesThing, dateThingLow); } +Float2 PlatformBase::GetMousePosition() +{ + const Window* win = Engine::MainWindow; + if (win) + return win->ClientToScreen(win->GetMousePosition()); + return Float2::Minimum; +} + +void PlatformBase::SetMousePosition(const Float2& position) +{ + const Window* win = Engine::MainWindow; + if (win) + win->SetMousePosition(win->ScreenToClient(position)); +} + Rectangle PlatformBase::GetMonitorBounds(const Float2& screenPos) { return Rectangle(Float2::Zero, Platform::GetDesktopSize()); diff --git a/Source/Engine/Platform/Base/PlatformBase.h b/Source/Engine/Platform/Base/PlatformBase.h index 46a2fa8f9..737427ca7 100644 --- a/Source/Engine/Platform/Base/PlatformBase.h +++ b/Source/Engine/Platform/Base/PlatformBase.h @@ -651,6 +651,18 @@ public: API_FUNCTION() static void OpenUrl(const StringView& url) = delete; public: + /// + /// Gets the mouse cursor position in screen-space coordinates. + /// + /// Mouse cursor coordinates. + API_PROPERTY() static Float2 GetMousePosition(); + + /// + /// Sets the mouse cursor position in screen-space coordinates. + /// + /// Cursor position to set. + API_PROPERTY() static void SetMousePosition(const Float2& position); + /// /// Gets the origin position and size of the monitor at the given screen-space location. /// diff --git a/Source/Engine/Platform/Linux/LinuxPlatform.cpp b/Source/Engine/Platform/Linux/LinuxPlatform.cpp index 23267b193..0434d8414 100644 --- a/Source/Engine/Platform/Linux/LinuxPlatform.cpp +++ b/Source/Engine/Platform/Linux/LinuxPlatform.cpp @@ -89,6 +89,7 @@ X11::Cursor Cursors[(int32)CursorType::MAX]; X11::XcursorImage* CursorsImg[(int32)CursorType::MAX]; Dictionary KeyNameMap; Array KeyCodeMap; +Delegate LinuxPlatform::xEventRecieved; // Message boxes configuration #define LINUX_DIALOG_MIN_BUTTON_WIDTH 64 @@ -2232,10 +2233,12 @@ void LinuxPlatform::Tick() { X11::XEvent event; X11::XNextEvent(xDisplay, &event); - if (X11::XFilterEvent(&event, 0)) continue; + // External event handling + xEventRecieved(&event); + LinuxWindow* window; switch (event.type) { @@ -2640,10 +2643,8 @@ Float2 LinuxPlatform::GetMousePosition() { if (!xDisplay) return Float2::Zero; - - int32 x, y; + int32 x = 0, y = 0; uint32 screenCount = (uint32)X11::XScreenCount(xDisplay); - for (uint32 i = 0; i < screenCount; i++) { X11::Window outRoot, outChild; @@ -2652,7 +2653,6 @@ Float2 LinuxPlatform::GetMousePosition() if (X11::XQueryPointer(xDisplay, X11::XRootWindow(xDisplay, i), &outRoot, &outChild, &x, &y, &childX, &childY, &mask)) break; } - return Float2((float)x, (float)y); } diff --git a/Source/Engine/Platform/Linux/LinuxPlatform.h b/Source/Engine/Platform/Linux/LinuxPlatform.h index 032ea4c6b..827a6b635 100644 --- a/Source/Engine/Platform/Linux/LinuxPlatform.h +++ b/Source/Engine/Platform/Linux/LinuxPlatform.h @@ -33,6 +33,11 @@ public: /// The user home directory. static const String& GetHomeDirectory(); + /// + /// An event that is fired when an XEvent is received during platform tick. + /// + static Delegate xEventRecieved; + public: // [UnixPlatform] diff --git a/Source/Engine/Platform/UWP/UWPPlatform.cpp b/Source/Engine/Platform/UWP/UWPPlatform.cpp index 0e9f465b6..eb496a4a1 100644 --- a/Source/Engine/Platform/UWP/UWPPlatform.cpp +++ b/Source/Engine/Platform/UWP/UWPPlatform.cpp @@ -158,27 +158,6 @@ void UWPPlatform::OpenUrl(const StringView& url) // TODO: add support for OpenUrl on UWP } -Float2 UWPPlatform::GetMousePosition() -{ - // Use the main window - auto win = Engine::MainWindow; - if (win) - { - return win->ClientToScreen(win->GetMousePosition()); - } - return Float2::Minimum; -} - -void UWPPlatform::SetMousePosition(const Float2& pos) -{ - // Use the main window - auto win = Engine::MainWindow; - if (win) - { - win->SetMousePosition(win->ScreenToClient(pos)); - } -} - Float2 UWPPlatform::GetDesktopSize() { Float2 result; diff --git a/Source/Engine/Platform/UWP/UWPPlatform.h b/Source/Engine/Platform/UWP/UWPPlatform.h index 794a8f97a..655209e9f 100644 --- a/Source/Engine/Platform/UWP/UWPPlatform.h +++ b/Source/Engine/Platform/UWP/UWPPlatform.h @@ -37,8 +37,6 @@ public: static bool GetHasFocus(); static bool CanOpenUrl(const StringView& url); static void OpenUrl(const StringView& url); - static Float2 GetMousePosition(); - static void SetMousePosition(const Float2& pos); static Float2 GetDesktopSize(); static Window* CreateWindow(const CreateWindowSettings& settings); static void* LoadLibrary(const Char* filename); diff --git a/Source/Engine/Platform/Win32/Win32Platform.h b/Source/Engine/Platform/Win32/Win32Platform.h index b50d31616..d3f9a5cdc 100644 --- a/Source/Engine/Platform/Win32/Win32Platform.h +++ b/Source/Engine/Platform/Win32/Win32Platform.h @@ -109,7 +109,7 @@ public: static void CreateGuid(Guid& result); static String GetMainDirectory(); static String GetExecutableFilePath(); - static struct Guid GetUniqueDeviceId(); + static Guid GetUniqueDeviceId(); static String GetWorkingDirectory(); static bool SetWorkingDirectory(const String& path); static void FreeLibrary(void* handle); diff --git a/Source/Engine/Platform/Windows/WindowsPlatform.cpp b/Source/Engine/Platform/Windows/WindowsPlatform.cpp index 0ac741f71..8d02312af 100644 --- a/Source/Engine/Platform/Windows/WindowsPlatform.cpp +++ b/Source/Engine/Platform/Windows/WindowsPlatform.cpp @@ -830,6 +830,18 @@ void WindowsPlatform::OpenUrl(const StringView& url) ::ShellExecuteW(nullptr, TEXT("open"), *url, nullptr, nullptr, SW_SHOWNORMAL); } +Float2 WindowsPlatform::GetMousePosition() +{ + POINT cursorPos; + GetCursorPos(&cursorPos); + return Float2((float)cursorPos.x, (float)cursorPos.y); +} + +void WindowsPlatform::SetMousePosition(const Float2& pos) +{ + ::SetCursorPos((int)pos.X, (int)pos.Y); +} + struct GetMonitorBoundsData { Float2 Pos; diff --git a/Source/Engine/Platform/Windows/WindowsPlatform.h b/Source/Engine/Platform/Windows/WindowsPlatform.h index fef8e4ac3..b4fd87a35 100644 --- a/Source/Engine/Platform/Windows/WindowsPlatform.h +++ b/Source/Engine/Platform/Windows/WindowsPlatform.h @@ -71,6 +71,8 @@ public: static bool GetHasFocus(); static bool CanOpenUrl(const StringView& url); static void OpenUrl(const StringView& url); + static Float2 GetMousePosition(); + static void SetMousePosition(const Float2& pos); static Rectangle GetMonitorBounds(const Float2& screenPos); static Float2 GetDesktopSize(); static Rectangle GetVirtualDesktopBounds(); diff --git a/Source/Engine/Utilities/Screenshot.cpp b/Source/Engine/Utilities/Screenshot.cpp index d67f8d123..7e1d3d902 100644 --- a/Source/Engine/Utilities/Screenshot.cpp +++ b/Source/Engine/Utilities/Screenshot.cpp @@ -10,7 +10,6 @@ #include "Engine/Graphics/GPUResourceProperty.h" #include "Engine/Graphics/GPUDevice.h" #include "Engine/Graphics/GPUSwapChain.h" -#include "Engine/Engine/Engine.h" #include "Engine/Threading/ThreadPoolTask.h" #include "Engine/Engine/Globals.h" #if COMPILE_WITH_TEXTURE_TOOL diff --git a/Source/FlaxEngine.Gen.cpp b/Source/FlaxEngine.Gen.cpp deleted file mode 100644 index 6e0ce7876..000000000 --- a/Source/FlaxEngine.Gen.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// This code was auto-generated. Do not modify it. - -#include "Engine/Scripting/BinaryModule.h" -#include "FlaxEngine.Gen.h" - -StaticallyLinkedBinaryModuleInitializer StaticallyLinkedBinaryModuleFlaxEngine(GetBinaryModuleFlaxEngine); - -extern "C" BinaryModule* GetBinaryModuleFlaxEngine() -{ - static NativeBinaryModule module("FlaxEngine"); - return &module; -} diff --git a/Source/FlaxEngine.Gen.cs b/Source/FlaxEngine.Gen.cs deleted file mode 100644 index 3afeab9fd..000000000 --- a/Source/FlaxEngine.Gen.cs +++ /dev/null @@ -1,19 +0,0 @@ -// This code was auto-generated. Do not modify it. - -using System.Reflection; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; - -[assembly: AssemblyTitle("FlaxEngine")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Flax")] -[assembly: AssemblyProduct("FlaxEngine")] -[assembly: AssemblyCopyright("Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] -[assembly: Guid("b8442186-4a70-7c85-704a-857c68060f38")] -[assembly: AssemblyVersion("1.6.6340")] -[assembly: AssemblyFileVersion("1.6.6340")] -[assembly: DisableRuntimeMarshalling] diff --git a/Source/FlaxEngine.Gen.h b/Source/FlaxEngine.Gen.h deleted file mode 100644 index 15d6f9783..000000000 --- a/Source/FlaxEngine.Gen.h +++ /dev/null @@ -1,15 +0,0 @@ -// This code was auto-generated. Do not modify it. - -#pragma once - -#define FLAXENGINE_NAME "FlaxEngine" -#define FLAXENGINE_VERSION Version(1, 6, 6340) -#define FLAXENGINE_VERSION_TEXT "1.6.6340" -#define FLAXENGINE_VERSION_MAJOR 1 -#define FLAXENGINE_VERSION_MINOR 6 -#define FLAXENGINE_VERSION_BUILD 6340 -#define FLAXENGINE_COMPANY "Flax" -#define FLAXENGINE_COPYRIGHT "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved." - -class BinaryModule; -extern "C" FLAXENGINE_API BinaryModule* GetBinaryModuleFlaxEngine(); diff --git a/Source/ThirdParty/tracy/client/TracyProfiler.cpp b/Source/ThirdParty/tracy/client/TracyProfiler.cpp index cba3593da..dfbb22a83 100644 --- a/Source/ThirdParty/tracy/client/TracyProfiler.cpp +++ b/Source/ThirdParty/tracy/client/TracyProfiler.cpp @@ -369,10 +369,7 @@ static int64_t SetupHwTimer() #endif } #endif -#else -static int64_t SetupHwTimer() -{ -#endif + return Profiler::GetTime(); } #else @@ -4786,4 +4783,4 @@ TRACY_API void ___tracy_shutdown_profiler( void ) #endif #endif - +#endif diff --git a/Source/Tools/Flax.Build/Build/NativeCpp/CompileEnvironment.cs b/Source/Tools/Flax.Build/Build/NativeCpp/CompileEnvironment.cs index 9ca96f4fe..72d0380e4 100644 --- a/Source/Tools/Flax.Build/Build/NativeCpp/CompileEnvironment.cs +++ b/Source/Tools/Flax.Build/Build/NativeCpp/CompileEnvironment.cs @@ -157,6 +157,11 @@ namespace Flax.Build.NativeCpp /// public readonly List IncludePaths = new List(); + /// + /// The collection of custom arguments to pass to the compilator. + /// + public readonly HashSet CustomArgs = new HashSet(); + /// public object Clone() { @@ -183,6 +188,7 @@ namespace Flax.Build.NativeCpp }; clone.PreprocessorDefinitions.AddRange(PreprocessorDefinitions); clone.IncludePaths.AddRange(IncludePaths); + clone.CustomArgs.AddRange(CustomArgs); return clone; } } diff --git a/Source/Tools/Flax.Build/Build/NativeCpp/LinkEnvironment.cs b/Source/Tools/Flax.Build/Build/NativeCpp/LinkEnvironment.cs index 34b7df03f..92f08d71f 100644 --- a/Source/Tools/Flax.Build/Build/NativeCpp/LinkEnvironment.cs +++ b/Source/Tools/Flax.Build/Build/NativeCpp/LinkEnvironment.cs @@ -106,6 +106,11 @@ namespace Flax.Build.NativeCpp /// public readonly List LibraryPaths = new List(); + /// + /// The collection of custom arguments to pass to the linker. + /// + public readonly HashSet CustomArgs = new HashSet(); + /// public object Clone() { @@ -127,6 +132,7 @@ namespace Flax.Build.NativeCpp clone.DocumentationFiles.AddRange(DocumentationFiles); clone.InputLibraries.AddRange(InputLibraries); clone.LibraryPaths.AddRange(LibraryPaths); + clone.CustomArgs.AddRange(CustomArgs); return clone; } } diff --git a/Source/Tools/Flax.Build/Platforms/Apple/AppleToolchain.cs b/Source/Tools/Flax.Build/Platforms/Apple/AppleToolchain.cs index 8d17a2d99..8c714c825 100644 --- a/Source/Tools/Flax.Build/Platforms/Apple/AppleToolchain.cs +++ b/Source/Tools/Flax.Build/Platforms/Apple/AppleToolchain.cs @@ -96,6 +96,7 @@ namespace Flax.Build.Platforms // Setup arguments shared by all source files var commonArgs = new List(); + commonArgs.AddRange(options.CompileEnv.CustomArgs); { commonArgs.Add("-c"); commonArgs.Add("-fmessage-length=0"); @@ -235,6 +236,7 @@ namespace Flax.Build.Platforms // Setup arguments var args = new List(); + args.AddRange(options.LinkEnv.CustomArgs); { args.Add(string.Format("-o \"{0}\"", outputFilePath)); AddArgsCommon(options, args); diff --git a/Source/Tools/Flax.Build/Platforms/Unix/UnixToolchain.cs b/Source/Tools/Flax.Build/Platforms/Unix/UnixToolchain.cs index 68520ef44..fc409858a 100644 --- a/Source/Tools/Flax.Build/Platforms/Unix/UnixToolchain.cs +++ b/Source/Tools/Flax.Build/Platforms/Unix/UnixToolchain.cs @@ -325,6 +325,7 @@ namespace Flax.Build.Platforms // Setup arguments shared by all source files var commonArgs = new List(); + commonArgs.AddRange(options.CompileEnv.CustomArgs); SetupCompileCppFilesArgs(graph, options, commonArgs, outputPath); { commonArgs.Add("-c"); @@ -511,6 +512,7 @@ namespace Flax.Build.Platforms // Setup arguments var args = new List(); + args.AddRange(options.LinkEnv.CustomArgs); { args.Add(string.Format("-o \"{0}\"", outputFilePath)); diff --git a/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs b/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs index 824b1b891..e7dbaac19 100644 --- a/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs +++ b/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs @@ -428,6 +428,7 @@ namespace Flax.Build.Platforms // Setup arguments shared by all source files var commonArgs = new List(); + commonArgs.AddRange(options.CompileEnv.CustomArgs); SetupCompileCppFilesArgs(graph, options, commonArgs); { // Suppress Startup Banner @@ -669,6 +670,7 @@ namespace Flax.Build.Platforms // Setup arguments var args = new List(); + args.AddRange(options.LinkEnv.CustomArgs); SetupLinkFilesArgs(graph, options, args); { // Suppress startup banner