diff --git a/Source/Editor/Content/Import/ImportFilesDialog.cs b/Source/Editor/Content/Import/ImportFilesDialog.cs
index ab2c7be15..967583cf6 100644
--- a/Source/Editor/Content/Import/ImportFilesDialog.cs
+++ b/Source/Editor/Content/Import/ImportFilesDialog.cs
@@ -139,7 +139,7 @@ namespace FlaxEditor.Content.Import
var menu = new ContextMenu();
menu.AddButton("Rename", OnRenameClicked);
menu.AddButton("Don't import", OnDontImportClicked);
- menu.AddButton("Show in Explorer", OnShowInExplorerClicked);
+ menu.AddButton(Utilities.Constants.ShowInExplorer, OnShowInExplorerClicked);
menu.Tag = node;
menu.Show(node, location);
}
diff --git a/Source/Editor/Content/Tree/MainContentTreeNode.cs b/Source/Editor/Content/Tree/MainContentTreeNode.cs
index 43b36986d..def873622 100644
--- a/Source/Editor/Content/Tree/MainContentTreeNode.cs
+++ b/Source/Editor/Content/Tree/MainContentTreeNode.cs
@@ -29,7 +29,7 @@ namespace FlaxEditor.Content
//_watcher.Changed += OnEvent;
_watcher.Created += OnEvent;
_watcher.Deleted += OnEvent;
- //_watcher.Renamed += OnEvent;
+ _watcher.Renamed += OnEvent;
}
private void OnEvent(object sender, FileSystemEventArgs e)
diff --git a/Source/Editor/CustomEditors/Dedicated/MissingScriptEditor.cs b/Source/Editor/CustomEditors/Dedicated/MissingScriptEditor.cs
new file mode 100644
index 000000000..03d5ddd55
--- /dev/null
+++ b/Source/Editor/CustomEditors/Dedicated/MissingScriptEditor.cs
@@ -0,0 +1,26 @@
+using FlaxEditor.CustomEditors.Editors;
+using FlaxEngine;
+using FlaxEngine.GUI;
+
+namespace FlaxEditor.CustomEditors.Dedicated;
+
+///
+/// The missing script editor.
+///
+[CustomEditor(typeof(MissingScript)), DefaultEditor]
+public class MissingScriptEditor : GenericEditor
+{
+ ///
+ public override void Initialize(LayoutElementsContainer layout)
+ {
+ if (layout.ContainerControl is not DropPanel dropPanel)
+ {
+ base.Initialize(layout);
+ return;
+ }
+
+ dropPanel.HeaderTextColor = Color.OrangeRed;
+
+ base.Initialize(layout);
+ }
+}
diff --git a/Source/Editor/Modules/ContentDatabaseModule.cs b/Source/Editor/Modules/ContentDatabaseModule.cs
index 143352421..552658aa1 100644
--- a/Source/Editor/Modules/ContentDatabaseModule.cs
+++ b/Source/Editor/Modules/ContentDatabaseModule.cs
@@ -931,6 +931,11 @@ namespace FlaxEditor.Modules
// Check if node already has that element (skip during init when we want to walk project dir very fast)
if (_isDuringFastSetup || !parent.Folder.ContainsChild(path))
{
+#if PLATFORM_MAC
+ if (path.EndsWith(".DS_Store", StringComparison.Ordinal))
+ continue;
+#endif
+
// Create file item
ContentItem item;
if (path.EndsWith(".cs"))
@@ -972,6 +977,11 @@ namespace FlaxEditor.Modules
// Check if node already has that element (skip during init when we want to walk project dir very fast)
if (_isDuringFastSetup || !parent.Folder.ContainsChild(path))
{
+#if PLATFORM_MAC
+ if (path.EndsWith(".DS_Store", StringComparison.Ordinal))
+ continue;
+#endif
+
// Create file item
ContentItem item = null;
if (FlaxEngine.Content.GetAssetInfo(path, out var assetInfo))
@@ -1197,6 +1207,7 @@ namespace FlaxEditor.Modules
{
case WatcherChangeTypes.Created:
case WatcherChangeTypes.Deleted:
+ case WatcherChangeTypes.Renamed:
{
lock (_dirtyNodes)
{
diff --git a/Source/Editor/Utilities/Constants.cs b/Source/Editor/Utilities/Constants.cs
index 176fed5f7..fb9f82cf5 100644
--- a/Source/Editor/Utilities/Constants.cs
+++ b/Source/Editor/Utilities/Constants.cs
@@ -14,5 +14,11 @@ namespace FlaxEditor.Utilities
public const string FacebookUrl = "https://facebook.com/FlaxEngine";
public const string YoutubeUrl = "https://youtube.com/c/FlaxEngine";
public const string TwitterUrl = "https://twitter.com/FlaxEngine";
+
+#if PLATFORM_MAC
+ public const string ShowInExplorer = "Show in Finder";
+#else
+ public const string ShowInExplorer = "Show in explorer";
+#endif
}
}
diff --git a/Source/Editor/Windows/ContentWindow.ContextMenu.cs b/Source/Editor/Windows/ContentWindow.ContextMenu.cs
index 6923d634d..1dd26ecf5 100644
--- a/Source/Editor/Windows/ContentWindow.ContextMenu.cs
+++ b/Source/Editor/Windows/ContentWindow.ContextMenu.cs
@@ -58,7 +58,7 @@ namespace FlaxEditor.Windows
if (item is ContentFolder contentFolder && contentFolder.Node is ProjectTreeNode)
{
- cm.AddButton("Show in explorer", () => FileSystem.ShowFileExplorer(CurrentViewFolder.Path));
+ cm.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(CurrentViewFolder.Path));
}
else if (isValidElement)
{
@@ -72,7 +72,7 @@ namespace FlaxEditor.Windows
Open(e);
});
- cm.AddButton("Show in explorer", () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(item.Path)));
+ cm.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(item.Path)));
if (item.HasDefaultThumbnail == false)
{
@@ -135,7 +135,7 @@ namespace FlaxEditor.Windows
}
else
{
- cm.AddButton("Show in explorer", () => FileSystem.ShowFileExplorer(CurrentViewFolder.Path));
+ cm.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(CurrentViewFolder.Path));
b = cm.AddButton("Paste", _view.Paste);
b.Enabled = _view.CanPaste();
diff --git a/Source/Editor/Windows/OutputLogWindow.cs b/Source/Editor/Windows/OutputLogWindow.cs
index 1d188a32c..3665b7073 100644
--- a/Source/Editor/Windows/OutputLogWindow.cs
+++ b/Source/Editor/Windows/OutputLogWindow.cs
@@ -195,7 +195,7 @@ namespace FlaxEditor.Windows
_contextMenu.AddButton("Clear log", Clear);
_contextMenu.AddButton("Copy selection", _output.Copy);
_contextMenu.AddButton("Select All", _output.SelectAll);
- _contextMenu.AddButton("Show in explorer", () => FileSystem.ShowFileExplorer(Path.Combine(Globals.ProjectFolder, "Logs")));
+ _contextMenu.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(Path.Combine(Globals.ProjectFolder, "Logs")));
_contextMenu.AddButton("Scroll to bottom", () => { _vScroll.TargetValue = _vScroll.Maximum; }).Icon = Editor.Icons.ArrowDown12;
// Setup editor options
diff --git a/Source/Editor/Windows/Profiler/Assets.cs b/Source/Editor/Windows/Profiler/Assets.cs
index e2a65d496..3ccf6e2eb 100644
--- a/Source/Editor/Windows/Profiler/Assets.cs
+++ b/Source/Editor/Windows/Profiler/Assets.cs
@@ -274,7 +274,7 @@ namespace FlaxEditor.Windows.Profiler
ContextMenuButton b;
b = cm.AddButton("Open", () => Editor.Instance.ContentEditing.Open(assetItem));
cm.AddButton("Show in content window", () => Editor.Instance.Windows.ContentWin.Select(assetItem));
- cm.AddButton("Show in explorer", () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(assetItem.Path)));
+ cm.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(assetItem.Path)));
cm.AddButton("Select actors using this asset", () => Editor.Instance.SceneEditing.SelectActorsUsingAsset(assetItem.ID));
cm.AddButton("Show asset references graph", () => Editor.Instance.Windows.Open(new AssetReferencesGraphWindow(Editor.Instance, assetItem)));
cm.AddButton("Copy name", () => Clipboard.Text = assetItem.NamePath);
diff --git a/Source/Editor/Windows/Search/SearchItem.cs b/Source/Editor/Windows/Search/SearchItem.cs
index e8bdc4e56..506d30d0d 100644
--- a/Source/Editor/Windows/Search/SearchItem.cs
+++ b/Source/Editor/Windows/Search/SearchItem.cs
@@ -157,7 +157,7 @@ namespace FlaxEditor.Windows.Search
var cm = new FlaxEditor.GUI.ContextMenu.ContextMenu { Tag = assetItem };
b = cm.AddButton("Open", () => Editor.Instance.ContentFinding.Open(Item));
cm.AddSeparator();
- cm.AddButton("Show in explorer", () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(assetItem.Path)));
+ cm.AddButton(Utilities.Constants.ShowInExplorer, () => FileSystem.ShowFileExplorer(System.IO.Path.GetDirectoryName(assetItem.Path)));
cm.AddButton("Show in Content window", () => Editor.Instance.Windows.ContentWin.Select(assetItem, true));
b.Enabled = proxy != null && proxy.CanReimport(assetItem);
if (assetItem is BinaryAssetItem binaryAsset)
diff --git a/Source/Engine/Core/Collections/ArrayExtensions.h b/Source/Engine/Core/Collections/ArrayExtensions.h
index 788b31edb..2ae6da9c8 100644
--- a/Source/Engine/Core/Collections/ArrayExtensions.h
+++ b/Source/Engine/Core/Collections/ArrayExtensions.h
@@ -4,7 +4,7 @@
#include "../Collections/Array.h"
#include "../Collections/Dictionary.h"
-#include
+#include "../Delegate.h"
class ArrayExtensions;
@@ -23,7 +23,6 @@ public:
///
/// Gets the common key.
///
- /// The key.
FORCE_INLINE const TKey& GetKey() const
{
return _key;
@@ -32,7 +31,6 @@ public:
///
/// Gets the common key.
///
- /// The key.
FORCE_INLINE TKey GetKey()
{
return _key;
@@ -52,7 +50,7 @@ public:
/// The prediction function. Should return true for the target element to find.
/// The index of the element or -1 if nothing found.
template
- static int32 IndexOf(const Array& obj, const std::function& predicate)
+ static int32 IndexOf(const Array& obj, const Function& predicate)
{
for (int32 i = 0; i < obj.Count(); i++)
{
@@ -71,7 +69,7 @@ public:
/// The prediction function.
/// True if any element in the collection matches the prediction, otherwise false.
template
- static bool Any(const Array& obj, const std::function& predicate)
+ static bool Any(const Array& obj, const Function& predicate)
{
for (int32 i = 0; i < obj.Count(); i++)
{
@@ -90,7 +88,7 @@ public:
/// The prediction function.
/// True if all elements in the collection matches the prediction, otherwise false.
template
- static int32 All(const Array& obj, const std::function& predicate)
+ static int32 All(const Array& obj, const Function& predicate)
{
for (int32 i = 0; i < obj.Count(); i++)
{
@@ -109,7 +107,7 @@ public:
/// A function to extract the key for each element.
/// The result collection with groups.
template
- static void GroupBy(const Array& obj, const std::function& keySelector, Array, AllocationType>& result)
+ static void GroupBy(const Array& obj, const Function& keySelector, Array, AllocationType>& result)
{
Dictionary> data(static_cast(obj.Count() * 3.0f));
for (int32 i = 0; i < obj.Count(); i++)
diff --git a/Source/Engine/Engine/Engine.cpp b/Source/Engine/Engine/Engine.cpp
index ec56861ba..5b93ab588 100644
--- a/Source/Engine/Engine/Engine.cpp
+++ b/Source/Engine/Engine/Engine.cpp
@@ -105,6 +105,14 @@ int32 Engine::Main(const Char* cmdLine)
Globals::StartupFolder = Globals::BinariesFolder = Platform::GetMainDirectory();
#if USE_EDITOR
Globals::StartupFolder /= TEXT("../../../..");
+#if PLATFORM_MAC
+ if (Globals::BinariesFolder.EndsWith(TEXT(".app/Contents")))
+ {
+ // If running editor from application package on macOS
+ Globals::StartupFolder = Globals::BinariesFolder;
+ Globals::BinariesFolder /= TEXT("MacOS");
+ }
+#endif
#endif
StringUtils::PathRemoveRelativeParts(Globals::StartupFolder);
FileSystem::NormalizePath(Globals::BinariesFolder);
@@ -122,7 +130,6 @@ int32 Engine::Main(const Char* cmdLine)
}
EngineImpl::InitPaths();
-
EngineImpl::InitLog();
#if USE_EDITOR
@@ -542,7 +549,8 @@ void EngineImpl::InitLog()
LOG(Info, "Product: {0}, Company: {1}", Globals::ProductName, Globals::CompanyName);
LOG(Info, "Current culture: {0}", Platform::GetUserLocaleName());
LOG(Info, "Command line: {0}", CommandLine);
- LOG(Info, "Base directory: {0}", Globals::StartupFolder);
+ LOG(Info, "Base folder: {0}", Globals::StartupFolder);
+ LOG(Info, "Binaries folder: {0}", Globals::BinariesFolder);
LOG(Info, "Temporary folder: {0}", Globals::TemporaryFolder);
LOG(Info, "Project folder: {0}", Globals::ProjectFolder);
#if USE_EDITOR
diff --git a/Source/Engine/Engine/InputAxis.cs b/Source/Engine/Engine/InputAxis.cs
index f8ba7e72b..c70bada74 100644
--- a/Source/Engine/Engine/InputAxis.cs
+++ b/Source/Engine/Engine/InputAxis.cs
@@ -1,5 +1,7 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
+using System;
+
namespace FlaxEngine
{
///
@@ -23,11 +25,17 @@ namespace FlaxEngine
///
public float ValueRaw => Input.GetAxisRaw(Name);
+ ///
+ /// Occurs when axis is changed. Called before scripts update.
+ ///
+ public event Action ValueChanged;
+
///
/// Initializes a new instance of the class.
///
public InputAxis()
{
+ Input.AxisValueChanged += Handler;
}
///
@@ -36,7 +44,31 @@ namespace FlaxEngine
/// The axis name.
public InputAxis(string name)
{
+ Input.AxisValueChanged += Handler;
Name = name;
}
+
+ private void Handler(string name)
+ {
+ if (string.Equals(Name, name, StringComparison.OrdinalIgnoreCase))
+ ValueChanged?.Invoke();
+ }
+
+ ///
+ /// Finalizes an instance of the class.
+ ///
+ ~InputAxis()
+ {
+ Input.AxisValueChanged -= Handler;
+ }
+
+ ///
+ /// Releases this object.
+ ///
+ public void Dispose()
+ {
+ Input.AxisValueChanged -= Handler;
+ GC.SuppressFinalize(this);
+ }
}
}
diff --git a/Source/Engine/Engine/InputEvent.cs b/Source/Engine/Engine/InputEvent.cs
index 176d21fd0..0267aed96 100644
--- a/Source/Engine/Engine/InputEvent.cs
+++ b/Source/Engine/Engine/InputEvent.cs
@@ -16,15 +16,36 @@ namespace FlaxEngine
public string Name;
///
- /// Returns true if the event has been triggered during the current frame (e.g. user pressed a key). Use to catch events without active waiting.
+ /// Returns true if the event has been triggered during the current frame (e.g. user pressed a key). Use to catch events without active waiting.
///
public bool Active => Input.GetAction(Name);
+ ///
+ /// Returns the event state. Use Use , , to catch events without active waiting.
+ ///
+ public InputActionState State => Input.GetActionState(Name);
+
///
/// Occurs when event is triggered (e.g. user pressed a key). Called before scripts update.
///
+ [System.Obsolete("Depreciated in 1.7, use Pressed Action.")]
public event Action Triggered;
+ ///
+ /// Occurs when event is pressed (e.g. user pressed a key). Called before scripts update.
+ ///
+ public event Action Pressed;
+
+ ///
+ /// Occurs when event is being pressing (e.g. user pressing a key). Called before scripts update.
+ ///
+ public event Action Pressing;
+
+ ///
+ /// Occurs when event is released (e.g. user releases a key). Called before scripts update.
+ ///
+ public event Action Released;
+
///
/// Initializes a new instance of the class.
///
@@ -51,10 +72,26 @@ namespace FlaxEngine
Input.ActionTriggered -= Handler;
}
- private void Handler(string name)
+ private void Handler(string name, InputActionState state)
{
- if (string.Equals(name, Name, StringComparison.OrdinalIgnoreCase))
+ if (!string.Equals(name, Name, StringComparison.OrdinalIgnoreCase))
+ return;
+ switch (state)
+ {
+ case InputActionState.None: break;
+ case InputActionState.Waiting: break;
+ case InputActionState.Pressing:
+ Pressing?.Invoke();
+ break;
+ case InputActionState.Press:
Triggered?.Invoke();
+ Pressed?.Invoke();
+ break;
+ case InputActionState.Release:
+ Released?.Invoke();
+ break;
+ default: break;
+ }
}
///
diff --git a/Source/Engine/Foliage/FoliageType.cpp b/Source/Engine/Foliage/FoliageType.cpp
index 785010c44..7d530dfed 100644
--- a/Source/Engine/Foliage/FoliageType.cpp
+++ b/Source/Engine/Foliage/FoliageType.cpp
@@ -130,7 +130,7 @@ void FoliageType::Serialize(SerializeStream& stream, const void* otherObj)
SERIALIZE(Model);
- const std::function IsValidMaterial = [](const ModelInstanceEntry& e) -> bool
+ const Function IsValidMaterial = [](const ModelInstanceEntry& e) -> bool
{
return e.Material;
};
diff --git a/Source/Engine/Graphics/Models/SkeletonMapping.h b/Source/Engine/Graphics/Models/SkeletonMapping.h
index ac2af245b..e3ec0c793 100644
--- a/Source/Engine/Graphics/Models/SkeletonMapping.h
+++ b/Source/Engine/Graphics/Models/SkeletonMapping.h
@@ -66,7 +66,7 @@ public:
const auto parentModelIndex = node.ParentIndex;
// Find matching node in skeleton (or map to best parent)
- const std::function f = [node](const T& x) -> bool
+ const Function f = [node](const T& x) -> bool
{
return x.Name == node.Name;
};
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp
index d52b446e3..b0bb1c733 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp
@@ -459,9 +459,9 @@ void GPUContextVulkan::UpdateDescriptorSets(const SpirvShaderDescriptorInfo& des
{
case VK_DESCRIPTOR_TYPE_SAMPLER:
{
- const VkSampler sampler = _samplerHandles[slot];
- ASSERT(sampler);
- needsWrite |= dsWriter.WriteSampler(descriptorIndex, sampler, index);
+ const VkSampler handle = _samplerHandles[slot];
+ ASSERT(handle);
+ needsWrite |= dsWriter.WriteSampler(descriptorIndex, handle, index);
break;
}
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
@@ -547,12 +547,18 @@ void GPUContextVulkan::UpdateDescriptorSets(const SpirvShaderDescriptorInfo& des
}
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
{
- auto cb = handles[slot];
- ASSERT(cb);
- VkBuffer buffer;
- VkDeviceSize offset, range;
- uint32 dynamicOffset;
- cb->DescriptorAsDynamicUniformBuffer(this, buffer, offset, range, dynamicOffset);
+ auto handle = handles[slot];
+ VkBuffer buffer = VK_NULL_HANDLE;
+ VkDeviceSize offset = 0, range = 0;
+ uint32 dynamicOffset = 0;
+ if (handle)
+ handle->DescriptorAsDynamicUniformBuffer(this, buffer, offset, range, dynamicOffset);
+ else
+ {
+ const auto dummy = _device->HelperResources.GetDummyBuffer();
+ buffer = dummy->GetHandle();
+ range = dummy->GetSize();
+ }
needsWrite |= dsWriter.WriteDynamicUniformBuffer(descriptorIndex, buffer, offset, range, dynamicOffset, index);
break;
}
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.Layers.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.Layers.cpp
index bdd92c762..0b857d394 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.Layers.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.Layers.cpp
@@ -35,6 +35,10 @@ static const char* GValidationLayers[] =
static const char* GInstanceExtensions[] =
{
+#if PLATFORM_APPLE_FAMILY && defined(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)
+ VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
+ VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
+#endif
#if VK_EXT_validation_cache
VK_EXT_VALIDATION_CACHE_EXTENSION_NAME,
#endif
@@ -46,6 +50,9 @@ static const char* GInstanceExtensions[] =
static const char* GDeviceExtensions[] =
{
+#if PLATFORM_APPLE_FAMILY && defined(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)
+ VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
+#endif
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
#if VK_KHR_maintenance1
VK_KHR_MAINTENANCE1_EXTENSION_NAME,
@@ -571,7 +578,7 @@ void GPUDeviceVulkan::ParseOptionalDeviceExtensions(const Array& de
const auto HasExtension = [&deviceExtensions](const char* name) -> bool
{
- const std::function CheckCallback = [&name](const char* const& extension) -> bool
+ const Function CheckCallback = [&name](const char* const& extension) -> bool
{
return StringUtils::Compare(extension, name) == 0;
};
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
index eb23c0871..b4a6112a9 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
@@ -431,7 +431,7 @@ void DeferredDeletionQueueVulkan::EnqueueGenericResource(Type type, uint64 handl
ScopeLock lock(_locker);
#if BUILD_DEBUG
- const std::function ContainsHandle = [handle](const Entry& e)
+ const Function ContainsHandle = [handle](const Entry& e)
{
return e.Handle == handle;
};
@@ -868,7 +868,7 @@ GPUBufferVulkan* HelperResourcesVulkan::GetDummyBuffer()
if (!_dummyBuffer)
{
_dummyBuffer = (GPUBufferVulkan*)_device->CreateBuffer(TEXT("DummyBuffer"));
- _dummyBuffer->Init(GPUBufferDescription::Buffer(sizeof(int32), GPUBufferFlags::ShaderResource | GPUBufferFlags::UnorderedAccess, PixelFormat::R32_SInt));
+ _dummyBuffer->Init(GPUBufferDescription::Buffer(sizeof(int32) * 256, GPUBufferFlags::ShaderResource | GPUBufferFlags::UnorderedAccess, PixelFormat::R32_SInt));
}
return _dummyBuffer;
@@ -1078,13 +1078,16 @@ GPUDevice* GPUDeviceVulkan::Create()
VkInstanceCreateInfo instInfo;
RenderToolsVulkan::ZeroStruct(instInfo, VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO);
+#if PLATFORM_APPLE_FAMILY
+ instInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
+#endif
instInfo.pApplicationInfo = &appInfo;
GetInstanceLayersAndExtensions(InstanceExtensions, InstanceLayers, SupportsDebugUtilsExt);
const auto hasExtension = [](const Array& extensions, const char* name) -> bool
{
- const std::function callback = [&name](const char* const& extension) -> bool
+ const Function callback = [&name](const char* const& extension) -> bool
{
return extension && StringUtils::Compare(extension, name) == 0;
};
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GraphicsDeviceVulkan.Build.cs b/Source/Engine/GraphicsDevice/Vulkan/GraphicsDeviceVulkan.Build.cs
index 252652978..9ffa68272 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GraphicsDeviceVulkan.Build.cs
+++ b/Source/Engine/GraphicsDevice/Vulkan/GraphicsDeviceVulkan.Build.cs
@@ -51,7 +51,8 @@ public sealed class VulkanSdk : Sdk
var subDirs = Directory.GetDirectories(path);
if (subDirs.Length != 0)
{
- path = Path.Combine(subDirs[0], "macOS");
+ Flax.Build.Utilities.SortVersionDirectories(subDirs);
+ path = Path.Combine(subDirs.Last(), "macOS");
if (Directory.Exists(path))
vulkanSdk = path;
}
diff --git a/Source/Engine/GraphicsDevice/Vulkan/IncludeVulkanHeaders.h b/Source/Engine/GraphicsDevice/Vulkan/IncludeVulkanHeaders.h
index 3a1b6a615..4e2694aab 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/IncludeVulkanHeaders.h
+++ b/Source/Engine/GraphicsDevice/Vulkan/IncludeVulkanHeaders.h
@@ -41,4 +41,15 @@
#define VMA_NOT_NULL
#include
+#if PLATFORM_APPLE_FAMILY
+// Declare potentially missing extensions from newer SDKs
+#ifndef VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME
+#define VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME "VK_KHR_portability_enumeration"
+#define VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR 0x00000001
+#endif
+#ifndef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
+#define VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME "VK_KHR_portability_subset"
+#endif
+#endif
+
#endif
diff --git a/Source/Engine/Input/Input.cpp b/Source/Engine/Input/Input.cpp
index 81411ed76..dbcdf66bd 100644
--- a/Source/Engine/Input/Input.cpp
+++ b/Source/Engine/Input/Input.cpp
@@ -97,7 +97,8 @@ Action Input::MouseLeave;
Delegate Input::TouchDown;
Delegate Input::TouchMove;
Delegate Input::TouchUp;
-Delegate Input::ActionTriggered;
+Delegate Input::ActionTriggered;
+Delegate Input::AxisValueChanged;
Array Input::ActionMappings;
Array Input::AxisMappings;
@@ -1017,14 +1018,22 @@ void InputService::Update()
Input::SetMousePosition(Screen::GetSize() * 0.5f);
}
- // Send events for the active actions (send events only in play mode)
+ // Send events for the active actions and axes (send events only in play mode)
if (!Time::GetGamePaused())
{
+ for (auto i = Axes.Begin(); i.IsNotEnd(); ++i)
+ {
+ if (Math::NotNearEqual(i->Value.Value, i->Value.PrevKeyValue))
+ {
+ Input::AxisValueChanged(i->Key);
+ }
+ }
+
for (auto i = Actions.Begin(); i.IsNotEnd(); ++i)
{
- if (i->Value.Active)
+ if (i->Value.State != InputActionState::Waiting)
{
- Input::ActionTriggered(i->Key);
+ Input::ActionTriggered(i->Key, i->Value.State);
}
}
}
diff --git a/Source/Engine/Input/Input.h b/Source/Engine/Input/Input.h
index 84d312fa3..c11026eff 100644
--- a/Source/Engine/Input/Input.h
+++ b/Source/Engine/Input/Input.h
@@ -293,7 +293,13 @@ public:
/// Event fired when virtual input action is triggered. Called before scripts update. See to edit configuration.
///
///
- API_EVENT() static Delegate ActionTriggered;
+ API_EVENT() static Delegate ActionTriggered;
+
+ ///
+ /// Event fired when virtual input axis is changed. Called before scripts update. See to edit configuration.
+ ///
+ ///
+ API_EVENT() static Delegate AxisValueChanged;
///
/// Gets the value of the virtual action identified by name. Use to get the current config.
diff --git a/Source/Engine/Level/Components/MissingScript.h b/Source/Engine/Level/Components/MissingScript.h
new file mode 100644
index 000000000..bfb73498f
--- /dev/null
+++ b/Source/Engine/Level/Components/MissingScript.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
+
+#pragma once
+
+#if USE_EDITOR
+
+#include "Engine/Core/Cache.h"
+#include "Engine/Scripting/Script.h"
+#include "Engine/Scripting/ScriptingObjectReference.h"
+#include "Engine/Serialization/JsonWriters.h"
+
+///
+/// Actor script component that represents missing script.
+///
+API_CLASS(Attributes="HideInEditor") class FLAXENGINE_API MissingScript : public Script
+{
+ API_AUTO_SERIALIZATION();
+ DECLARE_SCRIPTING_TYPE(MissingScript);
+
+private:
+ ScriptingObjectReference