Merge remote-tracking branch 'origin/master' into 1.8
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -12,6 +12,7 @@ Source/*.csproj
|
|||||||
/Package_*/
|
/Package_*/
|
||||||
!Source/Engine/Debug
|
!Source/Engine/Debug
|
||||||
/Source/Platforms/Editor/Linux/Mono/etc/mono/registry
|
/Source/Platforms/Editor/Linux/Mono/etc/mono/registry
|
||||||
|
PackageEditor_Cert.command
|
||||||
PackageEditor_Cert.bat
|
PackageEditor_Cert.bat
|
||||||
PackagePlatforms_Cert.bat
|
PackagePlatforms_Cert.bat
|
||||||
|
|
||||||
|
|||||||
BIN
Content/Editor/Particles/Smoke.flax
(Stored with Git LFS)
BIN
Content/Editor/Particles/Smoke.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Particles/Sparks.flax
(Stored with Git LFS)
BIN
Content/Editor/Particles/Sparks.flax
(Stored with Git LFS)
Binary file not shown.
@@ -33,4 +33,3 @@ public class %class% : Script
|
|||||||
// Here you can add code that needs to be called every frame
|
// Here you can add code that needs to be called every frame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
"Version": {
|
"Version": {
|
||||||
"Major": 1,
|
"Major": 1,
|
||||||
"Minor": 8,
|
"Minor": 8,
|
||||||
|
"Revision": 0,
|
||||||
"Build": 6500
|
"Build": 6500
|
||||||
},
|
},
|
||||||
"Company": "Flax",
|
"Company": "Flax",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ if errorlevel 1 goto BuildToolFailed
|
|||||||
|
|
||||||
:: Build bindings for all editor configurations
|
:: Build bindings for all editor configurations
|
||||||
echo Building C# bindings...
|
echo Building C# bindings...
|
||||||
Binaries\Tools\Flax.Build.exe -build -BuildBindingsOnly -arch=x64 -platform=Windows --buildTargets=FlaxEditor,FlaxGame
|
Binaries\Tools\Flax.Build.exe -build -BuildBindingsOnly -arch=x64 -platform=Windows --buildTargets=FlaxEditor
|
||||||
|
|
||||||
popd
|
popd
|
||||||
echo Done!
|
echo Done!
|
||||||
|
|||||||
@@ -14,4 +14,4 @@ bash ./Development/Scripts/Mac/CallBuildTool.sh --genproject "$@"
|
|||||||
# Build bindings for all editor configurations
|
# Build bindings for all editor configurations
|
||||||
echo Building C# bindings...
|
echo Building C# bindings...
|
||||||
# TODO: Detect the correct architecture here
|
# TODO: Detect the correct architecture here
|
||||||
Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=ARM64 -platform=Mac --buildTargets=FlaxEditor,FlaxGame
|
Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=ARM64 -platform=Mac --buildTargets=FlaxEditor
|
||||||
|
|||||||
@@ -14,4 +14,4 @@ bash ./Development/Scripts/Linux/CallBuildTool.sh --genproject "$@"
|
|||||||
# Build bindings for all editor configurations
|
# Build bindings for all editor configurations
|
||||||
echo Building C# bindings...
|
echo Building C# bindings...
|
||||||
# TODO: Detect the correct architecture here
|
# TODO: Detect the correct architecture here
|
||||||
Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=x64 -platform=Linux --buildTargets=FlaxEditor,FlaxGame
|
Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=x64 -platform=Linux --buildTargets=FlaxEditor
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<a href="https://flaxengine.com/discord"><img src="https://discordapp.com/api/guilds/437989205315158016/widget.png"/></a>
|
<a href="https://flaxengine.com/discord"><img src="https://discordapp.com/api/guilds/437989205315158016/widget.png"/></a>
|
||||||
|
|
||||||
Flax Engine is a high quality modern 3D game engine written in C++ and C#.
|
Flax Engine is a high quality modern 3D game engine written in C++ and C#.
|
||||||
From stunning graphics to powerful scripts - Flax can give everything for your games. Designed for fast workflow with many ready to use features waiting for you right now. To learn more see the website ([www.flaxengine.com](https://flaxengine.com)).
|
From stunning graphics to powerful scripts, it's designed for fast workflow with many ready-to-use features waiting for you right now. To learn more see the website ([www.flaxengine.com](https://flaxengine.com)).
|
||||||
|
|
||||||
This repository contains full source code of the Flax Engine (excluding NDA-protected platforms support). Anyone is welcome to contribute or use the modified source in Flax-based games.
|
This repository contains full source code of the Flax Engine (excluding NDA-protected platforms support). Anyone is welcome to contribute or use the modified source in Flax-based games.
|
||||||
|
|
||||||
|
|||||||
@@ -104,4 +104,19 @@ bool LinuxPlatformTools::OnDeployBinaries(CookingData& data)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LinuxPlatformTools::OnRun(CookingData& data, String& executableFile, String& commandLineFormat, String& workingDir)
|
||||||
|
{
|
||||||
|
// Pick the first executable file
|
||||||
|
Array<String> files;
|
||||||
|
FileSystem::DirectoryGetFiles(files, data.NativeCodeOutputPath, TEXT("*"), DirectorySearchOption::TopDirectoryOnly);
|
||||||
|
for (auto& file : files)
|
||||||
|
{
|
||||||
|
if (FileSystem::GetExtension(file).IsEmpty())
|
||||||
|
{
|
||||||
|
executableFile = file;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ public:
|
|||||||
ArchitectureType GetArchitecture() const override;
|
ArchitectureType GetArchitecture() const override;
|
||||||
bool UseSystemDotnet() const override;
|
bool UseSystemDotnet() const override;
|
||||||
bool OnDeployBinaries(CookingData& data) override;
|
bool OnDeployBinaries(CookingData& data) override;
|
||||||
|
void OnRun(CookingData& data, String& executableFile, String& commandLineFormat, String& workingDir) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -249,4 +249,19 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacPlatformTools::OnRun(CookingData& data, String& executableFile, String& commandLineFormat, String& workingDir)
|
||||||
|
{
|
||||||
|
// Pick the first executable file
|
||||||
|
Array<String> files;
|
||||||
|
FileSystem::DirectoryGetFiles(files, data.NativeCodeOutputPath, TEXT("*"), DirectorySearchOption::TopDirectoryOnly);
|
||||||
|
for (auto& file : files)
|
||||||
|
{
|
||||||
|
if (FileSystem::GetExtension(file).IsEmpty())
|
||||||
|
{
|
||||||
|
executableFile = file;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ public:
|
|||||||
bool IsNativeCodeFile(CookingData& data, const String& file) override;
|
bool IsNativeCodeFile(CookingData& data, const String& file) override;
|
||||||
void OnBuildStarted(CookingData& data) override;
|
void OnBuildStarted(CookingData& data) override;
|
||||||
bool OnPostProcess(CookingData& data) override;
|
bool OnPostProcess(CookingData& data) override;
|
||||||
|
void OnRun(CookingData& data, String& executableFile, String& commandLineFormat, String& workingDir) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -225,8 +225,15 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
}
|
}
|
||||||
_actor = actor;
|
_actor = actor;
|
||||||
|
|
||||||
var showActorPicker = actor == null || ParentEditor.Values.All(x => x is not Cloth);
|
if (ParentEditor.Values.Any(x => x is Cloth))
|
||||||
if (showActorPicker)
|
{
|
||||||
|
// Cloth always picks the parent model mesh
|
||||||
|
if (actor == null)
|
||||||
|
{
|
||||||
|
layout.Label("Cloth needs to be added as a child to model actor.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// Actor reference picker
|
// Actor reference picker
|
||||||
_actorPicker = layout.Custom<FlaxObjectRefPickerControl>();
|
_actorPicker = layout.Custom<FlaxObjectRefPickerControl>();
|
||||||
@@ -242,7 +249,10 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
{
|
{
|
||||||
var model = staticModel.Model;
|
var model = staticModel.Model;
|
||||||
if (model == null || model.WaitForLoaded())
|
if (model == null || model.WaitForLoaded())
|
||||||
|
{
|
||||||
|
layout.Label("No model.");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
var materials = model.MaterialSlots;
|
var materials = model.MaterialSlots;
|
||||||
var lods = model.LODs;
|
var lods = model.LODs;
|
||||||
meshNames = new string[lods.Length][];
|
meshNames = new string[lods.Length][];
|
||||||
@@ -267,7 +277,10 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
{
|
{
|
||||||
var skinnedModel = animatedModel.SkinnedModel;
|
var skinnedModel = animatedModel.SkinnedModel;
|
||||||
if (skinnedModel == null || skinnedModel.WaitForLoaded())
|
if (skinnedModel == null || skinnedModel.WaitForLoaded())
|
||||||
|
{
|
||||||
|
layout.Label("No model.");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
var materials = skinnedModel.MaterialSlots;
|
var materials = skinnedModel.MaterialSlots;
|
||||||
var lods = skinnedModel.LODs;
|
var lods = skinnedModel.LODs;
|
||||||
meshNames = new string[lods.Length][];
|
meshNames = new string[lods.Length][];
|
||||||
|
|||||||
@@ -44,11 +44,11 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
var mousePos = window.MousePosition;
|
var mousePos = window.MousePosition;
|
||||||
var previousSize = window.Size;
|
var previousSize = window.Size;
|
||||||
window.Restore();
|
window.Restore();
|
||||||
window.Position = FlaxEngine.Input.MouseScreenPosition - mousePos * window.Size / previousSize;
|
window.Position = Platform.MousePosition - mousePos * window.Size / previousSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate dragging offset and move window to the destination position
|
// Calculate dragging offset and move window to the destination position
|
||||||
var mouseScreenPosition = FlaxEngine.Input.MouseScreenPosition;
|
var mouseScreenPosition = Platform.MousePosition;
|
||||||
|
|
||||||
// If the _toMove window was not focused when initializing this window, the result vector only contains zeros
|
// If the _toMove window was not focused when initializing this window, the result vector only contains zeros
|
||||||
// and to prevent a failure, we need to perform an update for the drag offset at later time which will be done in the OnMouseMove event handler.
|
// and to prevent a failure, we need to perform an update for the drag offset at later time which will be done in the OnMouseMove event handler.
|
||||||
@@ -83,6 +83,7 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
// Enable hit window presentation
|
// Enable hit window presentation
|
||||||
Proxy.Window.RenderingEnabled = true;
|
Proxy.Window.RenderingEnabled = true;
|
||||||
Proxy.Window.Show();
|
Proxy.Window.Show();
|
||||||
|
Proxy.Window.Focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -113,7 +114,7 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
var window = _toMove.Window?.Window;
|
var window = _toMove.Window?.Window;
|
||||||
if (window == null)
|
if (window == null)
|
||||||
return;
|
return;
|
||||||
var mouse = FlaxEngine.Input.MouseScreenPosition;
|
var mouse = Platform.MousePosition;
|
||||||
|
|
||||||
// Move base window
|
// Move base window
|
||||||
window.Position = mouse - _dragOffset;
|
window.Position = mouse - _dragOffset;
|
||||||
@@ -193,7 +194,7 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
|
|
||||||
// Move window to the mouse position (with some offset for caption bar)
|
// Move window to the mouse position (with some offset for caption bar)
|
||||||
var window = (WindowRootControl)toMove.Root;
|
var window = (WindowRootControl)toMove.Root;
|
||||||
var mouse = FlaxEngine.Input.MouseScreenPosition;
|
var mouse = Platform.MousePosition;
|
||||||
window.Window.Position = mouse - new Float2(8, 8);
|
window.Window.Position = mouse - new Float2(8, 8);
|
||||||
|
|
||||||
// Get floating panel
|
// Get floating panel
|
||||||
@@ -244,7 +245,7 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
private void UpdateRects()
|
private void UpdateRects()
|
||||||
{
|
{
|
||||||
// Cache mouse position
|
// Cache mouse position
|
||||||
_mouse = FlaxEngine.Input.MouseScreenPosition;
|
_mouse = Platform.MousePosition;
|
||||||
|
|
||||||
// Check intersection with any dock panel
|
// Check intersection with any dock panel
|
||||||
var uiMouse = _mouse;
|
var uiMouse = _mouse;
|
||||||
@@ -270,15 +271,16 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
// Cache dock rectangles
|
// Cache dock rectangles
|
||||||
var size = _rectDock.Size;
|
var size = _rectDock.Size;
|
||||||
var offset = _rectDock.Location;
|
var offset = _rectDock.Location;
|
||||||
float BorderMargin = 4.0f;
|
var borderMargin = 4.0f;
|
||||||
float ProxyHintWindowsSize2 = Proxy.HintWindowsSize * 0.5f;
|
var hintWindowsSize = Proxy.HintWindowsSize * Platform.DpiScale;
|
||||||
float centerX = size.X * 0.5f;
|
var hintWindowsSize2 = hintWindowsSize * 0.5f;
|
||||||
float centerY = size.Y * 0.5f;
|
var centerX = size.X * 0.5f;
|
||||||
_rUpper = new Rectangle(centerX - ProxyHintWindowsSize2, BorderMargin, Proxy.HintWindowsSize, Proxy.HintWindowsSize) + offset;
|
var centerY = size.Y * 0.5f;
|
||||||
_rBottom = new Rectangle(centerX - ProxyHintWindowsSize2, size.Y - Proxy.HintWindowsSize - BorderMargin, Proxy.HintWindowsSize, Proxy.HintWindowsSize) + offset;
|
_rUpper = new Rectangle(centerX - hintWindowsSize2, borderMargin, hintWindowsSize, hintWindowsSize) + offset;
|
||||||
_rLeft = new Rectangle(BorderMargin, centerY - ProxyHintWindowsSize2, Proxy.HintWindowsSize, Proxy.HintWindowsSize) + offset;
|
_rBottom = new Rectangle(centerX - hintWindowsSize2, size.Y - hintWindowsSize - borderMargin, hintWindowsSize, hintWindowsSize) + offset;
|
||||||
_rRight = new Rectangle(size.X - Proxy.HintWindowsSize - BorderMargin, centerY - ProxyHintWindowsSize2, Proxy.HintWindowsSize, Proxy.HintWindowsSize) + offset;
|
_rLeft = new Rectangle(borderMargin, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
|
||||||
_rCenter = new Rectangle(centerX - ProxyHintWindowsSize2, centerY - ProxyHintWindowsSize2, Proxy.HintWindowsSize, Proxy.HintWindowsSize) + offset;
|
_rRight = new Rectangle(size.X - hintWindowsSize - borderMargin, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
|
||||||
|
_rCenter = new Rectangle(centerX - hintWindowsSize2, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
|
||||||
|
|
||||||
// Hit test
|
// Hit test
|
||||||
DockState toSet = DockState.Float;
|
DockState toSet = DockState.Float;
|
||||||
@@ -428,7 +430,6 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
{
|
{
|
||||||
if (Window == null)
|
if (Window == null)
|
||||||
{
|
{
|
||||||
// Create proxy window
|
|
||||||
var settings = CreateWindowSettings.Default;
|
var settings = CreateWindowSettings.Default;
|
||||||
settings.Title = "DockHint.Window";
|
settings.Title = "DockHint.Window";
|
||||||
settings.Size = initSize;
|
settings.Size = initSize;
|
||||||
@@ -440,12 +441,10 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
settings.IsRegularWindow = false;
|
settings.IsRegularWindow = false;
|
||||||
settings.SupportsTransparency = true;
|
settings.SupportsTransparency = true;
|
||||||
settings.ShowInTaskbar = false;
|
settings.ShowInTaskbar = false;
|
||||||
settings.ShowAfterFirstPaint = true;
|
settings.ShowAfterFirstPaint = false;
|
||||||
settings.IsTopmost = true;
|
settings.IsTopmost = true;
|
||||||
|
|
||||||
Window = Platform.CreateWindow(ref settings);
|
Window = Platform.CreateWindow(ref settings);
|
||||||
|
|
||||||
// Set opacity and background color
|
|
||||||
Window.Opacity = 0.6f;
|
Window.Opacity = 0.6f;
|
||||||
Window.GUI.BackgroundColor = Style.Current.DragWindow;
|
Window.GUI.BackgroundColor = Style.Current.DragWindow;
|
||||||
}
|
}
|
||||||
@@ -465,7 +464,7 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
|
|
||||||
var settings = CreateWindowSettings.Default;
|
var settings = CreateWindowSettings.Default;
|
||||||
settings.Title = name;
|
settings.Title = name;
|
||||||
settings.Size = new Float2(HintWindowsSize);
|
settings.Size = new Float2(HintWindowsSize * Platform.DpiScale);
|
||||||
settings.AllowInput = false;
|
settings.AllowInput = false;
|
||||||
settings.AllowMaximize = false;
|
settings.AllowMaximize = false;
|
||||||
settings.AllowMinimize = false;
|
settings.AllowMinimize = false;
|
||||||
@@ -479,7 +478,6 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
settings.ShowAfterFirstPaint = false;
|
settings.ShowAfterFirstPaint = false;
|
||||||
|
|
||||||
win = Platform.CreateWindow(ref settings);
|
win = Platform.CreateWindow(ref settings);
|
||||||
|
|
||||||
win.Opacity = 0.6f;
|
win.Opacity = 0.6f;
|
||||||
win.GUI.BackgroundColor = Style.Current.DragWindow;
|
win.GUI.BackgroundColor = Style.Current.DragWindow;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -776,11 +776,20 @@ namespace FlaxEditor.GUI.Tree
|
|||||||
// Check if mouse hits arrow
|
// Check if mouse hits arrow
|
||||||
if (_mouseOverArrow && HasAnyVisibleChild)
|
if (_mouseOverArrow && HasAnyVisibleChild)
|
||||||
{
|
{
|
||||||
// Toggle open state
|
if (ParentTree.Root.GetKey(KeyboardKeys.Alt))
|
||||||
if (_opened)
|
{
|
||||||
Collapse();
|
if (_opened)
|
||||||
|
CollapseAll();
|
||||||
|
else
|
||||||
|
ExpandAll();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
Expand();
|
{
|
||||||
|
if (_opened)
|
||||||
|
Collapse();
|
||||||
|
else
|
||||||
|
Expand();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if mouse hits bar
|
// Check if mouse hits bar
|
||||||
|
|||||||
@@ -513,7 +513,9 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_RunVisualScriptBreakpointLoopTick(floa
|
|||||||
WindowsManager::WindowsLocker.Unlock();
|
WindowsManager::WindowsLocker.Unlock();
|
||||||
}
|
}
|
||||||
WindowsManager::WindowsLocker.Lock();
|
WindowsManager::WindowsLocker.Lock();
|
||||||
for (auto& win : WindowsManager::Windows)
|
Array<Window*, InlinedAllocation<32>> windows;
|
||||||
|
windows.Add(WindowsManager::Windows);
|
||||||
|
for (Window* win : windows)
|
||||||
{
|
{
|
||||||
if (win->IsVisible())
|
if (win->IsVisible())
|
||||||
win->OnUpdate(deltaTime);
|
win->OnUpdate(deltaTime);
|
||||||
|
|||||||
@@ -237,7 +237,11 @@ namespace FlaxEditor.Modules
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void LoadDefaultLayout()
|
public void LoadDefaultLayout()
|
||||||
{
|
{
|
||||||
LoadLayout(StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/LayoutDefault.xml"));
|
var path = StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/LayoutDefault.xml");
|
||||||
|
if (File.Exists(path))
|
||||||
|
{
|
||||||
|
LoadLayout(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -259,10 +259,7 @@ namespace FlaxEditor.Options
|
|||||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||||||
{
|
{
|
||||||
if (sourceType == typeof(string))
|
if (sourceType == typeof(string))
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
return base.CanConvertFrom(context, sourceType);
|
return base.CanConvertFrom(context, sourceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,9 +267,7 @@ namespace FlaxEditor.Options
|
|||||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
||||||
{
|
{
|
||||||
if (destinationType == typeof(string))
|
if (destinationType == typeof(string))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
return base.CanConvertTo(context, destinationType);
|
return base.CanConvertTo(context, destinationType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,7 +279,6 @@ namespace FlaxEditor.Options
|
|||||||
InputBinding.TryParse(str, out var result);
|
InputBinding.TryParse(str, out var result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.ConvertFrom(context, culture, value);
|
return base.ConvertFrom(context, culture, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +289,6 @@ namespace FlaxEditor.Options
|
|||||||
{
|
{
|
||||||
return ((InputBinding)value).ToString();
|
return ((InputBinding)value).ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.ConvertTo(context, culture, value, destinationType);
|
return base.ConvertTo(context, culture, value, destinationType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,45 +26,108 @@ namespace FlaxEditor.Options
|
|||||||
public float MouseWheelSensitivity { get; set; } = 1.0f;
|
public float MouseWheelSensitivity { get; set; } = 1.0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the default movement speed for the viewport camera (must match the dropdown menu values in the viewport).
|
/// Gets or sets the total amount of steps the camera needs to go from minimum to maximum speed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DefaultValue(1.0f), Limit(0.01f, 100.0f)]
|
[DefaultValue(64), Limit(1, 128)]
|
||||||
[EditorDisplay("Defaults"), EditorOrder(110), Tooltip("The default movement speed for the viewport camera (must match the dropdown menu values in the viewport).")]
|
[EditorDisplay("Camera"), EditorOrder(110), Tooltip("The total amount of steps the camera needs to go from minimum to maximum speed.")]
|
||||||
public float DefaultMovementSpeed { get; set; } = 1.0f;
|
public int TotalCameraSpeedSteps { get; set; } = 64;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the degree to which the camera will be eased when using camera flight in the editor window.
|
||||||
|
/// </summary>
|
||||||
|
[DefaultValue(3.0f), Limit(1.0f, 8.0f)]
|
||||||
|
[EditorDisplay("Camera"), EditorOrder(111), Tooltip("The degree to which the camera will be eased when using camera flight in the editor window (ignored if camera easing degree is enabled).")]
|
||||||
|
public float CameraEasingDegree { get; set; } = 3.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the default movement speed for the viewport camera (must be in range between minimum and maximum movement speed values).
|
||||||
|
/// </summary>
|
||||||
|
[DefaultValue(1.0f), Limit(0.05f, 32.0f)]
|
||||||
|
[EditorDisplay("Defaults"), EditorOrder(120), Tooltip("The default movement speed for the viewport camera (must be in range between minimum and maximum movement speed values).")]
|
||||||
|
public float MovementSpeed { get; set; } = 1.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the default minimum camera movement speed.
|
||||||
|
/// </summary>
|
||||||
|
[DefaultValue(0.05f), Limit(0.05f, 32.0f)]
|
||||||
|
[EditorDisplay("Defaults"), EditorOrder(121), Tooltip("The default minimum movement speed for the viewport camera.")]
|
||||||
|
public float MinMovementSpeed { get; set; } = 0.05f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the default maximum camera movement speed.
|
||||||
|
/// </summary>
|
||||||
|
[DefaultValue(32.0f), Limit(16.0f, 1000.0f)]
|
||||||
|
[EditorDisplay("Defaults"), EditorOrder(122), Tooltip("The default maximum movement speed for the viewport camera.")]
|
||||||
|
public float MaxMovementSpeed { get; set; } = 32f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the default camera easing mode.
|
||||||
|
/// </summary>
|
||||||
|
[DefaultValue(true)]
|
||||||
|
[EditorDisplay("Defaults"), EditorOrder(130), Tooltip("The default camera easing mode.")]
|
||||||
|
public bool UseCameraEasing { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the default near clipping plane distance for the viewport camera.
|
/// Gets or sets the default near clipping plane distance for the viewport camera.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DefaultValue(10.0f), Limit(0.001f, 1000.0f)]
|
[DefaultValue(10.0f), Limit(0.001f, 1000.0f)]
|
||||||
[EditorDisplay("Defaults"), EditorOrder(120), Tooltip("The default near clipping plane distance for the viewport camera.")]
|
[EditorDisplay("Defaults"), EditorOrder(140), Tooltip("The default near clipping plane distance for the viewport camera.")]
|
||||||
public float DefaultNearPlane { get; set; } = 10.0f;
|
public float NearPlane { get; set; } = 10.0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the default far clipping plane distance for the viewport camera.
|
/// Gets or sets the default far clipping plane distance for the viewport camera.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DefaultValue(40000.0f), Limit(10.0f)]
|
[DefaultValue(40000.0f), Limit(10.0f)]
|
||||||
[EditorDisplay("Defaults"), EditorOrder(130), Tooltip("The default far clipping plane distance for the viewport camera.")]
|
[EditorDisplay("Defaults"), EditorOrder(150), Tooltip("The default far clipping plane distance for the viewport camera.")]
|
||||||
public float DefaultFarPlane { get; set; } = 40000.0f;
|
public float FarPlane { get; set; } = 40000.0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the default field of view angle (in degrees) for the viewport camera.
|
/// Gets or sets the default field of view angle (in degrees) for the viewport camera.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DefaultValue(60.0f), Limit(35.0f, 160.0f, 0.1f)]
|
[DefaultValue(60.0f), Limit(35.0f, 160.0f, 0.1f)]
|
||||||
[EditorDisplay("Defaults", "Default Field Of View"), EditorOrder(140), Tooltip("The default field of view angle (in degrees) for the viewport camera.")]
|
[EditorDisplay("Defaults"), EditorOrder(160), Tooltip("The default field of view angle (in degrees) for the viewport camera.")]
|
||||||
public float DefaultFieldOfView { get; set; } = 60.0f;
|
public float FieldOfView { get; set; } = 60.0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets if the panning direction is inverted for the viewport camera.
|
/// Gets or sets the default camera orthographic mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DefaultValue(false)]
|
[DefaultValue(false)]
|
||||||
[EditorDisplay("Defaults"), EditorOrder(150), Tooltip("Invert the panning direction for the viewport camera.")]
|
[EditorDisplay("Defaults"), EditorOrder(170), Tooltip("The default camera orthographic mode.")]
|
||||||
public bool DefaultInvertPanning { get; set; } = false;
|
public bool UseOrthographicProjection { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Scales editor viewport grid.
|
/// Gets or sets the default camera orthographic scale (if camera uses orthographic mode).
|
||||||
|
/// </summary>
|
||||||
|
[DefaultValue(5.0f), Limit(0.001f, 100000.0f, 0.1f)]
|
||||||
|
[EditorDisplay("Defaults"), EditorOrder(180), Tooltip("The default camera orthographic scale (if camera uses orthographic mode).")]
|
||||||
|
public float OrthographicScale { get; set; } = 5.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the default panning direction for the viewport camera.
|
||||||
|
/// </summary>
|
||||||
|
[DefaultValue(false)]
|
||||||
|
[EditorDisplay("Defaults"), EditorOrder(190), Tooltip("The default panning direction for the viewport camera.")]
|
||||||
|
public bool InvertPanning { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the default relative panning mode.
|
||||||
|
/// </summary>
|
||||||
|
[DefaultValue(true)]
|
||||||
|
[EditorDisplay("Defaults"), EditorOrder(200), Tooltip("The default relative panning mode. Uses distance between camera and target to determine panning speed.")]
|
||||||
|
public bool UseRelativePanning { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the default panning speed (ignored if relative panning is speed enabled).
|
||||||
|
/// </summary>
|
||||||
|
[DefaultValue(0.8f), Limit(0.01f, 128.0f, 0.1f)]
|
||||||
|
[EditorDisplay("Defaults"), EditorOrder(210), Tooltip("The default camera panning speed (ignored if relative panning is enabled).")]
|
||||||
|
public float PanningSpeed { get; set; } = 0.8f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the default editor viewport grid scale.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DefaultValue(50.0f), Limit(25.0f, 500.0f, 5.0f)]
|
[DefaultValue(50.0f), Limit(25.0f, 500.0f, 5.0f)]
|
||||||
[EditorDisplay("Defaults"), EditorOrder(160), Tooltip("Scales editor viewport grid.")]
|
[EditorDisplay("Defaults"), EditorOrder(220), Tooltip("The default editor viewport grid scale.")]
|
||||||
public float ViewportGridScale { get; set; } = 50.0f;
|
public float ViewportGridScale { get; set; } = 50.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -154,7 +154,8 @@ bool ProjectInfo::LoadProject(const String& projectPath)
|
|||||||
Version = ::Version(
|
Version = ::Version(
|
||||||
JsonTools::GetInt(version, "Major", 0),
|
JsonTools::GetInt(version, "Major", 0),
|
||||||
JsonTools::GetInt(version, "Minor", 0),
|
JsonTools::GetInt(version, "Minor", 0),
|
||||||
JsonTools::GetInt(version, "Build", 0));
|
JsonTools::GetInt(version, "Build", -1),
|
||||||
|
JsonTools::GetInt(version, "Revision", -1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Version.Revision() == 0)
|
if (Version.Revision() == 0)
|
||||||
|
|||||||
@@ -23,17 +23,11 @@ namespace FlaxEditor
|
|||||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
{
|
|
||||||
writer.WriteNull();
|
writer.WriteNull();
|
||||||
}
|
|
||||||
else if (value is Version)
|
else if (value is Version)
|
||||||
{
|
|
||||||
writer.WriteValue(value.ToString());
|
writer.WriteValue(value.ToString());
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
throw new JsonSerializationException("Expected Version object value");
|
throw new JsonSerializationException("Expected Version object value");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -47,65 +41,60 @@ namespace FlaxEditor
|
|||||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
if (reader.TokenType == JsonToken.Null)
|
if (reader.TokenType == JsonToken.Null)
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
else
|
if (reader.TokenType == JsonToken.StartObject)
|
||||||
{
|
{
|
||||||
if (reader.TokenType == JsonToken.StartObject)
|
try
|
||||||
{
|
{
|
||||||
try
|
reader.Read();
|
||||||
|
var values = new Dictionary<string, int>();
|
||||||
|
while (reader.TokenType == JsonToken.PropertyName)
|
||||||
{
|
{
|
||||||
|
var key = reader.Value as string;
|
||||||
reader.Read();
|
reader.Read();
|
||||||
Dictionary<string, int> values = new Dictionary<string, int>();
|
var val = (long)reader.Value;
|
||||||
while (reader.TokenType == JsonToken.PropertyName)
|
reader.Read();
|
||||||
{
|
values.Add(key, (int)val);
|
||||||
var key = reader.Value as string;
|
}
|
||||||
reader.Read();
|
|
||||||
var val = (long)reader.Value;
|
|
||||||
reader.Read();
|
|
||||||
values.Add(key, (int)val);
|
|
||||||
}
|
|
||||||
|
|
||||||
int major = 0, minor = 0, build = 0;
|
values.TryGetValue("Major", out var major);
|
||||||
values.TryGetValue("Major", out major);
|
values.TryGetValue("Minor", out var minor);
|
||||||
values.TryGetValue("Minor", out minor);
|
if (!values.TryGetValue("Build", out var build))
|
||||||
values.TryGetValue("Build", out build);
|
build = -1;
|
||||||
|
if (!values.TryGetValue("Revision", out var revision))
|
||||||
|
revision = -1;
|
||||||
|
|
||||||
Version v = new Version(major, minor, build);
|
if (build <= 0)
|
||||||
return v;
|
return new Version(major, minor);
|
||||||
}
|
if (revision <= 0)
|
||||||
catch (Exception ex)
|
return new Version(major, minor, build);
|
||||||
{
|
return new Version(major, minor, build, revision);
|
||||||
throw new Exception(String.Format("Error parsing version string: {0}", reader.Value), ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (reader.TokenType == JsonToken.String)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
try
|
throw new Exception(String.Format("Error parsing version string: {0}", reader.Value), ex);
|
||||||
{
|
|
||||||
Version v = new Version((string)reader.Value!);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw new Exception(String.Format("Error parsing version string: {0}", reader.Value), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Exception(String.Format("Unexpected token or value when parsing version. Token: {0}, Value: {1}", reader.TokenType, reader.Value));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (reader.TokenType == JsonToken.String)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new Version((string)reader.Value!);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new Exception(String.Format("Error parsing version string: {0}", reader.Value), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception(String.Format("Unexpected token or value when parsing version. Token: {0}, Value: {1}", reader.TokenType, reader.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether this instance can convert the specified object type.
|
/// Determines whether this instance can convert the specified object type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="objectType">Type of the object.</param>
|
/// <param name="objectType">Type of the object.</param>
|
||||||
/// <returns>
|
/// <returns><c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.</returns>
|
||||||
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
|
||||||
/// </returns>
|
|
||||||
public override bool CanConvert(Type objectType)
|
public override bool CanConvert(Type objectType)
|
||||||
{
|
{
|
||||||
return objectType == typeof(Version);
|
return objectType == typeof(Version);
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ namespace FlaxEditor.SceneGraph.GUI
|
|||||||
_orderInParent = actor.OrderInParent;
|
_orderInParent = actor.OrderInParent;
|
||||||
Visible = (actor.HideFlags & HideFlags.HideInHierarchy) == 0;
|
Visible = (actor.HideFlags & HideFlags.HideInHierarchy) == 0;
|
||||||
|
|
||||||
var id = actor.ID;
|
// Pick the correct id when inside a prefab window.
|
||||||
|
var id = actor.HasPrefabLink && actor.Scene == null ? actor.PrefabObjectID : actor.ID;
|
||||||
if (Editor.Instance.ProjectCache.IsExpandedActor(ref id))
|
if (Editor.Instance.ProjectCache.IsExpandedActor(ref id))
|
||||||
{
|
{
|
||||||
Expand(true);
|
Expand(true);
|
||||||
@@ -171,7 +172,8 @@ namespace FlaxEditor.SceneGraph.GUI
|
|||||||
// Restore cached state on query filter clear
|
// Restore cached state on query filter clear
|
||||||
if (noFilter && actor != null)
|
if (noFilter && actor != null)
|
||||||
{
|
{
|
||||||
var id = actor.ID;
|
// Pick the correct id when inside a prefab window.
|
||||||
|
var id = actor.HasPrefabLink && actor.Scene.Scene == null ? actor.PrefabObjectID : actor.ID;
|
||||||
isExpanded = Editor.Instance.ProjectCache.IsExpandedActor(ref id);
|
isExpanded = Editor.Instance.ProjectCache.IsExpandedActor(ref id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,10 +303,12 @@ namespace FlaxEditor.SceneGraph.GUI
|
|||||||
protected override void OnExpandedChanged()
|
protected override void OnExpandedChanged()
|
||||||
{
|
{
|
||||||
base.OnExpandedChanged();
|
base.OnExpandedChanged();
|
||||||
|
var actor = Actor;
|
||||||
|
|
||||||
if (!IsLayoutLocked && Actor)
|
if (!IsLayoutLocked && actor)
|
||||||
{
|
{
|
||||||
var id = Actor.ID;
|
// Pick the correct id when inside a prefab window.
|
||||||
|
var id = actor.HasPrefabLink && actor.Scene == null ? actor.PrefabObjectID : actor.ID;
|
||||||
Editor.Instance.ProjectCache.SetExpandedActor(ref id, IsExpanded);
|
Editor.Instance.ProjectCache.SetExpandedActor(ref id, IsExpanded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -225,6 +225,7 @@ namespace FlaxEngine.Tools
|
|||||||
var cloth = _cloth;
|
var cloth = _cloth;
|
||||||
if (cloth == null)
|
if (cloth == null)
|
||||||
return;
|
return;
|
||||||
|
var hasPaintInput = Owner.IsLeftMouseButtonDown && !Owner.IsAltKeyDown;
|
||||||
|
|
||||||
// Perform detailed tracing to find cursor location for the brush
|
// Perform detailed tracing to find cursor location for the brush
|
||||||
var ray = Owner.MouseRay;
|
var ray = Owner.MouseRay;
|
||||||
@@ -240,7 +241,7 @@ namespace FlaxEngine.Tools
|
|||||||
// Cursor hit other object or nothing
|
// Cursor hit other object or nothing
|
||||||
PaintEnd();
|
PaintEnd();
|
||||||
|
|
||||||
if (Owner.IsLeftMouseButtonDown)
|
if (hasPaintInput)
|
||||||
{
|
{
|
||||||
// Select something else
|
// Select something else
|
||||||
var view = new Ray(Owner.ViewPosition, Owner.ViewDirection);
|
var view = new Ray(Owner.ViewPosition, Owner.ViewDirection);
|
||||||
@@ -253,7 +254,7 @@ namespace FlaxEngine.Tools
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle painting
|
// Handle painting
|
||||||
if (Owner.IsLeftMouseButtonDown)
|
if (hasPaintInput)
|
||||||
PaintStart();
|
PaintStart();
|
||||||
else
|
else
|
||||||
PaintEnd();
|
PaintEnd();
|
||||||
|
|||||||
@@ -259,7 +259,10 @@ namespace FlaxEditor.Viewport.Cameras
|
|||||||
// Pan
|
// Pan
|
||||||
if (input.IsPanning)
|
if (input.IsPanning)
|
||||||
{
|
{
|
||||||
var panningSpeed = 0.8f;
|
var panningSpeed = (Viewport.RelativePanning)
|
||||||
|
? Mathf.Abs((position - TargetPoint).Length) * 0.005f
|
||||||
|
: Viewport.PanningSpeed;
|
||||||
|
|
||||||
if (Viewport.InvertPanning)
|
if (Viewport.InvertPanning)
|
||||||
{
|
{
|
||||||
position += up * (mouseDelta.Y * panningSpeed);
|
position += up * (mouseDelta.Y * panningSpeed);
|
||||||
|
|||||||
@@ -128,12 +128,26 @@ namespace FlaxEditor.Viewport
|
|||||||
public const int FpsCameraFilteringFrames = 3;
|
public const int FpsCameraFilteringFrames = 3;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The speed widget button.
|
/// The camera settings widget.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected ViewportWidgetButton _speedWidget;
|
protected ViewportWidgetsContainer _cameraWidget;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The camera settings widget button.
|
||||||
|
/// </summary>
|
||||||
|
protected ViewportWidgetButton _cameraButton;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The orthographic mode widget button.
|
||||||
|
/// </summary>
|
||||||
|
protected ViewportWidgetButton _orthographicModeButton;
|
||||||
|
|
||||||
|
private readonly Editor _editor;
|
||||||
|
|
||||||
private float _mouseSensitivity;
|
private float _mouseSensitivity;
|
||||||
private float _movementSpeed;
|
private float _movementSpeed;
|
||||||
|
private float _minMovementSpeed;
|
||||||
|
private float _maxMovementSpeed;
|
||||||
private float _mouseAccelerationScale;
|
private float _mouseAccelerationScale;
|
||||||
private bool _useMouseFiltering;
|
private bool _useMouseFiltering;
|
||||||
private bool _useMouseAcceleration;
|
private bool _useMouseAcceleration;
|
||||||
@@ -174,11 +188,17 @@ namespace FlaxEditor.Viewport
|
|||||||
private float _fieldOfView;
|
private float _fieldOfView;
|
||||||
private float _nearPlane;
|
private float _nearPlane;
|
||||||
private float _farPlane;
|
private float _farPlane;
|
||||||
private float _orthoSize = 1.0f;
|
private float _orthoSize;
|
||||||
private bool _isOrtho = false;
|
private bool _isOrtho;
|
||||||
private float _wheelMovementChangeDeltaSum = 0;
|
private bool _useCameraEasing;
|
||||||
|
private float _cameraEasingDegree;
|
||||||
|
private float _panningSpeed;
|
||||||
|
private bool _relativePanning;
|
||||||
private bool _invertPanning;
|
private bool _invertPanning;
|
||||||
|
|
||||||
|
private int _speedStep;
|
||||||
|
private int _maxSpeedSteps;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Speed of the mouse.
|
/// Speed of the mouse.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -189,6 +209,25 @@ namespace FlaxEditor.Viewport
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public float MouseWheelZoomSpeedFactor = 1;
|
public float MouseWheelZoomSpeedFactor = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Format of the text for the camera move speed.
|
||||||
|
/// </summary>
|
||||||
|
private string MovementSpeedTextFormat
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Mathf.Abs(_movementSpeed - _maxMovementSpeed) < Mathf.Epsilon || Mathf.Abs(_movementSpeed - _minMovementSpeed) < Mathf.Epsilon)
|
||||||
|
return "{0:0.##}";
|
||||||
|
|
||||||
|
if (_movementSpeed < 10.0f)
|
||||||
|
return "{0:0.00}";
|
||||||
|
else if (_movementSpeed < 100.0f)
|
||||||
|
return "{0:0.0}";
|
||||||
|
else
|
||||||
|
return "{0:#}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the camera movement speed.
|
/// Gets or sets the camera movement speed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -197,19 +236,40 @@ namespace FlaxEditor.Viewport
|
|||||||
get => _movementSpeed;
|
get => _movementSpeed;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
for (int i = 0; i < EditorViewportCameraSpeedValues.Length; i++)
|
_movementSpeed = value;
|
||||||
{
|
|
||||||
if (Math.Abs(value - EditorViewportCameraSpeedValues[i]) < 0.001f)
|
if (_cameraButton != null)
|
||||||
{
|
_cameraButton.Text = string.Format(MovementSpeedTextFormat, _movementSpeed);
|
||||||
_movementSpeed = EditorViewportCameraSpeedValues[i];
|
|
||||||
if (_speedWidget != null)
|
|
||||||
_speedWidget.Text = _movementSpeed.ToString();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the minimum camera movement speed.
|
||||||
|
/// </summary>
|
||||||
|
public float MinMovementSpeed
|
||||||
|
{
|
||||||
|
get => _minMovementSpeed;
|
||||||
|
set => _minMovementSpeed = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the maximum camera movement speed.
|
||||||
|
/// </summary>
|
||||||
|
public float MaxMovementSpeed
|
||||||
|
{
|
||||||
|
get => _maxMovementSpeed;
|
||||||
|
set => _maxMovementSpeed = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the camera easing mode.
|
||||||
|
/// </summary>
|
||||||
|
public bool UseCameraEasing
|
||||||
|
{
|
||||||
|
get => _useCameraEasing;
|
||||||
|
set => _useCameraEasing = value;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the mouse movement position delta (user press and move).
|
/// Gets the mouse movement position delta (user press and move).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -396,6 +456,15 @@ namespace FlaxEditor.Viewport
|
|||||||
set => _isOrtho = value;
|
set => _isOrtho = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets if the panning speed should be relative to the camera target.
|
||||||
|
/// </summary>
|
||||||
|
public bool RelativePanning
|
||||||
|
{
|
||||||
|
get => _relativePanning;
|
||||||
|
set => _relativePanning = value;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets if the panning direction is inverted.
|
/// Gets or sets if the panning direction is inverted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -405,6 +474,15 @@ namespace FlaxEditor.Viewport
|
|||||||
set => _invertPanning = value;
|
set => _invertPanning = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the camera panning speed.
|
||||||
|
/// </summary>
|
||||||
|
public float PanningSpeed
|
||||||
|
{
|
||||||
|
get => _panningSpeed;
|
||||||
|
set => _panningSpeed = value;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The input actions collection to processed during user input.
|
/// The input actions collection to processed during user input.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -419,6 +497,8 @@ namespace FlaxEditor.Viewport
|
|||||||
public EditorViewport(SceneRenderTask task, ViewportCamera camera, bool useWidgets)
|
public EditorViewport(SceneRenderTask task, ViewportCamera camera, bool useWidgets)
|
||||||
: base(task)
|
: base(task)
|
||||||
{
|
{
|
||||||
|
_editor = Editor.Instance;
|
||||||
|
|
||||||
_mouseAccelerationScale = 0.1f;
|
_mouseAccelerationScale = 0.1f;
|
||||||
_useMouseFiltering = false;
|
_useMouseFiltering = false;
|
||||||
_useMouseAcceleration = false;
|
_useMouseAcceleration = false;
|
||||||
@@ -431,43 +511,299 @@ namespace FlaxEditor.Viewport
|
|||||||
|
|
||||||
// Setup options
|
// Setup options
|
||||||
{
|
{
|
||||||
var options = Editor.Instance.Options.Options;
|
|
||||||
_movementSpeed = options.Viewport.DefaultMovementSpeed;
|
|
||||||
_nearPlane = options.Viewport.DefaultNearPlane;
|
|
||||||
_farPlane = options.Viewport.DefaultFarPlane;
|
|
||||||
_fieldOfView = options.Viewport.DefaultFieldOfView;
|
|
||||||
_invertPanning = options.Viewport.DefaultInvertPanning;
|
|
||||||
|
|
||||||
Editor.Instance.Options.OptionsChanged += OnEditorOptionsChanged;
|
Editor.Instance.Options.OptionsChanged += OnEditorOptionsChanged;
|
||||||
OnEditorOptionsChanged(options);
|
SetupViewportOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize camera values from cache
|
||||||
|
if (_editor.ProjectCache.TryGetCustomData("CameraMovementSpeedValue", out var cachedState))
|
||||||
|
MovementSpeed = float.Parse(cachedState);
|
||||||
|
if (_editor.ProjectCache.TryGetCustomData("CameraMinMovementSpeedValue", out cachedState))
|
||||||
|
_minMovementSpeed = float.Parse(cachedState);
|
||||||
|
if (_editor.ProjectCache.TryGetCustomData("CameraMaxMovementSpeedValue", out cachedState))
|
||||||
|
_maxMovementSpeed = float.Parse(cachedState);
|
||||||
|
if (_editor.ProjectCache.TryGetCustomData("UseCameraEasingState", out cachedState))
|
||||||
|
_useCameraEasing = bool.Parse(cachedState);
|
||||||
|
if (_editor.ProjectCache.TryGetCustomData("CameraPanningSpeedValue", out cachedState))
|
||||||
|
_panningSpeed = float.Parse(cachedState);
|
||||||
|
if (_editor.ProjectCache.TryGetCustomData("CameraInvertPanningState", out cachedState))
|
||||||
|
_invertPanning = bool.Parse(cachedState);
|
||||||
|
if (_editor.ProjectCache.TryGetCustomData("CameraRelativePanningState", out cachedState))
|
||||||
|
_relativePanning = bool.Parse(cachedState);
|
||||||
|
if (_editor.ProjectCache.TryGetCustomData("CameraOrthographicState", out cachedState))
|
||||||
|
_isOrtho = bool.Parse(cachedState);
|
||||||
|
if (_editor.ProjectCache.TryGetCustomData("CameraOrthographicSizeValue", out cachedState))
|
||||||
|
_orthoSize = float.Parse(cachedState);
|
||||||
|
if (_editor.ProjectCache.TryGetCustomData("CameraFieldOfViewValue", out cachedState))
|
||||||
|
_fieldOfView = float.Parse(cachedState);
|
||||||
|
if (_editor.ProjectCache.TryGetCustomData("CameraNearPlaneValue", out cachedState))
|
||||||
|
_nearPlane = float.Parse(cachedState);
|
||||||
|
if (_editor.ProjectCache.TryGetCustomData("CameraFarPlaneValue", out cachedState))
|
||||||
|
_farPlane = float.Parse(cachedState);
|
||||||
|
|
||||||
|
OnCameraMovementProgressChanged();
|
||||||
|
|
||||||
if (useWidgets)
|
if (useWidgets)
|
||||||
{
|
{
|
||||||
var largestText = "Invert Panning";
|
#region Camera settings widget
|
||||||
|
|
||||||
|
var largestText = "Relative Panning";
|
||||||
var textSize = Style.Current.FontMedium.MeasureText(largestText);
|
var textSize = Style.Current.FontMedium.MeasureText(largestText);
|
||||||
var xLocationForExtras = textSize.X + 5;
|
var xLocationForExtras = textSize.X + 5;
|
||||||
// Camera speed widget
|
var cameraSpeedTextWidth = Style.Current.FontMedium.MeasureText("0.00").X;
|
||||||
var camSpeed = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
|
|
||||||
var camSpeedCM = new ContextMenu();
|
// Camera Settings Widget
|
||||||
var camSpeedButton = new ViewportWidgetButton(_movementSpeed.ToString(), Editor.Instance.Icons.CamSpeed32, camSpeedCM)
|
_cameraWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
|
||||||
|
|
||||||
|
// Camera Settings Menu
|
||||||
|
var cameraCM = new ContextMenu();
|
||||||
|
_cameraButton = new ViewportWidgetButton(string.Format(MovementSpeedTextFormat, _movementSpeed), Editor.Instance.Icons.Camera64, cameraCM, false, cameraSpeedTextWidth)
|
||||||
{
|
{
|
||||||
Tag = this,
|
Tag = this,
|
||||||
TooltipText = "Camera speed scale"
|
TooltipText = "Camera Settings",
|
||||||
|
Parent = _cameraWidget
|
||||||
};
|
};
|
||||||
_speedWidget = camSpeedButton;
|
_cameraWidget.Parent = this;
|
||||||
for (int i = 0; i < EditorViewportCameraSpeedValues.Length; i++)
|
|
||||||
{
|
// Orthographic/Perspective Mode Widget
|
||||||
var v = EditorViewportCameraSpeedValues[i];
|
_orthographicModeButton = new ViewportWidgetButton(string.Empty, Editor.Instance.Icons.CamSpeed32, null, true)
|
||||||
var button = camSpeedCM.AddButton(v.ToString());
|
{
|
||||||
button.Tag = v;
|
Checked = !_isOrtho,
|
||||||
}
|
TooltipText = "Toggle Orthographic/Perspective Mode",
|
||||||
camSpeedCM.ButtonClicked += button => MovementSpeed = (float)button.Tag;
|
Parent = _cameraWidget
|
||||||
camSpeedCM.VisibleChanged += WidgetCamSpeedShowHide;
|
};
|
||||||
camSpeedButton.Parent = camSpeed;
|
_orthographicModeButton.Toggled += OnOrthographicModeToggled;
|
||||||
camSpeed.Parent = this;
|
|
||||||
|
// Camera Speed
|
||||||
|
var camSpeedButton = cameraCM.AddButton("Camera Speed");
|
||||||
|
camSpeedButton.CloseMenuOnClick = false;
|
||||||
|
var camSpeedValue = new FloatValueBox(_movementSpeed, xLocationForExtras, 2, 70.0f, _minMovementSpeed, _maxMovementSpeed, 0.5f)
|
||||||
|
{
|
||||||
|
Parent = camSpeedButton
|
||||||
|
};
|
||||||
|
|
||||||
|
camSpeedValue.ValueChanged += () => OnMovementSpeedChanged(camSpeedValue);
|
||||||
|
cameraCM.VisibleChanged += control => camSpeedValue.Value = _movementSpeed;
|
||||||
|
|
||||||
|
// Minimum & Maximum Camera Speed
|
||||||
|
var minCamSpeedButton = cameraCM.AddButton("Min Cam Speed");
|
||||||
|
minCamSpeedButton.CloseMenuOnClick = false;
|
||||||
|
var minCamSpeedValue = new FloatValueBox(_minMovementSpeed, xLocationForExtras, 2, 70.0f, 0.05f, _maxMovementSpeed, 0.5f)
|
||||||
|
{
|
||||||
|
Parent = minCamSpeedButton
|
||||||
|
};
|
||||||
|
var maxCamSpeedButton = cameraCM.AddButton("Max Cam Speed");
|
||||||
|
maxCamSpeedButton.CloseMenuOnClick = false;
|
||||||
|
var maxCamSpeedValue = new FloatValueBox(_maxMovementSpeed, xLocationForExtras, 2, 70.0f, _minMovementSpeed, 1000.0f, 0.5f)
|
||||||
|
{
|
||||||
|
Parent = maxCamSpeedButton
|
||||||
|
};
|
||||||
|
|
||||||
|
minCamSpeedValue.ValueChanged += () =>
|
||||||
|
{
|
||||||
|
OnMinMovementSpeedChanged(minCamSpeedValue);
|
||||||
|
|
||||||
|
maxCamSpeedValue.MinValue = minCamSpeedValue.Value;
|
||||||
|
|
||||||
|
if (Math.Abs(camSpeedValue.MinValue - minCamSpeedValue.Value) > Mathf.Epsilon)
|
||||||
|
camSpeedValue.MinValue = minCamSpeedValue.Value;
|
||||||
|
};
|
||||||
|
cameraCM.VisibleChanged += control => minCamSpeedValue.Value = _minMovementSpeed;
|
||||||
|
maxCamSpeedValue.ValueChanged += () =>
|
||||||
|
{
|
||||||
|
OnMaxMovementSpeedChanged(maxCamSpeedValue);
|
||||||
|
|
||||||
|
minCamSpeedValue.MaxValue = maxCamSpeedValue.Value;
|
||||||
|
|
||||||
|
if (Math.Abs(camSpeedValue.MaxValue - maxCamSpeedValue.Value) > Mathf.Epsilon)
|
||||||
|
camSpeedValue.MaxValue = maxCamSpeedValue.Value;
|
||||||
|
};
|
||||||
|
cameraCM.VisibleChanged += control => maxCamSpeedValue.Value = _maxMovementSpeed;
|
||||||
|
|
||||||
|
// Camera Easing
|
||||||
|
{
|
||||||
|
var useCameraEasing = cameraCM.AddButton("Camera Easing");
|
||||||
|
useCameraEasing.CloseMenuOnClick = false;
|
||||||
|
var useCameraEasingValue = new CheckBox(xLocationForExtras, 2, _useCameraEasing)
|
||||||
|
{
|
||||||
|
Parent = useCameraEasing
|
||||||
|
};
|
||||||
|
|
||||||
|
useCameraEasingValue.StateChanged += OnCameraEasingToggled;
|
||||||
|
cameraCM.VisibleChanged += control => useCameraEasingValue.Checked = _useCameraEasing;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Panning Speed
|
||||||
|
{
|
||||||
|
var panningSpeed = cameraCM.AddButton("Panning Speed");
|
||||||
|
panningSpeed.CloseMenuOnClick = false;
|
||||||
|
var panningSpeedValue = new FloatValueBox(_panningSpeed, xLocationForExtras, 2, 70.0f, 0.01f, 128.0f, 0.1f)
|
||||||
|
{
|
||||||
|
Parent = panningSpeed
|
||||||
|
};
|
||||||
|
|
||||||
|
panningSpeedValue.ValueChanged += () => OnPanningSpeedChanged(panningSpeedValue);
|
||||||
|
cameraCM.VisibleChanged += control =>
|
||||||
|
{
|
||||||
|
panningSpeed.Visible = !_relativePanning;
|
||||||
|
panningSpeedValue.Value = _panningSpeed;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relative Panning
|
||||||
|
{
|
||||||
|
var relativePanning = cameraCM.AddButton("Relative Panning");
|
||||||
|
relativePanning.CloseMenuOnClick = false;
|
||||||
|
var relativePanningValue = new CheckBox(xLocationForExtras, 2, _relativePanning)
|
||||||
|
{
|
||||||
|
Parent = relativePanning
|
||||||
|
};
|
||||||
|
|
||||||
|
relativePanningValue.StateChanged += checkBox =>
|
||||||
|
{
|
||||||
|
if (checkBox.Checked != _relativePanning)
|
||||||
|
{
|
||||||
|
OnRelativePanningToggled(checkBox);
|
||||||
|
cameraCM.Hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cameraCM.VisibleChanged += control => relativePanningValue.Checked = _relativePanning;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invert Panning
|
||||||
|
{
|
||||||
|
var invertPanning = cameraCM.AddButton("Invert Panning");
|
||||||
|
invertPanning.CloseMenuOnClick = false;
|
||||||
|
var invertPanningValue = new CheckBox(xLocationForExtras, 2, _invertPanning)
|
||||||
|
{
|
||||||
|
Parent = invertPanning
|
||||||
|
};
|
||||||
|
|
||||||
|
invertPanningValue.StateChanged += OnInvertPanningToggled;
|
||||||
|
cameraCM.VisibleChanged += control => invertPanningValue.Checked = _invertPanning;
|
||||||
|
}
|
||||||
|
|
||||||
|
cameraCM.AddSeparator();
|
||||||
|
|
||||||
|
// Camera Viewpoints
|
||||||
|
{
|
||||||
|
var cameraView = cameraCM.AddChildMenu("Viewpoints").ContextMenu;
|
||||||
|
for (int i = 0; i < EditorViewportCameraViewpointValues.Length; i++)
|
||||||
|
{
|
||||||
|
var co = EditorViewportCameraViewpointValues[i];
|
||||||
|
var button = cameraView.AddButton(co.Name);
|
||||||
|
button.Tag = co.Orientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
cameraView.ButtonClicked += OnViewpointChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Orthographic Mode
|
||||||
|
{
|
||||||
|
var ortho = cameraCM.AddButton("Orthographic");
|
||||||
|
ortho.CloseMenuOnClick = false;
|
||||||
|
var orthoValue = new CheckBox(xLocationForExtras, 2, _isOrtho)
|
||||||
|
{
|
||||||
|
Parent = ortho
|
||||||
|
};
|
||||||
|
|
||||||
|
orthoValue.StateChanged += checkBox =>
|
||||||
|
{
|
||||||
|
if (checkBox.Checked != _isOrtho)
|
||||||
|
{
|
||||||
|
OnOrthographicModeToggled(checkBox);
|
||||||
|
cameraCM.Hide();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cameraCM.VisibleChanged += control => orthoValue.Checked = _isOrtho;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field of View
|
||||||
|
{
|
||||||
|
var fov = cameraCM.AddButton("Field Of View");
|
||||||
|
fov.CloseMenuOnClick = false;
|
||||||
|
var fovValue = new FloatValueBox(_fieldOfView, xLocationForExtras, 2, 70.0f, 35.0f, 160.0f, 0.1f)
|
||||||
|
{
|
||||||
|
Parent = fov
|
||||||
|
};
|
||||||
|
|
||||||
|
fovValue.ValueChanged += () => OnFieldOfViewChanged(fovValue);
|
||||||
|
cameraCM.VisibleChanged += control =>
|
||||||
|
{
|
||||||
|
fov.Visible = !_isOrtho;
|
||||||
|
fovValue.Value = _fieldOfView;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Orthographic Scale
|
||||||
|
{
|
||||||
|
var orthoSize = cameraCM.AddButton("Ortho Scale");
|
||||||
|
orthoSize.CloseMenuOnClick = false;
|
||||||
|
var orthoSizeValue = new FloatValueBox(_orthoSize, xLocationForExtras, 2, 70.0f, 0.001f, 100000.0f, 0.01f)
|
||||||
|
{
|
||||||
|
Parent = orthoSize
|
||||||
|
};
|
||||||
|
|
||||||
|
orthoSizeValue.ValueChanged += () => OnOrthographicSizeChanged(orthoSizeValue);
|
||||||
|
cameraCM.VisibleChanged += control =>
|
||||||
|
{
|
||||||
|
orthoSize.Visible = _isOrtho;
|
||||||
|
orthoSizeValue.Value = _orthoSize;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Near Plane
|
||||||
|
{
|
||||||
|
var nearPlane = cameraCM.AddButton("Near Plane");
|
||||||
|
nearPlane.CloseMenuOnClick = false;
|
||||||
|
var nearPlaneValue = new FloatValueBox(_nearPlane, xLocationForExtras, 2, 70.0f, 0.001f, 1000.0f)
|
||||||
|
{
|
||||||
|
Parent = nearPlane
|
||||||
|
};
|
||||||
|
|
||||||
|
nearPlaneValue.ValueChanged += () => OnNearPlaneChanged(nearPlaneValue);
|
||||||
|
cameraCM.VisibleChanged += control => nearPlaneValue.Value = _nearPlane;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Far Plane
|
||||||
|
{
|
||||||
|
var farPlane = cameraCM.AddButton("Far Plane");
|
||||||
|
farPlane.CloseMenuOnClick = false;
|
||||||
|
var farPlaneValue = new FloatValueBox(_farPlane, xLocationForExtras, 2, 70.0f, 10.0f)
|
||||||
|
{
|
||||||
|
Parent = farPlane
|
||||||
|
};
|
||||||
|
|
||||||
|
farPlaneValue.ValueChanged += () => OnFarPlaneChanged(farPlaneValue);
|
||||||
|
cameraCM.VisibleChanged += control => farPlaneValue.Value = _farPlane;
|
||||||
|
}
|
||||||
|
|
||||||
|
cameraCM.AddSeparator();
|
||||||
|
|
||||||
|
// Reset Button
|
||||||
|
{
|
||||||
|
var reset = cameraCM.AddButton("Reset to default");
|
||||||
|
reset.ButtonClicked += button =>
|
||||||
|
{
|
||||||
|
SetupViewportOptions();
|
||||||
|
|
||||||
|
// if the context menu is opened without triggering the value changes beforehand,
|
||||||
|
// the movement speed will not be correctly reset to its default value in certain cases
|
||||||
|
// therefore, a UI update needs to be triggered here
|
||||||
|
minCamSpeedValue.Value = _minMovementSpeed;
|
||||||
|
camSpeedValue.Value = _movementSpeed;
|
||||||
|
maxCamSpeedValue.Value = _maxMovementSpeed;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Camera settings widget
|
||||||
|
|
||||||
|
#region View mode widget
|
||||||
|
|
||||||
|
largestText = "Brightness";
|
||||||
|
textSize = Style.Current.FontMedium.MeasureText(largestText);
|
||||||
|
xLocationForExtras = textSize.X + 5;
|
||||||
|
|
||||||
// View mode widget
|
|
||||||
var viewMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperLeft);
|
var viewMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperLeft);
|
||||||
ViewWidgetButtonMenu = new ContextMenu();
|
ViewWidgetButtonMenu = new ContextMenu();
|
||||||
var viewModeButton = new ViewportWidgetButton("View", SpriteHandle.Invalid, ViewWidgetButtonMenu)
|
var viewModeButton = new ViewportWidgetButton("View", SpriteHandle.Invalid, ViewWidgetButtonMenu)
|
||||||
@@ -484,8 +820,8 @@ namespace FlaxEditor.Viewport
|
|||||||
// Show FPS
|
// Show FPS
|
||||||
{
|
{
|
||||||
InitFpsCounter();
|
InitFpsCounter();
|
||||||
_showFpsButon = ViewWidgetShowMenu.AddButton("FPS Counter", () => ShowFpsCounter = !ShowFpsCounter);
|
_showFpsButton = ViewWidgetShowMenu.AddButton("FPS Counter", () => ShowFpsCounter = !ShowFpsCounter);
|
||||||
_showFpsButon.CloseMenuOnClick = false;
|
_showFpsButton.CloseMenuOnClick = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -610,104 +946,6 @@ namespace FlaxEditor.Viewport
|
|||||||
|
|
||||||
ViewWidgetButtonMenu.AddSeparator();
|
ViewWidgetButtonMenu.AddSeparator();
|
||||||
|
|
||||||
// Orthographic
|
|
||||||
{
|
|
||||||
var ortho = ViewWidgetButtonMenu.AddButton("Orthographic");
|
|
||||||
ortho.CloseMenuOnClick = false;
|
|
||||||
var orthoValue = new CheckBox(xLocationForExtras, 2, _isOrtho)
|
|
||||||
{
|
|
||||||
Parent = ortho
|
|
||||||
};
|
|
||||||
orthoValue.StateChanged += checkBox =>
|
|
||||||
{
|
|
||||||
if (checkBox.Checked != _isOrtho)
|
|
||||||
{
|
|
||||||
_isOrtho = checkBox.Checked;
|
|
||||||
ViewWidgetButtonMenu.Hide();
|
|
||||||
if (_isOrtho)
|
|
||||||
{
|
|
||||||
var orient = ViewOrientation;
|
|
||||||
OrientViewport(ref orient);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ViewWidgetButtonMenu.VisibleChanged += control => orthoValue.Checked = _isOrtho;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Camera Viewpoints
|
|
||||||
{
|
|
||||||
var cameraView = ViewWidgetButtonMenu.AddChildMenu("Viewpoints").ContextMenu;
|
|
||||||
for (int i = 0; i < EditorViewportCameraViewpointValues.Length; i++)
|
|
||||||
{
|
|
||||||
var co = EditorViewportCameraViewpointValues[i];
|
|
||||||
var button = cameraView.AddButton(co.Name);
|
|
||||||
button.Tag = co.Orientation;
|
|
||||||
}
|
|
||||||
cameraView.ButtonClicked += button =>
|
|
||||||
{
|
|
||||||
var orient = Quaternion.Euler((Float3)button.Tag);
|
|
||||||
OrientViewport(ref orient);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Field of View
|
|
||||||
{
|
|
||||||
var fov = ViewWidgetButtonMenu.AddButton("Field Of View");
|
|
||||||
fov.CloseMenuOnClick = false;
|
|
||||||
var fovValue = new FloatValueBox(1, xLocationForExtras, 2, 70.0f, 35.0f, 160.0f, 0.1f)
|
|
||||||
{
|
|
||||||
Parent = fov
|
|
||||||
};
|
|
||||||
|
|
||||||
fovValue.ValueChanged += () => _fieldOfView = fovValue.Value;
|
|
||||||
ViewWidgetButtonMenu.VisibleChanged += control =>
|
|
||||||
{
|
|
||||||
fov.Visible = !_isOrtho;
|
|
||||||
fovValue.Value = _fieldOfView;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ortho Scale
|
|
||||||
{
|
|
||||||
var orthoSize = ViewWidgetButtonMenu.AddButton("Ortho Scale");
|
|
||||||
orthoSize.CloseMenuOnClick = false;
|
|
||||||
var orthoSizeValue = new FloatValueBox(_orthoSize, xLocationForExtras, 2, 70.0f, 0.001f, 100000.0f, 0.01f)
|
|
||||||
{
|
|
||||||
Parent = orthoSize
|
|
||||||
};
|
|
||||||
|
|
||||||
orthoSizeValue.ValueChanged += () => _orthoSize = orthoSizeValue.Value;
|
|
||||||
ViewWidgetButtonMenu.VisibleChanged += control =>
|
|
||||||
{
|
|
||||||
orthoSize.Visible = _isOrtho;
|
|
||||||
orthoSizeValue.Value = _orthoSize;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Near Plane
|
|
||||||
{
|
|
||||||
var nearPlane = ViewWidgetButtonMenu.AddButton("Near Plane");
|
|
||||||
nearPlane.CloseMenuOnClick = false;
|
|
||||||
var nearPlaneValue = new FloatValueBox(2.0f, xLocationForExtras, 2, 70.0f, 0.001f, 1000.0f)
|
|
||||||
{
|
|
||||||
Parent = nearPlane
|
|
||||||
};
|
|
||||||
nearPlaneValue.ValueChanged += () => _nearPlane = nearPlaneValue.Value;
|
|
||||||
ViewWidgetButtonMenu.VisibleChanged += control => nearPlaneValue.Value = _nearPlane;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Far Plane
|
|
||||||
{
|
|
||||||
var farPlane = ViewWidgetButtonMenu.AddButton("Far Plane");
|
|
||||||
farPlane.CloseMenuOnClick = false;
|
|
||||||
var farPlaneValue = new FloatValueBox(1000, xLocationForExtras, 2, 70.0f, 10.0f)
|
|
||||||
{
|
|
||||||
Parent = farPlane
|
|
||||||
};
|
|
||||||
farPlaneValue.ValueChanged += () => _farPlane = farPlaneValue.Value;
|
|
||||||
ViewWidgetButtonMenu.VisibleChanged += control => farPlaneValue.Value = _farPlane;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Brightness
|
// Brightness
|
||||||
{
|
{
|
||||||
var brightness = ViewWidgetButtonMenu.AddButton("Brightness");
|
var brightness = ViewWidgetButtonMenu.AddButton("Brightness");
|
||||||
@@ -732,24 +970,7 @@ namespace FlaxEditor.Viewport
|
|||||||
ViewWidgetButtonMenu.VisibleChanged += control => resolutionValue.Value = ResolutionScale;
|
ViewWidgetButtonMenu.VisibleChanged += control => resolutionValue.Value = ResolutionScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invert Panning
|
#endregion View mode widget
|
||||||
{
|
|
||||||
var invert = ViewWidgetButtonMenu.AddButton("Invert Panning");
|
|
||||||
invert.CloseMenuOnClick = false;
|
|
||||||
var invertValue = new CheckBox(xLocationForExtras, 2, _invertPanning)
|
|
||||||
{
|
|
||||||
Parent = invert
|
|
||||||
};
|
|
||||||
|
|
||||||
invertValue.StateChanged += checkBox =>
|
|
||||||
{
|
|
||||||
if (checkBox.Checked != _invertPanning)
|
|
||||||
{
|
|
||||||
_invertPanning = checkBox.Checked;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ViewWidgetButtonMenu.VisibleChanged += control => invertValue.Checked = _invertPanning;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InputActions.Add(options => options.ViewpointTop, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Top").Orientation)));
|
InputActions.Add(options => options.ViewpointTop, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Top").Orientation)));
|
||||||
@@ -766,6 +987,135 @@ namespace FlaxEditor.Viewport
|
|||||||
task.Begin += OnRenderBegin;
|
task.Begin += OnRenderBegin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the viewport options to the default values.
|
||||||
|
/// </summary>
|
||||||
|
private void SetupViewportOptions()
|
||||||
|
{
|
||||||
|
var options = Editor.Instance.Options.Options;
|
||||||
|
_minMovementSpeed = options.Viewport.MinMovementSpeed;
|
||||||
|
MovementSpeed = options.Viewport.MovementSpeed;
|
||||||
|
_maxMovementSpeed = options.Viewport.MaxMovementSpeed;
|
||||||
|
_useCameraEasing = options.Viewport.UseCameraEasing;
|
||||||
|
_panningSpeed = options.Viewport.PanningSpeed;
|
||||||
|
_invertPanning = options.Viewport.InvertPanning;
|
||||||
|
_relativePanning = options.Viewport.UseRelativePanning;
|
||||||
|
|
||||||
|
_isOrtho = options.Viewport.UseOrthographicProjection;
|
||||||
|
_orthoSize = options.Viewport.OrthographicScale;
|
||||||
|
_fieldOfView = options.Viewport.FieldOfView;
|
||||||
|
_nearPlane = options.Viewport.NearPlane;
|
||||||
|
_farPlane = options.Viewport.FarPlane;
|
||||||
|
|
||||||
|
OnEditorOptionsChanged(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMovementSpeedChanged(FloatValueBox control)
|
||||||
|
{
|
||||||
|
var value = Mathf.Clamp(control.Value, _minMovementSpeed, _maxMovementSpeed);
|
||||||
|
MovementSpeed = value;
|
||||||
|
|
||||||
|
OnCameraMovementProgressChanged();
|
||||||
|
_editor.ProjectCache.SetCustomData("CameraMovementSpeedValue", _movementSpeed.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMinMovementSpeedChanged(FloatValueBox control)
|
||||||
|
{
|
||||||
|
var value = Mathf.Clamp(control.Value, 0.05f, _maxMovementSpeed);
|
||||||
|
_minMovementSpeed = value;
|
||||||
|
|
||||||
|
if (_movementSpeed < value)
|
||||||
|
MovementSpeed = value;
|
||||||
|
|
||||||
|
OnCameraMovementProgressChanged();
|
||||||
|
_editor.ProjectCache.SetCustomData("CameraMinMovementSpeedValue", _minMovementSpeed.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMaxMovementSpeedChanged(FloatValueBox control)
|
||||||
|
{
|
||||||
|
var value = Mathf.Clamp(control.Value, _minMovementSpeed, 1000.0f);
|
||||||
|
_maxMovementSpeed = value;
|
||||||
|
|
||||||
|
if (_movementSpeed > value)
|
||||||
|
MovementSpeed = value;
|
||||||
|
|
||||||
|
OnCameraMovementProgressChanged();
|
||||||
|
_editor.ProjectCache.SetCustomData("CameraMaxMovementSpeedValue", _maxMovementSpeed.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCameraEasingToggled(Control control)
|
||||||
|
{
|
||||||
|
_useCameraEasing = !_useCameraEasing;
|
||||||
|
|
||||||
|
OnCameraMovementProgressChanged();
|
||||||
|
_editor.ProjectCache.SetCustomData("UseCameraEasingState", _useCameraEasing.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPanningSpeedChanged(FloatValueBox control)
|
||||||
|
{
|
||||||
|
_panningSpeed = control.Value;
|
||||||
|
_editor.ProjectCache.SetCustomData("CameraPanningSpeedValue", _panningSpeed.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRelativePanningToggled(Control control)
|
||||||
|
{
|
||||||
|
_relativePanning = !_relativePanning;
|
||||||
|
_editor.ProjectCache.SetCustomData("CameraRelativePanningState", _relativePanning.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInvertPanningToggled(Control control)
|
||||||
|
{
|
||||||
|
_invertPanning = !_invertPanning;
|
||||||
|
_editor.ProjectCache.SetCustomData("CameraInvertPanningState", _invertPanning.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void OnViewpointChanged(ContextMenuButton button)
|
||||||
|
{
|
||||||
|
var orient = Quaternion.Euler((Float3)button.Tag);
|
||||||
|
OrientViewport(ref orient);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnFieldOfViewChanged(FloatValueBox control)
|
||||||
|
{
|
||||||
|
_fieldOfView = control.Value;
|
||||||
|
_editor.ProjectCache.SetCustomData("CameraFieldOfViewValue", _fieldOfView.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnOrthographicModeToggled(Control control)
|
||||||
|
{
|
||||||
|
_isOrtho = !_isOrtho;
|
||||||
|
|
||||||
|
if (_orthographicModeButton != null)
|
||||||
|
_orthographicModeButton.Checked = !_isOrtho;
|
||||||
|
|
||||||
|
if (_isOrtho)
|
||||||
|
{
|
||||||
|
var orient = ViewOrientation;
|
||||||
|
OrientViewport(ref orient);
|
||||||
|
}
|
||||||
|
|
||||||
|
_editor.ProjectCache.SetCustomData("CameraOrthographicState", _isOrtho.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnOrthographicSizeChanged(FloatValueBox control)
|
||||||
|
{
|
||||||
|
_orthoSize = control.Value;
|
||||||
|
_editor.ProjectCache.SetCustomData("CameraOrthographicSizeValue", _orthoSize.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnNearPlaneChanged(FloatValueBox control)
|
||||||
|
{
|
||||||
|
_nearPlane = control.Value;
|
||||||
|
_editor.ProjectCache.SetCustomData("CameraNearPlaneValue", _nearPlane.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnFarPlaneChanged(FloatValueBox control)
|
||||||
|
{
|
||||||
|
_farPlane = control.Value;
|
||||||
|
_editor.ProjectCache.SetCustomData("CameraNearPlaneValue", _farPlane.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether this viewport is using mouse currently (eg. user moving objects).
|
/// Gets a value indicating whether this viewport is using mouse currently (eg. user moving objects).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -798,33 +1148,59 @@ namespace FlaxEditor.Viewport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnCameraMovementProgressChanged()
|
||||||
|
{
|
||||||
|
// prevent NaN
|
||||||
|
if (Math.Abs(_minMovementSpeed - _maxMovementSpeed) < Mathf.Epsilon)
|
||||||
|
{
|
||||||
|
_speedStep = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.Abs(_movementSpeed - _maxMovementSpeed) < Mathf.Epsilon)
|
||||||
|
{
|
||||||
|
_speedStep = _maxSpeedSteps;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (Math.Abs(_movementSpeed - _minMovementSpeed) < Mathf.Epsilon)
|
||||||
|
{
|
||||||
|
_speedStep = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate current linear/eased progress
|
||||||
|
var progress = Mathf.Remap(_movementSpeed, _minMovementSpeed, _maxMovementSpeed, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
if (_useCameraEasing)
|
||||||
|
progress = Mathf.Pow(progress, 1.0f / _cameraEasingDegree);
|
||||||
|
|
||||||
|
_speedStep = Mathf.RoundToInt(progress * _maxSpeedSteps);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Increases or decreases the camera movement speed.
|
/// Increases or decreases the camera movement speed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="step">The stepping direction for speed adjustment.</param>
|
/// <param name="step">The stepping direction for speed adjustment.</param>
|
||||||
protected void AdjustCameraMoveSpeed(int step)
|
protected void AdjustCameraMoveSpeed(int step)
|
||||||
{
|
{
|
||||||
int camValueIndex = -1;
|
_speedStep = Mathf.Clamp(_speedStep + step, 0, _maxSpeedSteps);
|
||||||
for (int i = 0; i < EditorViewportCameraSpeedValues.Length; i++)
|
|
||||||
{
|
|
||||||
if (Mathf.NearEqual(EditorViewportCameraSpeedValues[i], _movementSpeed))
|
|
||||||
{
|
|
||||||
camValueIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (camValueIndex == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (step > 0)
|
// calculate new linear/eased progress
|
||||||
MovementSpeed = EditorViewportCameraSpeedValues[Mathf.Min(camValueIndex + 1, EditorViewportCameraSpeedValues.Length - 1)];
|
var progress = _useCameraEasing
|
||||||
else if (step < 0)
|
? Mathf.Pow((float)_speedStep / _maxSpeedSteps, _cameraEasingDegree)
|
||||||
MovementSpeed = EditorViewportCameraSpeedValues[Mathf.Max(camValueIndex - 1, 0)];
|
: (float)_speedStep / _maxSpeedSteps;
|
||||||
|
|
||||||
|
var speed = Mathf.Lerp(_minMovementSpeed, _maxMovementSpeed, progress);
|
||||||
|
MovementSpeed = (float)Math.Round(speed, 3);
|
||||||
|
_editor.ProjectCache.SetCustomData("CameraMovementSpeedValue", _movementSpeed.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEditorOptionsChanged(EditorOptions options)
|
private void OnEditorOptionsChanged(EditorOptions options)
|
||||||
{
|
{
|
||||||
_mouseSensitivity = options.Viewport.MouseSensitivity;
|
_mouseSensitivity = options.Viewport.MouseSensitivity;
|
||||||
|
_maxSpeedSteps = options.Viewport.TotalCameraSpeedSteps;
|
||||||
|
_cameraEasingDegree = options.Viewport.CameraEasingDegree;
|
||||||
|
OnCameraMovementProgressChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnRenderBegin(RenderTask task, GPUContext context)
|
private void OnRenderBegin(RenderTask task, GPUContext context)
|
||||||
@@ -863,7 +1239,7 @@ namespace FlaxEditor.Viewport
|
|||||||
}
|
}
|
||||||
|
|
||||||
private FpsCounter _fpsCounter;
|
private FpsCounter _fpsCounter;
|
||||||
private ContextMenuButton _showFpsButon;
|
private ContextMenuButton _showFpsButton;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether show or hide FPS counter.
|
/// Gets or sets a value indicating whether show or hide FPS counter.
|
||||||
@@ -875,7 +1251,7 @@ namespace FlaxEditor.Viewport
|
|||||||
{
|
{
|
||||||
_fpsCounter.Visible = value;
|
_fpsCounter.Visible = value;
|
||||||
_fpsCounter.Enabled = value;
|
_fpsCounter.Enabled = value;
|
||||||
_showFpsButon.Icon = value ? Style.Current.CheckBoxTick : SpriteHandle.Invalid;
|
_showFpsButton.Icon = value ? Style.Current.CheckBoxTick : SpriteHandle.Invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1016,8 +1392,6 @@ namespace FlaxEditor.Viewport
|
|||||||
/// <param name="win">The parent window.</param>
|
/// <param name="win">The parent window.</param>
|
||||||
protected virtual void OnControlMouseBegin(Window win)
|
protected virtual void OnControlMouseBegin(Window win)
|
||||||
{
|
{
|
||||||
_wheelMovementChangeDeltaSum = 0;
|
|
||||||
|
|
||||||
// Hide cursor and start tracking mouse movement
|
// Hide cursor and start tracking mouse movement
|
||||||
win.StartTrackingMouse(false);
|
win.StartTrackingMouse(false);
|
||||||
win.Cursor = CursorType.Hidden;
|
win.Cursor = CursorType.Hidden;
|
||||||
@@ -1113,8 +1487,8 @@ namespace FlaxEditor.Viewport
|
|||||||
_camera.Update(deltaTime);
|
_camera.Update(deltaTime);
|
||||||
useMovementSpeed = _camera.UseMovementSpeed;
|
useMovementSpeed = _camera.UseMovementSpeed;
|
||||||
|
|
||||||
if (_speedWidget != null)
|
if (_cameraButton != null)
|
||||||
_speedWidget.Parent.Visible = useMovementSpeed;
|
_cameraButton.Parent.Visible = useMovementSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get parent window
|
// Get parent window
|
||||||
@@ -1217,18 +1591,8 @@ namespace FlaxEditor.Viewport
|
|||||||
rmbWheel = useMovementSpeed && (_input.IsMouseRightDown || _isVirtualMouseRightDown) && wheelInUse;
|
rmbWheel = useMovementSpeed && (_input.IsMouseRightDown || _isVirtualMouseRightDown) && wheelInUse;
|
||||||
if (rmbWheel)
|
if (rmbWheel)
|
||||||
{
|
{
|
||||||
const float step = 4.0f;
|
var step = _input.MouseWheelDelta * options.Viewport.MouseWheelSensitivity;
|
||||||
_wheelMovementChangeDeltaSum += _input.MouseWheelDelta * options.Viewport.MouseWheelSensitivity;
|
AdjustCameraMoveSpeed(step > 0.0f ? 1 : -1);
|
||||||
if (_wheelMovementChangeDeltaSum >= step)
|
|
||||||
{
|
|
||||||
_wheelMovementChangeDeltaSum -= step;
|
|
||||||
AdjustCameraMoveSpeed(1);
|
|
||||||
}
|
|
||||||
else if (_wheelMovementChangeDeltaSum <= -step)
|
|
||||||
{
|
|
||||||
_wheelMovementChangeDeltaSum += step;
|
|
||||||
AdjustCameraMoveSpeed(-1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1497,22 +1861,6 @@ namespace FlaxEditor.Viewport
|
|||||||
new CameraViewpoint("Bottom", new Float3(-90, 0, 0))
|
new CameraViewpoint("Bottom", new Float3(-90, 0, 0))
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly float[] EditorViewportCameraSpeedValues =
|
|
||||||
{
|
|
||||||
0.05f,
|
|
||||||
0.1f,
|
|
||||||
0.25f,
|
|
||||||
0.5f,
|
|
||||||
1.0f,
|
|
||||||
2.0f,
|
|
||||||
4.0f,
|
|
||||||
6.0f,
|
|
||||||
8.0f,
|
|
||||||
16.0f,
|
|
||||||
32.0f,
|
|
||||||
64.0f,
|
|
||||||
};
|
|
||||||
|
|
||||||
private struct ViewModeOptions
|
private struct ViewModeOptions
|
||||||
{
|
{
|
||||||
public readonly string Name;
|
public readonly string Name;
|
||||||
@@ -1568,24 +1916,6 @@ namespace FlaxEditor.Viewport
|
|||||||
new ViewModeOptions(ViewMode.GlobalIllumination, "Global Illumination"),
|
new ViewModeOptions(ViewMode.GlobalIllumination, "Global Illumination"),
|
||||||
};
|
};
|
||||||
|
|
||||||
private void WidgetCamSpeedShowHide(Control cm)
|
|
||||||
{
|
|
||||||
if (cm.Visible == false)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var ccm = (ContextMenu)cm;
|
|
||||||
foreach (var e in ccm.Items)
|
|
||||||
{
|
|
||||||
if (e is ContextMenuButton b)
|
|
||||||
{
|
|
||||||
var v = (float)b.Tag;
|
|
||||||
b.Icon = Mathf.Abs(MovementSpeed - v) < 0.001f
|
|
||||||
? Style.Current.CheckBoxTick
|
|
||||||
: SpriteHandle.Invalid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WidgetViewModeShowHideClicked(ContextMenuButton button)
|
private void WidgetViewModeShowHideClicked(ContextMenuButton button)
|
||||||
{
|
{
|
||||||
if (button.Tag is ViewMode v)
|
if (button.Tag is ViewMode v)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ namespace FlaxEditor.Viewport.Widgets
|
|||||||
private bool _checked;
|
private bool _checked;
|
||||||
private bool _autoCheck;
|
private bool _autoCheck;
|
||||||
private bool _isMosueDown;
|
private bool _isMosueDown;
|
||||||
|
private float _forcedTextWidth;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event fired when user toggles checked state.
|
/// Event fired when user toggles checked state.
|
||||||
@@ -63,14 +64,16 @@ namespace FlaxEditor.Viewport.Widgets
|
|||||||
/// <param name="text">The text.</param>
|
/// <param name="text">The text.</param>
|
||||||
/// <param name="icon">The icon.</param>
|
/// <param name="icon">The icon.</param>
|
||||||
/// <param name="contextMenu">The context menu.</param>
|
/// <param name="contextMenu">The context menu.</param>
|
||||||
/// <param name="autoCheck">if set to <c>true</c> will be automatic checked on mouse click.</param>
|
/// <param name="autoCheck">If set to <c>true</c> will be automatic checked on mouse click.</param>
|
||||||
public ViewportWidgetButton(string text, SpriteHandle icon, ContextMenu contextMenu = null, bool autoCheck = false)
|
/// <param name="textWidth">Forces the text to be drawn with the specified width.</param>
|
||||||
: base(0, 0, CalculateButtonWidth(0, icon.IsValid), ViewportWidgetsContainer.WidgetsHeight)
|
public ViewportWidgetButton(string text, SpriteHandle icon, ContextMenu contextMenu = null, bool autoCheck = false, float textWidth = 0.0f)
|
||||||
|
: base(0, 0, CalculateButtonWidth(textWidth, icon.IsValid), ViewportWidgetsContainer.WidgetsHeight)
|
||||||
{
|
{
|
||||||
_text = text;
|
_text = text;
|
||||||
Icon = icon;
|
Icon = icon;
|
||||||
_cm = contextMenu;
|
_cm = contextMenu;
|
||||||
_autoCheck = autoCheck;
|
_autoCheck = autoCheck;
|
||||||
|
_forcedTextWidth = textWidth;
|
||||||
|
|
||||||
if (_cm != null)
|
if (_cm != null)
|
||||||
_cm.VisibleChanged += CmOnVisibleChanged;
|
_cm.VisibleChanged += CmOnVisibleChanged;
|
||||||
@@ -160,7 +163,7 @@ namespace FlaxEditor.Viewport.Widgets
|
|||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
|
|
||||||
if (style != null && style.FontMedium)
|
if (style != null && style.FontMedium)
|
||||||
Width = CalculateButtonWidth(style.FontMedium.MeasureText(_text).X, Icon.IsValid);
|
Width = CalculateButtonWidth(_forcedTextWidth > 0.0f ? _forcedTextWidth : style.FontMedium.MeasureText(_text).X, Icon.IsValid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
|
|
||||||
// Prefab structure tree
|
// Prefab structure tree
|
||||||
Graph = new LocalSceneGraph(new CustomRootNode(this));
|
Graph = new LocalSceneGraph(new CustomRootNode(this));
|
||||||
|
Graph.Root.TreeNode.Expand(true);
|
||||||
_tree = new PrefabTree
|
_tree = new PrefabTree
|
||||||
{
|
{
|
||||||
Margin = new Margin(0.0f, 0.0f, -16.0f, _treePanel.ScrollBarsSize), // Hide root node
|
Margin = new Margin(0.0f, 0.0f, -16.0f, _treePanel.ScrollBarsSize), // Hide root node
|
||||||
@@ -317,7 +318,7 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
Graph.MainActor = _viewport.Instance;
|
Graph.MainActor = _viewport.Instance;
|
||||||
Selection.Clear();
|
Selection.Clear();
|
||||||
Select(Graph.Main);
|
Select(Graph.Main);
|
||||||
Graph.Root.TreeNode.ExpandAll(true);
|
Graph.Root.TreeNode.Expand(true);
|
||||||
_undo.Clear();
|
_undo.Clear();
|
||||||
ClearEditedFlag();
|
ClearEditedFlag();
|
||||||
}
|
}
|
||||||
@@ -413,7 +414,7 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
_focusCamera = true;
|
_focusCamera = true;
|
||||||
Selection.Clear();
|
Selection.Clear();
|
||||||
Select(Graph.Main);
|
Select(Graph.Main);
|
||||||
Graph.Root.TreeNode.ExpandAll(true);
|
Graph.Root.TreeNode.Expand(true);
|
||||||
|
|
||||||
_undo.Clear();
|
_undo.Clear();
|
||||||
ClearEditedFlag();
|
ClearEditedFlag();
|
||||||
|
|||||||
@@ -369,7 +369,7 @@ namespace FlaxEditor.Windows
|
|||||||
}
|
}
|
||||||
|
|
||||||
var pluginPath = Path.Combine(Globals.ProjectFolder, "Source", nameTextBox.Text);
|
var pluginPath = Path.Combine(Globals.ProjectFolder, "Source", nameTextBox.Text);
|
||||||
if (Directory.Exists(pluginPath))
|
if (!IsValidModuleName(nameTextBox.Text) || Directory.Exists(pluginPath))
|
||||||
{
|
{
|
||||||
nameTextBox.BorderColor = Color.Red;
|
nameTextBox.BorderColor = Color.Red;
|
||||||
nameTextBox.BorderSelectedColor = Color.Red;
|
nameTextBox.BorderSelectedColor = Color.Red;
|
||||||
@@ -429,6 +429,12 @@ namespace FlaxEditor.Windows
|
|||||||
submitButton.Clicked += () =>
|
submitButton.Clicked += () =>
|
||||||
{
|
{
|
||||||
// TODO: Check all modules in project including plugins
|
// TODO: Check all modules in project including plugins
|
||||||
|
if (!IsValidModuleName(nameTextBox.Text))
|
||||||
|
{
|
||||||
|
Editor.LogWarning("Invalid module name. Module names cannot contain spaces, start with a number or contain non-alphanumeric characters.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Directory.Exists(Path.Combine(Globals.ProjectFolder, "Source", nameTextBox.Text)))
|
if (Directory.Exists(Path.Combine(Globals.ProjectFolder, "Source", nameTextBox.Text)))
|
||||||
{
|
{
|
||||||
Editor.LogWarning("Cannot create module due to name conflict.");
|
Editor.LogWarning("Cannot create module due to name conflict.");
|
||||||
@@ -460,5 +466,16 @@ namespace FlaxEditor.Windows
|
|||||||
button.ParentContextMenu.Hide();
|
button.ParentContextMenu.Hide();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsValidModuleName(string text)
|
||||||
|
{
|
||||||
|
if (text.Contains(' '))
|
||||||
|
return false;
|
||||||
|
if (char.IsDigit(text[0]))
|
||||||
|
return false;
|
||||||
|
if (text.Any(c => !char.IsLetterOrDigit(c) && c != '_'))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,29 +155,42 @@ namespace FlaxEditor.Windows
|
|||||||
|
|
||||||
public virtual void OnNotAvailableLayout(LayoutElementsContainer layout)
|
public virtual void OnNotAvailableLayout(LayoutElementsContainer layout)
|
||||||
{
|
{
|
||||||
layout.Label("Missing platform data tools for the target platform.", TextAlignment.Center);
|
string text = "Missing platform data tools for the target platform.";
|
||||||
if (FlaxEditor.Editor.IsOfficialBuild())
|
if (FlaxEditor.Editor.IsOfficialBuild())
|
||||||
{
|
{
|
||||||
switch (BuildPlatform)
|
switch (BuildPlatform)
|
||||||
{
|
{
|
||||||
|
#if PLATFORM_WINDOWS
|
||||||
case BuildPlatform.Windows32:
|
case BuildPlatform.Windows32:
|
||||||
case BuildPlatform.Windows64:
|
case BuildPlatform.Windows64:
|
||||||
case BuildPlatform.UWPx86:
|
case BuildPlatform.UWPx86:
|
||||||
case BuildPlatform.UWPx64:
|
case BuildPlatform.UWPx64:
|
||||||
case BuildPlatform.LinuxX64:
|
case BuildPlatform.LinuxX64:
|
||||||
case BuildPlatform.AndroidARM64:
|
case BuildPlatform.AndroidARM64:
|
||||||
layout.Label("Use Flax Launcher and download the required package.", TextAlignment.Center);
|
text += "\nUse Flax Launcher and download the required package.";
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
layout.Label("Engine source is required to target this platform.", TextAlignment.Center);
|
text += "\nEngine source is required to target this platform.";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var label = layout.Label("To target this platform separate engine source package is required.\nTo get access please contact via https://flaxengine.com/contact", TextAlignment.Center);
|
text += "\nTo target this platform separate engine source package is required.";
|
||||||
label.Label.AutoHeight = true;
|
switch (BuildPlatform)
|
||||||
|
{
|
||||||
|
case BuildPlatform.XboxOne:
|
||||||
|
case BuildPlatform.XboxScarlett:
|
||||||
|
case BuildPlatform.PS4:
|
||||||
|
case BuildPlatform.PS5:
|
||||||
|
case BuildPlatform.Switch:
|
||||||
|
text += "\nTo get access please contact via https://flaxengine.com/contact";
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
var label = layout.Label(text, TextAlignment.Center);
|
||||||
|
label.Label.AutoHeight = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Build()
|
public virtual void Build()
|
||||||
|
|||||||
@@ -82,7 +82,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
int32 _elementsCount = 0;
|
int32 _elementsCount = 0;
|
||||||
int32 _deletedCount = 0;
|
|
||||||
int32 _size = 0;
|
int32 _size = 0;
|
||||||
AllocationData _allocation;
|
AllocationData _allocation;
|
||||||
|
|
||||||
@@ -109,14 +108,11 @@ public:
|
|||||||
/// <param name="other">The other collection to move.</param>
|
/// <param name="other">The other collection to move.</param>
|
||||||
HashSet(HashSet&& other) noexcept
|
HashSet(HashSet&& other) noexcept
|
||||||
: _elementsCount(other._elementsCount)
|
: _elementsCount(other._elementsCount)
|
||||||
, _deletedCount(other._deletedCount)
|
|
||||||
, _size(other._size)
|
, _size(other._size)
|
||||||
{
|
{
|
||||||
_elementsCount = other._elementsCount;
|
_elementsCount = other._elementsCount;
|
||||||
_deletedCount = other._deletedCount;
|
|
||||||
_size = other._size;
|
_size = other._size;
|
||||||
other._elementsCount = 0;
|
other._elementsCount = 0;
|
||||||
other._deletedCount = 0;
|
|
||||||
other._size = 0;
|
other._size = 0;
|
||||||
_allocation.Swap(other._allocation);
|
_allocation.Swap(other._allocation);
|
||||||
}
|
}
|
||||||
@@ -154,10 +150,8 @@ public:
|
|||||||
Clear();
|
Clear();
|
||||||
_allocation.Free();
|
_allocation.Free();
|
||||||
_elementsCount = other._elementsCount;
|
_elementsCount = other._elementsCount;
|
||||||
_deletedCount = other._deletedCount;
|
|
||||||
_size = other._size;
|
_size = other._size;
|
||||||
other._elementsCount = 0;
|
other._elementsCount = 0;
|
||||||
other._deletedCount = 0;
|
|
||||||
other._size = 0;
|
other._size = 0;
|
||||||
_allocation.Swap(other._allocation);
|
_allocation.Swap(other._allocation);
|
||||||
}
|
}
|
||||||
@@ -337,12 +331,12 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
void Clear()
|
void Clear()
|
||||||
{
|
{
|
||||||
if (_elementsCount + _deletedCount != 0)
|
if (_elementsCount != 0)
|
||||||
{
|
{
|
||||||
Bucket* data = _allocation.Get();
|
Bucket* data = _allocation.Get();
|
||||||
for (int32 i = 0; i < _size; i++)
|
for (int32 i = 0; i < _size; i++)
|
||||||
data[i].Free();
|
data[i].Free();
|
||||||
_elementsCount = _deletedCount = 0;
|
_elementsCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,7 +371,7 @@ public:
|
|||||||
oldAllocation.Swap(_allocation);
|
oldAllocation.Swap(_allocation);
|
||||||
const int32 oldSize = _size;
|
const int32 oldSize = _size;
|
||||||
const int32 oldElementsCount = _elementsCount;
|
const int32 oldElementsCount = _elementsCount;
|
||||||
_deletedCount = _elementsCount = 0;
|
_elementsCount = 0;
|
||||||
if (capacity != 0 && (capacity & (capacity - 1)) != 0)
|
if (capacity != 0 && (capacity & (capacity - 1)) != 0)
|
||||||
{
|
{
|
||||||
// Align capacity value to the next power of two (http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2)
|
// Align capacity value to the next power of two (http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2)
|
||||||
@@ -439,7 +433,7 @@ public:
|
|||||||
bool Add(const ItemType& item)
|
bool Add(const ItemType& item)
|
||||||
{
|
{
|
||||||
// Ensure to have enough memory for the next item (in case of new element insertion)
|
// Ensure to have enough memory for the next item (in case of new element insertion)
|
||||||
EnsureCapacity(_elementsCount + _deletedCount + 1);
|
EnsureCapacity(_elementsCount + 1);
|
||||||
|
|
||||||
// Find location of the item or place to insert it
|
// Find location of the item or place to insert it
|
||||||
FindPositionResult pos;
|
FindPositionResult pos;
|
||||||
@@ -485,7 +479,6 @@ public:
|
|||||||
{
|
{
|
||||||
_allocation.Get()[pos.ObjectIndex].Delete();
|
_allocation.Get()[pos.ObjectIndex].Delete();
|
||||||
_elementsCount--;
|
_elementsCount--;
|
||||||
_deletedCount++;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -504,7 +497,6 @@ public:
|
|||||||
ASSERT(_allocation.Get()[i._index].IsOccupied());
|
ASSERT(_allocation.Get()[i._index].IsOccupied());
|
||||||
_allocation.Get()[i._index].Delete();
|
_allocation.Get()[i._index].Delete();
|
||||||
_elementsCount--;
|
_elementsCount--;
|
||||||
_deletedCount++;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -511,7 +511,7 @@ public:
|
|||||||
_locker = New<CriticalSection>();
|
_locker = New<CriticalSection>();
|
||||||
ScopeLock lock(*_locker);
|
ScopeLock lock(*_locker);
|
||||||
if (_functions == nullptr)
|
if (_functions == nullptr)
|
||||||
_functions = New<HashSet<FunctionType>>(32);
|
_functions = New<HashSet<FunctionType>>();
|
||||||
_functions->Add(f);
|
_functions->Add(f);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -583,18 +583,9 @@ public:
|
|||||||
template<void(*Method)(Params...)>
|
template<void(*Method)(Params...)>
|
||||||
void Unbind()
|
void Unbind()
|
||||||
{
|
{
|
||||||
#if DELEGATE_USE_ATOMIC
|
|
||||||
FunctionType f;
|
FunctionType f;
|
||||||
f.template Bind<Method>();
|
f.template Bind<Method>();
|
||||||
Unbind(f);
|
Unbind(f);
|
||||||
#else
|
|
||||||
if (_functions == nullptr)
|
|
||||||
return;
|
|
||||||
FunctionType f;
|
|
||||||
f.template Bind<Method>();
|
|
||||||
ScopeLock lock(*_locker);
|
|
||||||
_functions->Remove(f);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -604,18 +595,9 @@ public:
|
|||||||
template<class T, void(T::*Method)(Params...)>
|
template<class T, void(T::*Method)(Params...)>
|
||||||
void Unbind(T* callee)
|
void Unbind(T* callee)
|
||||||
{
|
{
|
||||||
#if DELEGATE_USE_ATOMIC
|
|
||||||
FunctionType f;
|
FunctionType f;
|
||||||
f.template Bind<T, Method>(callee);
|
f.template Bind<T, Method>(callee);
|
||||||
Unbind(f);
|
Unbind(f);
|
||||||
#else
|
|
||||||
if (_functions == nullptr)
|
|
||||||
return;
|
|
||||||
FunctionType f;
|
|
||||||
f.template Bind<T, Method>(callee);
|
|
||||||
ScopeLock lock(*_locker);
|
|
||||||
_functions->Remove(f);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -624,16 +606,8 @@ public:
|
|||||||
/// <param name="method">The method.</param>
|
/// <param name="method">The method.</param>
|
||||||
void Unbind(Signature method)
|
void Unbind(Signature method)
|
||||||
{
|
{
|
||||||
#if DELEGATE_USE_ATOMIC
|
|
||||||
FunctionType f(method);
|
FunctionType f(method);
|
||||||
Unbind(f);
|
Unbind(f);
|
||||||
#else
|
|
||||||
if (_functions == nullptr)
|
|
||||||
return;
|
|
||||||
FunctionType f(method);
|
|
||||||
ScopeLock lock(*_locker);
|
|
||||||
_functions->Remove(f);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -13,9 +13,7 @@ namespace FlaxEngine.TypeConverters
|
|||||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||||||
{
|
{
|
||||||
if (sourceType == typeof(string))
|
if (sourceType == typeof(string))
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
return base.CanConvertFrom(context, sourceType);
|
return base.CanConvertFrom(context, sourceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,9 +21,7 @@ namespace FlaxEngine.TypeConverters
|
|||||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
||||||
{
|
{
|
||||||
if (destinationType == typeof(string))
|
if (destinationType == typeof(string))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
return base.CanConvertTo(context, destinationType);
|
return base.CanConvertTo(context, destinationType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,34 +7,14 @@ using System.Globalization;
|
|||||||
|
|
||||||
namespace FlaxEngine.TypeConverters
|
namespace FlaxEngine.TypeConverters
|
||||||
{
|
{
|
||||||
internal class Double2Converter : TypeConverter
|
internal class Double2Converter : VectorConverter
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
|
||||||
{
|
|
||||||
if (sourceType == typeof(string))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return base.CanConvertFrom(context, sourceType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
|
||||||
{
|
|
||||||
if (destinationType == typeof(string))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return base.CanConvertTo(context, destinationType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||||
{
|
{
|
||||||
if (value is string str)
|
if (value is string str)
|
||||||
{
|
{
|
||||||
string[] v = str.Split(',');
|
string[] v = GetParts(str);
|
||||||
return new Double2(double.Parse(v[0], culture), double.Parse(v[1], culture));
|
return new Double2(double.Parse(v[0], culture), double.Parse(v[1], culture));
|
||||||
}
|
}
|
||||||
return base.ConvertFrom(context, culture, value);
|
return base.ConvertFrom(context, culture, value);
|
||||||
|
|||||||
@@ -7,34 +7,14 @@ using System.Globalization;
|
|||||||
|
|
||||||
namespace FlaxEngine.TypeConverters
|
namespace FlaxEngine.TypeConverters
|
||||||
{
|
{
|
||||||
internal class Double3Converter : TypeConverter
|
internal class Double3Converter : VectorConverter
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
|
||||||
{
|
|
||||||
if (sourceType == typeof(string))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return base.CanConvertFrom(context, sourceType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
|
||||||
{
|
|
||||||
if (destinationType == typeof(string))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return base.CanConvertTo(context, destinationType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||||
{
|
{
|
||||||
if (value is string str)
|
if (value is string str)
|
||||||
{
|
{
|
||||||
string[] v = str.Split(',');
|
string[] v = GetParts(str);
|
||||||
return new Double3(double.Parse(v[0], culture), double.Parse(v[1], culture), double.Parse(v[2], culture));
|
return new Double3(double.Parse(v[0], culture), double.Parse(v[1], culture), double.Parse(v[2], culture));
|
||||||
}
|
}
|
||||||
return base.ConvertFrom(context, culture, value);
|
return base.ConvertFrom(context, culture, value);
|
||||||
|
|||||||
@@ -7,34 +7,14 @@ using System.Globalization;
|
|||||||
|
|
||||||
namespace FlaxEngine.TypeConverters
|
namespace FlaxEngine.TypeConverters
|
||||||
{
|
{
|
||||||
internal class Double4Converter : TypeConverter
|
internal class Double4Converter : VectorConverter
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
|
||||||
{
|
|
||||||
if (sourceType == typeof(string))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return base.CanConvertFrom(context, sourceType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
|
||||||
{
|
|
||||||
if (destinationType == typeof(string))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return base.CanConvertTo(context, destinationType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||||
{
|
{
|
||||||
if (value is string str)
|
if (value is string str)
|
||||||
{
|
{
|
||||||
string[] v = str.Split(',');
|
string[] v = GetParts(str);
|
||||||
return new Double4(double.Parse(v[0], culture), double.Parse(v[1], culture), double.Parse(v[2], culture), double.Parse(v[3], culture));
|
return new Double4(double.Parse(v[0], culture), double.Parse(v[1], culture), double.Parse(v[2], culture), double.Parse(v[3], culture));
|
||||||
}
|
}
|
||||||
return base.ConvertFrom(context, culture, value);
|
return base.ConvertFrom(context, culture, value);
|
||||||
|
|||||||
@@ -7,34 +7,14 @@ using System.Globalization;
|
|||||||
|
|
||||||
namespace FlaxEngine.TypeConverters
|
namespace FlaxEngine.TypeConverters
|
||||||
{
|
{
|
||||||
internal class Float2Converter : TypeConverter
|
internal class Float2Converter : VectorConverter
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
|
||||||
{
|
|
||||||
if (sourceType == typeof(string))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return base.CanConvertFrom(context, sourceType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
|
||||||
{
|
|
||||||
if (destinationType == typeof(string))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return base.CanConvertTo(context, destinationType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||||
{
|
{
|
||||||
if (value is string str)
|
if (value is string str)
|
||||||
{
|
{
|
||||||
string[] v = str.Split(',');
|
string[] v = GetParts(str);
|
||||||
return new Float2(float.Parse(v[0], culture), float.Parse(v[1], culture));
|
return new Float2(float.Parse(v[0], culture), float.Parse(v[1], culture));
|
||||||
}
|
}
|
||||||
return base.ConvertFrom(context, culture, value);
|
return base.ConvertFrom(context, culture, value);
|
||||||
|
|||||||
@@ -7,34 +7,14 @@ using System.Globalization;
|
|||||||
|
|
||||||
namespace FlaxEngine.TypeConverters
|
namespace FlaxEngine.TypeConverters
|
||||||
{
|
{
|
||||||
internal class Float3Converter : TypeConverter
|
internal class Float3Converter : VectorConverter
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
|
||||||
{
|
|
||||||
if (sourceType == typeof(string))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return base.CanConvertFrom(context, sourceType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
|
||||||
{
|
|
||||||
if (destinationType == typeof(string))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return base.CanConvertTo(context, destinationType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||||
{
|
{
|
||||||
if (value is string str)
|
if (value is string str)
|
||||||
{
|
{
|
||||||
string[] v = str.Split(',');
|
string[] v = GetParts(str);
|
||||||
return new Float3(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture));
|
return new Float3(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture));
|
||||||
}
|
}
|
||||||
return base.ConvertFrom(context, culture, value);
|
return base.ConvertFrom(context, culture, value);
|
||||||
|
|||||||
@@ -7,15 +7,13 @@ using System.Globalization;
|
|||||||
|
|
||||||
namespace FlaxEngine.TypeConverters
|
namespace FlaxEngine.TypeConverters
|
||||||
{
|
{
|
||||||
internal class Float4Converter : TypeConverter
|
internal class VectorConverter : TypeConverter
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
||||||
{
|
{
|
||||||
if (sourceType == typeof(string))
|
if (sourceType == typeof(string))
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
return base.CanConvertFrom(context, sourceType);
|
return base.CanConvertFrom(context, sourceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,18 +21,32 @@ namespace FlaxEngine.TypeConverters
|
|||||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
||||||
{
|
{
|
||||||
if (destinationType == typeof(string))
|
if (destinationType == typeof(string))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
return base.CanConvertTo(context, destinationType);
|
return base.CanConvertTo(context, destinationType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static string[] GetParts(string str)
|
||||||
|
{
|
||||||
|
string[] v = str.Split(',');
|
||||||
|
if (v.Length == 1)
|
||||||
|
{
|
||||||
|
// When converting from ToString()
|
||||||
|
v = str.Split(' ');
|
||||||
|
for (int i = 0; i < v.Length; i++)
|
||||||
|
v[i] = v[i].Substring(v[i].IndexOf(':') + 1);
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class Float4Converter : VectorConverter
|
||||||
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||||
{
|
{
|
||||||
if (value is string str)
|
if (value is string str)
|
||||||
{
|
{
|
||||||
string[] v = str.Split(',');
|
string[] v = GetParts(str);
|
||||||
return new Float4(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), float.Parse(v[3], culture));
|
return new Float4(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), float.Parse(v[3], culture));
|
||||||
}
|
}
|
||||||
return base.ConvertFrom(context, culture, value);
|
return base.ConvertFrom(context, culture, value);
|
||||||
|
|||||||
@@ -7,34 +7,14 @@ using System.Globalization;
|
|||||||
|
|
||||||
namespace FlaxEngine.TypeConverters
|
namespace FlaxEngine.TypeConverters
|
||||||
{
|
{
|
||||||
internal class Int2Converter : TypeConverter
|
internal class Int2Converter : VectorConverter
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
|
||||||
{
|
|
||||||
if (sourceType == typeof(string))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return base.CanConvertFrom(context, sourceType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
|
||||||
{
|
|
||||||
if (destinationType == typeof(string))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return base.CanConvertTo(context, destinationType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||||
{
|
{
|
||||||
if (value is string str)
|
if (value is string str)
|
||||||
{
|
{
|
||||||
string[] v = str.Split(',');
|
string[] v = GetParts(str);
|
||||||
return new Int2(int.Parse(v[0], culture), int.Parse(v[1], culture));
|
return new Int2(int.Parse(v[0], culture), int.Parse(v[1], culture));
|
||||||
}
|
}
|
||||||
return base.ConvertFrom(context, culture, value);
|
return base.ConvertFrom(context, culture, value);
|
||||||
|
|||||||
@@ -7,34 +7,14 @@ using System.Globalization;
|
|||||||
|
|
||||||
namespace FlaxEngine.TypeConverters
|
namespace FlaxEngine.TypeConverters
|
||||||
{
|
{
|
||||||
internal class Int3Converter : TypeConverter
|
internal class Int3Converter : VectorConverter
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
|
||||||
{
|
|
||||||
if (sourceType == typeof(string))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return base.CanConvertFrom(context, sourceType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
|
||||||
{
|
|
||||||
if (destinationType == typeof(string))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return base.CanConvertTo(context, destinationType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||||
{
|
{
|
||||||
if (value is string str)
|
if (value is string str)
|
||||||
{
|
{
|
||||||
string[] v = str.Split(',');
|
string[] v = GetParts(str);
|
||||||
return new Int3(int.Parse(v[0], culture), int.Parse(v[1], culture), int.Parse(v[2], culture));
|
return new Int3(int.Parse(v[0], culture), int.Parse(v[1], culture), int.Parse(v[2], culture));
|
||||||
}
|
}
|
||||||
return base.ConvertFrom(context, culture, value);
|
return base.ConvertFrom(context, culture, value);
|
||||||
|
|||||||
@@ -7,34 +7,14 @@ using System.Globalization;
|
|||||||
|
|
||||||
namespace FlaxEngine.TypeConverters
|
namespace FlaxEngine.TypeConverters
|
||||||
{
|
{
|
||||||
internal class Int4Converter : TypeConverter
|
internal class Int4Converter : VectorConverter
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
|
||||||
{
|
|
||||||
if (sourceType == typeof(string))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return base.CanConvertFrom(context, sourceType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
|
||||||
{
|
|
||||||
if (destinationType == typeof(string))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return base.CanConvertTo(context, destinationType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||||
{
|
{
|
||||||
if (value is string str)
|
if (value is string str)
|
||||||
{
|
{
|
||||||
string[] v = str.Split(',');
|
string[] v = GetParts(str);
|
||||||
return new Int4(int.Parse(v[0], culture), int.Parse(v[1], culture), int.Parse(v[2], culture), int.Parse(v[3], culture));
|
return new Int4(int.Parse(v[0], culture), int.Parse(v[1], culture), int.Parse(v[2], culture), int.Parse(v[3], culture));
|
||||||
}
|
}
|
||||||
return base.ConvertFrom(context, culture, value);
|
return base.ConvertFrom(context, culture, value);
|
||||||
|
|||||||
@@ -7,34 +7,14 @@ using System.Globalization;
|
|||||||
|
|
||||||
namespace FlaxEngine.TypeConverters
|
namespace FlaxEngine.TypeConverters
|
||||||
{
|
{
|
||||||
internal class QuaternionConverter : TypeConverter
|
internal class QuaternionConverter : VectorConverter
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
|
||||||
{
|
|
||||||
if (sourceType == typeof(string))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return base.CanConvertFrom(context, sourceType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
|
||||||
{
|
|
||||||
if (destinationType == typeof(string))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return base.CanConvertTo(context, destinationType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||||
{
|
{
|
||||||
if (value is string str)
|
if (value is string str)
|
||||||
{
|
{
|
||||||
string[] v = str.Split(',');
|
string[] v = GetParts(str);
|
||||||
return new Quaternion(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), float.Parse(v[3], culture));
|
return new Quaternion(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), float.Parse(v[3], culture));
|
||||||
}
|
}
|
||||||
return base.ConvertFrom(context, culture, value);
|
return base.ConvertFrom(context, culture, value);
|
||||||
|
|||||||
@@ -7,34 +7,14 @@ using System.Globalization;
|
|||||||
|
|
||||||
namespace FlaxEngine.TypeConverters
|
namespace FlaxEngine.TypeConverters
|
||||||
{
|
{
|
||||||
internal class Vector2Converter : TypeConverter
|
internal class Vector2Converter : VectorConverter
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
|
||||||
{
|
|
||||||
if (sourceType == typeof(string))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return base.CanConvertFrom(context, sourceType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
|
||||||
{
|
|
||||||
if (destinationType == typeof(string))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return base.CanConvertTo(context, destinationType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||||
{
|
{
|
||||||
if (value is string str)
|
if (value is string str)
|
||||||
{
|
{
|
||||||
string[] v = str.Split(',');
|
string[] v = GetParts(str);
|
||||||
return new Vector2(float.Parse(v[0], culture), float.Parse(v[1], culture));
|
return new Vector2(float.Parse(v[0], culture), float.Parse(v[1], culture));
|
||||||
}
|
}
|
||||||
return base.ConvertFrom(context, culture, value);
|
return base.ConvertFrom(context, culture, value);
|
||||||
|
|||||||
@@ -7,34 +7,14 @@ using System.Globalization;
|
|||||||
|
|
||||||
namespace FlaxEngine.TypeConverters
|
namespace FlaxEngine.TypeConverters
|
||||||
{
|
{
|
||||||
internal class Vector3Converter : TypeConverter
|
internal class Vector3Converter : VectorConverter
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
|
||||||
{
|
|
||||||
if (sourceType == typeof(string))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return base.CanConvertFrom(context, sourceType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
|
||||||
{
|
|
||||||
if (destinationType == typeof(string))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return base.CanConvertTo(context, destinationType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||||
{
|
{
|
||||||
if (value is string str)
|
if (value is string str)
|
||||||
{
|
{
|
||||||
string[] v = str.Split(',');
|
string[] v = GetParts(str);
|
||||||
return new Vector3(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture));
|
return new Vector3(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture));
|
||||||
}
|
}
|
||||||
return base.ConvertFrom(context, culture, value);
|
return base.ConvertFrom(context, culture, value);
|
||||||
|
|||||||
@@ -7,34 +7,14 @@ using System.Globalization;
|
|||||||
|
|
||||||
namespace FlaxEngine.TypeConverters
|
namespace FlaxEngine.TypeConverters
|
||||||
{
|
{
|
||||||
internal class Vector4Converter : TypeConverter
|
internal class Vector4Converter : VectorConverter
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
|
|
||||||
{
|
|
||||||
if (sourceType == typeof(string))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return base.CanConvertFrom(context, sourceType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
|
||||||
{
|
|
||||||
if (destinationType == typeof(string))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return base.CanConvertTo(context, destinationType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
|
||||||
{
|
{
|
||||||
if (value is string str)
|
if (value is string str)
|
||||||
{
|
{
|
||||||
string[] v = str.Split(',');
|
string[] v = GetParts(str);
|
||||||
return new Vector4(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), float.Parse(v[3], culture));
|
return new Vector4(float.Parse(v[0], culture), float.Parse(v[1], culture), float.Parse(v[2], culture), float.Parse(v[3], culture));
|
||||||
}
|
}
|
||||||
return base.ConvertFrom(context, culture, value);
|
return base.ConvertFrom(context, culture, value);
|
||||||
|
|||||||
@@ -646,6 +646,12 @@ inline Vector2Base<T> operator/(typename TOtherFloat<T>::Type a, const Vector2Ba
|
|||||||
return Vector2Base<T>(a) / b;
|
return Vector2Base<T>(a) / b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline uint32 GetHash(const Vector2Base<T>& key)
|
||||||
|
{
|
||||||
|
return (*(uint32*)&key.X * 397) ^ *(uint32*)&key.Y;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Math
|
namespace Math
|
||||||
{
|
{
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|||||||
@@ -977,6 +977,12 @@ inline Vector3Base<T> operator/(typename TOtherFloat<T>::Type a, const Vector3Ba
|
|||||||
return Vector3Base<T>(a) / b;
|
return Vector3Base<T>(a) / b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline uint32 GetHash(const Vector3Base<T>& key)
|
||||||
|
{
|
||||||
|
return (((*(uint32*)&key.X * 397) ^ *(uint32*)&key.Y) * 397) ^ *(uint32*)&key.Z;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Math
|
namespace Math
|
||||||
{
|
{
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|||||||
@@ -552,6 +552,12 @@ inline Vector4Base<T> operator/(typename TOtherFloat<T>::Type a, const Vector4Ba
|
|||||||
return Vector4Base<T>(a) / b;
|
return Vector4Base<T>(a) / b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline uint32 GetHash(const Vector4Base<T>& key)
|
||||||
|
{
|
||||||
|
return (((((*(uint32*)&key.X * 397) ^ *(uint32*)&key.Y) * 397) ^ *(uint32*)&key.Z) * 397) ^*(uint32*)&key.W;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Math
|
namespace Math
|
||||||
{
|
{
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "Collections/Dictionary.h"
|
#include "Collections/Dictionary.h"
|
||||||
#include "Engine/Engine/Time.h"
|
#include "Engine/Engine/Time.h"
|
||||||
#include "Engine/Engine/EngineService.h"
|
#include "Engine/Engine/EngineService.h"
|
||||||
|
#include "Engine/Platform/CriticalSection.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
#include "Engine/Scripting/ScriptingObject.h"
|
#include "Engine/Scripting/ScriptingObject.h"
|
||||||
|
|
||||||
|
|||||||
@@ -7,15 +7,15 @@ Version::Version(int32 major, int32 minor, int32 build, int32 revision)
|
|||||||
{
|
{
|
||||||
_major = Math::Max(major, 0);
|
_major = Math::Max(major, 0);
|
||||||
_minor = Math::Max(minor, 0);
|
_minor = Math::Max(minor, 0);
|
||||||
_build = Math::Max(build, 0);
|
_build = Math::Max(build, -1);
|
||||||
_revision = Math::Max(revision, 0);
|
_revision = Math::Max(revision, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Version::Version(int32 major, int32 minor, int32 build)
|
Version::Version(int32 major, int32 minor, int32 build)
|
||||||
{
|
{
|
||||||
_major = Math::Max(major, 0);
|
_major = Math::Max(major, 0);
|
||||||
_minor = Math::Max(minor, 0);
|
_minor = Math::Max(minor, 0);
|
||||||
_build = Math::Max(build, 0);
|
_build = Math::Max(build, -1);
|
||||||
_revision = -1;
|
_revision = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,10 +51,14 @@ namespace Utilities
|
|||||||
int32 i = 0;
|
int32 i = 0;
|
||||||
double dblSUnits = static_cast<double>(units);
|
double dblSUnits = static_cast<double>(units);
|
||||||
for (; static_cast<uint64>(units / static_cast<double>(divider)) > 0; i++, units /= divider)
|
for (; static_cast<uint64>(units / static_cast<double>(divider)) > 0; i++, units /= divider)
|
||||||
dblSUnits = units / static_cast<double>(divider);
|
dblSUnits = (double)units / (double)divider;
|
||||||
if (i >= sizes.Length())
|
if (i >= sizes.Length())
|
||||||
i = 0;
|
i = 0;
|
||||||
return String::Format(TEXT("{0} {1}"), RoundTo2DecimalPlaces(dblSUnits), sizes[i]);
|
String text = String::Format(TEXT("{}"), RoundTo2DecimalPlaces(dblSUnits));
|
||||||
|
const int32 dot = text.FindLast('.');
|
||||||
|
if (dot != -1)
|
||||||
|
text = text.Left(dot + 3);
|
||||||
|
return String::Format(TEXT("{0} {1}"), text, sizes[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts size of the file (in bytes) to the best fitting string
|
// Converts size of the file (in bytes) to the best fitting string
|
||||||
|
|||||||
@@ -1302,7 +1302,8 @@ namespace FlaxEngine.Interop
|
|||||||
#if !USE_AOT
|
#if !USE_AOT
|
||||||
internal bool TryGetDelegate(out Invoker.MarshalAndInvokeDelegate outDeleg, out object outDelegInvoke)
|
internal bool TryGetDelegate(out Invoker.MarshalAndInvokeDelegate outDeleg, out object outDelegInvoke)
|
||||||
{
|
{
|
||||||
if (invokeDelegate == null)
|
// Skip using in-built delegate for value types (eg. Transform) to properly handle instance value passing to method
|
||||||
|
if (invokeDelegate == null && !method.DeclaringType.IsValueType)
|
||||||
{
|
{
|
||||||
List<Type> methodTypes = new List<Type>();
|
List<Type> methodTypes = new List<Type>();
|
||||||
if (!method.IsStatic)
|
if (!method.IsStatic)
|
||||||
|
|||||||
@@ -313,6 +313,8 @@ bool GPUDevice::Init()
|
|||||||
|
|
||||||
_res->TasksManager.SetExecutor(CreateTasksExecutor());
|
_res->TasksManager.SetExecutor(CreateTasksExecutor());
|
||||||
LOG(Info, "Total graphics memory: {0}", Utilities::BytesToText(TotalGraphicsMemory));
|
LOG(Info, "Total graphics memory: {0}", Utilities::BytesToText(TotalGraphicsMemory));
|
||||||
|
if (!Limits.HasCompute)
|
||||||
|
LOG(Warning, "Compute Shaders are not supported");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,11 @@ bool GPUShader::Create(MemoryReadStream& stream)
|
|||||||
GPUShaderProgramInitializer initializer;
|
GPUShaderProgramInitializer initializer;
|
||||||
#if !BUILD_RELEASE
|
#if !BUILD_RELEASE
|
||||||
initializer.Owner = this;
|
initializer.Owner = this;
|
||||||
|
const StringView name = GetName();
|
||||||
|
#else
|
||||||
|
const StringView name;
|
||||||
#endif
|
#endif
|
||||||
|
const bool hasCompute = GPUDevice::Instance->Limits.HasCompute;
|
||||||
for (int32 i = 0; i < shadersCount; i++)
|
for (int32 i = 0; i < shadersCount; i++)
|
||||||
{
|
{
|
||||||
const ShaderStage type = static_cast<ShaderStage>(stream.ReadByte());
|
const ShaderStage type = static_cast<ShaderStage>(stream.ReadByte());
|
||||||
@@ -117,10 +121,15 @@ bool GPUShader::Create(MemoryReadStream& stream)
|
|||||||
stream.ReadBytes(&initializer.Bindings, sizeof(ShaderBindings));
|
stream.ReadBytes(&initializer.Bindings, sizeof(ShaderBindings));
|
||||||
|
|
||||||
// Create shader program
|
// Create shader program
|
||||||
|
if (type == ShaderStage::Compute && !hasCompute)
|
||||||
|
{
|
||||||
|
LOG(Warning, "Failed to create {} Shader program '{}' ({}).", ::ToString(type), String(initializer.Name), name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
GPUShaderProgram* shader = CreateGPUShaderProgram(type, initializer, cache, cacheSize, stream);
|
GPUShaderProgram* shader = CreateGPUShaderProgram(type, initializer, cache, cacheSize, stream);
|
||||||
if (shader == nullptr)
|
if (shader == nullptr)
|
||||||
{
|
{
|
||||||
LOG(Error, "Failed to create {} Shader program '{}'.", ::ToString(type), String(initializer.Name));
|
LOG(Error, "Failed to create {} Shader program '{}' ({}).", ::ToString(type), String(initializer.Name), name);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -122,6 +122,19 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
class GPUShaderProgramVS : public GPUShaderProgram
|
class GPUShaderProgramVS : public GPUShaderProgram
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
// Input element run-time data (see VertexShaderMeta::InputElement for compile-time data)
|
||||||
|
PACK_STRUCT(struct InputElement
|
||||||
|
{
|
||||||
|
byte Type; // VertexShaderMeta::InputType
|
||||||
|
byte Index;
|
||||||
|
byte Format; // PixelFormat
|
||||||
|
byte InputSlot;
|
||||||
|
uint32 AlignedByteOffset; // Fixed value or INPUT_LAYOUT_ELEMENT_ALIGN if auto
|
||||||
|
byte InputSlotClass; // INPUT_LAYOUT_ELEMENT_PER_VERTEX_DATA or INPUT_LAYOUT_ELEMENT_PER_INSTANCE_DATA
|
||||||
|
uint32 InstanceDataStepRate; // 0 if per-vertex
|
||||||
|
});
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets input layout description handle (platform dependent).
|
/// Gets input layout description handle (platform dependent).
|
||||||
|
|||||||
@@ -15,32 +15,21 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
|
|||||||
{
|
{
|
||||||
case ShaderStage::Vertex:
|
case ShaderStage::Vertex:
|
||||||
{
|
{
|
||||||
D3D11_INPUT_ELEMENT_DESC inputLayoutDesc[VERTEX_SHADER_MAX_INPUT_ELEMENTS];
|
// Load Input Layout
|
||||||
|
|
||||||
// Temporary variables
|
|
||||||
byte Type, Format, Index, InputSlot, InputSlotClass;
|
|
||||||
uint32 AlignedByteOffset, InstanceDataStepRate;
|
|
||||||
|
|
||||||
// Load Input Layout (it may be empty)
|
|
||||||
byte inputLayoutSize;
|
byte inputLayoutSize;
|
||||||
stream.ReadByte(&inputLayoutSize);
|
stream.ReadByte(&inputLayoutSize);
|
||||||
ASSERT(inputLayoutSize <= VERTEX_SHADER_MAX_INPUT_ELEMENTS);
|
ASSERT(inputLayoutSize <= VERTEX_SHADER_MAX_INPUT_ELEMENTS);
|
||||||
|
D3D11_INPUT_ELEMENT_DESC inputLayoutDesc[VERTEX_SHADER_MAX_INPUT_ELEMENTS];
|
||||||
for (int32 a = 0; a < inputLayoutSize; a++)
|
for (int32 a = 0; a < inputLayoutSize; a++)
|
||||||
{
|
{
|
||||||
// Read description
|
// Read description
|
||||||
// TODO: maybe use struct and load at once?
|
GPUShaderProgramVS::InputElement inputElement;
|
||||||
stream.ReadByte(&Type);
|
stream.Read(inputElement);
|
||||||
stream.ReadByte(&Index);
|
|
||||||
stream.ReadByte(&Format);
|
|
||||||
stream.ReadByte(&InputSlot);
|
|
||||||
stream.ReadUint32(&AlignedByteOffset);
|
|
||||||
stream.ReadByte(&InputSlotClass);
|
|
||||||
stream.ReadUint32(&InstanceDataStepRate);
|
|
||||||
|
|
||||||
// Get semantic name
|
// Get semantic name
|
||||||
const char* semanticName = nullptr;
|
const char* semanticName = nullptr;
|
||||||
// TODO: maybe use enum+mapping ?
|
// TODO: maybe use enum+mapping ?
|
||||||
switch (Type)
|
switch (inputElement.Type)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
semanticName = "POSITION";
|
semanticName = "POSITION";
|
||||||
@@ -70,7 +59,7 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
|
|||||||
semanticName = "BLENDWEIGHT";
|
semanticName = "BLENDWEIGHT";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG(Fatal, "Invalid vertex shader element semantic type: {0}", Type);
|
LOG(Fatal, "Invalid vertex shader element semantic type: {0}", inputElement.Type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,12 +67,12 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
|
|||||||
inputLayoutDesc[a] =
|
inputLayoutDesc[a] =
|
||||||
{
|
{
|
||||||
semanticName,
|
semanticName,
|
||||||
static_cast<UINT>(Index),
|
static_cast<UINT>(inputElement.Index),
|
||||||
static_cast<DXGI_FORMAT>(Format),
|
static_cast<DXGI_FORMAT>(inputElement.Format),
|
||||||
static_cast<UINT>(InputSlot),
|
static_cast<UINT>(inputElement.InputSlot),
|
||||||
static_cast<UINT>(AlignedByteOffset),
|
static_cast<UINT>(inputElement.AlignedByteOffset),
|
||||||
static_cast<D3D11_INPUT_CLASSIFICATION>(InputSlotClass),
|
static_cast<D3D11_INPUT_CLASSIFICATION>(inputElement.InputSlotClass),
|
||||||
static_cast<UINT>(InstanceDataStepRate)
|
static_cast<UINT>(inputElement.InstanceDataStepRate)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,32 +20,21 @@ GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const
|
|||||||
{
|
{
|
||||||
case ShaderStage::Vertex:
|
case ShaderStage::Vertex:
|
||||||
{
|
{
|
||||||
D3D12_INPUT_ELEMENT_DESC inputLayout[VERTEX_SHADER_MAX_INPUT_ELEMENTS];
|
|
||||||
|
|
||||||
// Temporary variables
|
|
||||||
byte Type, Format, Index, InputSlot, InputSlotClass;
|
|
||||||
uint32 AlignedByteOffset, InstanceDataStepRate;
|
|
||||||
|
|
||||||
// Load Input Layout (it may be empty)
|
// Load Input Layout (it may be empty)
|
||||||
byte inputLayoutSize;
|
byte inputLayoutSize;
|
||||||
stream.ReadByte(&inputLayoutSize);
|
stream.ReadByte(&inputLayoutSize);
|
||||||
ASSERT(inputLayoutSize <= VERTEX_SHADER_MAX_INPUT_ELEMENTS);
|
ASSERT(inputLayoutSize <= VERTEX_SHADER_MAX_INPUT_ELEMENTS);
|
||||||
|
D3D12_INPUT_ELEMENT_DESC inputLayout[VERTEX_SHADER_MAX_INPUT_ELEMENTS];
|
||||||
for (int32 a = 0; a < inputLayoutSize; a++)
|
for (int32 a = 0; a < inputLayoutSize; a++)
|
||||||
{
|
{
|
||||||
// Read description
|
// Read description
|
||||||
// TODO: maybe use struct and load at once?
|
GPUShaderProgramVS::InputElement inputElement;
|
||||||
stream.ReadByte(&Type);
|
stream.Read(inputElement);
|
||||||
stream.ReadByte(&Index);
|
|
||||||
stream.ReadByte(&Format);
|
|
||||||
stream.ReadByte(&InputSlot);
|
|
||||||
stream.ReadUint32(&AlignedByteOffset);
|
|
||||||
stream.ReadByte(&InputSlotClass);
|
|
||||||
stream.ReadUint32(&InstanceDataStepRate);
|
|
||||||
|
|
||||||
// Get semantic name
|
// Get semantic name
|
||||||
const char* semanticName = nullptr;
|
const char* semanticName = nullptr;
|
||||||
// TODO: maybe use enum+mapping ?
|
// TODO: maybe use enum+mapping ?
|
||||||
switch (Type)
|
switch (inputElement.Type)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
semanticName = "POSITION";
|
semanticName = "POSITION";
|
||||||
@@ -75,7 +64,7 @@ GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const
|
|||||||
semanticName = "BLENDWEIGHT";
|
semanticName = "BLENDWEIGHT";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG(Fatal, "Invalid vertex shader element semantic type: {0}", Type);
|
LOG(Fatal, "Invalid vertex shader element semantic type: {0}", inputElement.Type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,12 +72,12 @@ GPUShaderProgram* GPUShaderDX12::CreateGPUShaderProgram(ShaderStage type, const
|
|||||||
inputLayout[a] =
|
inputLayout[a] =
|
||||||
{
|
{
|
||||||
semanticName,
|
semanticName,
|
||||||
static_cast<UINT>(Index),
|
static_cast<UINT>(inputElement.Index),
|
||||||
static_cast<DXGI_FORMAT>(Format),
|
static_cast<DXGI_FORMAT>(inputElement.Format),
|
||||||
static_cast<UINT>(InputSlot),
|
static_cast<UINT>(inputElement.InputSlot),
|
||||||
static_cast<UINT>(AlignedByteOffset),
|
static_cast<UINT>(inputElement.AlignedByteOffset),
|
||||||
static_cast<D3D12_INPUT_CLASSIFICATION>(InputSlotClass),
|
static_cast<D3D12_INPUT_CLASSIFICATION>(inputElement.InputSlotClass),
|
||||||
static_cast<UINT>(InstanceDataStepRate)
|
static_cast<UINT>(inputElement.InstanceDataStepRate)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,9 @@
|
|||||||
#include "Engine/Graphics/PixelFormatExtensions.h"
|
#include "Engine/Graphics/PixelFormatExtensions.h"
|
||||||
|
|
||||||
#if PLATFORM_DESKTOP
|
#if PLATFORM_DESKTOP
|
||||||
#define VULKAN_UNIFORM_RING_BUFFER_SIZE 24 * 1024 * 1024
|
#define VULKAN_UNIFORM_RING_BUFFER_SIZE (24 * 1024 * 1024)
|
||||||
#else
|
#else
|
||||||
#define VULKAN_UNIFORM_RING_BUFFER_SIZE 8 * 1024 * 1024
|
#define VULKAN_UNIFORM_RING_BUFFER_SIZE (8 * 1024 * 1024)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
UniformBufferUploaderVulkan::UniformBufferUploaderVulkan(GPUDeviceVulkan* device)
|
UniformBufferUploaderVulkan::UniformBufferUploaderVulkan(GPUDeviceVulkan* device)
|
||||||
@@ -153,10 +153,6 @@ GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, cons
|
|||||||
vertexBindingDescriptions[i].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
vertexBindingDescriptions[i].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temporary variables
|
|
||||||
byte Type, Format, Index, InputSlot, InputSlotClass;
|
|
||||||
uint32 AlignedByteOffset, InstanceDataStepRate;
|
|
||||||
|
|
||||||
// Load Input Layout (it may be empty)
|
// Load Input Layout (it may be empty)
|
||||||
byte inputLayoutSize;
|
byte inputLayoutSize;
|
||||||
stream.ReadByte(&inputLayoutSize);
|
stream.ReadByte(&inputLayoutSize);
|
||||||
@@ -167,32 +163,26 @@ GPUShaderProgram* GPUShaderVulkan::CreateGPUShaderProgram(ShaderStage type, cons
|
|||||||
for (int32 a = 0; a < inputLayoutSize; a++)
|
for (int32 a = 0; a < inputLayoutSize; a++)
|
||||||
{
|
{
|
||||||
// Read description
|
// Read description
|
||||||
// TODO: maybe use struct and load at once?
|
GPUShaderProgramVS::InputElement inputElement;
|
||||||
stream.ReadByte(&Type);
|
stream.Read(inputElement);
|
||||||
stream.ReadByte(&Index);
|
|
||||||
stream.ReadByte(&Format);
|
|
||||||
stream.ReadByte(&InputSlot);
|
|
||||||
stream.ReadUint32(&AlignedByteOffset);
|
|
||||||
stream.ReadByte(&InputSlotClass);
|
|
||||||
stream.ReadUint32(&InstanceDataStepRate);
|
|
||||||
|
|
||||||
const auto size = PixelFormatExtensions::SizeInBytes((PixelFormat)Format);
|
const auto size = PixelFormatExtensions::SizeInBytes((PixelFormat)inputElement.Format);
|
||||||
if (AlignedByteOffset != INPUT_LAYOUT_ELEMENT_ALIGN)
|
if (inputElement.AlignedByteOffset != INPUT_LAYOUT_ELEMENT_ALIGN)
|
||||||
offset = AlignedByteOffset;
|
offset = inputElement.AlignedByteOffset;
|
||||||
|
|
||||||
auto& vertexBindingDescription = vertexBindingDescriptions[InputSlot];
|
auto& vertexBindingDescription = vertexBindingDescriptions[inputElement.InputSlot];
|
||||||
vertexBindingDescription.binding = InputSlot;
|
vertexBindingDescription.binding = inputElement.InputSlot;
|
||||||
vertexBindingDescription.stride = Math::Max(vertexBindingDescription.stride, (uint32_t)(offset + size));
|
vertexBindingDescription.stride = Math::Max(vertexBindingDescription.stride, (uint32_t)(offset + size));
|
||||||
vertexBindingDescription.inputRate = InputSlotClass == INPUT_LAYOUT_ELEMENT_PER_VERTEX_DATA ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
|
vertexBindingDescription.inputRate = inputElement.InputSlotClass == INPUT_LAYOUT_ELEMENT_PER_VERTEX_DATA ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
|
||||||
ASSERT(InstanceDataStepRate == 0 || InstanceDataStepRate == 1);
|
ASSERT(inputElement.InstanceDataStepRate == 0 || inputElement.InstanceDataStepRate == 1);
|
||||||
|
|
||||||
auto& vertexAttributeDescription = vertexAttributeDescriptions[a];
|
auto& vertexAttributeDescription = vertexAttributeDescriptions[a];
|
||||||
vertexAttributeDescription.location = a;
|
vertexAttributeDescription.location = a;
|
||||||
vertexAttributeDescription.binding = InputSlot;
|
vertexAttributeDescription.binding = inputElement.InputSlot;
|
||||||
vertexAttributeDescription.format = RenderToolsVulkan::ToVulkanFormat((PixelFormat)Format);
|
vertexAttributeDescription.format = RenderToolsVulkan::ToVulkanFormat((PixelFormat)inputElement.Format);
|
||||||
vertexAttributeDescription.offset = offset;
|
vertexAttributeDescription.offset = offset;
|
||||||
|
|
||||||
bindingsCount = Math::Max(bindingsCount, (uint32)InputSlot + 1);
|
bindingsCount = Math::Max(bindingsCount, (uint32)inputElement.InputSlot + 1);
|
||||||
offset += size;
|
offset += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -416,7 +416,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load scene
|
// Load scene
|
||||||
if (Level::loadScene(SceneAsset.Get()))
|
if (Level::loadScene(SceneAsset))
|
||||||
{
|
{
|
||||||
LOG(Error, "Failed to deserialize scene {0}", SceneId);
|
LOG(Error, "Failed to deserialize scene {0}", SceneId);
|
||||||
CallSceneEvent(SceneEventType::OnSceneLoadError, nullptr, SceneId);
|
CallSceneEvent(SceneEventType::OnSceneLoadError, nullptr, SceneId);
|
||||||
@@ -816,40 +816,10 @@ bool LevelImpl::unloadScenes()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Level::loadScene(const Guid& sceneId)
|
|
||||||
{
|
|
||||||
const auto sceneAsset = Content::LoadAsync<JsonAsset>(sceneId);
|
|
||||||
return loadScene(sceneAsset);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Level::loadScene(const String& scenePath)
|
|
||||||
{
|
|
||||||
LOG(Info, "Loading scene from file. Path: \'{0}\'", scenePath);
|
|
||||||
|
|
||||||
// Check for missing file
|
|
||||||
if (!FileSystem::FileExists(scenePath))
|
|
||||||
{
|
|
||||||
LOG(Error, "Missing scene file.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load file
|
|
||||||
BytesContainer sceneData;
|
|
||||||
if (File::ReadAllBytes(scenePath, sceneData))
|
|
||||||
{
|
|
||||||
LOG(Error, "Cannot load data from file.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return loadScene(sceneData);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Level::loadScene(JsonAsset* sceneAsset)
|
bool Level::loadScene(JsonAsset* sceneAsset)
|
||||||
{
|
{
|
||||||
// Keep reference to the asset (prevent unloading during action)
|
// Keep reference to the asset (prevent unloading during action)
|
||||||
AssetReference<JsonAsset> ref = sceneAsset;
|
AssetReference<JsonAsset> ref = sceneAsset;
|
||||||
|
|
||||||
// Wait for loaded
|
|
||||||
if (sceneAsset == nullptr || sceneAsset->WaitForLoaded())
|
if (sceneAsset == nullptr || sceneAsset->WaitForLoaded())
|
||||||
{
|
{
|
||||||
LOG(Error, "Cannot load scene asset.");
|
LOG(Error, "Cannot load scene asset.");
|
||||||
@@ -879,6 +849,7 @@ bool Level::loadScene(const BytesContainer& sceneData, Scene** outScene)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScopeLock lock(ScenesLock);
|
||||||
return loadScene(document, outScene);
|
return loadScene(document, outScene);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -975,6 +946,7 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, Scene** ou
|
|||||||
SceneObject** objects = sceneObjects->Get();
|
SceneObject** objects = sceneObjects->Get();
|
||||||
if (context.Async)
|
if (context.Async)
|
||||||
{
|
{
|
||||||
|
ScenesLock.Unlock(); // Unlock scenes from Main Thread so Job Threads can use it to safely setup actors hierarchy (see Actor::Deserialize)
|
||||||
JobSystem::Execute([&](int32 i)
|
JobSystem::Execute([&](int32 i)
|
||||||
{
|
{
|
||||||
i++; // Start from 1. at index [0] was scene
|
i++; // Start from 1. at index [0] was scene
|
||||||
@@ -992,6 +964,7 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, Scene** ou
|
|||||||
else
|
else
|
||||||
SceneObjectsFactory::HandleObjectDeserializationError(stream);
|
SceneObjectsFactory::HandleObjectDeserializationError(stream);
|
||||||
}, objectsCount - 1);
|
}, objectsCount - 1);
|
||||||
|
ScenesLock.Lock();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1330,6 +1303,7 @@ bool Level::LoadScene(const Guid& id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load scene
|
// Load scene
|
||||||
|
ScopeLock lock(ScenesLock);
|
||||||
if (loadScene(sceneAsset))
|
if (loadScene(sceneAsset))
|
||||||
{
|
{
|
||||||
LOG(Error, "Failed to deserialize scene {0}", id);
|
LOG(Error, "Failed to deserialize scene {0}", id);
|
||||||
|
|||||||
@@ -541,8 +541,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void callActorEvent(ActorEventType eventType, Actor* a, Actor* b);
|
static void callActorEvent(ActorEventType eventType, Actor* a, Actor* b);
|
||||||
static bool loadScene(const Guid& sceneId);
|
|
||||||
static bool loadScene(const String& scenePath);
|
// All loadScene assume that ScenesLock has been taken by the calling thread
|
||||||
static bool loadScene(JsonAsset* sceneAsset);
|
static bool loadScene(JsonAsset* sceneAsset);
|
||||||
static bool loadScene(const BytesContainer& sceneData, Scene** outScene = nullptr);
|
static bool loadScene(const BytesContainer& sceneData, Scene** outScene = nullptr);
|
||||||
static bool loadScene(rapidjson_flax::Document& document, Scene** outScene = nullptr);
|
static bool loadScene(rapidjson_flax::Document& document, Scene** outScene = nullptr);
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ PrefabManagerService PrefabManagerServiceInstance;
|
|||||||
Actor* PrefabManager::SpawnPrefab(Prefab* prefab)
|
Actor* PrefabManager::SpawnPrefab(Prefab* prefab)
|
||||||
{
|
{
|
||||||
Actor* parent = Level::Scenes.Count() != 0 ? Level::Scenes.Get()[0] : nullptr;
|
Actor* parent = Level::Scenes.Count() != 0 ? Level::Scenes.Get()[0] : nullptr;
|
||||||
return SpawnPrefab(prefab, Transform::Identity, parent, nullptr);
|
return SpawnPrefab(prefab, Transform(Vector3::Minimum), parent, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Vector3& position)
|
Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Vector3& position)
|
||||||
@@ -73,12 +73,12 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, const Transform
|
|||||||
|
|
||||||
Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent)
|
Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent)
|
||||||
{
|
{
|
||||||
return SpawnPrefab(prefab, Transform::Identity, parent, nullptr);
|
return SpawnPrefab(prefab, Transform(Vector3::Minimum), parent, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, Dictionary<Guid, const void*>* objectsCache, bool withSynchronization)
|
Actor* PrefabManager::SpawnPrefab(Prefab* prefab, Actor* parent, Dictionary<Guid, const void*>* objectsCache, bool withSynchronization)
|
||||||
{
|
{
|
||||||
return SpawnPrefab(prefab, Transform::Identity, parent, objectsCache, withSynchronization);
|
return SpawnPrefab(prefab, Transform(Vector3::Minimum), parent, objectsCache, withSynchronization);
|
||||||
}
|
}
|
||||||
|
|
||||||
Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Transform& transform, Actor* parent, Dictionary<Guid, const void*>* objectsCache, bool withSynchronization)
|
Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Transform& transform, Actor* parent, Dictionary<Guid, const void*>* objectsCache, bool withSynchronization)
|
||||||
@@ -191,7 +191,7 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Transform& transform, Ac
|
|||||||
parent->Children.Add(root);
|
parent->Children.Add(root);
|
||||||
|
|
||||||
// Move root to the right location
|
// Move root to the right location
|
||||||
if (transform != Transform::Identity)
|
if (transform.Translation != Vector3::Minimum)
|
||||||
root->SetTransform(transform);
|
root->SetTransform(transform);
|
||||||
|
|
||||||
// Link actors hierarchy
|
// Link actors hierarchy
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "Engine/Threading/ThreadLocal.h"
|
#include "Engine/Threading/ThreadLocal.h"
|
||||||
#if !BUILD_RELEASE || USE_EDITOR
|
#if !BUILD_RELEASE || USE_EDITOR
|
||||||
#include "Engine/Level/Level.h"
|
#include "Engine/Level/Level.h"
|
||||||
|
#include "Engine/Threading/Threading.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SceneObjectsFactory::Context::Context(ISerializeModifier* modifier)
|
SceneObjectsFactory::Context::Context(ISerializeModifier* modifier)
|
||||||
@@ -279,9 +280,9 @@ void SceneObjectsFactory::HandleObjectDeserializationError(const ISerializable::
|
|||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
// Add dummy script
|
// Add dummy script
|
||||||
auto* dummyScript = parent->AddScript<MissingScript>();
|
auto* dummyScript = parent->AddScript<MissingScript>();
|
||||||
const auto parentIdMember = value.FindMember("TypeName");
|
const auto typeNameMember = value.FindMember("TypeName");
|
||||||
if (parentIdMember != value.MemberEnd() && parentIdMember->value.IsString())
|
if (typeNameMember != value.MemberEnd() && typeNameMember->value.IsString())
|
||||||
dummyScript->MissingTypeName = parentIdMember->value.GetString();
|
dummyScript->MissingTypeName = typeNameMember->value.GetString();
|
||||||
dummyScript->Data = MoveTemp(bufferStr);
|
dummyScript->Data = MoveTemp(bufferStr);
|
||||||
#endif
|
#endif
|
||||||
LOG(Warning, "Parent actor of the missing object: {0}", parent->GetName());
|
LOG(Warning, "Parent actor of the missing object: {0}", parent->GetName());
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "Engine/Level/Level.h"
|
#include "Engine/Level/Level.h"
|
||||||
#include "Engine/Level/Scene/Scene.h"
|
#include "Engine/Level/Scene/Scene.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
#include "Engine/Threading/Threading.h"
|
||||||
#include <ThirdParty/recastnavigation/DetourCrowd.h>
|
#include <ThirdParty/recastnavigation/DetourCrowd.h>
|
||||||
|
|
||||||
NavCrowd::NavCrowd(const SpawnParams& params)
|
NavCrowd::NavCrowd(const SpawnParams& params)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Current GPU particles emitter shader version.
|
/// Current GPU particles emitter shader version.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#define PARTICLE_GPU_GRAPH_VERSION 9
|
#define PARTICLE_GPU_GRAPH_VERSION 10
|
||||||
|
|
||||||
#if COMPILE_WITH_PARTICLE_GPU_GRAPH
|
#if COMPILE_WITH_PARTICLE_GPU_GRAPH
|
||||||
|
|
||||||
|
|||||||
@@ -284,6 +284,7 @@ void ParticleEffect::UpdateSimulation(bool singleFrame)
|
|||||||
void ParticleEffect::Play()
|
void ParticleEffect::Play()
|
||||||
{
|
{
|
||||||
_isPlaying = true;
|
_isPlaying = true;
|
||||||
|
_isStopped = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParticleEffect::Pause()
|
void ParticleEffect::Pause()
|
||||||
@@ -293,6 +294,7 @@ void ParticleEffect::Pause()
|
|||||||
|
|
||||||
void ParticleEffect::Stop()
|
void ParticleEffect::Stop()
|
||||||
{
|
{
|
||||||
|
_isStopped = true;
|
||||||
_isPlaying = false;
|
_isPlaying = false;
|
||||||
ResetSimulation();
|
ResetSimulation();
|
||||||
}
|
}
|
||||||
@@ -448,7 +450,7 @@ void ParticleEffect::Update()
|
|||||||
void ParticleEffect::UpdateExecuteInEditor()
|
void ParticleEffect::UpdateExecuteInEditor()
|
||||||
{
|
{
|
||||||
// Auto-play in Editor
|
// Auto-play in Editor
|
||||||
if (!Editor::IsPlayMode)
|
if (!Editor::IsPlayMode && !_isStopped)
|
||||||
{
|
{
|
||||||
_isPlaying = true;
|
_isPlaying = true;
|
||||||
Update();
|
Update();
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The particle system instance that plays the particles simulation in the game.
|
/// The particle system instance that plays the particles simulation in the game.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_CLASS(Attributes="ActorContextMenu(\"New/Visuals/Particle Effects\"), ActorToolbox(\"Visuals\")")
|
API_CLASS(Attributes="ActorContextMenu(\"New/Visuals/Particle Effect\"), ActorToolbox(\"Visuals\")")
|
||||||
class FLAXENGINE_API ParticleEffect : public Actor
|
class FLAXENGINE_API ParticleEffect : public Actor
|
||||||
{
|
{
|
||||||
DECLARE_SCENE_OBJECT(ParticleEffect);
|
DECLARE_SCENE_OBJECT(ParticleEffect);
|
||||||
@@ -185,6 +185,7 @@ private:
|
|||||||
Array<ParticleEffectParameter> _parameters; // Cached for scripting API
|
Array<ParticleEffectParameter> _parameters; // Cached for scripting API
|
||||||
Array<ParameterOverride> _parametersOverrides; // Cached parameter modifications to be applied to the parameters
|
Array<ParameterOverride> _parametersOverrides; // Cached parameter modifications to be applied to the parameters
|
||||||
bool _isPlaying = false;
|
bool _isPlaying = false;
|
||||||
|
bool _isStopped = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1318,6 +1318,8 @@ void ParticlesSystem::Job(int32 index)
|
|||||||
emitterInstance.Buffer = nullptr;
|
emitterInstance.Buffer = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Stop playing effect.
|
||||||
|
effect->Stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1332,7 +1334,8 @@ void ParticlesSystem::Job(int32 index)
|
|||||||
auto emitter = particleSystem->Emitters[track.AsEmitter.Index].Get();
|
auto emitter = particleSystem->Emitters[track.AsEmitter.Index].Get();
|
||||||
auto& data = instance.Emitters[track.AsEmitter.Index];
|
auto& data = instance.Emitters[track.AsEmitter.Index];
|
||||||
ASSERT(emitter && emitter->IsLoaded());
|
ASSERT(emitter && emitter->IsLoaded());
|
||||||
ASSERT(emitter->Capacity != 0 && emitter->Graph.Layout.Size != 0);
|
if (emitter->Capacity == 0 || emitter->Graph.Layout.Size == 0)
|
||||||
|
continue;
|
||||||
PROFILE_CPU_ASSET(emitter);
|
PROFILE_CPU_ASSET(emitter);
|
||||||
|
|
||||||
// Calculate new time position
|
// Calculate new time position
|
||||||
|
|||||||
@@ -95,14 +95,17 @@ void Cloth::SetFabric(const FabricSettings& value)
|
|||||||
void Cloth::Rebuild()
|
void Cloth::Rebuild()
|
||||||
{
|
{
|
||||||
#if WITH_CLOTH
|
#if WITH_CLOTH
|
||||||
// Remove old
|
if (_cloth)
|
||||||
if (IsDuringPlay())
|
{
|
||||||
PhysicsBackend::RemoveCloth(GetPhysicsScene()->GetPhysicsScene(), _cloth);
|
// Remove old
|
||||||
DestroyCloth();
|
if (IsDuringPlay())
|
||||||
|
PhysicsBackend::RemoveCloth(GetPhysicsScene()->GetPhysicsScene(), _cloth);
|
||||||
|
DestroyCloth();
|
||||||
|
}
|
||||||
|
|
||||||
// Create new
|
// Create new
|
||||||
CreateCloth();
|
CreateCloth();
|
||||||
if (IsDuringPlay())
|
if (IsDuringPlay() && _cloth)
|
||||||
PhysicsBackend::AddCloth(GetPhysicsScene()->GetPhysicsScene(), _cloth);
|
PhysicsBackend::AddCloth(GetPhysicsScene()->GetPhysicsScene(), _cloth);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -232,13 +232,13 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the mesh to use for the cloth simulation (single mesh from specific LOD).
|
/// Gets the mesh to use for the cloth simulation (single mesh from specific LOD). Always from the parent static or animated model actor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_PROPERTY(Attributes="EditorOrder(0), EditorDisplay(\"Cloth\")")
|
API_PROPERTY(Attributes="EditorOrder(0), EditorDisplay(\"Cloth\")")
|
||||||
ModelInstanceActor::MeshReference GetMesh() const;
|
ModelInstanceActor::MeshReference GetMesh() const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the mesh to use for the cloth simulation (single mesh from specific LOD).
|
/// Sets the mesh to use for the cloth simulation (single mesh from specific LOD). Always from the parent static or animated model actor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_PROPERTY() void SetMesh(const ModelInstanceActor::MeshReference& value);
|
API_PROPERTY() void SetMesh(const ModelInstanceActor::MeshReference& value);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
#include "PhysicsColliderActor.h"
|
#include "PhysicsColliderActor.h"
|
||||||
#include "Engine/Scripting/Script.h"
|
|
||||||
#include "RigidBody.h"
|
#include "RigidBody.h"
|
||||||
|
|
||||||
PhysicsColliderActor::PhysicsColliderActor(const SpawnParams& params)
|
PhysicsColliderActor::PhysicsColliderActor(const SpawnParams& params)
|
||||||
|
|||||||
@@ -117,9 +117,7 @@ void SimulationEventCallback::onContact(const PxContactPairHeader& pairHeader, c
|
|||||||
{
|
{
|
||||||
// Skip sending events to removed actors
|
// Skip sending events to removed actors
|
||||||
if (pairHeader.flags & (PxContactPairHeaderFlag::eREMOVED_ACTOR_0 | PxContactPairHeaderFlag::eREMOVED_ACTOR_1))
|
if (pairHeader.flags & (PxContactPairHeaderFlag::eREMOVED_ACTOR_0 | PxContactPairHeaderFlag::eREMOVED_ACTOR_1))
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
Collision c;
|
Collision c;
|
||||||
PxContactPairExtraDataIterator j(pairHeader.extraDataStream, pairHeader.extraDataStreamSize);
|
PxContactPairExtraDataIterator j(pairHeader.extraDataStream, pairHeader.extraDataStreamSize);
|
||||||
@@ -193,7 +191,7 @@ void SimulationEventCallback::onContact(const PxContactPairHeader& pairHeader, c
|
|||||||
RemovedCollisions.Add(c);
|
RemovedCollisions.Add(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ASSERT(!j.nextItemSet());
|
//ASSERT(!j.nextItemSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulationEventCallback::onTrigger(PxTriggerPair* pairs, PxU32 count)
|
void SimulationEventCallback::onTrigger(PxTriggerPair* pairs, PxU32 count)
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ CPUInfo Cpu;
|
|||||||
String UserLocale;
|
String UserLocale;
|
||||||
double SecondsPerCycle;
|
double SecondsPerCycle;
|
||||||
NSAutoreleasePool* AutoreleasePool = nullptr;
|
NSAutoreleasePool* AutoreleasePool = nullptr;
|
||||||
|
int32 AutoreleasePoolInterval = 0;
|
||||||
|
|
||||||
float ApplePlatform::ScreenScale = 1.0f;
|
float ApplePlatform::ScreenScale = 1.0f;
|
||||||
|
|
||||||
@@ -245,13 +246,40 @@ void ApplePlatform::GetUTCTime(int32& year, int32& month, int32& dayOfWeek, int3
|
|||||||
millisecond = time.tv_usec / 1000;
|
millisecond = time.tv_usec / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !BUILD_RELEASE
|
||||||
|
|
||||||
void ApplePlatform::Log(const StringView& msg)
|
void ApplePlatform::Log(const StringView& msg)
|
||||||
{
|
{
|
||||||
#if !BUILD_RELEASE && !USE_EDITOR
|
#if !USE_EDITOR
|
||||||
NSLog(@"%s", StringAsANSI<>(*msg, msg.Length()).Get());
|
NSLog(@"%s", StringAsANSI<>(*msg, msg.Length()).Get());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ApplePlatform::IsDebuggerPresent()
|
||||||
|
{
|
||||||
|
// Reference: https://developer.apple.com/library/archive/qa/qa1361/_index.html
|
||||||
|
int mib[4];
|
||||||
|
struct kinfo_proc info;
|
||||||
|
|
||||||
|
// Initialize the flags so that, if sysctl fails for some bizarre reason, we get a predictable result
|
||||||
|
info.kp_proc.p_flag = 0;
|
||||||
|
|
||||||
|
// Initialize mib, which tells sysctl the info we want, in this case we're looking for information about a specific process ID
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = KERN_PROC;
|
||||||
|
mib[2] = KERN_PROC_PID;
|
||||||
|
mib[3] = getpid();
|
||||||
|
|
||||||
|
// Call sysctl
|
||||||
|
size_t size = sizeof(info);
|
||||||
|
sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
|
||||||
|
|
||||||
|
// We're being debugged if the P_TRACED flag is set
|
||||||
|
return ((info.kp_proc.p_flag & P_TRACED) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
bool ApplePlatform::Init()
|
bool ApplePlatform::Init()
|
||||||
{
|
{
|
||||||
if (UnixPlatform::Init())
|
if (UnixPlatform::Init())
|
||||||
@@ -332,9 +360,13 @@ bool ApplePlatform::Init()
|
|||||||
|
|
||||||
void ApplePlatform::Tick()
|
void ApplePlatform::Tick()
|
||||||
{
|
{
|
||||||
// TODO: do it once every X fames
|
AutoreleasePoolInterval++;
|
||||||
[AutoreleasePool drain];
|
if (AutoreleasePoolInterval >= 60)
|
||||||
AutoreleasePool = [[NSAutoreleasePool alloc] init];
|
{
|
||||||
|
AutoreleasePoolInterval = 0;
|
||||||
|
[AutoreleasePool drain];
|
||||||
|
AutoreleasePool = [[NSAutoreleasePool alloc] init];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplePlatform::BeforeExit()
|
void ApplePlatform::BeforeExit()
|
||||||
@@ -343,6 +375,11 @@ void ApplePlatform::BeforeExit()
|
|||||||
|
|
||||||
void ApplePlatform::Exit()
|
void ApplePlatform::Exit()
|
||||||
{
|
{
|
||||||
|
if (AutoreleasePool)
|
||||||
|
{
|
||||||
|
[AutoreleasePool drain];
|
||||||
|
AutoreleasePool = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplePlatform::SetHighDpiAwarenessEnabled(bool enable)
|
void ApplePlatform::SetHighDpiAwarenessEnabled(bool enable)
|
||||||
@@ -369,9 +406,7 @@ bool ApplePlatform::GetHasFocus()
|
|||||||
if (window->IsFocused())
|
if (window->IsFocused())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
// Default to true if has no windows open
|
|
||||||
return WindowsManager::Windows.IsEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplePlatform::CreateGuid(Guid& result)
|
void ApplePlatform::CreateGuid(Guid& result)
|
||||||
|
|||||||
@@ -79,7 +79,10 @@ public:
|
|||||||
static uint64 GetClockFrequency();
|
static uint64 GetClockFrequency();
|
||||||
static void GetSystemTime(int32& year, int32& month, int32& dayOfWeek, int32& day, int32& hour, int32& minute, int32& second, int32& millisecond);
|
static void GetSystemTime(int32& year, int32& month, int32& dayOfWeek, int32& day, int32& hour, int32& minute, int32& second, int32& millisecond);
|
||||||
static void GetUTCTime(int32& year, int32& month, int32& dayOfWeek, int32& day, int32& hour, int32& minute, int32& second, int32& millisecond);
|
static void GetUTCTime(int32& year, int32& month, int32& dayOfWeek, int32& day, int32& hour, int32& minute, int32& second, int32& millisecond);
|
||||||
|
#if !BUILD_RELEASE
|
||||||
static void Log(const StringView& msg);
|
static void Log(const StringView& msg);
|
||||||
|
static bool IsDebuggerPresent();
|
||||||
|
#endif
|
||||||
static bool Init();
|
static bool Init();
|
||||||
static void Tick();
|
static void Tick();
|
||||||
static void BeforeExit();
|
static void BeforeExit();
|
||||||
|
|||||||
@@ -59,9 +59,11 @@ void WindowsManagerService::Update()
|
|||||||
// Update windows
|
// Update windows
|
||||||
const float deltaTime = Time::Update.UnscaledDeltaTime.GetTotalSeconds();
|
const float deltaTime = Time::Update.UnscaledDeltaTime.GetTotalSeconds();
|
||||||
WindowsManager::WindowsLocker.Lock();
|
WindowsManager::WindowsLocker.Lock();
|
||||||
for (Window* win : WindowsManager::Windows)
|
Array<Window*, InlinedAllocation<32>> windows;
|
||||||
|
windows.Add(WindowsManager::Windows);
|
||||||
|
for (Window* win : windows)
|
||||||
{
|
{
|
||||||
if (win && win->IsVisible())
|
if (win->IsVisible())
|
||||||
win->OnUpdate(deltaTime);
|
win->OnUpdate(deltaTime);
|
||||||
}
|
}
|
||||||
WindowsManager::WindowsLocker.Unlock();
|
WindowsManager::WindowsLocker.Unlock();
|
||||||
@@ -71,7 +73,8 @@ void WindowsManagerService::Dispose()
|
|||||||
{
|
{
|
||||||
// Close remaining windows
|
// Close remaining windows
|
||||||
WindowsManager::WindowsLocker.Lock();
|
WindowsManager::WindowsLocker.Lock();
|
||||||
auto windows = WindowsManager::Windows;
|
Array<Window*, InlinedAllocation<32>> windows;
|
||||||
|
windows.Add(WindowsManager::Windows);
|
||||||
for (Window* win : windows)
|
for (Window* win : windows)
|
||||||
{
|
{
|
||||||
win->Close(ClosingReason::EngineExit);
|
win->Close(ClosingReason::EngineExit);
|
||||||
|
|||||||
@@ -2622,9 +2622,7 @@ bool LinuxPlatform::GetHasFocus()
|
|||||||
if (window->IsFocused())
|
if (window->IsFocused())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
// Default to true if has no windows open
|
|
||||||
return WindowsManager::Windows.IsEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxPlatform::CanOpenUrl(const StringView& url)
|
bool LinuxPlatform::CanOpenUrl(const StringView& url)
|
||||||
|
|||||||
@@ -4,7 +4,14 @@
|
|||||||
|
|
||||||
#include "../Window.h"
|
#include "../Window.h"
|
||||||
#include "Engine/Platform/Apple/AppleUtils.h"
|
#include "Engine/Platform/Apple/AppleUtils.h"
|
||||||
|
#include "Engine/Platform/WindowsManager.h"
|
||||||
#include "Engine/Platform/IGuiData.h"
|
#include "Engine/Platform/IGuiData.h"
|
||||||
|
#if USE_EDITOR
|
||||||
|
#include "Engine/Platform/CriticalSection.h"
|
||||||
|
#include "Engine/Threading/ThreadPoolTask.h"
|
||||||
|
#include "Engine/Threading/ThreadPool.h"
|
||||||
|
#include "Engine/Engine/Engine.h"
|
||||||
|
#endif
|
||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
#include "Engine/Input/Input.h"
|
#include "Engine/Input/Input.h"
|
||||||
#include "Engine/Input/Mouse.h"
|
#include "Engine/Input/Mouse.h"
|
||||||
@@ -14,6 +21,37 @@
|
|||||||
#include <AppKit/AppKit.h>
|
#include <AppKit/AppKit.h>
|
||||||
#include <QuartzCore/CAMetalLayer.h>
|
#include <QuartzCore/CAMetalLayer.h>
|
||||||
|
|
||||||
|
#if USE_EDITOR
|
||||||
|
// Data for drawing window while doing drag&drop on Mac (engine is paused during platform tick)
|
||||||
|
CriticalSection MacDragLocker;
|
||||||
|
NSDraggingSession* MacDragSession = nullptr;
|
||||||
|
class DoDragDropJob* MacDragJob = nullptr;
|
||||||
|
|
||||||
|
class DoDragDropJob : public ThreadPoolTask
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int64 ExitFlag = 0;
|
||||||
|
|
||||||
|
bool Run() override
|
||||||
|
{
|
||||||
|
while (Platform::AtomicRead(&ExitFlag) == 0)
|
||||||
|
{
|
||||||
|
Engine::OnDraw();
|
||||||
|
Platform::Sleep(20);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline bool IsWindowInvalid(Window* win)
|
||||||
|
{
|
||||||
|
WindowsManager::WindowsLocker.Lock();
|
||||||
|
const bool hasWindow = WindowsManager::Windows.Contains(win);
|
||||||
|
WindowsManager::WindowsLocker.Unlock();
|
||||||
|
return !hasWindow || !win;
|
||||||
|
}
|
||||||
|
|
||||||
KeyboardKeys GetKey(NSEvent* event)
|
KeyboardKeys GetKey(NSEvent* event)
|
||||||
{
|
{
|
||||||
switch ([event keyCode])
|
switch ([event keyCode])
|
||||||
@@ -268,17 +306,20 @@ NSDragOperation GetDragDropOperation(DragDropEffect dragDropEffect)
|
|||||||
// Handle resizing to be sure that content has valid size when window was resized
|
// Handle resizing to be sure that content has valid size when window was resized
|
||||||
[self windowDidResize:notification];
|
[self windowDidResize:notification];
|
||||||
|
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
Window->OnGotFocus();
|
Window->OnGotFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)windowDidResignKey:(NSNotification*)notification
|
- (void)windowDidResignKey:(NSNotification*)notification
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
Window->OnLostFocus();
|
Window->OnLostFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)windowWillClose:(NSNotification*)notification
|
- (void)windowWillClose:(NSNotification*)notification
|
||||||
{
|
{
|
||||||
[self setDelegate: nil];
|
[self setDelegate: nil];
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
Window->Close(ClosingReason::User);
|
Window->Close(ClosingReason::User);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,7 +352,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface MacViewImpl : NSView
|
@interface MacViewImpl : NSView <NSDraggingSource, NSPasteboardItemDataProvider>
|
||||||
{
|
{
|
||||||
MacWindow* Window;
|
MacWindow* Window;
|
||||||
NSTrackingArea* TrackingArea;
|
NSTrackingArea* TrackingArea;
|
||||||
@@ -375,6 +416,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
|||||||
|
|
||||||
- (void)keyDown:(NSEvent*)event
|
- (void)keyDown:(NSEvent*)event
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
KeyboardKeys key = GetKey(event);
|
KeyboardKeys key = GetKey(event);
|
||||||
if (key != KeyboardKeys::None)
|
if (key != KeyboardKeys::None)
|
||||||
Input::Keyboard->OnKeyDown(key, Window);
|
Input::Keyboard->OnKeyDown(key, Window);
|
||||||
@@ -405,6 +447,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
|||||||
|
|
||||||
- (void)keyUp:(NSEvent*)event
|
- (void)keyUp:(NSEvent*)event
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
KeyboardKeys key = GetKey(event);
|
KeyboardKeys key = GetKey(event);
|
||||||
if (key != KeyboardKeys::None)
|
if (key != KeyboardKeys::None)
|
||||||
Input::Keyboard->OnKeyUp(key, Window);
|
Input::Keyboard->OnKeyUp(key, Window);
|
||||||
@@ -412,6 +455,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
|||||||
|
|
||||||
- (void)flagsChanged:(NSEvent*)event
|
- (void)flagsChanged:(NSEvent*)event
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
int32 modMask;
|
int32 modMask;
|
||||||
int32 keyCode = [event keyCode];
|
int32 keyCode = [event keyCode];
|
||||||
if (keyCode == 0x36 || keyCode == 0x37)
|
if (keyCode == 0x36 || keyCode == 0x37)
|
||||||
@@ -437,6 +481,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
|||||||
|
|
||||||
- (void)scrollWheel:(NSEvent*)event
|
- (void)scrollWheel:(NSEvent*)event
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
Float2 mousePos = GetMousePosition(Window, event);
|
Float2 mousePos = GetMousePosition(Window, event);
|
||||||
double deltaX = [event scrollingDeltaX];
|
double deltaX = [event scrollingDeltaX];
|
||||||
double deltaY = [event scrollingDeltaY];
|
double deltaY = [event scrollingDeltaY];
|
||||||
@@ -451,32 +496,39 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
|||||||
|
|
||||||
- (void)mouseMoved:(NSEvent*)event
|
- (void)mouseMoved:(NSEvent*)event
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
Float2 mousePos = GetMousePosition(Window, event);
|
Float2 mousePos = GetMousePosition(Window, event);
|
||||||
if (!Window->IsMouseTracking() && !IsMouseOver)
|
if (Window->IsMouseTracking())
|
||||||
|
return; // Skip mouse events when tracking mouse (handled in MacWindow::OnUpdate)
|
||||||
|
if (!IsMouseOver)
|
||||||
return;
|
return;
|
||||||
Input::Mouse->OnMouseMove(Window->ClientToScreen(mousePos), Window);
|
Input::Mouse->OnMouseMove(Window->ClientToScreen(mousePos), Window);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseEntered:(NSEvent*)event
|
- (void)mouseEntered:(NSEvent*)event
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
IsMouseOver = true;
|
IsMouseOver = true;
|
||||||
Window->SetIsMouseOver(true);
|
Window->SetIsMouseOver(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseExited:(NSEvent*)event
|
- (void)mouseExited:(NSEvent*)event
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
IsMouseOver = false;
|
IsMouseOver = false;
|
||||||
Window->SetIsMouseOver(false);
|
Window->SetIsMouseOver(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseDown:(NSEvent*)event
|
- (void)mouseDown:(NSEvent*)event
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
Float2 mousePos = GetMousePosition(Window, event);
|
Float2 mousePos = GetMousePosition(Window, event);
|
||||||
|
mousePos = Window->ClientToScreen(mousePos);
|
||||||
MouseButton mouseButton = MouseButton::Left;
|
MouseButton mouseButton = MouseButton::Left;
|
||||||
if ([event clickCount] == 2)
|
if ([event clickCount] == 2)
|
||||||
Input::Mouse->OnMouseDoubleClick(Window->ClientToScreen(mousePos), mouseButton, Window);
|
Input::Mouse->OnMouseDoubleClick(mousePos, mouseButton, Window);
|
||||||
else
|
else
|
||||||
Input::Mouse->OnMouseDown(Window->ClientToScreen(mousePos), mouseButton, Window);
|
Input::Mouse->OnMouseDown(mousePos, mouseButton, Window);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)mouseDragged:(NSEvent*)event
|
- (void)mouseDragged:(NSEvent*)event
|
||||||
@@ -486,13 +538,28 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
|||||||
|
|
||||||
- (void)mouseUp:(NSEvent*)event
|
- (void)mouseUp:(NSEvent*)event
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
Float2 mousePos = GetMousePosition(Window, event);
|
Float2 mousePos = GetMousePosition(Window, event);
|
||||||
|
mousePos = Window->ClientToScreen(mousePos);
|
||||||
MouseButton mouseButton = MouseButton::Left;
|
MouseButton mouseButton = MouseButton::Left;
|
||||||
Input::Mouse->OnMouseUp(Window->ClientToScreen(mousePos), mouseButton, Window);
|
Input::Mouse->OnMouseUp(mousePos, mouseButton, Window);
|
||||||
|
|
||||||
|
// Redirect event to any window that tracks the mouse (eg. dock window in Editor)
|
||||||
|
WindowsManager::WindowsLocker.Lock();
|
||||||
|
for (auto* win : WindowsManager::Windows)
|
||||||
|
{
|
||||||
|
if (win->IsVisible() && win->IsMouseTracking() && win != Window)
|
||||||
|
{
|
||||||
|
Input::Mouse->OnMouseUp(mousePos, mouseButton, win);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WindowsManager::WindowsLocker.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)rightMouseDown:(NSEvent*)event
|
- (void)rightMouseDown:(NSEvent*)event
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
Float2 mousePos = GetMousePosition(Window, event);
|
Float2 mousePos = GetMousePosition(Window, event);
|
||||||
MouseButton mouseButton = MouseButton::Right;
|
MouseButton mouseButton = MouseButton::Right;
|
||||||
if ([event clickCount] == 2)
|
if ([event clickCount] == 2)
|
||||||
@@ -508,6 +575,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
|||||||
|
|
||||||
- (void)rightMouseUp:(NSEvent*)event
|
- (void)rightMouseUp:(NSEvent*)event
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
Float2 mousePos = GetMousePosition(Window, event);
|
Float2 mousePos = GetMousePosition(Window, event);
|
||||||
MouseButton mouseButton = MouseButton::Right;
|
MouseButton mouseButton = MouseButton::Right;
|
||||||
Input::Mouse->OnMouseUp(Window->ClientToScreen(mousePos), mouseButton, Window);
|
Input::Mouse->OnMouseUp(Window->ClientToScreen(mousePos), mouseButton, Window);
|
||||||
@@ -515,6 +583,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
|||||||
|
|
||||||
- (void)otherMouseDown:(NSEvent*)event
|
- (void)otherMouseDown:(NSEvent*)event
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
Float2 mousePos = GetMousePosition(Window, event);
|
Float2 mousePos = GetMousePosition(Window, event);
|
||||||
MouseButton mouseButton;
|
MouseButton mouseButton;
|
||||||
switch ([event buttonNumber])
|
switch ([event buttonNumber])
|
||||||
@@ -544,6 +613,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
|||||||
|
|
||||||
- (void)otherMouseUp:(NSEvent*)event
|
- (void)otherMouseUp:(NSEvent*)event
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
Float2 mousePos = GetMousePosition(Window, event);
|
Float2 mousePos = GetMousePosition(Window, event);
|
||||||
MouseButton mouseButton;
|
MouseButton mouseButton;
|
||||||
switch ([event buttonNumber])
|
switch ([event buttonNumber])
|
||||||
@@ -565,6 +635,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
|||||||
|
|
||||||
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
|
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return NSDragOperationNone;
|
||||||
Float2 mousePos;
|
Float2 mousePos;
|
||||||
MacDropData dropData;
|
MacDropData dropData;
|
||||||
GetDragDropData(Window, sender, mousePos, dropData);
|
GetDragDropData(Window, sender, mousePos, dropData);
|
||||||
@@ -580,6 +651,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
|||||||
|
|
||||||
- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender
|
- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return NSDragOperationNone;
|
||||||
Float2 mousePos;
|
Float2 mousePos;
|
||||||
MacDropData dropData;
|
MacDropData dropData;
|
||||||
GetDragDropData(Window, sender, mousePos, dropData);
|
GetDragDropData(Window, sender, mousePos, dropData);
|
||||||
@@ -590,6 +662,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
|||||||
|
|
||||||
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender
|
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return NO;
|
||||||
Float2 mousePos;
|
Float2 mousePos;
|
||||||
MacDropData dropData;
|
MacDropData dropData;
|
||||||
GetDragDropData(Window, sender, mousePos, dropData);
|
GetDragDropData(Window, sender, mousePos, dropData);
|
||||||
@@ -600,9 +673,38 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
|||||||
|
|
||||||
- (void)draggingExited:(id<NSDraggingInfo>)sender
|
- (void)draggingExited:(id<NSDraggingInfo>)sender
|
||||||
{
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
Window->OnDragLeave();
|
Window->OnDragLeave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSDragOperation)draggingSession:(NSDraggingSession*)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context
|
||||||
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return NSDragOperationNone;
|
||||||
|
return NSDragOperationMove;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)draggingSession:(NSDraggingSession*)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation
|
||||||
|
{
|
||||||
|
#if USE_EDITOR
|
||||||
|
// Stop background worker once the drag ended
|
||||||
|
MacDragLocker.Lock();
|
||||||
|
if (MacDragSession && MacDragSession == session)
|
||||||
|
{
|
||||||
|
Platform::AtomicStore(&MacDragJob->ExitFlag, 1);
|
||||||
|
MacDragJob->Wait();
|
||||||
|
MacDragSession = nullptr;
|
||||||
|
MacDragJob = nullptr;
|
||||||
|
}
|
||||||
|
MacDragLocker.Unlock();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)pasteboard:(nullable NSPasteboard*)pasteboard item:(NSPasteboardItem*)item provideDataForType:(NSPasteboardType)type
|
||||||
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
|
[pasteboard setString:(NSString*)AppleUtils::ToString(Window->GetDragText()) forType:NSPasteboardTypeString];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
MacWindow::MacWindow(const CreateWindowSettings& settings)
|
MacWindow::MacWindow(const CreateWindowSettings& settings)
|
||||||
@@ -624,6 +726,8 @@ MacWindow::MacWindow(const CreateWindowSettings& settings)
|
|||||||
{
|
{
|
||||||
styleMask |= NSWindowStyleMaskBorderless;
|
styleMask |= NSWindowStyleMaskBorderless;
|
||||||
}
|
}
|
||||||
|
if (settings.Fullscreen)
|
||||||
|
styleMask |= NSWindowStyleMaskFullScreen;
|
||||||
if (settings.HasBorder)
|
if (settings.HasBorder)
|
||||||
{
|
{
|
||||||
styleMask |= NSWindowStyleMaskTitled;
|
styleMask |= NSWindowStyleMaskTitled;
|
||||||
@@ -650,9 +754,11 @@ MacWindow::MacWindow(const CreateWindowSettings& settings)
|
|||||||
[window setMaxSize:NSMakeSize(settings.MaximumSize.X, settings.MaximumSize.Y)];
|
[window setMaxSize:NSMakeSize(settings.MaximumSize.X, settings.MaximumSize.Y)];
|
||||||
[window setOpaque:!settings.SupportsTransparency];
|
[window setOpaque:!settings.SupportsTransparency];
|
||||||
[window setContentView:view];
|
[window setContentView:view];
|
||||||
[window setAcceptsMouseMovedEvents:YES];
|
if (settings.AllowInput)
|
||||||
|
[window setAcceptsMouseMovedEvents:YES];
|
||||||
[window setDelegate:window];
|
[window setDelegate:window];
|
||||||
_window = window;
|
_window = window;
|
||||||
|
_view = view;
|
||||||
if (settings.AllowDragAndDrop)
|
if (settings.AllowDragAndDrop)
|
||||||
{
|
{
|
||||||
[view registerForDraggedTypes:@[NSPasteboardTypeFileURL, NSPasteboardTypeString]];
|
[view registerForDraggedTypes:@[NSPasteboardTypeFileURL, NSPasteboardTypeString]];
|
||||||
@@ -664,8 +770,6 @@ MacWindow::MacWindow(const CreateWindowSettings& settings)
|
|||||||
layer.contentsScale = screenScale;
|
layer.contentsScale = screenScale;
|
||||||
|
|
||||||
// TODO: impl Parent for MacWindow
|
// TODO: impl Parent for MacWindow
|
||||||
// TODO: impl StartPosition for MacWindow
|
|
||||||
// TODO: impl Fullscreen for MacWindow
|
|
||||||
// TODO: impl ShowInTaskbar for MacWindow
|
// TODO: impl ShowInTaskbar for MacWindow
|
||||||
// TODO: impl IsTopmost for MacWindow
|
// TODO: impl IsTopmost for MacWindow
|
||||||
}
|
}
|
||||||
@@ -676,6 +780,7 @@ MacWindow::~MacWindow()
|
|||||||
[window close];
|
[window close];
|
||||||
[window release];
|
[window release];
|
||||||
_window = nullptr;
|
_window = nullptr;
|
||||||
|
_view = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacWindow::CheckForResize(float width, float height)
|
void MacWindow::CheckForResize(float width, float height)
|
||||||
@@ -699,7 +804,6 @@ void MacWindow::SetIsMouseOver(bool value)
|
|||||||
// Refresh cursor typet
|
// Refresh cursor typet
|
||||||
SetCursor(CursorType::Default);
|
SetCursor(CursorType::Default);
|
||||||
SetCursor(cursor);
|
SetCursor(cursor);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -714,6 +818,22 @@ void* MacWindow::GetNativePtr() const
|
|||||||
return _window;
|
return _window;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacWindow::OnUpdate(float dt)
|
||||||
|
{
|
||||||
|
if (IsMouseTracking())
|
||||||
|
{
|
||||||
|
// Keep sending mouse movement events no matter if window has focus
|
||||||
|
Float2 mousePos = Platform::GetMousePosition();
|
||||||
|
if (_mouseTrackPos != mousePos)
|
||||||
|
{
|
||||||
|
_mouseTrackPos = mousePos;
|
||||||
|
Input::Mouse->OnMouseMove(mousePos, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowBase::OnUpdate(dt);
|
||||||
|
}
|
||||||
|
|
||||||
void MacWindow::Show()
|
void MacWindow::Show()
|
||||||
{
|
{
|
||||||
if (!_visible)
|
if (!_visible)
|
||||||
@@ -728,7 +848,10 @@ void MacWindow::Show()
|
|||||||
|
|
||||||
// Show
|
// Show
|
||||||
NSWindow* window = (NSWindow*)_window;
|
NSWindow* window = (NSWindow*)_window;
|
||||||
[window makeKeyAndOrderFront:window];
|
if (_settings.AllowInput)
|
||||||
|
[window makeKeyAndOrderFront:window];
|
||||||
|
else
|
||||||
|
[window orderFront:window];
|
||||||
if (_settings.ActivateWhenFirstShown)
|
if (_settings.ActivateWhenFirstShown)
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
_focused = true;
|
_focused = true;
|
||||||
@@ -746,7 +869,7 @@ void MacWindow::Hide()
|
|||||||
|
|
||||||
// Hide
|
// Hide
|
||||||
NSWindow* window = (NSWindow*)_window;
|
NSWindow* window = (NSWindow*)_window;
|
||||||
[window orderOut:nil];
|
[window orderOut:window];
|
||||||
|
|
||||||
// Base
|
// Base
|
||||||
WindowBase::Hide();
|
WindowBase::Hide();
|
||||||
@@ -782,14 +905,9 @@ void MacWindow::Restore()
|
|||||||
[window zoom:nil];
|
[window zoom:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacWindow::IsClosed() const
|
|
||||||
{
|
|
||||||
return _window != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MacWindow::IsForegroundWindow() const
|
bool MacWindow::IsForegroundWindow() const
|
||||||
{
|
{
|
||||||
return Platform::GetHasFocus() && IsFocused();
|
return IsFocused() && Platform::GetHasFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacWindow::BringToFront(bool force)
|
void MacWindow::BringToFront(bool force)
|
||||||
@@ -808,14 +926,13 @@ void MacWindow::SetClientBounds(const Rectangle& clientArea)
|
|||||||
NSWindow* window = (NSWindow*)_window;
|
NSWindow* window = (NSWindow*)_window;
|
||||||
if (!window)
|
if (!window)
|
||||||
return;
|
return;
|
||||||
|
const float screenScale = MacPlatform::ScreenScale;
|
||||||
|
|
||||||
NSRect oldRect = [window frame];
|
NSRect oldRect = [window frame];
|
||||||
NSRect newRect = NSMakeRect(0, 0, clientArea.Size.X, clientArea.Size.Y);
|
NSRect newRect = NSMakeRect(0, 0, clientArea.Size.X / screenScale, clientArea.Size.Y / screenScale);
|
||||||
newRect = [window frameRectForContentRect:newRect];
|
newRect = [window frameRectForContentRect:newRect];
|
||||||
|
|
||||||
//newRect.origin.x = oldRect.origin.x;
|
Float2 pos = AppleUtils::PosToCoca(clientArea.Location) / screenScale;
|
||||||
//newRect.origin.y = NSMaxY(oldRect) - newRect.size.height;
|
|
||||||
|
|
||||||
Float2 pos = AppleUtils::PosToCoca(clientArea.Location);
|
|
||||||
Float2 titleSize = GetWindowTitleSize(this);
|
Float2 titleSize = GetWindowTitleSize(this);
|
||||||
newRect.origin.x = pos.X + titleSize.X;
|
newRect.origin.x = pos.X + titleSize.X;
|
||||||
newRect.origin.y = pos.Y - newRect.size.height + titleSize.Y;
|
newRect.origin.y = pos.Y - newRect.size.height + titleSize.Y;
|
||||||
@@ -909,8 +1026,63 @@ void MacWindow::SetTitle(const StringView& title)
|
|||||||
|
|
||||||
DragDropEffect MacWindow::DoDragDrop(const StringView& data)
|
DragDropEffect MacWindow::DoDragDrop(const StringView& data)
|
||||||
{
|
{
|
||||||
// TODO: implement using beginDraggingSession and NSDraggingSource
|
NSWindow* window = (NSWindow*)_window;
|
||||||
return DragDropEffect::None;
|
MacViewImpl* view = (MacViewImpl*)_view;
|
||||||
|
_dragText = data;
|
||||||
|
|
||||||
|
// Create mouse drag event
|
||||||
|
NSEvent* event = [NSEvent
|
||||||
|
mouseEventWithType:NSEventTypeLeftMouseDragged
|
||||||
|
location:window.mouseLocationOutsideOfEventStream
|
||||||
|
modifierFlags:0
|
||||||
|
timestamp:NSApp.currentEvent.timestamp
|
||||||
|
windowNumber:window.windowNumber
|
||||||
|
context:nil
|
||||||
|
eventNumber:0
|
||||||
|
clickCount:1
|
||||||
|
pressure:1.0];
|
||||||
|
|
||||||
|
// Create drag item
|
||||||
|
NSPasteboardItem* pasteItem = [NSPasteboardItem new];
|
||||||
|
[pasteItem setDataProvider:view forTypes:[NSArray arrayWithObjects:NSPasteboardTypeString, nil]];
|
||||||
|
NSDraggingItem* dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter:pasteItem];
|
||||||
|
[dragItem setDraggingFrame:NSMakeRect(event.locationInWindow.x, event.locationInWindow.y, 1, 1) contents:nil];
|
||||||
|
|
||||||
|
// Start dragging session
|
||||||
|
NSDraggingSession* draggingSession = [view beginDraggingSessionWithItems:[NSArray arrayWithObject:dragItem] event:event source:view];
|
||||||
|
DragDropEffect result = DragDropEffect::None;
|
||||||
|
|
||||||
|
#if USE_EDITOR
|
||||||
|
// Create background worker that will keep updating GUI (perform rendering)
|
||||||
|
MacDragLocker.Lock();
|
||||||
|
ASSERT(!MacDragSession && !MacDragJob);
|
||||||
|
MacDragSession = draggingSession;
|
||||||
|
MacDragJob = New<DoDragDropJob>();
|
||||||
|
Task::StartNew(MacDragJob);
|
||||||
|
MacDragLocker.Unlock();
|
||||||
|
while (MacDragJob->GetState() == TaskState::Queued)
|
||||||
|
Platform::Sleep(1);
|
||||||
|
// TODO: maybe wait for the drag end to return result?
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacWindow::StartTrackingMouse(bool useMouseScreenOffset)
|
||||||
|
{
|
||||||
|
if (_isTrackingMouse || !_window)
|
||||||
|
return;
|
||||||
|
_isTrackingMouse = true;
|
||||||
|
_trackingMouseOffset = Float2::Zero;
|
||||||
|
_isUsingMouseOffset = useMouseScreenOffset;
|
||||||
|
_mouseTrackPos = Float2::Minimum;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacWindow::EndTrackingMouse()
|
||||||
|
{
|
||||||
|
if (!_isTrackingMouse || !_window)
|
||||||
|
return;
|
||||||
|
_isTrackingMouse = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacWindow::SetCursor(CursorType type)
|
void MacWindow::SetCursor(CursorType type)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "Engine/Platform/Base/WindowBase.h"
|
#include "Engine/Platform/Base/WindowBase.h"
|
||||||
#include "Engine/Platform/Platform.h"
|
#include "Engine/Platform/Platform.h"
|
||||||
|
#include "Engine/Core/Math/Vector2.h"
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implementation of the window class for Mac platform.
|
/// Implementation of the window class for Mac platform.
|
||||||
@@ -13,28 +14,32 @@
|
|||||||
class FLAXENGINE_API MacWindow : public WindowBase
|
class FLAXENGINE_API MacWindow : public WindowBase
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
void* _window = nullptr;
|
||||||
void* _window;
|
void* _view = nullptr;
|
||||||
bool _isMouseOver = false;
|
bool _isMouseOver = false;
|
||||||
|
Float2 _mouseTrackPos = Float2::Minimum;
|
||||||
|
String _dragText;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MacWindow(const CreateWindowSettings& settings);
|
MacWindow(const CreateWindowSettings& settings);
|
||||||
~MacWindow();
|
~MacWindow();
|
||||||
|
|
||||||
void CheckForResize(float width, float height);
|
void CheckForResize(float width, float height);
|
||||||
void SetIsMouseOver(bool value);
|
void SetIsMouseOver(bool value);
|
||||||
|
const String& GetDragText() const
|
||||||
|
{
|
||||||
|
return _dragText;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// [WindowBase]
|
// [WindowBase]
|
||||||
void* GetNativePtr() const override;
|
void* GetNativePtr() const override;
|
||||||
|
void OnUpdate(float dt) override;
|
||||||
void Show() override;
|
void Show() override;
|
||||||
void Hide() override;
|
void Hide() override;
|
||||||
void Minimize() override;
|
void Minimize() override;
|
||||||
void Maximize() override;
|
void Maximize() override;
|
||||||
void Restore() override;
|
void Restore() override;
|
||||||
bool IsClosed() const override;
|
|
||||||
bool IsForegroundWindow() const override;
|
bool IsForegroundWindow() const override;
|
||||||
void BringToFront(bool force = false) override;
|
void BringToFront(bool force = false) override;
|
||||||
void SetClientBounds(const Rectangle& clientArea) override;
|
void SetClientBounds(const Rectangle& clientArea) override;
|
||||||
@@ -50,6 +55,8 @@ public:
|
|||||||
void Focus() override;
|
void Focus() override;
|
||||||
void SetTitle(const StringView& title) override;
|
void SetTitle(const StringView& title) override;
|
||||||
DragDropEffect DoDragDrop(const StringView& data) override;
|
DragDropEffect DoDragDrop(const StringView& data) override;
|
||||||
|
void StartTrackingMouse(bool useMouseScreenOffset) override;
|
||||||
|
void EndTrackingMouse() override;
|
||||||
void SetCursor(CursorType type) override;
|
void SetCursor(CursorType type) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,11 @@ static bool CreateEndPointFromAddr(sockaddr* addr, NetworkEndPoint& endPoint)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
char strPort[6];
|
char strPort[6];
|
||||||
|
#if __APPLE__
|
||||||
|
snprintf(strPort, sizeof(strPort), "%d", port);
|
||||||
|
#else
|
||||||
sprintf(strPort, "%d", port);
|
sprintf(strPort, "%d", port);
|
||||||
|
#endif
|
||||||
endPoint.IPVersion = addr->sa_family == AF_INET6 ? NetworkIPVersion::IPv6 : NetworkIPVersion::IPv4;
|
endPoint.IPVersion = addr->sa_family == AF_INET6 ? NetworkIPVersion::IPv6 : NetworkIPVersion::IPv4;
|
||||||
memcpy(endPoint.Data, addr, size);
|
memcpy(endPoint.Data, addr, size);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -16,16 +16,13 @@ class FLAXENGINE_API Win32CriticalSection
|
|||||||
friend Win32ConditionVariable;
|
friend Win32ConditionVariable;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
mutable Windows::CRITICAL_SECTION _criticalSection;
|
mutable Windows::CRITICAL_SECTION _criticalSection;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Win32CriticalSection(const Win32CriticalSection&);
|
Win32CriticalSection(const Win32CriticalSection&);
|
||||||
Win32CriticalSection& operator=(const Win32CriticalSection&);
|
Win32CriticalSection& operator=(const Win32CriticalSection&);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Win32CriticalSection"/> class.
|
/// Initializes a new instance of the <see cref="Win32CriticalSection"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -43,17 +40,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Locks the critical section.
|
/// Locks the critical section.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Lock() const
|
void Lock() const
|
||||||
{
|
{
|
||||||
// Spin first before entering critical section, causing ring-0 transition and context switch
|
Windows::EnterCriticalSection(&_criticalSection);
|
||||||
if (Windows::TryEnterCriticalSection(&_criticalSection) == 0)
|
|
||||||
{
|
|
||||||
Windows::EnterCriticalSection(&_criticalSection);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -451,6 +451,7 @@ DialogResult MessageBox::Show(Window* parent, const StringView& text, const Stri
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
flags |= MB_TASKMODAL;
|
||||||
|
|
||||||
// Show dialog
|
// Show dialog
|
||||||
int result = MessageBoxW(parent ? static_cast<HWND>(parent->GetNativePtr()) : nullptr, String(text).GetText(), String(caption).GetText(), flags);
|
int result = MessageBoxW(parent ? static_cast<HWND>(parent->GetNativePtr()) : nullptr, String(text).GetText(), String(caption).GetText(), flags);
|
||||||
|
|||||||
@@ -410,7 +410,7 @@ bool iOSWindow::IsClosed() const
|
|||||||
|
|
||||||
bool iOSWindow::IsForegroundWindow() const
|
bool iOSWindow::IsForegroundWindow() const
|
||||||
{
|
{
|
||||||
return Platform::GetHasFocus() && IsFocused();
|
return IsFocused() && Platform::GetHasFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void iOSWindow::BringToFront(bool force)
|
void iOSWindow::BringToFront(bool force)
|
||||||
|
|||||||
@@ -202,16 +202,14 @@ GPUTexture* DepthOfFieldPass::getDofBokehShape(DepthOfFieldSettings& dofSettings
|
|||||||
|
|
||||||
void DepthOfFieldPass::Render(RenderContext& renderContext, GPUTexture*& frame, GPUTexture*& tmp)
|
void DepthOfFieldPass::Render(RenderContext& renderContext, GPUTexture*& frame, GPUTexture*& tmp)
|
||||||
{
|
{
|
||||||
if (!_platformSupportsDoF || checkIfSkipPass())
|
DepthOfFieldSettings& dofSettings = renderContext.List->Settings.DepthOfField;
|
||||||
|
const bool useDoF = EnumHasAnyFlags(renderContext.View.Flags, ViewFlags::DepthOfField) && dofSettings.Enabled;
|
||||||
|
if (!useDoF || !_platformSupportsDoF || checkIfSkipPass())
|
||||||
return;
|
return;
|
||||||
auto device = GPUDevice::Instance;
|
auto device = GPUDevice::Instance;
|
||||||
auto context = device->GetMainContext();
|
auto context = device->GetMainContext();
|
||||||
const auto depthBuffer = renderContext.Buffers->DepthBuffer;
|
const auto depthBuffer = renderContext.Buffers->DepthBuffer;
|
||||||
const auto shader = _shader->GetShader();
|
const auto shader = _shader->GetShader();
|
||||||
DepthOfFieldSettings& dofSettings = renderContext.List->Settings.DepthOfField;
|
|
||||||
const bool useDoF = _platformSupportsDoF && EnumHasAnyFlags(renderContext.View.Flags, ViewFlags::DepthOfField) && dofSettings.Enabled;
|
|
||||||
if (!useDoF)
|
|
||||||
return;
|
|
||||||
PROFILE_GPU_CPU("Depth Of Field");
|
PROFILE_GPU_CPU("Depth Of Field");
|
||||||
|
|
||||||
context->ResetSR();
|
context->ResetSR();
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ PACK_STRUCT(struct EyeAdaptationData {
|
|||||||
|
|
||||||
void EyeAdaptationPass::Render(RenderContext& renderContext, GPUTexture* colorBuffer)
|
void EyeAdaptationPass::Render(RenderContext& renderContext, GPUTexture* colorBuffer)
|
||||||
{
|
{
|
||||||
// Cache data
|
|
||||||
auto device = GPUDevice::Instance;
|
auto device = GPUDevice::Instance;
|
||||||
auto context = device->GetMainContext();
|
auto context = device->GetMainContext();
|
||||||
auto& view = renderContext.View;
|
auto& view = renderContext.View;
|
||||||
@@ -45,12 +44,8 @@ void EyeAdaptationPass::Render(RenderContext& renderContext, GPUTexture* colorBu
|
|||||||
//const float frameDelta = Time::ElapsedGameTime.GetTotalSeconds();
|
//const float frameDelta = Time::ElapsedGameTime.GetTotalSeconds();
|
||||||
const float frameDelta = time - renderContext.Buffers->LastEyeAdaptationTime;
|
const float frameDelta = time - renderContext.Buffers->LastEyeAdaptationTime;
|
||||||
renderContext.Buffers->LastEyeAdaptationTime = 0.0f;
|
renderContext.Buffers->LastEyeAdaptationTime = 0.0f;
|
||||||
|
if ((view.Flags & ViewFlags::EyeAdaptation) == ViewFlags::None || settings.Mode == EyeAdaptationMode::None || checkIfSkipPass())
|
||||||
// Optionally skip the rendering
|
|
||||||
if (checkIfSkipPass() || (view.Flags & ViewFlags::EyeAdaptation) == ViewFlags::None || settings.Mode == EyeAdaptationMode::None)
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
PROFILE_GPU_CPU("Eye Adaptation");
|
PROFILE_GPU_CPU("Eye Adaptation");
|
||||||
|
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ void MotionBlurPass::RenderDebug(RenderContext& renderContext, GPUTextureView* f
|
|||||||
{
|
{
|
||||||
auto context = GPUDevice::Instance->GetMainContext();
|
auto context = GPUDevice::Instance->GetMainContext();
|
||||||
const auto motionVectors = renderContext.Buffers->MotionVectors;
|
const auto motionVectors = renderContext.Buffers->MotionVectors;
|
||||||
if (!motionVectors->IsAllocated() || checkIfSkipPass())
|
if (!motionVectors || !motionVectors->IsAllocated() || checkIfSkipPass())
|
||||||
{
|
{
|
||||||
context->Draw(frame);
|
context->Draw(frame);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ void PostProcessingPass::Render(RenderContext& renderContext, GPUTexture* input,
|
|||||||
bool useLensFlares = EnumHasAnyFlags(view.Flags, ViewFlags::LensFlares) && settings.LensFlares.Intensity > 0.0f && useBloom;
|
bool useLensFlares = EnumHasAnyFlags(view.Flags, ViewFlags::LensFlares) && settings.LensFlares.Intensity > 0.0f && useBloom;
|
||||||
|
|
||||||
// Ensure to have valid data and if at least one effect should be applied
|
// Ensure to have valid data and if at least one effect should be applied
|
||||||
if (checkIfSkipPass() || !(useBloom || useToneMapping || useCameraArtifacts))
|
if (!(useBloom || useToneMapping || useCameraArtifacts) || checkIfSkipPass())
|
||||||
{
|
{
|
||||||
// Resources are missing. Do not perform rendering. Just copy raw frame
|
// Resources are missing. Do not perform rendering. Just copy raw frame
|
||||||
context->SetViewportAndScissors((float)output->Width(), (float)output->Height());
|
context->SetViewportAndScissors((float)output->Width(), (float)output->Height());
|
||||||
|
|||||||
@@ -1270,7 +1270,11 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp
|
|||||||
|
|
||||||
// Invoke the method
|
// Invoke the method
|
||||||
MObject* exception = nullptr;
|
MObject* exception = nullptr;
|
||||||
|
#if USE_NETCORE // NetCore uses the same path for both virtual and non-virtual calls
|
||||||
|
MObject* resultObject = mMethod->Invoke(mInstance, params, &exception);
|
||||||
|
#else
|
||||||
MObject* resultObject = withInterfaces ? mMethod->InvokeVirtual((MObject*)mInstance, params, &exception) : mMethod->Invoke(mInstance, params, &exception);
|
MObject* resultObject = withInterfaces ? mMethod->InvokeVirtual((MObject*)mInstance, params, &exception) : mMethod->Invoke(mInstance, params, &exception);
|
||||||
|
#endif
|
||||||
if (exception)
|
if (exception)
|
||||||
{
|
{
|
||||||
MException ex(exception);
|
MException ex(exception);
|
||||||
|
|||||||
@@ -320,7 +320,7 @@ namespace FlaxEngine
|
|||||||
internal static partial Object Internal_Create2(string typeName);
|
internal static partial Object Internal_Create2(string typeName);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_ManagedInstanceCreated", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_ManagedInstanceCreated", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
|
||||||
internal static partial void Internal_ManagedInstanceCreated(Object managedInstance, IntPtr theKlass);
|
internal static partial void Internal_ManagedInstanceCreated(Object managedInstance, IntPtr typeClass);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_ManagedInstanceDeleted", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "ObjectInternal_ManagedInstanceDeleted", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
|
||||||
internal static partial void Internal_ManagedInstanceDeleted(IntPtr nativeInstance);
|
internal static partial void Internal_ManagedInstanceDeleted(IntPtr nativeInstance);
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
#include <mono/metadata/metadata.h>
|
#include <mono/metadata/metadata.h>
|
||||||
#include <mono/metadata/threads.h>
|
#include <mono/metadata/threads.h>
|
||||||
#include <mono/metadata/reflection.h>
|
#include <mono/metadata/reflection.h>
|
||||||
|
#include <mono/metadata/mono-gc.h>
|
||||||
#include <mono/metadata/mono-private-unstable.h>
|
#include <mono/metadata/mono-private-unstable.h>
|
||||||
typedef char char_t;
|
typedef char char_t;
|
||||||
#define DOTNET_HOST_MONO_DEBUG 0
|
#define DOTNET_HOST_MONO_DEBUG 0
|
||||||
@@ -522,7 +523,8 @@ void MCore::GC::FreeMemory(void* ptr, bool coTaskMem)
|
|||||||
|
|
||||||
void MCore::Thread::Attach()
|
void MCore::Thread::Attach()
|
||||||
{
|
{
|
||||||
#if DOTNET_HOST_MONO
|
// TODO: find a way to properly register native thread so Mono Stop The World (stw) won't freeze when native threads (eg. Job System) are running native code only
|
||||||
|
#if DOTNET_HOST_MONO && 0
|
||||||
if (!IsInMainThread() && !mono_domain_get())
|
if (!IsInMainThread() && !mono_domain_get())
|
||||||
{
|
{
|
||||||
mono_thread_attach(MonoDomainHandle);
|
mono_thread_attach(MonoDomainHandle);
|
||||||
@@ -2056,7 +2058,7 @@ bool InitHostfxr()
|
|||||||
// Setup debugger
|
// Setup debugger
|
||||||
{
|
{
|
||||||
int32 debuggerLogLevel = 0;
|
int32 debuggerLogLevel = 0;
|
||||||
if (CommandLine::Options.MonoLog.IsTrue())
|
if (CommandLine::Options.MonoLog.IsTrue() || DOTNET_HOST_MONO_DEBUG)
|
||||||
{
|
{
|
||||||
LOG(Info, "Using detailed Mono logging");
|
LOG(Info, "Using detailed Mono logging");
|
||||||
mono_trace_set_level_string("debug");
|
mono_trace_set_level_string("debug");
|
||||||
@@ -2139,6 +2141,7 @@ bool InitHostfxr()
|
|||||||
LOG(Fatal, "Failed to initialize Mono.");
|
LOG(Fatal, "Failed to initialize Mono.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
mono_gc_init_finalizer_thread();
|
||||||
|
|
||||||
// Log info
|
// Log info
|
||||||
char* buildInfo = mono_get_runtime_build_info();
|
char* buildInfo = mono_get_runtime_build_info();
|
||||||
|
|||||||
@@ -460,16 +460,15 @@ bool ShaderCompiler::WriteCustomDataVS(ShaderCompilationContext* context, Shader
|
|||||||
auto& element = layout[a];
|
auto& element = layout[a];
|
||||||
if (!layoutVisible[a])
|
if (!layoutVisible[a])
|
||||||
continue;
|
continue;
|
||||||
|
GPUShaderProgramVS::InputElement data;
|
||||||
// TODO: serialize whole struct?
|
data.Type = static_cast<byte>(element.Type);
|
||||||
|
data.Index = element.Index;
|
||||||
output->WriteByte(static_cast<byte>(element.Type));
|
data.Format = static_cast<byte>(element.Format);
|
||||||
output->WriteByte(element.Index);
|
data.InputSlot = element.InputSlot;
|
||||||
output->WriteByte(static_cast<byte>(element.Format));
|
data.AlignedByteOffset = element.AlignedByteOffset;
|
||||||
output->WriteByte(element.InputSlot);
|
data.InputSlotClass = element.InputSlotClass;
|
||||||
output->WriteUint32(element.AlignedByteOffset);
|
data.InstanceDataStepRate = element.InstanceDataStepRate;
|
||||||
output->WriteByte(element.InputSlotClass);
|
output->Write(data);
|
||||||
output->WriteUint32(element.InstanceDataStepRate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Binary file not shown.
@@ -222,7 +222,7 @@ ${PBXResourcesGroup}
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
HEADER_SEARCH_PATHS = ${HeaderSearchPaths};
|
HEADER_SEARCH_PATHS = "${HeaderSearchPaths}";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
@@ -275,7 +275,7 @@ ${PBXResourcesGroup}
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
HEADER_SEARCH_PATHS = ${HeaderSearchPaths};
|
HEADER_SEARCH_PATHS = "${HeaderSearchPaths}";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
|
|||||||
2
Source/ThirdParty/stb/stb_image_write.h
vendored
2
Source/ThirdParty/stb/stb_image_write.h
vendored
@@ -758,6 +758,8 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f
|
|||||||
|
|
||||||
#ifdef __STDC_WANT_SECURE_LIB__
|
#ifdef __STDC_WANT_SECURE_LIB__
|
||||||
len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
|
len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
|
||||||
|
#elif __APPLE__
|
||||||
|
len = snprintf(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
|
||||||
#else
|
#else
|
||||||
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
|
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
9
Source/ThirdParty/volk/volk.Build.cs
vendored
9
Source/ThirdParty/volk/volk.Build.cs
vendored
@@ -1,5 +1,6 @@
|
|||||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Flax.Build;
|
using Flax.Build;
|
||||||
using Flax.Build.NativeCpp;
|
using Flax.Build.NativeCpp;
|
||||||
@@ -62,4 +63,12 @@ public class volk : ThirdPartyModule
|
|||||||
Log.ErrorOnce("Missing VulkanSDK.", ref _missingSDKError);
|
Log.ErrorOnce("Missing VulkanSDK.", ref _missingSDKError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void GetFilesToDeploy(List<string> files)
|
||||||
|
{
|
||||||
|
base.GetFilesToDeploy(files);
|
||||||
|
|
||||||
|
files.Add(Path.Combine(FolderPath, "volk.h"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3135,14 +3135,17 @@ namespace Flax.Build.Bindings
|
|||||||
contents.AppendLine("#pragma once");
|
contents.AppendLine("#pragma once");
|
||||||
contents.AppendLine();
|
contents.AppendLine();
|
||||||
contents.AppendLine($"#define {binaryModuleNameUpper}_NAME \"{binaryModuleName}\"");
|
contents.AppendLine($"#define {binaryModuleNameUpper}_NAME \"{binaryModuleName}\"");
|
||||||
if (version.Build == -1)
|
if (version.Build <= 0)
|
||||||
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION Version({version.Major}, {version.Minor})");
|
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION Version({version.Major}, {version.Minor})");
|
||||||
else
|
else if (version.Revision <= 0)
|
||||||
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION Version({version.Major}, {version.Minor}, {version.Build})");
|
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION Version({version.Major}, {version.Minor}, {version.Build})");
|
||||||
|
else
|
||||||
|
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION Version({version.Major}, {version.Minor}, {version.Build}, {version.Revision})");
|
||||||
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_TEXT \"{version}\"");
|
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_TEXT \"{version}\"");
|
||||||
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_MAJOR {version.Major}");
|
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_MAJOR {version.Major}");
|
||||||
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_MINOR {version.Minor}");
|
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_MINOR {version.Minor}");
|
||||||
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_BUILD {version.Build}");
|
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_BUILD {version.Build}");
|
||||||
|
contents.AppendLine($"#define {binaryModuleNameUpper}_VERSION_REVISION {version.Revision}");
|
||||||
contents.AppendLine($"#define {binaryModuleNameUpper}_COMPANY \"{project.Company}\"");
|
contents.AppendLine($"#define {binaryModuleNameUpper}_COMPANY \"{project.Company}\"");
|
||||||
contents.AppendLine($"#define {binaryModuleNameUpper}_COPYRIGHT \"{project.Copyright}\"");
|
contents.AppendLine($"#define {binaryModuleNameUpper}_COPYRIGHT \"{project.Copyright}\"");
|
||||||
contents.AppendLine();
|
contents.AppendLine();
|
||||||
|
|||||||
@@ -44,6 +44,12 @@ namespace Flax.Build
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[CommandLine("deployCertPass", "Certificate file password for binaries signing.")]
|
[CommandLine("deployCertPass", "Certificate file password for binaries signing.")]
|
||||||
public static string DeployCertPass;
|
public static string DeployCertPass;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Apple keychain profile name to use for app notarize action (installed locally).
|
||||||
|
/// </summary>
|
||||||
|
[CommandLine("deployKeychainProfile", "Apple keychain profile name to use for app notarize action (installed locally).")]
|
||||||
|
public static string DeployKeychainProfile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,12 +72,6 @@ namespace Flax.Deploy
|
|||||||
{
|
{
|
||||||
Initialize();
|
Initialize();
|
||||||
|
|
||||||
if (Configuration.DeployEditor)
|
|
||||||
{
|
|
||||||
BuildEditor();
|
|
||||||
Deployment.Editor.Package();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Configuration.DeployPlatforms)
|
if (Configuration.DeployPlatforms)
|
||||||
{
|
{
|
||||||
if (Configuration.BuildPlatforms == null || Configuration.BuildPlatforms.Length == 0)
|
if (Configuration.BuildPlatforms == null || Configuration.BuildPlatforms.Length == 0)
|
||||||
@@ -94,6 +94,12 @@ namespace Flax.Deploy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Configuration.DeployEditor)
|
||||||
|
{
|
||||||
|
BuildEditor();
|
||||||
|
Deployment.Editor.Package();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -183,6 +189,10 @@ namespace Flax.Deploy
|
|||||||
{
|
{
|
||||||
if (Platform.IsPlatformSupported(platform, architecture))
|
if (Platform.IsPlatformSupported(platform, architecture))
|
||||||
{
|
{
|
||||||
|
Log.Info(string.Empty);
|
||||||
|
Log.Info($"Build {platform} {architecture} platform");
|
||||||
|
Log.Info(string.Empty);
|
||||||
|
|
||||||
foreach (var configuration in Configurations)
|
foreach (var configuration in Configurations)
|
||||||
{
|
{
|
||||||
FlaxBuild.Build(Globals.EngineRoot, "FlaxGame", platform, architecture, configuration);
|
FlaxBuild.Build(Globals.EngineRoot, "FlaxGame", platform, architecture, configuration);
|
||||||
|
|||||||
@@ -127,6 +127,33 @@ namespace Flax.Deploy
|
|||||||
// Deploy project
|
// Deploy project
|
||||||
DeployFile(RootPath, OutputPath, "Flax.flaxproj");
|
DeployFile(RootPath, OutputPath, "Flax.flaxproj");
|
||||||
|
|
||||||
|
// When deploying Editor with Platforms at once then bundle them inside it
|
||||||
|
if (Configuration.DeployPlatforms && Platforms.PackagedPlatforms != null)
|
||||||
|
{
|
||||||
|
foreach (var platform in Platforms.PackagedPlatforms)
|
||||||
|
{
|
||||||
|
Log.Info(string.Empty);
|
||||||
|
Log.Info($"Bunding {platform} platform with Editor");
|
||||||
|
Log.Info(string.Empty);
|
||||||
|
|
||||||
|
string platformName = platform.ToString();
|
||||||
|
string platformFiles = Path.Combine(Deployer.PackageOutputPath, platformName);
|
||||||
|
string platformData = Path.Combine(OutputPath, "Source", "Platforms", platformName);
|
||||||
|
if (Directory.Exists(platformFiles))
|
||||||
|
{
|
||||||
|
// Copy deployed files
|
||||||
|
Utilities.DirectoryCopy(platformFiles, platformData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Extract deployed files
|
||||||
|
var packageZipPath = Path.Combine(Deployer.PackageOutputPath, platformName + ".zip");
|
||||||
|
Log.Verbose(packageZipPath + " -> " + platformData);
|
||||||
|
System.IO.Compression.ZipFile.ExtractToDirectory(packageZipPath, platformData, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Package Editor into macOS app
|
// Package Editor into macOS app
|
||||||
if (Platform.BuildTargetPlatform == TargetPlatform.Mac)
|
if (Platform.BuildTargetPlatform == TargetPlatform.Mac)
|
||||||
{
|
{
|
||||||
@@ -164,12 +191,34 @@ namespace Flax.Deploy
|
|||||||
var defaultEditorConfig = "Development";
|
var defaultEditorConfig = "Development";
|
||||||
var ediotrBinariesPath = Path.Combine(appContentsPath, "Binaries/Editor/Mac", defaultEditorConfig);
|
var ediotrBinariesPath = Path.Combine(appContentsPath, "Binaries/Editor/Mac", defaultEditorConfig);
|
||||||
Utilities.DirectoryCopy(ediotrBinariesPath, appBinariesPath, true, true);
|
Utilities.DirectoryCopy(ediotrBinariesPath, appBinariesPath, true, true);
|
||||||
|
|
||||||
|
// Sign app resources
|
||||||
|
CodeSign(appPath);
|
||||||
|
|
||||||
|
// Build a disk image
|
||||||
|
var dmgPath = Path.Combine(Deployer.PackageOutputPath, "FlaxEditor.dmg");
|
||||||
|
Log.Info(string.Empty);
|
||||||
|
Log.Info("Building disk image...");
|
||||||
|
if (File.Exists(dmgPath))
|
||||||
|
File.Delete(dmgPath);
|
||||||
|
Utilities.Run("hdiutil", $"create -srcFolder \"{appPath}\" -o \"{dmgPath}\"", null, null, Utilities.RunOptions.Default | Utilities.RunOptions.ThrowExceptionOnError);
|
||||||
|
CodeSign(dmgPath);
|
||||||
|
Log.Info("Output disk image size: " + Utilities.GetFileSize(dmgPath));
|
||||||
|
|
||||||
|
// Notarize disk image
|
||||||
|
if (!string.IsNullOrEmpty(Configuration.DeployKeychainProfile))
|
||||||
|
{
|
||||||
|
Log.Info(string.Empty);
|
||||||
|
Log.Info("Notarizing disk image...");
|
||||||
|
Utilities.Run("xcrun", $"notarytool submit \"{dmgPath}\" --wait --keychain-profile \"{Configuration.DeployKeychainProfile}\"", null, null, Utilities.RunOptions.Default | Utilities.RunOptions.ThrowExceptionOnError);
|
||||||
|
Utilities.Run("xcrun", $"stapler staple \"{dmgPath}\"", null, null, Utilities.RunOptions.Default | Utilities.RunOptions.ThrowExceptionOnError);
|
||||||
|
Log.Info("App notarized for macOS distribution!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compress
|
// Compress
|
||||||
if (Configuration.DontCompress)
|
if (Configuration.DontCompress)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Log.Info(string.Empty);
|
Log.Info(string.Empty);
|
||||||
Log.Info("Compressing editor files...");
|
Log.Info("Compressing editor files...");
|
||||||
string editorPackageZipPath;
|
string editorPackageZipPath;
|
||||||
@@ -299,6 +348,7 @@ namespace Flax.Deploy
|
|||||||
Utilities.Run("strip", "FlaxEditor.dylib", null, dst, Utilities.RunOptions.None);
|
Utilities.Run("strip", "FlaxEditor.dylib", null, dst, Utilities.RunOptions.None);
|
||||||
Utilities.Run("strip", "libMoltenVK.dylib", null, dst, Utilities.RunOptions.None);
|
Utilities.Run("strip", "libMoltenVK.dylib", null, dst, Utilities.RunOptions.None);
|
||||||
|
|
||||||
|
// Sign binaries
|
||||||
CodeSign(Path.Combine(dst, "FlaxEditor"));
|
CodeSign(Path.Combine(dst, "FlaxEditor"));
|
||||||
CodeSign(Path.Combine(dst, "FlaxEditor.dylib"));
|
CodeSign(Path.Combine(dst, "FlaxEditor.dylib"));
|
||||||
CodeSign(Path.Combine(dst, "libMoltenVK.dylib"));
|
CodeSign(Path.Combine(dst, "libMoltenVK.dylib"));
|
||||||
|
|||||||
@@ -10,8 +10,13 @@ namespace Flax.Deploy
|
|||||||
{
|
{
|
||||||
public class Platforms
|
public class Platforms
|
||||||
{
|
{
|
||||||
|
internal static List<TargetPlatform> PackagedPlatforms;
|
||||||
|
|
||||||
public static void Package(TargetPlatform platform)
|
public static void Package(TargetPlatform platform)
|
||||||
{
|
{
|
||||||
|
if (PackagedPlatforms == null)
|
||||||
|
PackagedPlatforms = new List<TargetPlatform>();
|
||||||
|
PackagedPlatforms.Add(platform);
|
||||||
var platformsRoot = Path.Combine(Globals.EngineRoot, "Source", "Platforms");
|
var platformsRoot = Path.Combine(Globals.EngineRoot, "Source", "Platforms");
|
||||||
|
|
||||||
Log.Info(string.Empty);
|
Log.Info(string.Empty);
|
||||||
@@ -50,6 +55,20 @@ namespace Flax.Deploy
|
|||||||
CodeSign(Path.Combine(binaries, "FlaxGame.exe"));
|
CodeSign(Path.Combine(binaries, "FlaxGame.exe"));
|
||||||
CodeSign(Path.Combine(binaries, "FlaxEngine.CSharp.dll"));
|
CodeSign(Path.Combine(binaries, "FlaxEngine.CSharp.dll"));
|
||||||
}
|
}
|
||||||
|
else if (platform == TargetPlatform.Mac)
|
||||||
|
{
|
||||||
|
var binaries = Path.Combine(dst, "Binaries", "Game", "arm64", "Debug");
|
||||||
|
CodeSign(Path.Combine(binaries, "FlaxGame"));
|
||||||
|
CodeSign(Path.Combine(binaries, "FlaxGame.dylib"));
|
||||||
|
|
||||||
|
binaries = Path.Combine(dst, "Binaries", "Game", "arm64", "Development");
|
||||||
|
CodeSign(Path.Combine(binaries, "FlaxGame"));
|
||||||
|
CodeSign(Path.Combine(binaries, "FlaxGame.dylib"));
|
||||||
|
|
||||||
|
binaries = Path.Combine(dst, "Binaries", "Game", "arm64", "Release");
|
||||||
|
CodeSign(Path.Combine(binaries, "FlaxGame"));
|
||||||
|
CodeSign(Path.Combine(binaries, "FlaxGame.dylib"));
|
||||||
|
}
|
||||||
|
|
||||||
// Don't distribute engine deps
|
// Don't distribute engine deps
|
||||||
Utilities.DirectoryDelete(Path.Combine(dst, "Binaries", "ThirdParty"));
|
Utilities.DirectoryDelete(Path.Combine(dst, "Binaries", "ThirdParty"));
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ namespace Flax.Deploy
|
|||||||
if (!string.IsNullOrEmpty(Configuration.Compiler))
|
if (!string.IsNullOrEmpty(Configuration.Compiler))
|
||||||
cmdLine += " -compiler=" + Configuration.Compiler;
|
cmdLine += " -compiler=" + Configuration.Compiler;
|
||||||
|
|
||||||
|
Log.Info($"Building {target} for {platform} {architecture} {configuration}...");
|
||||||
int result = Utilities.Run(flaxBuildTool, cmdLine, null, root);
|
int result = Utilities.Run(flaxBuildTool, cmdLine, null, root);
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -53,10 +53,19 @@ namespace Flax.Build.Platforms
|
|||||||
/// <param name="signIdenity">App code signing idenity name (from local Mac keychain). Use 'security find-identity -v -p codesigning' to list possible options.</param>
|
/// <param name="signIdenity">App code signing idenity name (from local Mac keychain). Use 'security find-identity -v -p codesigning' to list possible options.</param>
|
||||||
public static void CodeSign(string file, string signIdenity)
|
public static void CodeSign(string file, string signIdenity)
|
||||||
{
|
{
|
||||||
if (!File.Exists(file))
|
var isDirectory = Directory.Exists(file);
|
||||||
|
if (!isDirectory && !File.Exists(file))
|
||||||
throw new FileNotFoundException("Missing file to sign.", file);
|
throw new FileNotFoundException("Missing file to sign.", file);
|
||||||
string cmdLine = string.Format("--force --timestamp -s \"{0}\" \"{1}\"", signIdenity, file);
|
string cmdLine = string.Format("--force --timestamp -s \"{0}\" \"{1}\"", signIdenity, file);
|
||||||
if (string.IsNullOrEmpty(Path.GetExtension(file)))
|
if (isDirectory)
|
||||||
|
{
|
||||||
|
// Automatically sign contents
|
||||||
|
cmdLine += " --deep";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Enable the hardened runtime
|
||||||
|
cmdLine += " --options=runtime";
|
||||||
|
}
|
||||||
{
|
{
|
||||||
// Add entitlements file with some settings for the app execution
|
// Add entitlements file with some settings for the app execution
|
||||||
cmdLine += string.Format(" --entitlements \"{0}\"", Path.Combine(Globals.EngineRoot, "Source/Platforms/Mac/Default.entitlements"));
|
cmdLine += string.Format(" --entitlements \"{0}\"", Path.Combine(Globals.EngineRoot, "Source/Platforms/Mac/Default.entitlements"));
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user