diff --git a/Development/Scripts/Windows/CallBuildTool.bat b/Development/Scripts/Windows/CallBuildTool.bat
index 9f60368c5..22c2d1dd7 100644
--- a/Development/Scripts/Windows/CallBuildTool.bat
+++ b/Development/Scripts/Windows/CallBuildTool.bat
@@ -11,16 +11,6 @@ for %%I in (Source\Logo.png) do if %%~zI LSS 2000 (
call "Development\Scripts\Windows\GetMSBuildPath.bat"
if errorlevel 1 goto Error_NoVisualStudioEnvironment
-if not exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" goto Compile
-for /f "delims=" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -products * -requires Microsoft.Component.MSBuild -property installationPath') do (
- for %%j in (15.0, Current) do (
- if exist "%%i\MSBuild\%%j\Bin\MSBuild.exe" (
- set MSBUILD_PATH="%%i\MSBuild\%%j\Bin\MSBuild.exe"
- goto Compile
- )
- )
-)
-
:Compile
md Cache\Intermediate >nul 2>nul
dir /s /b Source\Tools\Flax.Build\*.cs >Cache\Intermediate\Flax.Build.Files.txt
@@ -44,7 +34,7 @@ goto Exit
echo CallBuildTool ERROR: The script is in invalid directory.
goto Exit
:Error_NoVisualStudioEnvironment
-echo CallBuildTool ERROR: Missing Visual Studio 2015 or newer.
+echo CallBuildTool ERROR: Missing Visual Studio 2022 or newer.
goto Exit
:Error_CompilationFailed
echo CallBuildTool ERROR: Failed to compile Flax.Build project.
diff --git a/Development/Scripts/Windows/GetMSBuildPath.bat b/Development/Scripts/Windows/GetMSBuildPath.bat
index b20230118..f44155272 100644
--- a/Development/Scripts/Windows/GetMSBuildPath.bat
+++ b/Development/Scripts/Windows/GetMSBuildPath.bat
@@ -4,66 +4,26 @@ rem Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
set MSBUILD_PATH=
+rem Look for MSBuild version 17.0 or later
if not exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" goto VsWhereNotFound
-for /f "delims=" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -products * -requires Microsoft.Component.MSBuild -property installationPath') do (
- if exist "%%i\MSBuild\15.0\Bin\MSBuild.exe" (
- set MSBUILD_PATH="%%i\MSBuild\15.0\Bin\MSBuild.exe"
- goto End
- )
-)
-for /f "delims=" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -prerelease -products * -requires Microsoft.Component.MSBuild -property installationPath') do (
- if exist "%%i\MSBuild\15.0\Bin\MSBuild.exe" (
- set MSBUILD_PATH="%%i\MSBuild\15.0\Bin\MSBuild.exe"
- goto End
- )
+for /f "delims=" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -version 17.0 -latest -products * -requires Microsoft.Component.MSBuild -property installationPath') do (
if exist "%%i\MSBuild\Current\Bin\MSBuild.exe" (
set MSBUILD_PATH="%%i\MSBuild\Current\Bin\MSBuild.exe"
goto End
)
)
-:VsWhereNotFound
-if exist "%ProgramFiles(x86)%\MSBuild\14.0\bin\MSBuild.exe" (
- set MSBUILD_PATH="%ProgramFiles(x86)%\MSBuild\14.0\bin\MSBuild.exe"
- goto End
+rem Look for MSBuild version 17.0 or later in pre-release versions
+for /f "delims=" %%i in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -version 17.0 -latest -prerelease -products * -requires Microsoft.Component.MSBuild -property installationPath') do (
+ if exist "%%i\MSBuild\Current\Bin\MSBuild.exe" (
+ set MSBUILD_PATH="%%i\MSBuild\Current\Bin\MSBuild.exe"
+ goto End
+ )
)
-
-call :GetInstallPath Microsoft\VisualStudio\SxS\VS7 15.0 MSBuild\15.0\bin\MSBuild.exe
-if not errorlevel 1 goto End
-call :GetInstallPath Microsoft\MSBuild\ToolsVersions\14.0 MSBuildToolsPath MSBuild.exe
-if not errorlevel 1 goto End
-call :GetInstallPath Microsoft\MSBuild\ToolsVersions\12.0 MSBuildToolsPath MSBuild.exe
-if not errorlevel 1 goto End
-call :GetInstallPath Microsoft\MSBuild\ToolsVersions\4.0 MSBuildToolsPath MSBuild.exe
-if not errorlevel 1 goto End
-
+echo GetMSBuildPath ERROR: Could not find MSBuild version 17.0 or later.
+exit /B 1
+:VsWhereNotFound
+echo GetMSBuildPath ERROR: vswhere.exe was not found.
exit /B 1
:End
-exit /B 0
-
-:GetInstallPath
-for /f "tokens=2,*" %%A in ('REG.exe query HKCU\SOFTWARE\%1 /v %2 2^>Nul') do (
- if exist "%%B%%3" (
- set MSBUILD_PATH="%%B%3"
- exit /B 0
- )
-)
-for /f "tokens=2,*" %%A in ('REG.exe query HKLM\SOFTWARE\%1 /v %2 2^>Nul') do (
- if exist "%%B%3" (
- set MSBUILD_PATH="%%B%3"
- exit /B 0
- )
-)
-for /f "tokens=2,*" %%A in ('REG.exe query HKCU\SOFTWARE\Wow6432Node\%1 /v %2 2^>Nul') do (
- if exist "%%B%%3" (
- set MSBUILD_PATH="%%B%3"
- exit /B 0
- )
-)
-for /f "tokens=2,*" %%A in ('REG.exe query HKLM\SOFTWARE\Wow6432Node\%1 /v %2 2^>Nul') do (
- if exist "%%B%3" (
- set MSBUILD_PATH="%%B%3"
- exit /B 0
- )
-)
-exit /B 1
+exit /B 0
\ No newline at end of file
diff --git a/Flax.flaxproj b/Flax.flaxproj
index 50fcaeda3..fbf48cc2b 100644
--- a/Flax.flaxproj
+++ b/Flax.flaxproj
@@ -3,7 +3,7 @@
"Version": {
"Major": 1,
"Minor": 6,
- "Build": 6344
+ "Build": 6345
},
"Company": "Flax",
"Copyright": "Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.",
diff --git a/Flax.sln.DotSettings b/Flax.sln.DotSettings
index e8af1461c..6a22f211b 100644
--- a/Flax.sln.DotSettings
+++ b/Flax.sln.DotSettings
@@ -291,6 +291,8 @@
True
True
True
+ True
+ True
True
True
True
diff --git a/GenerateProjectFiles.bat b/GenerateProjectFiles.bat
index 1b766457f..622939c34 100644
--- a/GenerateProjectFiles.bat
+++ b/GenerateProjectFiles.bat
@@ -1,15 +1,22 @@
@echo off
-
-rem Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
+:: Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
setlocal
pushd
+
echo Generating Flax Engine project files...
-rem Run Flax.Build to generate Visual Studio solution and project files (also pass the arguments)
-call "Development\Scripts\Windows\CallBuildTool.bat" -genproject %*
+:: Change the path to the script root
+cd /D "%~dp0"
+
+:: Run Flax.Build to generate Visual Studio solution and project files (also pass the arguments)
+call "Development\Scripts\Windows\CallBuildTool.bat" -genproject %*
if errorlevel 1 goto BuildToolFailed
+:: Build bindings for all editor configurations
+echo Building C# bindings...
+Binaries\Tools\Flax.Build.exe -build -BuildBindingsOnly -arch=x64 -platform=Windows --buildTargets=FlaxEditor,FlaxGame
+
popd
echo Done!
exit /B 0
diff --git a/GenerateProjectFiles.command b/GenerateProjectFiles.command
index 6554886bc..5ee5c0783 100755
--- a/GenerateProjectFiles.command
+++ b/GenerateProjectFiles.command
@@ -10,3 +10,8 @@ cd "`dirname "$0"`"
# Run Flax.Build to generate project files (also pass the arguments)
bash ./Development/Scripts/Mac/CallBuildTool.sh --genproject "$@"
+
+# Build bindings for all editor configurations
+echo Building C# bindings...
+# TODO: Detect the correct architecture here
+Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=ARM64 -platform=Mac --buildTargets=FlaxEditor,FlaxGame
diff --git a/GenerateProjectFiles.sh b/GenerateProjectFiles.sh
index fcda1acc1..dceb8abe8 100755
--- a/GenerateProjectFiles.sh
+++ b/GenerateProjectFiles.sh
@@ -10,3 +10,8 @@ cd "`dirname "$0"`"
# Run Flax.Build to generate project files (also pass the arguments)
bash ./Development/Scripts/Linux/CallBuildTool.sh --genproject "$@"
+
+# Build bindings for all editor configurations
+echo Building C# bindings...
+# TODO: Detect the correct architecture here
+Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=x64 -platform=Linux --buildTargets=FlaxEditor,FlaxGame
diff --git a/README.md b/README.md
index dc5abb84f..fac631a6a 100644
--- a/README.md
+++ b/README.md
@@ -31,19 +31,20 @@ Follow the instructions below to compile and run the engine from source.
* Install Visual Studio 2022 or newer
* Install Windows 8.1 SDK or newer (via Visual Studio Installer)
* Install Microsoft Visual C++ 2015 v140 toolset or newer (via Visual Studio Installer)
-* Install .Net 7 SDK (via Visual Studio Installer or [from web](https://dotnet.microsoft.com/en-us/download/dotnet/7.0))
+* Install .NET 7 SDK for **Windows x64** (via Visual Studio Installer or [from web](https://dotnet.microsoft.com/en-us/download/dotnet/7.0))
* Install Git with LFS
* Clone repo (with LFS)
* Run **GenerateProjectFiles.bat**
* Open `Flax.sln` and set solution configuration to **Editor.Development** and solution platform to **Win64**
* Set Flax (C++) or FlaxEngine (C#) as startup project
* Compile Flax project (hit F7 or CTRL+Shift+B)
+* Optionally set Debug Type to **Managed Only (.NET Core)** to debug C#-only, or **Mixed (.NET Core)** to debug both C++ and C#
* Run Flax (hit F5 key)
## Linux
* Install Visual Studio Code
-* Install .Net 7 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0))
+* Install .NET 7 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0))
* Ubuntu: `sudo apt install dotnet-sdk-7.0`
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
* Ubuntu: `sudo apt install vulkan-sdk`
@@ -66,7 +67,7 @@ Follow the instructions below to compile and run the engine from source.
## Mac
* Install XCode
-* Install .Net 7 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0))
+* Install .NET 7 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0))
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
* Clone repo (with LFS)
* Run `GenerateProjectFiles.command`
diff --git a/Source/Editor/Cooker/Platform/Mac/MacPlatformTools.cpp b/Source/Editor/Cooker/Platform/Mac/MacPlatformTools.cpp
index c059acba9..b66a96a9b 100644
--- a/Source/Editor/Cooker/Platform/Mac/MacPlatformTools.cpp
+++ b/Source/Editor/Cooker/Platform/Mac/MacPlatformTools.cpp
@@ -5,6 +5,7 @@
#include "MacPlatformTools.h"
#include "Engine/Platform/File.h"
#include "Engine/Platform/FileSystem.h"
+#include "Engine/Platform/CreateProcessSettings.h"
#include "Engine/Platform/Mac/MacPlatformSettings.h"
#include "Engine/Core/Config/GameSettings.h"
#include "Engine/Core/Config/BuildSettings.h"
@@ -124,17 +125,35 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
LOG(Error, "Failed to export application icon.");
return true;
}
- bool failed = Platform::RunProcess(TEXT("sips -z 16 16 icon_1024x1024.png --out icon_16x16.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 32 32 icon_1024x1024.png --out icon_16x16@2x.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 32 32 icon_1024x1024.png --out icon_32x32.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 64 64 icon_1024x1024.png --out icon_32x32@2x.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 128 128 icon_1024x1024.png --out icon_128x128.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 256 256 icon_1024x1024.png --out icon_128x128@2x.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 256 256 icon_1024x1024.png --out icon_256x256.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 512 512 icon_1024x1024.png --out icon_256x256@2x.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 512 512 icon_1024x1024.png --out icon_512x512.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("sips -z 1024 1024 icon_1024x1024.png --out icon_512x512@2x.png"), tmpFolderPath);
- failed |= Platform::RunProcess(TEXT("iconutil -c icns icon.iconset"), iconFolderPath);
+ CreateProcessSettings procSettings;
+ procSettings.HiddenWindow = true;
+ procSettings.FileName = TEXT("/usr/bin/sips");
+ procSettings.WorkingDirectory = tmpFolderPath;
+ procSettings.Arguments = TEXT("-z 16 16 icon_1024x1024.png --out icon_16x16.png");
+ bool failed = false;
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 32 32 icon_1024x1024.png --out icon_16x16@2x.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 32 32 icon_1024x1024.png --out icon_32x32.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 64 64 icon_1024x1024.png --out icon_32x32@2x.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 128 128 icon_1024x1024.png --out icon_128x128.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 256 256 icon_1024x1024.png --out icon_128x128@2x.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 256 256 icon_1024x1024.png --out icon_256x256.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 512 512 icon_1024x1024.png --out icon_256x256@2x.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 512 512 icon_1024x1024.png --out icon_512x512.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.Arguments = TEXT("-z 1024 1024 icon_1024x1024.png --out icon_512x512@2x.png");
+ failed |= Platform::CreateProcess(procSettings);
+ procSettings.FileName = TEXT("/usr/bin/iconutil");
+ procSettings.Arguments = TEXT("-c icns icon.iconset");
+ procSettings.WorkingDirectory = iconFolderPath;
+ failed |= Platform::CreateProcess(procSettings);
if (failed)
{
LOG(Error, "Failed to export application icon.");
@@ -210,16 +229,22 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
return false;
GameCooker::PackageFiles();
LOG(Info, "Building app package...");
- const String dmgPath = data.OriginalOutputPath / appName + TEXT(".dmg");
- const String dmgCommand = String::Format(TEXT("hdiutil create {0}.dmg -volname {0} -fs HFS+ -srcfolder {0}.app"), appName);
- const int32 result = Platform::RunProcess(dmgCommand, data.OriginalOutputPath);
- if (result != 0)
{
- data.Error(String::Format(TEXT("Failed to package app (result code: {0}). See log for more info."), result));
- return true;
+ const String dmgPath = data.OriginalOutputPath / appName + TEXT(".dmg");
+ CreateProcessSettings procSettings;
+ procSettings.HiddenWindow = true;
+ procSettings.WorkingDirectory = data.OriginalOutputPath;
+ procSettings.FileName = TEXT("/usr/bin/hdiutil");
+ procSettings.Arguments = String::Format(TEXT("create {0}.dmg -volname {0} -fs HFS+ -srcfolder {0}.app"), appName);
+ const int32 result = Platform::CreateProcess(procSettings);
+ if (result != 0)
+ {
+ data.Error(String::Format(TEXT("Failed to package app (result code: {0}). See log for more info."), result));
+ return true;
+ }
+ // TODO: sign dmg
+ LOG(Info, "Output application package: {0} (size: {1} MB)", dmgPath, FileSystem::GetFileSize(dmgPath) / 1024 / 1024);
}
- // TODO: sign dmg
- LOG(Info, "Output application package: {0} (size: {1} MB)", dmgPath, FileSystem::GetFileSize(dmgPath) / 1024 / 1024);
return false;
}
diff --git a/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp b/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp
index 8b0cf06a8..85a7f99fa 100644
--- a/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp
+++ b/Source/Editor/Cooker/Platform/iOS/iOSPlatformTools.cpp
@@ -260,15 +260,20 @@ bool iOSPlatformTools::OnPostProcess(CookingData& data)
{
LOG(Info, "Building app package...");
const Char* configuration = data.Configuration == BuildConfiguration::Release ? TEXT("Release") : TEXT("Debug");
- String command = String::Format(TEXT("xcodebuild -project FlaxGame.xcodeproj -configuration {} -scheme FlaxGame -archivePath FlaxGame.xcarchive archive"), configuration);
- int32 result = Platform::RunProcess(command, data.OriginalOutputPath);
+ CreateProcessSettings procSettings;
+ procSettings.HiddenWindow = true;
+ procSettings.WorkingDirectory = data.OriginalOutputPath;
+ procSettings.FileName = TEXT("/usr/bin/xcodebuild");
+ procSettings.Arguments = String::Format(TEXT("-project FlaxGame.xcodeproj -configuration {} -scheme FlaxGame -archivePath FlaxGame.xcarchive archive"), configuration);
+ int32 result = Platform::CreateProcess(procSettings);
if (result != 0)
{
data.Error(String::Format(TEXT("Failed to package app (result code: {0}). See log for more info."), result));
return true;
}
- command = TEXT("xcodebuild -exportArchive -archivePath FlaxGame.xcarchive -allowProvisioningUpdates -exportPath . -exportOptionsPlist ExportOptions.plist");
- result = Platform::RunProcess(command, data.OriginalOutputPath);
+ procSettings.FileName = TEXT("/usr/bin/xcodebuild");
+ procSettings.Arguments = TEXT("-exportArchive -archivePath FlaxGame.xcarchive -allowProvisioningUpdates -exportPath . -exportOptionsPlist ExportOptions.plist");
+ result = Platform::CreateProcess(procSettings);
if (result != 0)
{
data.Error(String::Format(TEXT("Failed to package app (result code: {0}). See log for more info."), result));
diff --git a/Source/Editor/CustomEditors/Dedicated/ParticleEffectEditor.cs b/Source/Editor/CustomEditors/Dedicated/ParticleEffectEditor.cs
index ec71348cf..5b2cfc144 100644
--- a/Source/Editor/CustomEditors/Dedicated/ParticleEffectEditor.cs
+++ b/Source/Editor/CustomEditors/Dedicated/ParticleEffectEditor.cs
@@ -25,9 +25,20 @@ namespace FlaxEditor.CustomEditors.Dedicated
get
{
// All selected particle effects use the same system
- var effect = (ParticleEffect)Values[0];
- var system = effect.ParticleSystem;
- return system != null && Values.TrueForAll(x => (x as ParticleEffect)?.ParticleSystem == system);
+ var effect = Values[0] as ParticleEffect;
+ var system = effect ? effect.ParticleSystem : null;
+ if (system && Values.TrueForAll(x => x is ParticleEffect fx && fx && fx.ParticleSystem == system))
+ {
+ // All parameters can be accessed
+ var parameters = effect.Parameters;
+ foreach (var parameter in parameters)
+ {
+ if (!parameter)
+ return false;
+ }
+ return true;
+ }
+ return false;
}
}
diff --git a/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs b/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs
index bf82e19da..aaf45bc52 100644
--- a/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs
+++ b/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs
@@ -25,6 +25,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
private DragHandlers _dragHandlers;
private DragScriptItems _dragScripts;
private DragAssets _dragAssets;
+ private Button _addScriptsButton;
///
/// The parent scripts editor.
@@ -40,16 +41,19 @@ namespace FlaxEditor.CustomEditors.Dedicated
AutoFocus = false;
// Add script button
- float addScriptButtonWidth = 60.0f;
- var addScriptButton = new Button
+ var buttonText = "Add script";
+ var textSize = Style.Current.FontMedium.MeasureText(buttonText);
+ float addScriptButtonWidth = (textSize.X < 60.0f) ? 60.0f : textSize.X + 4;
+ var buttonHeight = (textSize.Y < 18) ? 18 : textSize.Y + 4;
+ _addScriptsButton = new Button
{
TooltipText = "Add new scripts to the actor",
AnchorPreset = AnchorPresets.MiddleCenter,
- Text = "Add script",
+ Text = buttonText,
Parent = this,
- Bounds = new Rectangle((Width - addScriptButtonWidth) / 2, 1, addScriptButtonWidth, 18),
+ Bounds = new Rectangle((Width - addScriptButtonWidth) / 2, 1, addScriptButtonWidth, buttonHeight),
};
- addScriptButton.ButtonClicked += OnAddScriptButtonClicked;
+ _addScriptsButton.ButtonClicked += OnAddScriptButtonClicked;
}
private void OnAddScriptButtonClicked(Button button)
@@ -82,7 +86,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
var size = Size;
// Info
- Render2D.DrawText(style.FontSmall, "Drag scripts here", new Rectangle(2, 22, size.X - 4, size.Y - 4 - 20), style.ForegroundDisabled, TextAlignment.Center, TextAlignment.Center);
+ Render2D.DrawText(style.FontSmall, "Drag scripts here", new Rectangle(2, _addScriptsButton.Height + 4, size.X - 4, size.Y - 4 - 20), style.ForegroundDisabled, TextAlignment.Center, TextAlignment.Center);
// Check if drag is over
if (IsDragOver && _dragHandlers != null && _dragHandlers.HasValidDrag)
@@ -576,8 +580,8 @@ namespace FlaxEditor.CustomEditors.Dedicated
return;
for (int j = 0; j < e.Length; j++)
{
- var t1 = scripts[j]?.TypeName;
- var t2 = e[j]?.TypeName;
+ var t1 = scripts[j] != null ? scripts[j].TypeName : null;
+ var t2 = e[j] != null ? e[j].TypeName : null;
if (t1 != t2)
return;
}
diff --git a/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs b/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs
index fde4967e8..5215e23a4 100644
--- a/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs
+++ b/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs
@@ -422,12 +422,14 @@ namespace FlaxEditor.CustomEditors.Dedicated
// Set control type button
var space = layout.Space(20);
- float setTypeButtonWidth = 60.0f;
+ var buttonText = "Set Type";
+ var textSize = FlaxEngine.GUI.Style.Current.FontMedium.MeasureText(buttonText);
+ float setTypeButtonWidth = (textSize.X < 60.0f) ? 60.0f : textSize.X + 4;
var setTypeButton = new Button
{
TooltipText = "Sets the control to the given type",
AnchorPreset = AnchorPresets.MiddleCenter,
- Text = "Set Type",
+ Text = buttonText,
Parent = space.Spacer,
Bounds = new Rectangle((space.Spacer.Width - setTypeButtonWidth) / 2, 1, setTypeButtonWidth, 18),
};
diff --git a/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs b/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs
index cb4e7b9c1..4aa02ac78 100644
--- a/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs
@@ -88,20 +88,20 @@ namespace FlaxEditor.CustomEditors.Editors
LinkValues = Editor.Instance.Windows.PropertiesWin.ScaleLinked;
// Add button with the link icon
+
_linkButton = new Button
{
BackgroundBrush = new SpriteBrush(Editor.Instance.Icons.Link32),
Parent = LinkedLabel,
Width = 18,
Height = 18,
- AnchorPreset = AnchorPresets.TopLeft,
+ AnchorPreset = AnchorPresets.MiddleLeft,
};
_linkButton.Clicked += ToggleLink;
ToggleEnabled();
SetLinkStyle();
- var x = LinkedLabel.Text.Value.Length * 7 + 5;
- _linkButton.LocalX += x;
- _linkButton.LocalY += 1;
+ var textSize = FlaxEngine.GUI.Style.Current.FontMedium.MeasureText(LinkedLabel.Text.Value);
+ _linkButton.LocalX += textSize.X + 10;
LinkedLabel.SetupContextMenu += (label, menu, editor) =>
{
menu.AddSeparator();
diff --git a/Source/Editor/CustomEditors/Editors/BooleanEditor.cs b/Source/Editor/CustomEditors/Editors/BooleanEditor.cs
index f5edafed8..803b7b4dd 100644
--- a/Source/Editor/CustomEditors/Editors/BooleanEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/BooleanEditor.cs
@@ -34,7 +34,9 @@ namespace FlaxEditor.CustomEditors.Editors
}
else
{
- element.CheckBox.Checked = (bool)Values[0];
+ var value = (bool?)Values[0];
+ if (value != null)
+ element.CheckBox.Checked = value.Value;
}
}
}
diff --git a/Source/Editor/CustomEditors/Editors/InputEditor.cs b/Source/Editor/CustomEditors/Editors/InputEditor.cs
index 416626e81..7b2682a84 100644
--- a/Source/Editor/CustomEditors/Editors/InputEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/InputEditor.cs
@@ -1,8 +1,10 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System.Collections.Generic;
+using FlaxEditor.CustomEditors.GUI;
+using FlaxEditor.GUI;
+using FlaxEditor.GUI.ContextMenu;
using FlaxEngine;
-using FlaxEngine.GUI;
namespace FlaxEditor.CustomEditors.Editors
{
@@ -12,7 +14,7 @@ namespace FlaxEditor.CustomEditors.Editors
[CustomEditor(typeof(InputEvent)), DefaultEditor]
public class InputEventEditor : CustomEditor
{
- private Dropdown _dropdown;
+ private ComboBox _comboBox;
///
public override DisplayStyle Style => DisplayStyle.Inline;
@@ -20,23 +22,30 @@ namespace FlaxEditor.CustomEditors.Editors
///
public override void Initialize(LayoutElementsContainer layout)
{
- var dropdownElement = layout.Custom();
- _dropdown = dropdownElement.CustomControl;
- var names = new List();
+ LinkedLabel.SetupContextMenu += OnSetupContextMenu;
+ var comboBoxElement = layout.ComboBox();
+ _comboBox = comboBoxElement.ComboBox;
+ var names = new List();
foreach (var mapping in Input.ActionMappings)
{
if (!names.Contains(mapping.Name))
names.Add(mapping.Name);
}
- _dropdown.Items = names;
+ _comboBox.Items = names;
if (Values[0] is InputEvent inputEvent && names.Contains(inputEvent.Name))
- _dropdown.SelectedItem = inputEvent.Name;
- _dropdown.SelectedIndexChanged += OnSelectedIndexChanged;
+ _comboBox.SelectedItem = inputEvent.Name;
+ _comboBox.SelectedIndexChanged += OnSelectedIndexChanged;
}
- private void OnSelectedIndexChanged(Dropdown dropdown)
+ private void OnSetupContextMenu(PropertyNameLabel label, ContextMenu menu, CustomEditor linkededitor)
{
- SetValue(new InputEvent(dropdown.SelectedItem));
+ var button = menu.AddButton("Set to null");
+ button.Clicked += () => _comboBox.SelectedItem = null;
+ }
+
+ private void OnSelectedIndexChanged(ComboBox comboBox)
+ {
+ SetValue(comboBox.SelectedItem == null ? null : new InputEvent(comboBox.SelectedItem));
}
///
@@ -49,17 +58,21 @@ namespace FlaxEditor.CustomEditors.Editors
}
else
{
- if (Values[0] is InputEvent inputEvent && _dropdown.Items.Contains(inputEvent.Name))
- _dropdown.SelectedItem = inputEvent.Name;
+ if (Values[0] is InputEvent inputEvent && _comboBox.Items.Contains(inputEvent.Name))
+ _comboBox.SelectedItem = inputEvent.Name;
+ else
+ _comboBox.SelectedItem = null;
}
}
///
protected override void Deinitialize()
{
- if (_dropdown != null)
- _dropdown.SelectedIndexChanged -= OnSelectedIndexChanged;
- _dropdown = null;
+ if (LinkedLabel != null)
+ LinkedLabel.SetupContextMenu -= OnSetupContextMenu;
+ if (_comboBox != null)
+ _comboBox.SelectedIndexChanged -= OnSelectedIndexChanged;
+ _comboBox = null;
}
}
@@ -69,7 +82,7 @@ namespace FlaxEditor.CustomEditors.Editors
[CustomEditor(typeof(InputAxis)), DefaultEditor]
public class InputAxisEditor : CustomEditor
{
- private Dropdown _dropdown;
+ private ComboBox _comboBox;
///
public override DisplayStyle Style => DisplayStyle.Inline;
@@ -77,23 +90,30 @@ namespace FlaxEditor.CustomEditors.Editors
///
public override void Initialize(LayoutElementsContainer layout)
{
- var dropdownElement = layout.Custom();
- _dropdown = dropdownElement.CustomControl;
- var names = new List();
+ LinkedLabel.SetupContextMenu += OnSetupContextMenu;
+ var comboBoxElement = layout.ComboBox();
+ _comboBox = comboBoxElement.ComboBox;
+ var names = new List();
foreach (var mapping in Input.AxisMappings)
{
if (!names.Contains(mapping.Name))
names.Add(mapping.Name);
}
- _dropdown.Items = names;
+ _comboBox.Items = names;
if (Values[0] is InputAxis inputAxis && names.Contains(inputAxis.Name))
- _dropdown.SelectedItem = inputAxis.Name;
- _dropdown.SelectedIndexChanged += OnSelectedIndexChanged;
+ _comboBox.SelectedItem = inputAxis.Name;
+ _comboBox.SelectedIndexChanged += OnSelectedIndexChanged;
}
- private void OnSelectedIndexChanged(Dropdown dropdown)
+ private void OnSetupContextMenu(PropertyNameLabel label, ContextMenu menu, CustomEditor linkededitor)
{
- SetValue(new InputAxis(dropdown.SelectedItem));
+ var button = menu.AddButton("Set to null");
+ button.Clicked += () => _comboBox.SelectedItem = null;
+ }
+
+ private void OnSelectedIndexChanged(ComboBox comboBox)
+ {
+ SetValue(comboBox.SelectedItem == null ? null : new InputAxis(comboBox.SelectedItem));
}
///
@@ -106,17 +126,21 @@ namespace FlaxEditor.CustomEditors.Editors
}
else
{
- if (Values[0] is InputAxis inputAxis && _dropdown.Items.Contains(inputAxis.Name))
- _dropdown.SelectedItem = inputAxis.Name;
+ if (Values[0] is InputAxis inputAxis && _comboBox.Items.Contains(inputAxis.Name))
+ _comboBox.SelectedItem = inputAxis.Name;
+ else
+ _comboBox.SelectedItem = null;
}
}
///
protected override void Deinitialize()
{
- if (_dropdown != null)
- _dropdown.SelectedIndexChanged -= OnSelectedIndexChanged;
- _dropdown = null;
+ if (LinkedLabel != null)
+ LinkedLabel.SetupContextMenu -= OnSetupContextMenu;
+ if (_comboBox != null)
+ _comboBox.SelectedIndexChanged -= OnSelectedIndexChanged;
+ _comboBox = null;
}
}
}
diff --git a/Source/Editor/CustomEditors/Editors/TagEditor.cs b/Source/Editor/CustomEditors/Editors/TagEditor.cs
index 3d2dd86aa..911397785 100644
--- a/Source/Editor/CustomEditors/Editors/TagEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/TagEditor.cs
@@ -623,13 +623,18 @@ namespace FlaxEditor.CustomEditors.Editors
{
_label = layout.ClickableLabel(GetText(out _)).CustomControl;
_label.RightClick += ShowPicker;
+ var buttonText = "...";
var button = new Button
{
Size = new Float2(16.0f),
- Text = "...",
+ Text = buttonText,
TooltipText = "Edit...",
Parent = _label,
};
+ var textSize = FlaxEngine.GUI.Style.Current.FontMedium.MeasureText(buttonText);
+ if (textSize.Y > button.Width)
+ button.Width = textSize.Y + 2;
+
button.SetAnchorPreset(AnchorPresets.MiddleRight, false, true);
button.Clicked += ShowPicker;
}
@@ -674,9 +679,9 @@ namespace FlaxEditor.CustomEditors.Editors
}
set
{
- if (Values[0] is Tag[])
+ if (Values[0] is Tag[] || Values.Type.Type == typeof(Tag[]))
SetValue(value);
- if (Values[0] is List)
+ else if (Values[0] is List || Values.Type.Type == typeof(List))
SetValue(new List(value));
}
}
diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs
index 7f0359331..06a6f0979 100644
--- a/Source/Editor/Editor.cs
+++ b/Source/Editor/Editor.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
@@ -13,6 +14,7 @@ using FlaxEditor.Content.Thumbnails;
using FlaxEditor.Modules;
using FlaxEditor.Modules.SourceCodeEditing;
using FlaxEditor.Options;
+using FlaxEditor.SceneGraph.Actors;
using FlaxEditor.States;
using FlaxEditor.Windows;
using FlaxEditor.Windows.Assets;
@@ -1274,6 +1276,69 @@ namespace FlaxEditor
Scene.MarkSceneEdited(scenes);
}
+ ///
+ /// Bakes all environmental probes in the scene.
+ ///
+ public void BakeAllEnvProbes()
+ {
+ Scene.ExecuteOnGraph(node =>
+ {
+ if (node is EnvironmentProbeNode envProbeNode && envProbeNode.IsActive)
+ {
+ ((EnvironmentProbe)envProbeNode.Actor).Bake();
+ node.ParentScene.IsEdited = true;
+ }
+ else if (node is SkyLightNode skyLightNode && skyLightNode.IsActive && skyLightNode.Actor is SkyLight skyLight && skyLight.Mode == SkyLight.Modes.CaptureScene)
+ {
+ skyLight.Bake();
+ node.ParentScene.IsEdited = true;
+ }
+
+ return node.IsActive;
+ });
+ }
+
+ ///
+ /// Builds CSG for all open scenes.
+ ///
+ public void BuildCSG()
+ {
+ var scenes = Level.Scenes;
+ scenes.ToList().ForEach(x => x.BuildCSG(0));
+ Scene.MarkSceneEdited(scenes);
+ }
+
+ ///
+ /// Builds Nav mesh for all open scenes.
+ ///
+ public void BuildNavMesh()
+ {
+ var scenes = Level.Scenes;
+ scenes.ToList().ForEach(x => Navigation.BuildNavMesh(x, 0));
+ Scene.MarkSceneEdited(scenes);
+ }
+
+ ///
+ /// Builds SDF for all static models in the scene.
+ ///
+ public void BuildAllMeshesSDF()
+ {
+ // TODO: async maybe with progress reporting?
+ Scene.ExecuteOnGraph(node =>
+ {
+ if (node is StaticModelNode staticModelNode && staticModelNode.Actor is StaticModel staticModel)
+ {
+ if (staticModel.DrawModes.HasFlag(DrawPass.GlobalSDF) && staticModel.Model != null && !staticModel.Model.IsVirtual && staticModel.Model.SDF.Texture == null)
+ {
+ Log("Generating SDF for " + staticModel.Model);
+ if (!staticModel.Model.GenerateSDF())
+ staticModel.Model.Save();
+ }
+ }
+ return true;
+ });
+ }
+
#endregion
#region Internal Calls
diff --git a/Source/Editor/EditorAssets.cs b/Source/Editor/EditorAssets.cs
index 7fa920ca6..eb2f21356 100644
--- a/Source/Editor/EditorAssets.cs
+++ b/Source/Editor/EditorAssets.cs
@@ -36,7 +36,9 @@ namespace FlaxEditor
public static void OnEditorOptionsChanged(Options.EditorOptions options)
{
- var param = _highlightMaterial?.GetParameter("Color");
+ if (!_highlightMaterial)
+ return;
+ var param = _highlightMaterial.GetParameter("Color");
if (param != null)
param.Value = options.Visual.HighlightColor;
}
diff --git a/Source/Editor/GUI/ComboBox.cs b/Source/Editor/GUI/ComboBox.cs
index da2106450..0417cc7e3 100644
--- a/Source/Editor/GUI/ComboBox.cs
+++ b/Source/Editor/GUI/ComboBox.cs
@@ -545,7 +545,7 @@ namespace FlaxEditor.GUI
Render2D.DrawRectangle(clientRect.MakeExpanded(-2.0f), borderColor);
// Check if has selected item
- if (_selectedIndices.Count > 0)
+ if (_selectedIndices != null && _selectedIndices.Count > 0)
{
string text = _selectedIndices.Count == 1 ? _items[_selectedIndices[0]] : "Multiple Values";
diff --git a/Source/Editor/GUI/ContextMenu/ContextMenu.cs b/Source/Editor/GUI/ContextMenu/ContextMenu.cs
index f2e5d30e3..25f45a1f8 100644
--- a/Source/Editor/GUI/ContextMenu/ContextMenu.cs
+++ b/Source/Editor/GUI/ContextMenu/ContextMenu.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using FlaxEditor.Options;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -269,6 +270,24 @@ namespace FlaxEditor.GUI.ContextMenu
return item;
}
+ ///
+ /// Adds the button.
+ ///
+ /// The text.
+ /// The input binding.
+ /// On button clicked event.
+ /// Created context menu item control.
+ public ContextMenuButton AddButton(string text, InputBinding binding, Action clicked)
+ {
+ var item = new ContextMenuButton(this, text, binding.ToString())
+ {
+ Parent = _panel
+ };
+ item.Clicked += clicked;
+ SortButtons();
+ return item;
+ }
+
///
/// Gets the child menu (with that name).
///
diff --git a/Source/Editor/GUI/Dialogs/Dialog.cs b/Source/Editor/GUI/Dialogs/Dialog.cs
index 8910cfe49..07fc3ff0d 100644
--- a/Source/Editor/GUI/Dialogs/Dialog.cs
+++ b/Source/Editor/GUI/Dialogs/Dialog.cs
@@ -290,7 +290,11 @@ namespace FlaxEditor.GUI.Dialogs
OnCancel();
return true;
case KeyboardKeys.Tab:
- Root?.Navigate(NavDirection.Next);
+ if (Root != null)
+ {
+ bool shiftDown = Root.GetKey(KeyboardKeys.Shift);
+ Root.Navigate(shiftDown ? NavDirection.Previous : NavDirection.Next);
+ }
return true;
}
return false;
diff --git a/Source/Editor/GUI/Docking/DockHintWindow.cs b/Source/Editor/GUI/Docking/DockHintWindow.cs
index 6dc700731..52c5dcd3c 100644
--- a/Source/Editor/GUI/Docking/DockHintWindow.cs
+++ b/Source/Editor/GUI/Docking/DockHintWindow.cs
@@ -476,6 +476,7 @@ namespace FlaxEditor.GUI.Docking
settings.ShowInTaskbar = false;
settings.ActivateWhenFirstShown = false;
settings.IsTopmost = true;
+ settings.ShowAfterFirstPaint = false;
win = Platform.CreateWindow(ref settings);
diff --git a/Source/Editor/GUI/MainMenu.cs b/Source/Editor/GUI/MainMenu.cs
index 370ad056b..b313fed9f 100644
--- a/Source/Editor/GUI/MainMenu.cs
+++ b/Source/Editor/GUI/MainMenu.cs
@@ -292,7 +292,8 @@ namespace FlaxEditor.GUI
return true;
#if PLATFORM_WINDOWS
- if (_useCustomWindowSystem)
+ var child = GetChildAtRecursive(location);
+ if (_useCustomWindowSystem && child is not Button && child is not MainMenuButton)
{
if (_window.IsMaximized)
_window.Restore();
diff --git a/Source/Editor/GUI/Row.cs b/Source/Editor/GUI/Row.cs
index 8dad8b20d..b07d693e5 100644
--- a/Source/Editor/GUI/Row.cs
+++ b/Source/Editor/GUI/Row.cs
@@ -37,6 +37,9 @@ namespace FlaxEditor.GUI
: base(0, 0, 100, height)
{
Depth = -1;
+
+ if (Height < Style.Current.FontMedium.Height)
+ Height = Style.Current.FontMedium.Height + 4;
}
///
diff --git a/Source/Editor/GUI/Timeline/SceneAnimationTimeline.cs b/Source/Editor/GUI/Timeline/SceneAnimationTimeline.cs
index c5989cca5..76b6ca246 100644
--- a/Source/Editor/GUI/Timeline/SceneAnimationTimeline.cs
+++ b/Source/Editor/GUI/Timeline/SceneAnimationTimeline.cs
@@ -33,7 +33,7 @@ namespace FlaxEditor.GUI.Timeline
///
public SceneAnimationPlayer Player
{
- get => _player;
+ get => _player != null ? _player : null;
set
{
if (_player == value)
@@ -268,7 +268,7 @@ namespace FlaxEditor.GUI.Timeline
///
public override void OnSeek(int frame)
{
- if (_player?.Animation)
+ if (_player != null && _player.Animation)
{
_player.Animation.WaitForLoaded();
_player.Time = frame / _player.Animation.FramesPerSecond;
diff --git a/Source/Editor/Modules/ContentDatabaseModule.cs b/Source/Editor/Modules/ContentDatabaseModule.cs
index 29d6b2c00..143352421 100644
--- a/Source/Editor/Modules/ContentDatabaseModule.cs
+++ b/Source/Editor/Modules/ContentDatabaseModule.cs
@@ -643,7 +643,8 @@ namespace FlaxEditor.Modules
/// Deletes the specified item.
///
/// The item.
- public void Delete(ContentItem item)
+ /// If the file was deleted by the user and not outside the editor.
+ public void Delete(ContentItem item, bool deletedByUser = false)
{
if (item == null)
throw new ArgumentNullException();
@@ -667,12 +668,12 @@ namespace FlaxEditor.Modules
var children = folder.Children.ToArray();
for (int i = 0; i < children.Length; i++)
{
- Delete(children[i]);
+ Delete(children[i], deletedByUser);
}
}
// Remove directory
- if (Directory.Exists(path))
+ if (deletedByUser && Directory.Exists(path))
{
try
{
@@ -701,7 +702,7 @@ namespace FlaxEditor.Modules
// Delete asset by using content pool
FlaxEngine.Content.DeleteAsset(path);
}
- else
+ else if (deletedByUser)
{
// Delete file
if (File.Exists(path))
@@ -847,7 +848,7 @@ namespace FlaxEditor.Modules
Editor.Log(string.Format($"Content item \'{child.Path}\' has been removed"));
// Destroy it
- Delete(child);
+ Delete(child, false);
i--;
}
diff --git a/Source/Editor/Modules/ContentEditingModule.cs b/Source/Editor/Modules/ContentEditingModule.cs
index 3db27af40..a6d8132f0 100644
--- a/Source/Editor/Modules/ContentEditingModule.cs
+++ b/Source/Editor/Modules/ContentEditingModule.cs
@@ -90,6 +90,12 @@ namespace FlaxEditor.Modules
hint = "Too long name.";
return false;
}
+
+ if (item.IsFolder && shortName.EndsWith("."))
+ {
+ hint = "Name cannot end with '.'";
+ return false;
+ }
// Find invalid characters
if (Utilities.Utils.HasInvalidPathChar(shortName))
@@ -120,7 +126,7 @@ namespace FlaxEditor.Modules
// Cache data
string sourcePath = item.Path;
string sourceFolder = System.IO.Path.GetDirectoryName(sourcePath);
- string extension = System.IO.Path.GetExtension(sourcePath);
+ string extension = item.IsFolder ? "" : System.IO.Path.GetExtension(sourcePath);
string destinationPath = StringUtils.CombinePaths(sourceFolder, shortName + extension);
if (item.IsFolder)
diff --git a/Source/Editor/Modules/ProgressReportingModule.cs b/Source/Editor/Modules/ProgressReportingModule.cs
index 16acd7f8b..22ae5ea98 100644
--- a/Source/Editor/Modules/ProgressReportingModule.cs
+++ b/Source/Editor/Modules/ProgressReportingModule.cs
@@ -129,6 +129,7 @@ namespace FlaxEditor.Modules
else
{
Editor.UI.UpdateProgress(string.Empty, 0);
+ Editor.UI.UpdateStatusBar();
}
}
diff --git a/Source/Editor/Modules/UIModule.cs b/Source/Editor/Modules/UIModule.cs
index 08ec09de8..299865dea 100644
--- a/Source/Editor/Modules/UIModule.cs
+++ b/Source/Editor/Modules/UIModule.cs
@@ -42,8 +42,10 @@ namespace FlaxEditor.Modules
private ContextMenuButton _menuFileSaveScenes;
private ContextMenuButton _menuFileCloseScenes;
+ private ContextMenuButton _menuFileOpenScriptsProject;
private ContextMenuButton _menuFileGenerateScriptsProjectFiles;
- private ContextMenuButton _menuSaveAll;
+ private ContextMenuButton _menuFileRecompileScripts;
+ private ContextMenuButton _menuFileSaveAll;
private ContextMenuButton _menuEditUndo;
private ContextMenuButton _menuEditRedo;
private ContextMenuButton _menuEditCut;
@@ -62,15 +64,19 @@ namespace FlaxEditor.Modules
private ContextMenuButton _menuGamePlayCurrentScenes;
private ContextMenuButton _menuGameStop;
private ContextMenuButton _menuGamePause;
+ private ContextMenuButton _menuGameCookAndRun;
+ private ContextMenuButton _menuGameRunCookedGame;
private ContextMenuButton _menuToolsBuildScenes;
private ContextMenuButton _menuToolsBakeLightmaps;
private ContextMenuButton _menuToolsClearLightmaps;
private ContextMenuButton _menuToolsBakeAllEnvProbes;
private ContextMenuButton _menuToolsBuildCSGMesh;
private ContextMenuButton _menuToolsBuildNavMesh;
- private ContextMenuButton _menuToolsBuildAllMesgesSDF;
+ private ContextMenuButton _menuToolsBuildAllMeshesSDF;
private ContextMenuButton _menuToolsCancelBuilding;
+ private ContextMenuButton _menuToolsProfilerWindow;
private ContextMenuButton _menuToolsSetTheCurrentSceneViewAsDefault;
+ private ContextMenuButton _menuToolsTakeScreenshot;
private ContextMenuChildMenu _menuWindowApplyWindowLayout;
private ToolStripButton _toolStripSaveAll;
@@ -279,7 +285,7 @@ namespace FlaxEditor.Modules
Color color;
if (Editor.StateMachine.IsPlayMode)
- color = Color.OrangeRed;
+ color = Style.Current.Statusbar.PlayMode;
else
color = Style.Current.BackgroundSelected;
@@ -293,6 +299,11 @@ namespace FlaxEditor.Modules
else
text = "Ready";
+ if(ProgressVisible)
+ {
+ color = Style.Current.Statusbar.Loading;
+ }
+
StatusBar.Text = text;
StatusBar.StatusColor = color;
_contentStats = contentStats;
@@ -338,7 +349,7 @@ namespace FlaxEditor.Modules
internal void ProgressFailed(string message)
{
_progressFailed = true;
- StatusBar.StatusColor = Color.Red;
+ StatusBar.StatusColor = Style.Current.Statusbar.Failed;
StatusBar.Text = message;
_outputLogButton.Visible = true;
}
@@ -391,6 +402,10 @@ namespace FlaxEditor.Modules
{
UpdateStatusBar();
}
+ else if(ProgressVisible)
+ {
+ UpdateStatusBar();
+ }
}
private class CustomWindowBorderControl : Control
@@ -510,13 +525,13 @@ namespace FlaxEditor.Modules
MenuFile = MainMenu.AddButton("File");
var cm = MenuFile.ContextMenu;
cm.VisibleChanged += OnMenuFileShowHide;
- _menuSaveAll = cm.AddButton("Save All", inputOptions.Save.ToString(), Editor.SaveAll);
- _menuFileSaveScenes = cm.AddButton("Save scenes", Editor.Scene.SaveScenes);
- _menuFileCloseScenes = cm.AddButton("Close scenes", Editor.Scene.CloseAllScenes);
+ _menuFileSaveAll = cm.AddButton("Save All", inputOptions.Save, Editor.SaveAll);
+ _menuFileSaveScenes = cm.AddButton("Save scenes", inputOptions.SaveScenes, Editor.Scene.SaveScenes);
+ _menuFileCloseScenes = cm.AddButton("Close scenes", inputOptions.CloseScenes, Editor.Scene.CloseAllScenes);
cm.AddSeparator();
- cm.AddButton("Open scripts project", Editor.CodeEditing.OpenSolution);
- _menuFileGenerateScriptsProjectFiles = cm.AddButton("Generate scripts project files", Editor.ProgressReporting.GenerateScriptsProjectFiles.RunAsync);
- cm.AddButton("Recompile scripts", ScriptsBuilder.Compile);
+ _menuFileOpenScriptsProject = cm.AddButton("Open scripts project", inputOptions.OpenScriptsProject, Editor.CodeEditing.OpenSolution);
+ _menuFileGenerateScriptsProjectFiles = cm.AddButton("Generate scripts project files", inputOptions.GenerateScriptsProject, Editor.ProgressReporting.GenerateScriptsProjectFiles.RunAsync);
+ _menuFileRecompileScripts = cm.AddButton("Recompile scripts", inputOptions.RecompileScripts, ScriptsBuilder.Compile);
cm.AddSeparator();
cm.AddButton("Open project...", OpenProject);
cm.AddSeparator();
@@ -526,27 +541,27 @@ namespace FlaxEditor.Modules
MenuEdit = MainMenu.AddButton("Edit");
cm = MenuEdit.ContextMenu;
cm.VisibleChanged += OnMenuEditShowHide;
- _menuEditUndo = cm.AddButton(string.Empty, inputOptions.Undo.ToString(), Editor.PerformUndo);
- _menuEditRedo = cm.AddButton(string.Empty, inputOptions.Redo.ToString(), Editor.PerformRedo);
+ _menuEditUndo = cm.AddButton(string.Empty, inputOptions.Undo, Editor.PerformUndo);
+ _menuEditRedo = cm.AddButton(string.Empty, inputOptions.Redo, Editor.PerformRedo);
cm.AddSeparator();
- _menuEditCut = cm.AddButton("Cut", inputOptions.Cut.ToString(), Editor.SceneEditing.Cut);
- _menuEditCopy = cm.AddButton("Copy", inputOptions.Copy.ToString(), Editor.SceneEditing.Copy);
- _menuEditPaste = cm.AddButton("Paste", inputOptions.Paste.ToString(), Editor.SceneEditing.Paste);
+ _menuEditCut = cm.AddButton("Cut", inputOptions.Cut, Editor.SceneEditing.Cut);
+ _menuEditCopy = cm.AddButton("Copy", inputOptions.Copy, Editor.SceneEditing.Copy);
+ _menuEditPaste = cm.AddButton("Paste", inputOptions.Paste, Editor.SceneEditing.Paste);
cm.AddSeparator();
- _menuEditDelete = cm.AddButton("Delete", inputOptions.Delete.ToString(), Editor.SceneEditing.Delete);
- _menuEditDuplicate = cm.AddButton("Duplicate", inputOptions.Duplicate.ToString(), Editor.SceneEditing.Duplicate);
+ _menuEditDelete = cm.AddButton("Delete", inputOptions.Delete, Editor.SceneEditing.Delete);
+ _menuEditDuplicate = cm.AddButton("Duplicate", inputOptions.Duplicate, Editor.SceneEditing.Duplicate);
cm.AddSeparator();
- _menuEditSelectAll = cm.AddButton("Select all", inputOptions.SelectAll.ToString(), Editor.SceneEditing.SelectAllScenes);
- _menuEditFind = cm.AddButton("Find", inputOptions.Search.ToString(), Editor.Windows.SceneWin.Search);
+ _menuEditSelectAll = cm.AddButton("Select all", inputOptions.SelectAll, Editor.SceneEditing.SelectAllScenes);
+ _menuEditFind = cm.AddButton("Find", inputOptions.Search, Editor.Windows.SceneWin.Search);
// Scene
MenuScene = MainMenu.AddButton("Scene");
cm = MenuScene.ContextMenu;
cm.VisibleChanged += OnMenuSceneShowHide;
- _menuSceneMoveActorToViewport = cm.AddButton("Move actor to viewport", MoveActorToViewport);
- _menuSceneAlignActorWithViewport = cm.AddButton("Align actor with viewport", AlignActorWithViewport);
- _menuSceneAlignViewportWithActor = cm.AddButton("Align viewport with actor", AlignViewportWithActor);
- _menuScenePilotActor = cm.AddButton("Pilot actor", PilotActor);
+ _menuSceneMoveActorToViewport = cm.AddButton("Move actor to viewport", inputOptions.MoveActorToViewport, MoveActorToViewport);
+ _menuSceneAlignActorWithViewport = cm.AddButton("Align actor with viewport", inputOptions.AlignActorWithViewport, AlignActorWithViewport);
+ _menuSceneAlignViewportWithActor = cm.AddButton("Align viewport with actor", inputOptions.AlignViewportWithActor, AlignViewportWithActor);
+ _menuScenePilotActor = cm.AddButton("Pilot actor", inputOptions.PilotActor, PilotActor);
cm.AddSeparator();
_menuSceneCreateTerrain = cm.AddButton("Create terrain", CreateTerrain);
@@ -555,39 +570,41 @@ namespace FlaxEditor.Modules
cm = MenuGame.ContextMenu;
cm.VisibleChanged += OnMenuGameShowHide;
- _menuGamePlayGame = cm.AddButton("Play Game", Editor.Simulation.RequestPlayGameOrStopPlay);
- _menuGamePlayCurrentScenes = cm.AddButton("Play Current Scenes", Editor.Simulation.RequestPlayScenesOrStopPlay);
- _menuGameStop = cm.AddButton("Stop Game", Editor.Simulation.RequestStopPlay);
- _menuGamePause = cm.AddButton("Pause", inputOptions.Pause.ToString(), Editor.Simulation.RequestPausePlay);
+ _menuGamePlayGame = cm.AddButton("Play Game", inputOptions.Play, Editor.Simulation.RequestPlayGameOrStopPlay);
+ _menuGamePlayCurrentScenes = cm.AddButton("Play Current Scenes", inputOptions.PlayCurrentScenes, Editor.Simulation.RequestPlayScenesOrStopPlay);
+ _menuGameStop = cm.AddButton("Stop Game", inputOptions.Play, Editor.Simulation.RequestStopPlay);
+ _menuGamePause = cm.AddButton("Pause", inputOptions.Pause, Editor.Simulation.RequestPausePlay);
cm.AddSeparator();
var numberOfClientsMenu = cm.AddChildMenu("Number of game clients");
_numberOfClientsGroup.AddItemsToContextMenu(numberOfClientsMenu.ContextMenu);
cm.AddSeparator();
- cm.AddButton("Cook & Run", Editor.Windows.GameCookerWin.BuildAndRun).LinkTooltip("Runs Game Cooker to build the game for this platform and runs the game after.");
- cm.AddButton("Run cooked game", Editor.Windows.GameCookerWin.RunCooked).LinkTooltip("Runs the game build from the last cooking output. Use Cook&Play or Game Cooker first.");
+ _menuGameCookAndRun = cm.AddButton("Cook & Run", inputOptions.CookAndRun, Editor.Windows.GameCookerWin.BuildAndRun);
+ _menuGameCookAndRun.LinkTooltip("Runs Game Cooker to build the game for this platform and runs the game after.");
+ _menuGameRunCookedGame = cm.AddButton("Run cooked game", inputOptions.RunCookedGame, Editor.Windows.GameCookerWin.RunCooked);
+ _menuGameRunCookedGame.LinkTooltip("Runs the game build from the last cooking output. Use 'Cook & Run' or Game Cooker first.");
// Tools
MenuTools = MainMenu.AddButton("Tools");
cm = MenuTools.ContextMenu;
cm.VisibleChanged += OnMenuToolsShowHide;
- _menuToolsBuildScenes = cm.AddButton("Build scenes data", "Ctrl+F10", Editor.BuildScenesOrCancel);
+ _menuToolsBuildScenes = cm.AddButton("Build scenes data", inputOptions.BuildScenesData, Editor.BuildScenesOrCancel);
cm.AddSeparator();
- _menuToolsBakeLightmaps = cm.AddButton("Bake lightmaps", Editor.BakeLightmapsOrCancel);
- _menuToolsClearLightmaps = cm.AddButton("Clear lightmaps data", Editor.ClearLightmaps);
- _menuToolsBakeAllEnvProbes = cm.AddButton("Bake all env probes", BakeAllEnvProbes);
- _menuToolsBuildCSGMesh = cm.AddButton("Build CSG mesh", BuildCSG);
- _menuToolsBuildNavMesh = cm.AddButton("Build Nav Mesh", BuildNavMesh);
- _menuToolsBuildAllMesgesSDF = cm.AddButton("Build all meshes SDF", BuildAllMeshesSDF);
+ _menuToolsBakeLightmaps = cm.AddButton("Bake lightmaps", inputOptions.BakeLightmaps, Editor.BakeLightmapsOrCancel);
+ _menuToolsClearLightmaps = cm.AddButton("Clear lightmaps data", inputOptions.ClearLightmaps, Editor.ClearLightmaps);
+ _menuToolsBakeAllEnvProbes = cm.AddButton("Bake all env probes", inputOptions.BakeEnvProbes, Editor.BakeAllEnvProbes);
+ _menuToolsBuildCSGMesh = cm.AddButton("Build CSG mesh", inputOptions.BuildCSG, Editor.BuildCSG);
+ _menuToolsBuildNavMesh = cm.AddButton("Build Nav Mesh", inputOptions.BuildNav, Editor.BuildNavMesh);
+ _menuToolsBuildAllMeshesSDF = cm.AddButton("Build all meshes SDF", inputOptions.BuildSDF, Editor.BuildAllMeshesSDF);
cm.AddSeparator();
cm.AddButton("Game Cooker", Editor.Windows.GameCookerWin.FocusOrShow);
_menuToolsCancelBuilding = cm.AddButton("Cancel building game", () => GameCooker.Cancel());
cm.AddSeparator();
- cm.AddButton("Profiler", Editor.Windows.ProfilerWin.FocusOrShow);
+ _menuToolsProfilerWindow = cm.AddButton("Profiler", inputOptions.ProfilerWindow, () => Editor.Windows.ProfilerWin.FocusOrShow());
cm.AddSeparator();
_menuToolsSetTheCurrentSceneViewAsDefault = cm.AddButton("Set current scene view as project default", SetTheCurrentSceneViewAsDefault);
- cm.AddButton("Take screenshot", "F12", Editor.Windows.TakeScreenshot);
+ _menuToolsTakeScreenshot = cm.AddButton("Take screenshot", inputOptions.TakeScreenshot, Editor.Windows.TakeScreenshot);
cm.AddSeparator();
cm.AddButton("Plugins", () => Editor.Windows.PluginsWin.Show());
cm.AddButton("Options", () => Editor.Windows.EditorOptionsWin.Show());
@@ -606,7 +623,7 @@ namespace FlaxEditor.Modules
cm.AddButton("Output Log", Editor.Windows.OutputLogWin.FocusOrShow);
cm.AddButton("Graphics Quality", Editor.Windows.GraphicsQualityWin.FocusOrShow);
cm.AddButton("Game Cooker", Editor.Windows.GameCookerWin.FocusOrShow);
- cm.AddButton("Profiler", Editor.Windows.ProfilerWin.FocusOrShow);
+ cm.AddButton("Profiler", inputOptions.ProfilerWindow, Editor.Windows.ProfilerWin.FocusOrShow);
cm.AddButton("Content Search", Editor.ContentFinding.ShowSearch);
cm.AddButton("Visual Script Debugger", Editor.Windows.VisualScriptDebuggerWin.FocusOrShow);
cm.AddSeparator();
@@ -633,7 +650,12 @@ namespace FlaxEditor.Modules
{
var inputOptions = options.Input;
- _menuSaveAll.ShortKeys = inputOptions.Save.ToString();
+ _menuFileSaveAll.ShortKeys = inputOptions.Save.ToString();
+ _menuFileSaveScenes.ShortKeys = inputOptions.SaveScenes.ToString();
+ _menuFileCloseScenes.ShortKeys = inputOptions.CloseScenes.ToString();
+ _menuFileOpenScriptsProject.ShortKeys = inputOptions.OpenScriptsProject.ToString();
+ _menuFileGenerateScriptsProjectFiles.ShortKeys = inputOptions.GenerateScriptsProject.ToString();
+ _menuFileRecompileScripts.ShortKeys = inputOptions.RecompileScripts.ToString();
_menuEditUndo.ShortKeys = inputOptions.Undo.ToString();
_menuEditRedo.ShortKeys = inputOptions.Redo.ToString();
_menuEditCut.ShortKeys = inputOptions.Cut.ToString();
@@ -642,8 +664,21 @@ namespace FlaxEditor.Modules
_menuEditDuplicate.ShortKeys = inputOptions.Duplicate.ToString();
_menuEditSelectAll.ShortKeys = inputOptions.SelectAll.ToString();
_menuEditFind.ShortKeys = inputOptions.Search.ToString();
- _menuGamePlayCurrentScenes.ShortKeys = inputOptions.Play.ToString();
+ _menuGamePlayGame.ShortKeys = inputOptions.Play.ToString();
+ _menuGamePlayCurrentScenes.ShortKeys = inputOptions.PlayCurrentScenes.ToString();
_menuGamePause.ShortKeys = inputOptions.Pause.ToString();
+ _menuGameStop.ShortKeys = inputOptions.Play.ToString();
+ _menuGameCookAndRun.ShortKeys = inputOptions.CookAndRun.ToString();
+ _menuGameRunCookedGame.ShortKeys = inputOptions.RunCookedGame.ToString();
+ _menuToolsBuildScenes.ShortKeys = inputOptions.BuildScenesData.ToString();
+ _menuToolsBakeLightmaps.ShortKeys = inputOptions.BakeLightmaps.ToString();
+ _menuToolsClearLightmaps.ShortKeys = inputOptions.ClearLightmaps.ToString();
+ _menuToolsBakeAllEnvProbes.ShortKeys = inputOptions.BakeEnvProbes.ToString();
+ _menuToolsBuildCSGMesh.ShortKeys = inputOptions.BuildCSG.ToString();
+ _menuToolsBuildNavMesh.ShortKeys = inputOptions.BuildNav.ToString();
+ _menuToolsBuildAllMeshesSDF.ShortKeys = inputOptions.BuildSDF.ToString();
+ _menuToolsProfilerWindow.ShortKeys = inputOptions.ProfilerWindow.ToString();
+ _menuToolsTakeScreenshot.ShortKeys = inputOptions.TakeScreenshot.ToString();
MainMenuShortcutKeysUpdated?.Invoke();
}
@@ -668,10 +703,10 @@ namespace FlaxEditor.Modules
ToolStrip.AddSeparator();
// Cook scenes
- _toolStripBuildScenes = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Build64, Editor.BuildScenesOrCancel).LinkTooltip("Build scenes data - CSG, navmesh, static lighting, env probes - configurable via Build Actions in editor options (Ctrl+F10)");
+ _toolStripBuildScenes = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Build64, Editor.BuildScenesOrCancel).LinkTooltip($"Build scenes data - CSG, navmesh, static lighting, env probes - configurable via Build Actions in editor options ({inputOptions.BuildScenesData})");
// Cook and run
- _toolStripCook = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.ShipIt64, Editor.Windows.GameCookerWin.BuildAndRun).LinkTooltip("Cook & Run - build game for the current platform and run it locally");
+ _toolStripCook = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.ShipIt64, Editor.Windows.GameCookerWin.BuildAndRun).LinkTooltip($"Cook & Run - build game for the current platform and run it locally ({inputOptions.Play})");
_toolStripCook.ContextMenu = new ContextMenu();
_toolStripCook.ContextMenu.AddButton("Run cooked game", Editor.Windows.GameCookerWin.RunCooked);
_toolStripCook.ContextMenu.AddSeparator();
@@ -692,7 +727,7 @@ namespace FlaxEditor.Modules
playActionGroup.SelectedChanged = SetPlayAction;
Editor.Options.OptionsChanged += options => { playActionGroup.Selected = options.Interface.PlayButtonAction; };
- _toolStripPause = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Pause64, Editor.Simulation.RequestResumeOrPause).LinkTooltip($"Pause/Resume game({inputOptions.Pause})");
+ _toolStripPause = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Pause64, Editor.Simulation.RequestResumeOrPause).LinkTooltip($"Pause/Resume game ({inputOptions.Pause})");
_toolStripStep = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Skip64, Editor.Simulation.RequestPlayOneFrame).LinkTooltip("Step one frame in game");
UpdateToolstrip();
@@ -752,7 +787,7 @@ namespace FlaxEditor.Modules
HorizontalAlignment = TextAlignment.Far,
AnchorPreset = AnchorPresets.HorizontalStretchMiddle,
Parent = progressPanel,
- Offsets = new Margin(progressBarRightMargin, progressBarWidth + progressBarLeftMargin + progressBarRightMargin, 0, 0),
+ Offsets = new Margin(progressBarRightMargin, progressBarWidth + progressBarLeftMargin + progressBarRightMargin, 0, 0)
};
UpdateStatusBar();
@@ -872,7 +907,7 @@ namespace FlaxEditor.Modules
_menuToolsBakeLightmaps.Text = isBakingLightmaps ? "Cancel baking lightmaps" : "Bake lightmaps";
_menuToolsClearLightmaps.Enabled = canEdit;
_menuToolsBakeAllEnvProbes.Enabled = canEdit;
- _menuToolsBuildAllMesgesSDF.Enabled = canEdit && !isBakingLightmaps;
+ _menuToolsBuildAllMeshesSDF.Enabled = canEdit && !isBakingLightmaps;
_menuToolsBuildCSGMesh.Enabled = canEdit;
_menuToolsBuildNavMesh.Enabled = canEdit;
_menuToolsCancelBuilding.Enabled = GameCooker.IsRunning;
@@ -911,7 +946,7 @@ namespace FlaxEditor.Modules
Editor.Windows.LoadLayout((string)button.Tag);
}
- private void AlignViewportWithActor()
+ internal void AlignViewportWithActor()
{
var selection = Editor.SceneEditing;
if (selection.HasSthSelected && selection.Selection[0] is ActorNode node)
@@ -922,7 +957,7 @@ namespace FlaxEditor.Modules
}
}
- private void MoveActorToViewport()
+ internal void MoveActorToViewport()
{
var selection = Editor.SceneEditing;
if (selection.HasSthSelected && selection.Selection[0] is ActorNode node)
@@ -936,7 +971,7 @@ namespace FlaxEditor.Modules
}
}
- private void AlignActorWithViewport()
+ internal void AlignActorWithViewport()
{
var selection = Editor.SceneEditing;
if (selection.HasSthSelected && selection.Selection[0] is ActorNode node)
@@ -972,57 +1007,6 @@ namespace FlaxEditor.Modules
new Tools.Terrain.CreateTerrainDialog().Show(Editor.Windows.MainWindow);
}
- private void BakeAllEnvProbes()
- {
- Editor.Scene.ExecuteOnGraph(node =>
- {
- if (node is EnvironmentProbeNode envProbeNode && envProbeNode.IsActive)
- {
- ((EnvironmentProbe)envProbeNode.Actor).Bake();
- node.ParentScene.IsEdited = true;
- }
- else if (node is SkyLightNode skyLightNode && skyLightNode.IsActive && skyLightNode.Actor is SkyLight skyLight && skyLight.Mode == SkyLight.Modes.CaptureScene)
- {
- skyLight.Bake();
- node.ParentScene.IsEdited = true;
- }
-
- return node.IsActive;
- });
- }
-
- private void BuildCSG()
- {
- var scenes = Level.Scenes;
- scenes.ToList().ForEach(x => x.BuildCSG(0));
- Editor.Scene.MarkSceneEdited(scenes);
- }
-
- private void BuildNavMesh()
- {
- var scenes = Level.Scenes;
- scenes.ToList().ForEach(x => Navigation.BuildNavMesh(x, 0));
- Editor.Scene.MarkSceneEdited(scenes);
- }
-
- private void BuildAllMeshesSDF()
- {
- // TODO: async maybe with progress reporting?
- Editor.Scene.ExecuteOnGraph(node =>
- {
- if (node is StaticModelNode staticModelNode && staticModelNode.Actor is StaticModel staticModel)
- {
- if (staticModel.DrawModes.HasFlag(DrawPass.GlobalSDF) && staticModel.Model != null && !staticModel.Model.IsVirtual && staticModel.Model.SDF.Texture == null)
- {
- Editor.Log("Generating SDF for " + staticModel.Model);
- if (!staticModel.Model.GenerateSDF())
- staticModel.Model.Save();
- }
- }
- return true;
- });
- }
-
private void SetTheCurrentSceneViewAsDefault()
{
var projectInfo = Editor.GameProject;
diff --git a/Source/Editor/Modules/WindowsModule.cs b/Source/Editor/Modules/WindowsModule.cs
index 61220f7d5..d0c8b9747 100644
--- a/Source/Editor/Modules/WindowsModule.cs
+++ b/Source/Editor/Modules/WindowsModule.cs
@@ -721,7 +721,7 @@ namespace FlaxEditor.Modules
// Create main window
var settings = CreateWindowSettings.Default;
settings.Title = "Flax Editor";
- settings.Size = Platform.DesktopSize;
+ settings.Size = Platform.DesktopSize * 0.75f;
settings.StartPosition = WindowStartPosition.CenterScreen;
settings.ShowAfterFirstPaint = true;
diff --git a/Source/Editor/Options/InputBinding.cs b/Source/Editor/Options/InputBinding.cs
index 2e18dab9e..eb61c0f68 100644
--- a/Source/Editor/Options/InputBinding.cs
+++ b/Source/Editor/Options/InputBinding.cs
@@ -134,6 +134,66 @@ namespace FlaxEditor.Options
return false;
}
+ private bool ProcessModifiers(Control control)
+ {
+ return ProcessModifiers(control.Root.GetKey);
+ }
+
+ private bool ProcessModifiers(Window window)
+ {
+ return ProcessModifiers(window.GetKey);
+ }
+
+ private bool ProcessModifiers(Func getKeyFunc)
+ {
+ bool ctrlPressed = getKeyFunc(KeyboardKeys.Control);
+ bool shiftPressed = getKeyFunc(KeyboardKeys.Shift);
+ bool altPressed = getKeyFunc(KeyboardKeys.Alt);
+
+ bool mod1 = false;
+ if (Modifier1 == KeyboardKeys.None)
+ mod1 = true;
+ else if (Modifier1 == KeyboardKeys.Control)
+ {
+ mod1 = ctrlPressed;
+ ctrlPressed = false;
+ }
+ else if (Modifier1 == KeyboardKeys.Shift)
+ {
+ mod1 = shiftPressed;
+ shiftPressed = false;
+ }
+ else if (Modifier1 == KeyboardKeys.Alt)
+ {
+ mod1 = altPressed;
+ altPressed = false;
+ }
+
+ bool mod2 = false;
+ if (Modifier2 == KeyboardKeys.None)
+ mod2 = true;
+ else if (Modifier2 == KeyboardKeys.Control)
+ {
+ mod2 = ctrlPressed;
+ ctrlPressed = false;
+ }
+ else if (Modifier2 == KeyboardKeys.Shift)
+ {
+ mod2 = shiftPressed;
+ shiftPressed = false;
+ }
+ else if (Modifier2 == KeyboardKeys.Alt)
+ {
+ mod2 = altPressed;
+ altPressed = false;
+ }
+
+ // Check if any unhandled modifiers are not pressed
+ if (mod1 && mod2)
+ return !ctrlPressed && !shiftPressed && !altPressed;
+ return false;
+ }
+
///
/// Processes this input binding to check if state matches.
///
@@ -142,19 +202,7 @@ namespace FlaxEditor.Options
public bool Process(Control control)
{
var root = control.Root;
-
- if (root.GetKey(Key))
- {
- if (Modifier1 == KeyboardKeys.None || root.GetKey(Modifier1))
- {
- if (Modifier2 == KeyboardKeys.None || root.GetKey(Modifier2))
- {
- return true;
- }
- }
- }
-
- return false;
+ return root.GetKey(Key) && ProcessModifiers(control);
}
///
@@ -165,20 +213,20 @@ namespace FlaxEditor.Options
/// True if input has been processed, otherwise false.
public bool Process(Control control, KeyboardKeys key)
{
- var root = control.Root;
+ if (key != Key)
+ return false;
- if (key == Key)
- {
- if (Modifier1 == KeyboardKeys.None || root.GetKey(Modifier1))
- {
- if (Modifier2 == KeyboardKeys.None || root.GetKey(Modifier2))
- {
- return true;
- }
- }
- }
+ return ProcessModifiers(control);
+ }
- return false;
+ ///
+ /// Processes this input binding to check if state matches.
+ ///
+ /// The input providing window.
+ /// True if input has been processed, otherwise false.
+ public bool Process(Window window)
+ {
+ return window.GetKey(Key) && ProcessModifiers(window);
}
///
diff --git a/Source/Editor/Options/InputOptions.cs b/Source/Editor/Options/InputOptions.cs
index e0a51622b..90d098bb6 100644
--- a/Source/Editor/Options/InputOptions.cs
+++ b/Source/Editor/Options/InputOptions.cs
@@ -78,6 +78,30 @@ namespace FlaxEditor.Options
#endregion
+ #region File
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("File"), EditorOrder(300)]
+ public InputBinding SaveScenes = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("File"), EditorOrder(310)]
+ public InputBinding CloseScenes = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("File"), EditorOrder(320)]
+ public InputBinding OpenScriptsProject = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("File"), EditorOrder(330)]
+ public InputBinding GenerateScriptsProject = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("File"), EditorOrder(340)]
+ public InputBinding RecompileScripts = new InputBinding(KeyboardKeys.None);
+
+ #endregion
+
#region Scene
[DefaultValue(typeof(InputBinding), "End")]
@@ -85,35 +109,115 @@ namespace FlaxEditor.Options
public InputBinding SnapToGround = new InputBinding(KeyboardKeys.End);
[DefaultValue(typeof(InputBinding), "F5")]
- [EditorDisplay("Scene"), EditorOrder(510)]
+ [EditorDisplay("Scene", "Play/Stop"), EditorOrder(510)]
public InputBinding Play = new InputBinding(KeyboardKeys.F5);
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Scene", "Play Current Scenes/Stop"), EditorOrder(520)]
+ public InputBinding PlayCurrentScenes = new InputBinding(KeyboardKeys.None);
+
[DefaultValue(typeof(InputBinding), "F6")]
- [EditorDisplay("Scene"), EditorOrder(520)]
+ [EditorDisplay("Scene"), EditorOrder(530)]
public InputBinding Pause = new InputBinding(KeyboardKeys.F6);
[DefaultValue(typeof(InputBinding), "F11")]
- [EditorDisplay("Scene"), EditorOrder(530)]
+ [EditorDisplay("Scene"), EditorOrder(540)]
public InputBinding StepFrame = new InputBinding(KeyboardKeys.F11);
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Scene", "Cook & Run"), EditorOrder(550)]
+ public InputBinding CookAndRun = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Scene", "Run cooked game"), EditorOrder(560)]
+ public InputBinding RunCookedGame = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Scene", "Move actor to viewport"), EditorOrder(570)]
+ public InputBinding MoveActorToViewport = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Scene", "Align actor with viewport"), EditorOrder(571)]
+ public InputBinding AlignActorWithViewport = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Scene", "Align viewport with actor"), EditorOrder(572)]
+ public InputBinding AlignViewportWithActor = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Scene"), EditorOrder(573)]
+ public InputBinding PilotActor = new InputBinding(KeyboardKeys.None);
+
+ #endregion
+
+ #region Tools
+
+ [DefaultValue(typeof(InputBinding), "Ctrl+F10")]
+ [EditorDisplay("Tools", "Build scenes data"), EditorOrder(600)]
+ public InputBinding BuildScenesData = new InputBinding(KeyboardKeys.F10, KeyboardKeys.Control);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Tools", "Bake lightmaps"), EditorOrder(601)]
+ public InputBinding BakeLightmaps = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Tools", "Clear lightmaps data"), EditorOrder(602)]
+ public InputBinding ClearLightmaps = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Tools", "Bake all env probes"), EditorOrder(603)]
+ public InputBinding BakeEnvProbes = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Tools", "Build CSG mesh"), EditorOrder(604)]
+ public InputBinding BuildCSG = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Tools", "Build Nav Mesh"), EditorOrder(605)]
+ public InputBinding BuildNav = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Tools", "Build all meshes SDF"), EditorOrder(606)]
+ public InputBinding BuildSDF = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "F12")]
+ [EditorDisplay("Tools", "Take screenshot"), EditorOrder(607)]
+ public InputBinding TakeScreenshot = new InputBinding(KeyboardKeys.F12);
+
+ #endregion
+
+ #region Profiler
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Profiler", "Open Profiler Window"), EditorOrder(630)]
+ public InputBinding ProfilerWindow = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Profiler", "Start/Stop Profiler"), EditorOrder(631)]
+ public InputBinding ProfilerStartStop = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Profiler", "Clear Profiler data"), EditorOrder(632)]
+ public InputBinding ProfilerClear = new InputBinding(KeyboardKeys.None);
+
#endregion
#region Debugger
[DefaultValue(typeof(InputBinding), "F5")]
- [EditorDisplay("Debugger", "Continue"), EditorOrder(610)]
+ [EditorDisplay("Debugger", "Continue"), EditorOrder(810)]
public InputBinding DebuggerContinue = new InputBinding(KeyboardKeys.F5);
[DefaultValue(typeof(InputBinding), "F10")]
- [EditorDisplay("Debugger", "Step Over"), EditorOrder(620)]
+ [EditorDisplay("Debugger", "Step Over"), EditorOrder(820)]
public InputBinding DebuggerStepOver = new InputBinding(KeyboardKeys.F10);
[DefaultValue(typeof(InputBinding), "F11")]
- [EditorDisplay("Debugger", "Step Into"), EditorOrder(630)]
+ [EditorDisplay("Debugger", "Step Into"), EditorOrder(830)]
public InputBinding DebuggerStepInto = new InputBinding(KeyboardKeys.F11);
[DefaultValue(typeof(InputBinding), "Shift+F11")]
- [EditorDisplay("Debugger", "Step Out"), EditorOrder(640)]
+ [EditorDisplay("Debugger", "Step Out"), EditorOrder(840)]
public InputBinding DebuggerStepOut = new InputBinding(KeyboardKeys.F11, KeyboardKeys.Shift);
#endregion
@@ -132,6 +236,10 @@ namespace FlaxEditor.Options
[EditorDisplay("Gizmo"), EditorOrder(1020)]
public InputBinding ScaleMode = new InputBinding(KeyboardKeys.Alpha3);
+ [DefaultValue(typeof(InputBinding), "Alpha4")]
+ [EditorDisplay("Gizmo"), EditorOrder(1030)]
+ public InputBinding ToggleTransformSpace = new InputBinding(KeyboardKeys.Alpha4);
+
#endregion
#region Viewport
@@ -160,28 +268,40 @@ namespace FlaxEditor.Options
[EditorDisplay("Viewport"), EditorOrder(1550)]
public InputBinding Down = new InputBinding(KeyboardKeys.Q);
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Viewport", "Toggle Camera Rotation"), EditorOrder(1560)]
+ public InputBinding CameraToggleRotation = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Viewport", "Increase Camera Move Speed"), EditorOrder(1570)]
+ public InputBinding CameraIncreaseMoveSpeed = new InputBinding(KeyboardKeys.None);
+
+ [DefaultValue(typeof(InputBinding), "None")]
+ [EditorDisplay("Viewport", "Decrease Camera Move Speed"), EditorOrder(1571)]
+ public InputBinding CameraDecreaseMoveSpeed = new InputBinding(KeyboardKeys.None);
+
[DefaultValue(typeof(InputBinding), "Numpad0")]
- [EditorDisplay("Viewport"), EditorOrder(1600)]
+ [EditorDisplay("Viewport"), EditorOrder(1700)]
public InputBinding ViewpointFront = new InputBinding(KeyboardKeys.Numpad0);
[DefaultValue(typeof(InputBinding), "Numpad5")]
- [EditorDisplay("Viewport"), EditorOrder(1610)]
+ [EditorDisplay("Viewport"), EditorOrder(1710)]
public InputBinding ViewpointBack = new InputBinding(KeyboardKeys.Numpad5);
[DefaultValue(typeof(InputBinding), "Numpad4")]
- [EditorDisplay("Viewport"), EditorOrder(1620)]
+ [EditorDisplay("Viewport"), EditorOrder(1720)]
public InputBinding ViewpointLeft = new InputBinding(KeyboardKeys.Numpad4);
[DefaultValue(typeof(InputBinding), "Numpad6")]
- [EditorDisplay("Viewport"), EditorOrder(1630)]
+ [EditorDisplay("Viewport"), EditorOrder(1730)]
public InputBinding ViewpointRight = new InputBinding(KeyboardKeys.Numpad6);
[DefaultValue(typeof(InputBinding), "Numpad8")]
- [EditorDisplay("Viewport"), EditorOrder(1640)]
+ [EditorDisplay("Viewport"), EditorOrder(1740)]
public InputBinding ViewpointTop = new InputBinding(KeyboardKeys.Numpad8);
[DefaultValue(typeof(InputBinding), "Numpad2")]
- [EditorDisplay("Viewport"), EditorOrder(1650)]
+ [EditorDisplay("Viewport"), EditorOrder(1750)]
public InputBinding ViewpointBottom = new InputBinding(KeyboardKeys.Numpad2);
#endregion
diff --git a/Source/Editor/Options/OptionsModule.cs b/Source/Editor/Options/OptionsModule.cs
index 68aa11626..c2d744239 100644
--- a/Source/Editor/Options/OptionsModule.cs
+++ b/Source/Editor/Options/OptionsModule.cs
@@ -244,6 +244,13 @@ namespace FlaxEditor.Options
CollectionBackgroundColor = Color.FromBgra(0x14CCCCCC),
ProgressNormal = Color.FromBgra(0xFF0ad328),
+ Statusbar = new Style.StatusbarStyle()
+ {
+ PlayMode = Color.FromBgra(0xFF2F9135),
+ Failed = Color.FromBgra(0xFF9C2424),
+ Loading = Color.FromBgra(0xFF2D2D30)
+ },
+
// Fonts
FontTitle = options.Interface.TitleFont.GetFont(),
FontLarge = options.Interface.LargeFont.GetFont(),
diff --git a/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp b/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp
index e28d1e381..7f5ca6f17 100644
--- a/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp
+++ b/Source/Editor/Scripting/CodeEditors/RiderCodeEditor.cpp
@@ -24,7 +24,8 @@ namespace
String version;
RiderInstallation(const String& path_, const String& version_)
- : path(path_), version(version_)
+ : path(path_)
+ , version(version_)
{
}
};
@@ -44,6 +45,10 @@ namespace
if (document.HasParseError())
return;
+ // Check if this is actually rider and not another jetbrains product
+ if (document.FindMember("name")->value != "JetBrains Rider")
+ return;
+
// Find version
auto versionMember = document.FindMember("version");
if (versionMember == document.MemberEnd())
@@ -141,14 +146,14 @@ bool sortInstallations(RiderInstallation* const& i1, RiderInstallation* const& i
int32 version2[3] = { 0 };
StringUtils::Parse(values1[0].Get(), &version1[0]);
StringUtils::Parse(values1[1].Get(), &version1[1]);
-
- if(values1.Count() > 2)
+
+ if (values1.Count() > 2)
StringUtils::Parse(values1[2].Get(), &version1[2]);
-
+
StringUtils::Parse(values2[0].Get(), &version2[0]);
StringUtils::Parse(values2[1].Get(), &version2[1]);
-
- if(values2.Count() > 2)
+
+ if (values2.Count() > 2)
StringUtils::Parse(values2[2].Get(), &version2[2]);
// Compare by MAJOR.MINOR.BUILD
@@ -174,7 +179,7 @@ void RiderCodeEditor::FindEditors(Array* output)
String localAppDataPath;
FileSystem::GetSpecialFolderPath(SpecialFolder::LocalAppData, localAppDataPath);
-
+
#if PLATFORM_WINDOWS
// Lookup from all known registry locations
SearchRegistry(&installations, HKEY_CURRENT_USER, TEXT("SOFTWARE\\WOW6432Node\\JetBrains\\Rider for Unreal Engine"));
@@ -187,6 +192,7 @@ void RiderCodeEditor::FindEditors(Array* output)
SearchRegistry(&installations, HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\WOW6432Node\\JetBrains\\JetBrains Rider"));
// Versions installed via JetBrains Toolbox
+ FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT("Programs"));
FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT("JetBrains\\Toolbox\\apps\\Rider\\ch-0\\"));
FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT("JetBrains\\Toolbox\\apps\\Rider\\ch-1\\")); // Beta versions
#endif
@@ -201,6 +207,7 @@ void RiderCodeEditor::FindEditors(Array* output)
FileSystem::GetChildDirectories(subDirectories, TEXT("/opt/"));
// Versions installed via JetBrains Toolbox
+ SearchDirectory(&installations, localAppDataPath / TEXT(".local/share/JetBrains/Toolbox/apps/rider/"));
FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT(".local/share/JetBrains/Toolbox/apps/Rider/ch-0"));
FileSystem::GetChildDirectories(subDirectories, localAppDataPath / TEXT(".local/share/JetBrains/Toolbox/apps/Rider/ch-1")); // Beta versions
@@ -210,7 +217,24 @@ void RiderCodeEditor::FindEditors(Array* output)
TEXT("flatpak run com.jetbrains.Rider"));
#endif
- for (auto directory : subDirectories)
+#if PLATFORM_MAC
+ String applicationSupportFolder;
+ FileSystem::GetSpecialFolderPath(SpecialFolder::ProgramData, applicationSupportFolder);
+
+ Array subMacDirectories;
+ FileSystem::GetChildDirectories(subMacDirectories, applicationSupportFolder / TEXT("JetBrains/Toolbox/apps/Rider/ch-0/"));
+ FileSystem::GetChildDirectories(subMacDirectories, applicationSupportFolder / TEXT("JetBrains/Toolbox/apps/Rider/ch-1/"));
+ for (const String& directory : subMacDirectories)
+ {
+ String riderAppDirectory = directory / TEXT("Rider.app/Contents/Resources");
+ SearchDirectory(&installations, riderAppDirectory);
+ }
+
+ // Check the local installer version
+ SearchDirectory(&installations, TEXT("/Applications/Rider.app/Contents/Resources"));
+#endif
+
+ for (const String& directory : subDirectories)
SearchDirectory(&installations, directory);
// Sort found installations by version number
@@ -244,8 +268,16 @@ void RiderCodeEditor::OpenFile(const String& path, int32 line)
// Open file
line = line > 0 ? line : 1;
CreateProcessSettings procSettings;
+
+#if !PLATFORM_MAC
procSettings.FileName = _execPath;
procSettings.Arguments = String::Format(TEXT("\"{0}\" --line {2} \"{1}\""), _solutionPath, path, line);
+#else
+ // This follows pretty much how all the other engines open rider which deals with cross architecture issues
+ procSettings.FileName = "/usr/bin/open";
+ procSettings.Arguments = String::Format(TEXT("-n -a \"{0}\" --args \"{1}\" --line {3} \"{2}\""), _execPath, _solutionPath, path, line);
+#endif
+
procSettings.HiddenWindow = false;
procSettings.WaitForEnd = false;
procSettings.LogOutput = false;
@@ -263,8 +295,14 @@ void RiderCodeEditor::OpenSolution()
// Open solution
CreateProcessSettings procSettings;
+#if !PLATFORM_MAC
procSettings.FileName = _execPath;
procSettings.Arguments = String::Format(TEXT("\"{0}\""), _solutionPath);
+#else
+ // This follows pretty much how all the other engines open rider which deals with cross architecture issues
+ procSettings.FileName = "/usr/bin/open";
+ procSettings.Arguments = String::Format(TEXT("-n -a \"{0}\" \"{1}\""), _execPath, _solutionPath);
+#endif
procSettings.HiddenWindow = false;
procSettings.WaitForEnd = false;
procSettings.LogOutput = false;
diff --git a/Source/Editor/Scripting/ScriptsBuilder.cpp b/Source/Editor/Scripting/ScriptsBuilder.cpp
index 3082a531e..8807379cf 100644
--- a/Source/Editor/Scripting/ScriptsBuilder.cpp
+++ b/Source/Editor/Scripting/ScriptsBuilder.cpp
@@ -246,20 +246,17 @@ bool ScriptsBuilder::RunBuildTool(const StringView& args, const StringView& work
Log::FileNotFoundException(monoPath).SetLevel(LogType::Fatal);
return true;
}
- //const String monoPath = TEXT("mono");
- cmdLine.Append(TEXT("\""));
+ const String monoPath = TEXT("mono");
cmdLine.Append(monoPath);
- cmdLine.Append(TEXT("\" "));
+ cmdLine.Append(TEXT(" "));
// TODO: Set env var for the mono MONO_GC_PARAMS=nursery-size64m to boost build performance -> profile it
#endif
- cmdLine.Append(TEXT("\""));
cmdLine.Append(buildToolPath);
- cmdLine.Append(TEXT("\" "));
- cmdLine.Append(args.Get(), args.Length());
// Call build tool
CreateProcessSettings procSettings;
procSettings.FileName = StringView(*cmdLine, cmdLine.Length());
+ procSettings.Arguments = args.Get();
procSettings.WorkingDirectory = workingDir;
const int32 result = Platform::CreateProcess(procSettings);
if (result != 0)
diff --git a/Source/Editor/States/LoadingState.cs b/Source/Editor/States/LoadingState.cs
index 746c8d92b..698dc192f 100644
--- a/Source/Editor/States/LoadingState.cs
+++ b/Source/Editor/States/LoadingState.cs
@@ -1,6 +1,7 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
+using System.IO;
using FlaxEngine;
using FlaxEngine.Utilities;
@@ -54,6 +55,13 @@ namespace FlaxEditor.States
}
else if (Editor.Options.Options.General.ForceScriptCompilationOnStartup && !skipCompile)
{
+ // Generate project files when Cache is missing or was cleared previously
+ if (!Directory.Exists(Path.Combine(Editor.GameProject?.ProjectFolderPath, "Cache", "Intermediate")) ||
+ !Directory.Exists(Path.Combine(Editor.GameProject?.ProjectFolderPath, "Cache", "Projects")))
+ {
+ var customArgs = Editor.Instance.CodeEditing.SelectedEditor.GenerateProjectCustomArgs;
+ ScriptsBuilder.GenerateProject(customArgs);
+ }
// Compile scripts before loading any scenes, then we load them and can open scenes
ScriptsBuilder.Compile();
}
diff --git a/Source/Editor/Surface/Archetypes/Math.cs b/Source/Editor/Surface/Archetypes/Math.cs
index 1b8f62e62..fe2f1e044 100644
--- a/Source/Editor/Surface/Archetypes/Math.cs
+++ b/Source/Editor/Surface/Archetypes/Math.cs
@@ -126,7 +126,7 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Clamp",
Description = "Clamps value to the specified range",
Flags = NodeFlags.AllGraphs,
- Size = new Float2(110, 60),
+ Size = new Float2(140, 60),
ConnectionsHints = ConnectionsHint.Numeric,
IndependentBoxes = new[] { 0 },
DependentBoxes = new[] { 1, 2, 3 },
diff --git a/Source/Editor/Surface/Elements/OutputBox.cs b/Source/Editor/Surface/Elements/OutputBox.cs
index 67b6e8409..cf78b559c 100644
--- a/Source/Editor/Surface/Elements/OutputBox.cs
+++ b/Source/Editor/Surface/Elements/OutputBox.cs
@@ -34,10 +34,8 @@ namespace FlaxEditor.Surface.Elements
public static void DrawConnection(ref Float2 start, ref Float2 end, ref Color color, float thickness = 1)
{
// Calculate control points
- var dst = (end - start) * new Float2(0.5f, 0.05f);
- var control1 = new Float2(start.X + dst.X, start.Y + dst.Y);
- var control2 = new Float2(end.X - dst.X, end.Y + dst.Y);
-
+ CalculateBezierControlPoints(start, end, out var control1, out var control2);
+
// Draw line
Render2D.DrawBezier(start, control1, control2, end, color, thickness);
@@ -49,6 +47,23 @@ namespace FlaxEditor.Surface.Elements
*/
}
+ private static void CalculateBezierControlPoints(Float2 start, Float2 end, out Float2 control1, out Float2 control2)
+ {
+ // Control points parameters
+ const float minControlLength = 100f;
+ const float maxControlLength = 150f;
+ var dst = (end - start).Length;
+ var yDst = Mathf.Abs(start.Y - end.Y);
+
+ // Calculate control points
+ var minControlDst = dst * 0.5f;
+ var maxControlDst = Mathf.Max(Mathf.Min(maxControlLength, dst), minControlLength);
+ var controlDst = Mathf.Lerp(minControlDst, maxControlDst, Mathf.Clamp(yDst / minControlLength, 0f, 1f));
+
+ control1 = new Float2(start.X + controlDst, start.Y);
+ control2 = new Float2(end.X - controlDst, end.Y);
+ }
+
///
/// Checks if a point intersects a connection
///
@@ -75,13 +90,9 @@ namespace FlaxEditor.Surface.Elements
float offset = Mathf.Sign(end.Y - start.Y) * distance;
if ((point.Y - (start.Y - offset)) * ((end.Y + offset) - point.Y) < 0) return false;
-
- // Taken from the Render2D.DrawBezier code
+
float squaredDistance = distance;
-
- var dst = (end - start) * new Float2(0.5f, 0.05f);
- var control1 = new Float2(start.X + dst.X, start.Y + dst.Y);
- var control2 = new Float2(end.X - dst.X, end.Y + dst.Y);
+ CalculateBezierControlPoints(start, end, out var control1, out var control2);
var d1 = control1 - start;
var d2 = control2 - control1;
diff --git a/Source/Editor/Surface/VisjectSurface.Input.cs b/Source/Editor/Surface/VisjectSurface.Input.cs
index be64019b6..0b664768d 100644
--- a/Source/Editor/Surface/VisjectSurface.Input.cs
+++ b/Source/Editor/Surface/VisjectSurface.Input.cs
@@ -238,6 +238,23 @@ namespace FlaxEditor.Surface
return;
}
+ if (_middleMouseDown)
+ {
+ // Calculate delta
+ var delta = location - _middleMouseDownPos;
+ if (delta.LengthSquared > 0.01f)
+ {
+ // Move view
+ _mouseMoveAmount += delta.Length;
+ _rootControl.Location += delta;
+ _middleMouseDownPos = location;
+ Cursor = CursorType.SizeAll;
+ }
+
+ // Handled
+ return;
+ }
+
// Check if user is selecting or moving node(s)
if (_leftMouseDown)
{
@@ -316,6 +333,11 @@ namespace FlaxEditor.Surface
_rightMouseDown = false;
Cursor = CursorType.Default;
}
+ if (_middleMouseDown)
+ {
+ _middleMouseDown = false;
+ Cursor = CursorType.Default;
+ }
_isMovingSelection = false;
ConnectingEnd(null);
@@ -338,7 +360,7 @@ namespace FlaxEditor.Surface
if (IsMouseOver && !_leftMouseDown && !IsPrimaryMenuOpened)
{
var nextViewScale = ViewScale + delta * 0.1f;
-
+
if (delta > 0 && !_rightMouseDown)
{
// Scale towards mouse when zooming in
@@ -353,7 +375,7 @@ namespace FlaxEditor.Surface
ViewScale = nextViewScale;
ViewCenterPosition = viewCenter;
}
-
+
return true;
}
@@ -427,6 +449,7 @@ namespace FlaxEditor.Surface
_isMovingSelection = false;
_rightMouseDown = false;
_leftMouseDown = false;
+ _middleMouseDown = false;
return true;
}
@@ -446,6 +469,11 @@ namespace FlaxEditor.Surface
_rightMouseDown = true;
_rightMouseDownPos = location;
}
+ if (button == MouseButton.Middle)
+ {
+ _middleMouseDown = true;
+ _middleMouseDownPos = location;
+ }
// Check if any node is under the mouse
SurfaceControl controlUnderMouse = GetControlUnderMouse();
@@ -491,7 +519,7 @@ namespace FlaxEditor.Surface
Focus();
return true;
}
- if (_rightMouseDown)
+ if (_rightMouseDown || _middleMouseDown)
{
// Start navigating
StartMouseCapture();
@@ -560,6 +588,13 @@ namespace FlaxEditor.Surface
}
_mouseMoveAmount = 0;
}
+ if (_middleMouseDown && button == MouseButton.Middle)
+ {
+ _middleMouseDown = false;
+ EndMouseCapture();
+ Cursor = CursorType.Default;
+ _mouseMoveAmount = 0;
+ }
// Base
bool handled = base.OnMouseUp(location, button);
@@ -570,6 +605,7 @@ namespace FlaxEditor.Surface
// Clear flags
_rightMouseDown = false;
_leftMouseDown = false;
+ _middleMouseDown = false;
return true;
}
@@ -753,6 +789,8 @@ namespace FlaxEditor.Surface
{
if (_inputBrackets.Count == 0)
{
+ if (currentInputText.StartsWith(' '))
+ currentInputText = "";
ResetInput();
ShowPrimaryMenu(_mousePos, false, currentInputText);
}
diff --git a/Source/Editor/Surface/VisjectSurface.cs b/Source/Editor/Surface/VisjectSurface.cs
index 50c112418..9a125f004 100644
--- a/Source/Editor/Surface/VisjectSurface.cs
+++ b/Source/Editor/Surface/VisjectSurface.cs
@@ -69,6 +69,11 @@ namespace FlaxEditor.Surface
///
protected bool _rightMouseDown;
+ ///
+ /// The middle mouse down flag.
+ ///
+ protected bool _middleMouseDown;
+
///
/// The left mouse down position.
///
@@ -79,6 +84,11 @@ namespace FlaxEditor.Surface
///
protected Float2 _rightMouseDownPos = Float2.Minimum;
+ ///
+ /// The middle mouse down position.
+ ///
+ protected Float2 _middleMouseDownPos = Float2.Minimum;
+
///
/// The mouse position.
///
@@ -912,7 +922,7 @@ namespace FlaxEditor.Surface
{
return _context.FindNode(id);
}
-
+
///
/// Adds the undo action to be batched (eg. if multiple undo actions is performed in a sequence during single update).
///
diff --git a/Source/Editor/Tools/Foliage/FoliageTab.cs b/Source/Editor/Tools/Foliage/FoliageTab.cs
index 814376c75..10358a8c0 100644
--- a/Source/Editor/Tools/Foliage/FoliageTab.cs
+++ b/Source/Editor/Tools/Foliage/FoliageTab.cs
@@ -137,14 +137,23 @@ namespace FlaxEditor.Tools.Foliage
Offsets = Margin.Zero,
Parent = _noFoliagePanel
};
+
+ var buttonText = "Create new foliage";
_createNewFoliage = new Button
{
- Text = "Create new foliage",
+ Text = buttonText,
AnchorPreset = AnchorPresets.MiddleCenter,
Offsets = new Margin(-60, 120, -12, 24),
Parent = _noFoliagePanel,
Enabled = false
};
+ var textSize = Style.Current.FontMedium.MeasureText(buttonText);
+ if (_createNewFoliage.Width < textSize.X)
+ {
+ _createNewFoliage.LocalX -= (textSize.X - _createNewFoliage.Width) / 2;
+ _createNewFoliage.Width = textSize.X + 6;
+ }
+
_createNewFoliage.Clicked += OnCreateNewFoliageClicked;
}
diff --git a/Source/Editor/Tools/Foliage/FoliageTypesTab.cs b/Source/Editor/Tools/Foliage/FoliageTypesTab.cs
index 2a51d972c..8934f5058 100644
--- a/Source/Editor/Tools/Foliage/FoliageTypesTab.cs
+++ b/Source/Editor/Tools/Foliage/FoliageTypesTab.cs
@@ -375,7 +375,7 @@ namespace FlaxEditor.Tools.Foliage
private void OnModified()
{
- Editor.Instance.Scene.MarkSceneEdited(_proxy.Foliage?.Scene);
+ Editor.Instance.Scene.MarkSceneEdited(_proxy.Foliage != null ? _proxy.Foliage.Scene : null);
}
private void OnSelectedFoliageChanged()
diff --git a/Source/Editor/Tools/Foliage/PaintTab.cs b/Source/Editor/Tools/Foliage/PaintTab.cs
index e4f01661b..ba31ca18b 100644
--- a/Source/Editor/Tools/Foliage/PaintTab.cs
+++ b/Source/Editor/Tools/Foliage/PaintTab.cs
@@ -218,7 +218,7 @@ namespace FlaxEditor.Tools.Foliage
private void OnModified()
{
- Editor.Instance.Scene.MarkSceneEdited(_proxy.Foliage?.Scene);
+ Editor.Instance.Scene.MarkSceneEdited(_proxy.Foliage != null ? _proxy.Foliage.Scene : null);
}
private void OnSelectedFoliageChanged()
diff --git a/Source/Editor/Tools/Terrain/CarveTab.cs b/Source/Editor/Tools/Terrain/CarveTab.cs
index 6bee0bd92..000f90817 100644
--- a/Source/Editor/Tools/Terrain/CarveTab.cs
+++ b/Source/Editor/Tools/Terrain/CarveTab.cs
@@ -95,14 +95,23 @@ namespace FlaxEditor.Tools.Terrain
Offsets = Margin.Zero,
Parent = _noTerrainPanel
};
+
+ var buttonText = "Create new terrain";
_createTerrainButton = new Button
{
- Text = "Create new terrain",
+ Text = buttonText,
AnchorPreset = AnchorPresets.MiddleCenter,
Offsets = new Margin(-60, 120, -12, 24),
Parent = _noTerrainPanel,
Enabled = false
};
+ var textSize = Style.Current.FontMedium.MeasureText(buttonText);
+ if (_createTerrainButton.Width < textSize.X)
+ {
+ _createTerrainButton.LocalX -= (textSize.X - _createTerrainButton.Width) / 2;
+ _createTerrainButton.Width = textSize.X + 6;
+ }
+
_createTerrainButton.Clicked += OnCreateNewTerrainClicked;
}
diff --git a/Source/Editor/Tools/VertexPainting.cs b/Source/Editor/Tools/VertexPainting.cs
index 0863569c2..6934a754b 100644
--- a/Source/Editor/Tools/VertexPainting.cs
+++ b/Source/Editor/Tools/VertexPainting.cs
@@ -544,7 +544,7 @@ namespace FlaxEditor.Tools
public override bool IsControllingMouse => IsPainting;
///
- public override BoundingSphere FocusBounds => _selectedModel?.Sphere ?? base.FocusBounds;
+ public override BoundingSphere FocusBounds => _selectedModel != null ? _selectedModel.Sphere : base.FocusBounds;
///
public override void Update(float dt)
diff --git a/Source/Editor/Undo/Actions/PasteActorsAction.cs b/Source/Editor/Undo/Actions/PasteActorsAction.cs
index 8b0d040d8..7aee40878 100644
--- a/Source/Editor/Undo/Actions/PasteActorsAction.cs
+++ b/Source/Editor/Undo/Actions/PasteActorsAction.cs
@@ -144,7 +144,7 @@ namespace FlaxEditor.Actions
{
var node = nodeParents[i];
var actor = node.Actor;
- var parent = actor?.Parent;
+ var parent = actor != null ? actor.Parent : null;
if (parent != null)
{
bool IsNameValid(string name)
diff --git a/Source/Editor/Utilities/Utils.cs b/Source/Editor/Utilities/Utils.cs
index fe801bbaf..863bdbedb 100644
--- a/Source/Editor/Utilities/Utils.cs
+++ b/Source/Editor/Utilities/Utils.cs
@@ -18,10 +18,10 @@ using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Input;
using FlaxEditor.GUI.Tree;
using FlaxEditor.SceneGraph;
-using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.GUI;
using FlaxEngine.Utilities;
+using FlaxEditor.Windows;
namespace FlaxEngine
{
@@ -1235,5 +1235,60 @@ namespace FlaxEditor.Utilities
}
return s;
}
+
+ ///
+ /// Binds global input actions for the window.
+ ///
+ /// The editor window.
+ public static void SetupCommonInputActions(EditorWindow window)
+ {
+ var inputActions = window.InputActions;
+
+ // Setup input actions
+ inputActions.Add(options => options.Save, Editor.Instance.SaveAll);
+ inputActions.Add(options => options.Undo, () =>
+ {
+ Editor.Instance.PerformUndo();
+ window.Focus();
+ });
+ inputActions.Add(options => options.Redo, () =>
+ {
+ Editor.Instance.PerformRedo();
+ window.Focus();
+ });
+ inputActions.Add(options => options.Cut, Editor.Instance.SceneEditing.Cut);
+ inputActions.Add(options => options.Copy, Editor.Instance.SceneEditing.Copy);
+ inputActions.Add(options => options.Paste, Editor.Instance.SceneEditing.Paste);
+ inputActions.Add(options => options.Duplicate, Editor.Instance.SceneEditing.Duplicate);
+ inputActions.Add(options => options.SelectAll, Editor.Instance.SceneEditing.SelectAllScenes);
+ inputActions.Add(options => options.Delete, Editor.Instance.SceneEditing.Delete);
+ inputActions.Add(options => options.Search, () => Editor.Instance.Windows.SceneWin.Search());
+ inputActions.Add(options => options.MoveActorToViewport, Editor.Instance.UI.MoveActorToViewport);
+ inputActions.Add(options => options.AlignActorWithViewport, Editor.Instance.UI.AlignActorWithViewport);
+ inputActions.Add(options => options.AlignViewportWithActor, Editor.Instance.UI.AlignViewportWithActor);
+ inputActions.Add(options => options.PilotActor, Editor.Instance.UI.PilotActor);
+ inputActions.Add(options => options.Play, Editor.Instance.Simulation.DelegatePlayOrStopPlayInEditor);
+ inputActions.Add(options => options.PlayCurrentScenes, Editor.Instance.Simulation.RequestPlayScenesOrStopPlay);
+ inputActions.Add(options => options.Pause, Editor.Instance.Simulation.RequestResumeOrPause);
+ inputActions.Add(options => options.StepFrame, Editor.Instance.Simulation.RequestPlayOneFrame);
+ inputActions.Add(options => options.CookAndRun, () => Editor.Instance.Windows.GameCookerWin.BuildAndRun());
+ inputActions.Add(options => options.RunCookedGame, () => Editor.Instance.Windows.GameCookerWin.RunCooked());
+ inputActions.Add(options => options.BuildScenesData, Editor.Instance.BuildScenesOrCancel);
+ inputActions.Add(options => options.BakeLightmaps, Editor.Instance.BakeLightmapsOrCancel);
+ inputActions.Add(options => options.ClearLightmaps, Editor.Instance.ClearLightmaps);
+ inputActions.Add(options => options.BakeEnvProbes, Editor.Instance.BakeAllEnvProbes);
+ inputActions.Add(options => options.BuildCSG, Editor.Instance.BuildCSG);
+ inputActions.Add(options => options.BuildNav, Editor.Instance.BuildNavMesh);
+ inputActions.Add(options => options.BuildSDF, Editor.Instance.BuildAllMeshesSDF);
+ inputActions.Add(options => options.TakeScreenshot, Editor.Instance.Windows.TakeScreenshot);
+ inputActions.Add(options => options.ProfilerWindow, () => Editor.Instance.Windows.ProfilerWin.FocusOrShow());
+ inputActions.Add(options => options.ProfilerStartStop, () => { Editor.Instance.Windows.ProfilerWin.LiveRecording = !Editor.Instance.Windows.ProfilerWin.LiveRecording; Editor.Instance.UI.AddStatusMessage($"Profiling {(Editor.Instance.Windows.ProfilerWin.LiveRecording ? "started" : "stopped")}."); });
+ inputActions.Add(options => options.ProfilerClear, () => { Editor.Instance.Windows.ProfilerWin.Clear(); Editor.Instance.UI.AddStatusMessage($"Profiling results cleared."); });
+ inputActions.Add(options => options.SaveScenes, () => Editor.Instance.Scene.SaveScenes());
+ inputActions.Add(options => options.CloseScenes, () => Editor.Instance.Scene.CloseAllScenes());
+ inputActions.Add(options => options.OpenScriptsProject, () => Editor.Instance.CodeEditing.OpenSolution());
+ inputActions.Add(options => options.GenerateScriptsProject, () => Editor.Instance.ProgressReporting.GenerateScriptsProjectFiles.RunAsync());
+ inputActions.Add(options => options.RecompileScripts, ScriptsBuilder.Compile);
+ }
}
}
diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs
index ad7e06ba5..8c71a8b02 100644
--- a/Source/Editor/Viewport/EditorViewport.cs
+++ b/Source/Editor/Viewport/EditorViewport.cs
@@ -137,7 +137,7 @@ namespace FlaxEditor.Viewport
// Input
- private bool _isControllingMouse, _isViewportControllingMouse;
+ private bool _isControllingMouse, _isViewportControllingMouse, _wasVirtualMouseRightDown, _isVirtualMouseRightDown;
private int _deltaFilteringStep;
private Float2 _startPos;
private Float2 _mouseDeltaLast;
@@ -441,6 +441,9 @@ namespace FlaxEditor.Viewport
if (useWidgets)
{
+ var largestText = "Invert Panning";
+ var textSize = Style.Current.FontMedium.MeasureText(largestText);
+ var xLocationForExtras = textSize.X + 5;
// Camera speed widget
var camSpeed = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
var camSpeedCM = new ContextMenu();
@@ -541,7 +544,7 @@ namespace FlaxEditor.Viewport
{
var ortho = ViewWidgetButtonMenu.AddButton("Orthographic");
ortho.CloseMenuOnClick = false;
- var orthoValue = new CheckBox(90, 2, _isOrtho)
+ var orthoValue = new CheckBox(xLocationForExtras, 2, _isOrtho)
{
Parent = ortho
};
@@ -581,7 +584,7 @@ namespace FlaxEditor.Viewport
{
var fov = ViewWidgetButtonMenu.AddButton("Field Of View");
fov.CloseMenuOnClick = false;
- var fovValue = new FloatValueBox(1, 90, 2, 70.0f, 35.0f, 160.0f, 0.1f)
+ var fovValue = new FloatValueBox(1, xLocationForExtras, 2, 70.0f, 35.0f, 160.0f, 0.1f)
{
Parent = fov
};
@@ -598,7 +601,7 @@ namespace FlaxEditor.Viewport
{
var orthoSize = ViewWidgetButtonMenu.AddButton("Ortho Scale");
orthoSize.CloseMenuOnClick = false;
- var orthoSizeValue = new FloatValueBox(_orthoSize, 90, 2, 70.0f, 0.001f, 100000.0f, 0.01f)
+ var orthoSizeValue = new FloatValueBox(_orthoSize, xLocationForExtras, 2, 70.0f, 0.001f, 100000.0f, 0.01f)
{
Parent = orthoSize
};
@@ -615,7 +618,7 @@ namespace FlaxEditor.Viewport
{
var nearPlane = ViewWidgetButtonMenu.AddButton("Near Plane");
nearPlane.CloseMenuOnClick = false;
- var nearPlaneValue = new FloatValueBox(2.0f, 90, 2, 70.0f, 0.001f, 1000.0f)
+ var nearPlaneValue = new FloatValueBox(2.0f, xLocationForExtras, 2, 70.0f, 0.001f, 1000.0f)
{
Parent = nearPlane
};
@@ -627,7 +630,7 @@ namespace FlaxEditor.Viewport
{
var farPlane = ViewWidgetButtonMenu.AddButton("Far Plane");
farPlane.CloseMenuOnClick = false;
- var farPlaneValue = new FloatValueBox(1000, 90, 2, 70.0f, 10.0f)
+ var farPlaneValue = new FloatValueBox(1000, xLocationForExtras, 2, 70.0f, 10.0f)
{
Parent = farPlane
};
@@ -639,7 +642,7 @@ namespace FlaxEditor.Viewport
{
var brightness = ViewWidgetButtonMenu.AddButton("Brightness");
brightness.CloseMenuOnClick = false;
- var brightnessValue = new FloatValueBox(1.0f, 90, 2, 70.0f, 0.001f, 10.0f, 0.001f)
+ var brightnessValue = new FloatValueBox(1.0f, xLocationForExtras, 2, 70.0f, 0.001f, 10.0f, 0.001f)
{
Parent = brightness
};
@@ -651,7 +654,7 @@ namespace FlaxEditor.Viewport
{
var resolution = ViewWidgetButtonMenu.AddButton("Resolution");
resolution.CloseMenuOnClick = false;
- var resolutionValue = new FloatValueBox(1.0f, 90, 2, 70.0f, 0.1f, 4.0f, 0.001f)
+ var resolutionValue = new FloatValueBox(1.0f, xLocationForExtras, 2, 70.0f, 0.1f, 4.0f, 0.001f)
{
Parent = resolution
};
@@ -663,7 +666,7 @@ namespace FlaxEditor.Viewport
{
var invert = ViewWidgetButtonMenu.AddButton("Invert Panning");
invert.CloseMenuOnClick = false;
- var invertValue = new CheckBox(90, 2, _invertPanning)
+ var invertValue = new CheckBox(xLocationForExtras, 2, _invertPanning)
{
Parent = invert
};
@@ -685,6 +688,9 @@ namespace FlaxEditor.Viewport
InputActions.Add(options => options.ViewpointBack, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Back").Orientation)));
InputActions.Add(options => options.ViewpointRight, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Right").Orientation)));
InputActions.Add(options => options.ViewpointLeft, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Left").Orientation)));
+ InputActions.Add(options => options.CameraToggleRotation, () => _isVirtualMouseRightDown = !_isVirtualMouseRightDown);
+ InputActions.Add(options => options.CameraIncreaseMoveSpeed, () => AdjustCameraMoveSpeed(1));
+ InputActions.Add(options => options.CameraDecreaseMoveSpeed, () => AdjustCameraMoveSpeed(-1));
// Link for task event
task.Begin += OnRenderBegin;
@@ -722,6 +728,30 @@ namespace FlaxEditor.Viewport
}
}
+ ///
+ /// Increases or decreases the camera movement speed.
+ ///
+ /// The stepping direction for speed adjustment.
+ protected void AdjustCameraMoveSpeed(int step)
+ {
+ int camValueIndex = -1;
+ for (int i = 0; i < EditorViewportCameraSpeedValues.Length; i++)
+ {
+ if (Mathf.NearEqual(EditorViewportCameraSpeedValues[i], _movementSpeed))
+ {
+ camValueIndex = i;
+ break;
+ }
+ }
+ if (camValueIndex == -1)
+ return;
+
+ if (step > 0)
+ MovementSpeed = EditorViewportCameraSpeedValues[Mathf.Min(camValueIndex + 1, EditorViewportCameraSpeedValues.Length - 1)];
+ else if (step < 0)
+ MovementSpeed = EditorViewportCameraSpeedValues[Mathf.Max(camValueIndex - 1, 0)];
+ }
+
private void OnEditorOptionsChanged(EditorOptions options)
{
_mouseSensitivity = options.Viewport.MouseSensitivity;
@@ -1048,6 +1078,15 @@ namespace FlaxEditor.Viewport
// Track controlling mouse state change
bool wasControllingMouse = _prevInput.IsControllingMouse;
_isControllingMouse = _input.IsControllingMouse;
+
+ // Simulate holding mouse right down for trackpad users
+ if ((_prevInput.IsMouseRightDown && !_input.IsMouseRightDown) || win.GetKeyDown(KeyboardKeys.Escape))
+ _isVirtualMouseRightDown = false; // Cancel when mouse right or escape is pressed
+ if (_wasVirtualMouseRightDown)
+ wasControllingMouse = true;
+ if (_isVirtualMouseRightDown)
+ _isControllingMouse = _isVirtualMouseRightDown;
+
if (wasControllingMouse != _isControllingMouse)
{
if (_isControllingMouse)
@@ -1061,16 +1100,18 @@ namespace FlaxEditor.Viewport
OnLeftMouseButtonDown();
else if (_prevInput.IsMouseLeftDown && !_input.IsMouseLeftDown)
OnLeftMouseButtonUp();
- //
- if (!_prevInput.IsMouseRightDown && _input.IsMouseRightDown)
+
+ if ((!_prevInput.IsMouseRightDown && _input.IsMouseRightDown) || (!_wasVirtualMouseRightDown && _isVirtualMouseRightDown))
OnRightMouseButtonDown();
- else if (_prevInput.IsMouseRightDown && !_input.IsMouseRightDown)
+ else if ((_prevInput.IsMouseRightDown && !_input.IsMouseRightDown) || (_wasVirtualMouseRightDown && !_isVirtualMouseRightDown))
OnRightMouseButtonUp();
- //
+
if (!_prevInput.IsMouseMiddleDown && _input.IsMouseMiddleDown)
OnMiddleMouseButtonDown();
else if (_prevInput.IsMouseMiddleDown && !_input.IsMouseMiddleDown)
OnMiddleMouseButtonUp();
+
+ _wasVirtualMouseRightDown = _isVirtualMouseRightDown;
}
// Get clamped delta time (more stable during lags)
@@ -1088,7 +1129,7 @@ namespace FlaxEditor.Viewport
bool isAltDown = _input.IsAltDown;
bool lbDown = _input.IsMouseLeftDown;
bool mbDown = _input.IsMouseMiddleDown;
- bool rbDown = _input.IsMouseRightDown;
+ bool rbDown = _input.IsMouseRightDown || _isVirtualMouseRightDown;
bool wheelInUse = Math.Abs(_input.MouseWheelDelta) > Mathf.Epsilon;
_input.IsPanning = !isAltDown && mbDown && !rbDown;
@@ -1098,32 +1139,20 @@ namespace FlaxEditor.Viewport
_input.IsOrbiting = isAltDown && lbDown && !mbDown && !rbDown;
// Control move speed with RMB+Wheel
- rmbWheel = useMovementSpeed && _input.IsMouseRightDown && wheelInUse;
+ rmbWheel = useMovementSpeed && (_input.IsMouseRightDown || _isVirtualMouseRightDown) && wheelInUse;
if (rmbWheel)
{
- float step = 4.0f;
+ const float step = 4.0f;
_wheelMovementChangeDeltaSum += _input.MouseWheelDelta * options.Viewport.MouseWheelSensitivity;
- int camValueIndex = -1;
- for (int i = 0; i < EditorViewportCameraSpeedValues.Length; i++)
+ if (_wheelMovementChangeDeltaSum >= step)
{
- if (Mathf.NearEqual(EditorViewportCameraSpeedValues[i], _movementSpeed))
- {
- camValueIndex = i;
- break;
- }
+ _wheelMovementChangeDeltaSum -= step;
+ AdjustCameraMoveSpeed(1);
}
- if (camValueIndex != -1)
+ else if (_wheelMovementChangeDeltaSum <= -step)
{
- if (_wheelMovementChangeDeltaSum >= step)
- {
- _wheelMovementChangeDeltaSum -= step;
- MovementSpeed = EditorViewportCameraSpeedValues[Mathf.Min(camValueIndex + 1, EditorViewportCameraSpeedValues.Length - 1)];
- }
- else if (_wheelMovementChangeDeltaSum <= -step)
- {
- _wheelMovementChangeDeltaSum += step;
- MovementSpeed = EditorViewportCameraSpeedValues[Mathf.Max(camValueIndex - 1, 0)];
- }
+ _wheelMovementChangeDeltaSum += step;
+ AdjustCameraMoveSpeed(-1);
}
}
}
@@ -1165,7 +1194,7 @@ namespace FlaxEditor.Viewport
// Calculate smooth mouse delta not dependant on viewport size
var offset = _viewMousePos - _startPos;
- if (_input.IsZooming && !_input.IsMouseRightDown && !_input.IsMouseLeftDown && !_input.IsMouseMiddleDown && !_isOrtho && !rmbWheel)
+ if (_input.IsZooming && !_input.IsMouseRightDown && !_input.IsMouseLeftDown && !_input.IsMouseMiddleDown && !_isOrtho && !rmbWheel && !_isVirtualMouseRightDown)
{
offset = Float2.Zero;
}
@@ -1213,7 +1242,7 @@ namespace FlaxEditor.Viewport
UpdateView(dt, ref moveDelta, ref mouseDelta, out var centerMouse);
// Move mouse back to the root position
- if (centerMouse && (_input.IsMouseRightDown || _input.IsMouseLeftDown || _input.IsMouseMiddleDown))
+ if (centerMouse && (_input.IsMouseRightDown || _input.IsMouseLeftDown || _input.IsMouseMiddleDown || _isVirtualMouseRightDown))
{
var center = PointToWindow(_startPos);
win.MousePosition = center;
@@ -1229,7 +1258,7 @@ namespace FlaxEditor.Viewport
}
else
{
- if (_input.IsMouseLeftDown || _input.IsMouseRightDown)
+ if (_input.IsMouseLeftDown || _input.IsMouseRightDown || _isVirtualMouseRightDown)
{
// Calculate smooth mouse delta not dependant on viewport size
var offset = _viewMousePos - _startPos;
@@ -1359,6 +1388,7 @@ namespace FlaxEditor.Viewport
{
OnControlMouseEnd(RootWindow.Window);
_isControllingMouse = false;
+ _isVirtualMouseRightDown = false;
}
}
diff --git a/Source/Editor/Viewport/MainEditorGizmoViewport.cs b/Source/Editor/Viewport/MainEditorGizmoViewport.cs
index 9cbfce562..6c52ce46b 100644
--- a/Source/Editor/Viewport/MainEditorGizmoViewport.cs
+++ b/Source/Editor/Viewport/MainEditorGizmoViewport.cs
@@ -194,6 +194,7 @@ namespace FlaxEditor.Viewport
{
_editor = editor;
_dragAssets = new DragAssets(ValidateDragItem);
+ var inputOptions = editor.Options.Options.Input;
// Prepare rendering task
Task.ActorsSource = ActorsSources.Scenes;
@@ -250,7 +251,7 @@ namespace FlaxEditor.Viewport
var transformSpaceToggle = new ViewportWidgetButton(string.Empty, editor.Icons.Globe32, null, true)
{
Checked = TransformGizmo.ActiveTransformSpace == TransformGizmoBase.TransformSpace.World,
- TooltipText = "Gizmo transform space (world or local)",
+ TooltipText = $"Gizmo transform space (world or local) ({inputOptions.ToggleTransformSpace})",
Parent = transformSpaceWidget
};
transformSpaceToggle.Toggled += OnTransformSpaceToggle;
@@ -347,7 +348,7 @@ namespace FlaxEditor.Viewport
_gizmoModeTranslate = new ViewportWidgetButton(string.Empty, editor.Icons.Translate32, null, true)
{
Tag = TransformGizmoBase.Mode.Translate,
- TooltipText = "Translate gizmo mode",
+ TooltipText = $"Translate gizmo mode ({inputOptions.TranslateMode})",
Checked = true,
Parent = gizmoMode
};
@@ -355,14 +356,14 @@ namespace FlaxEditor.Viewport
_gizmoModeRotate = new ViewportWidgetButton(string.Empty, editor.Icons.Rotate32, null, true)
{
Tag = TransformGizmoBase.Mode.Rotate,
- TooltipText = "Rotate gizmo mode",
+ TooltipText = $"Rotate gizmo mode ({inputOptions.RotateMode})",
Parent = gizmoMode
};
_gizmoModeRotate.Toggled += OnGizmoModeToggle;
_gizmoModeScale = new ViewportWidgetButton(string.Empty, editor.Icons.Scale32, null, true)
{
Tag = TransformGizmoBase.Mode.Scale,
- TooltipText = "Scale gizmo mode",
+ TooltipText = $"Scale gizmo mode ({inputOptions.ScaleMode})",
Parent = gizmoMode
};
_gizmoModeScale.Toggled += OnGizmoModeToggle;
@@ -390,6 +391,7 @@ namespace FlaxEditor.Viewport
InputActions.Add(options => options.TranslateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate);
InputActions.Add(options => options.RotateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate);
InputActions.Add(options => options.ScaleMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale);
+ InputActions.Add(options => options.ToggleTransformSpace, () => { OnTransformSpaceToggle(transformSpaceToggle); transformSpaceToggle.Checked = !transformSpaceToggle.Checked; });
InputActions.Add(options => options.LockFocusSelection, LockFocusSelection);
InputActions.Add(options => options.FocusSelection, FocusSelection);
InputActions.Add(options => options.RotateSelection, RotateSelection);
diff --git a/Source/Editor/Viewport/PrefabWindowViewport.cs b/Source/Editor/Viewport/PrefabWindowViewport.cs
index ec6a983ce..c02d6b6e8 100644
--- a/Source/Editor/Viewport/PrefabWindowViewport.cs
+++ b/Source/Editor/Viewport/PrefabWindowViewport.cs
@@ -84,6 +84,7 @@ namespace FlaxEditor.Viewport
_dragAssets = new DragAssets(ValidateDragItem);
ShowDebugDraw = true;
ShowEditorPrimitives = true;
+ var inputOptions = window.Editor.Options.Options.Input;
// Prepare rendering task
Task.ActorsSource = ActorsSources.CustomActors;
@@ -113,7 +114,7 @@ namespace FlaxEditor.Viewport
var transformSpaceToggle = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Globe32, null, true)
{
Checked = TransformGizmo.ActiveTransformSpace == TransformGizmoBase.TransformSpace.World,
- TooltipText = "Gizmo transform space (world or local)",
+ TooltipText = $"Gizmo transform space (world or local) ({inputOptions.ToggleTransformSpace})",
Parent = transformSpaceWidget
};
transformSpaceToggle.Toggled += OnTransformSpaceToggle;
@@ -205,7 +206,7 @@ namespace FlaxEditor.Viewport
_gizmoModeTranslate = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Translate32, null, true)
{
Tag = TransformGizmoBase.Mode.Translate,
- TooltipText = "Translate gizmo mode",
+ TooltipText = $"Translate gizmo mode ({inputOptions.TranslateMode})",
Checked = true,
Parent = gizmoMode
};
@@ -213,14 +214,14 @@ namespace FlaxEditor.Viewport
_gizmoModeRotate = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Rotate32, null, true)
{
Tag = TransformGizmoBase.Mode.Rotate,
- TooltipText = "Rotate gizmo mode",
+ TooltipText = $"Rotate gizmo mode ({inputOptions.RotateMode})",
Parent = gizmoMode
};
_gizmoModeRotate.Toggled += OnGizmoModeToggle;
_gizmoModeScale = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Scale32, null, true)
{
Tag = TransformGizmoBase.Mode.Scale,
- TooltipText = "Scale gizmo mode",
+ TooltipText = $"Scale gizmo mode ({inputOptions.ScaleMode})",
Parent = gizmoMode
};
_gizmoModeScale.Toggled += OnGizmoModeToggle;
@@ -233,6 +234,7 @@ namespace FlaxEditor.Viewport
InputActions.Add(options => options.TranslateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate);
InputActions.Add(options => options.RotateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate);
InputActions.Add(options => options.ScaleMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale);
+ InputActions.Add(options => options.ToggleTransformSpace, () => { OnTransformSpaceToggle(transformSpaceToggle); transformSpaceToggle.Checked = !transformSpaceToggle.Checked; });
InputActions.Add(options => options.FocusSelection, ShowSelectedActors);
SetUpdate(ref _update, OnUpdate);
diff --git a/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs b/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs
index fc7fcdbe1..c6ce5a7b5 100644
--- a/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs
+++ b/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs
@@ -68,7 +68,7 @@ namespace FlaxEditor.Viewport.Previews
///
public bool ShowBounds
{
- get => _boundsModel?.IsActive ?? false;
+ get => _boundsModel != null ? _boundsModel.IsActive : false;
set
{
if (value == ShowBounds)
@@ -110,7 +110,7 @@ namespace FlaxEditor.Viewport.Previews
///
public bool ShowOrigin
{
- get => _originModel?.IsActive ?? false;
+ get => _originModel != null ? _originModel.IsActive : false;
set
{
if (value == ShowOrigin)
diff --git a/Source/Editor/Viewport/Previews/TexturePreview.cs b/Source/Editor/Viewport/Previews/TexturePreview.cs
index a33a61f86..ec10bb019 100644
--- a/Source/Editor/Viewport/Previews/TexturePreview.cs
+++ b/Source/Editor/Viewport/Previews/TexturePreview.cs
@@ -500,7 +500,7 @@ namespace FlaxEditor.Viewport.Previews
///
protected override void CalculateTextureRect(out Rectangle rect)
{
- CalculateTextureRect(_asset?.Size ?? new Float2(100), Size, out rect);
+ CalculateTextureRect(_asset != null ? _asset.Size : new Float2(100), Size, out rect);
}
///
@@ -549,7 +549,7 @@ namespace FlaxEditor.Viewport.Previews
///
protected override void CalculateTextureRect(out Rectangle rect)
{
- CalculateTextureRect(_asset?.Size ?? new Float2(100), Size, out rect);
+ CalculateTextureRect(_asset != null ? _asset.Size : new Float2(100), Size, out rect);
}
///
@@ -604,7 +604,7 @@ namespace FlaxEditor.Viewport.Previews
///
protected override void CalculateTextureRect(out Rectangle rect)
{
- CalculateTextureRect(_asset?.Size ?? new Float2(100), Size, out rect);
+ CalculateTextureRect(_asset != null ? _asset.Size : new Float2(100), Size, out rect);
}
///
@@ -659,7 +659,7 @@ namespace FlaxEditor.Viewport.Previews
///
protected override void CalculateTextureRect(out Rectangle rect)
{
- CalculateTextureRect(_asset?.Size ?? new Float2(100), Size, out rect);
+ CalculateTextureRect(_asset != null ? _asset.Size : new Float2(100), Size, out rect);
}
///
diff --git a/Source/Editor/Windows/AboutDialog.cs b/Source/Editor/Windows/AboutDialog.cs
index 4b9595445..b059dadcb 100644
--- a/Source/Editor/Windows/AboutDialog.cs
+++ b/Source/Editor/Windows/AboutDialog.cs
@@ -52,9 +52,11 @@ namespace FlaxEditor.Windows
VerticalAlignment = TextAlignment.Near,
Parent = this
};
- var copyVersionButton = new Button(Width - 104, 6, 100, 20)
+ var buttonText = "Copy version info";
+ var fontSize = Style.Current.FontMedium.MeasureText(buttonText);
+ var copyVersionButton = new Button(Width - fontSize.X - 8, 6, fontSize.X + 4, 20)
{
- Text = "Copy version info",
+ Text = buttonText,
TooltipText = "Copies the current engine version information to system clipboard.",
Parent = this
};
diff --git a/Source/Editor/Windows/Assets/CollisionDataWindow.cs b/Source/Editor/Windows/Assets/CollisionDataWindow.cs
index cc1daa45b..1b6ed914c 100644
--- a/Source/Editor/Windows/Assets/CollisionDataWindow.cs
+++ b/Source/Editor/Windows/Assets/CollisionDataWindow.cs
@@ -200,6 +200,7 @@ namespace FlaxEditor.Windows.Assets
ViewportCamera = new FPSCamera(),
Parent = _split.Panel1
};
+ _preview.Task.ViewFlags &= ~ViewFlags.Sky & ~ViewFlags.Bloom;
// Asset properties
_propertiesPresenter = new CustomEditorPresenter(null);
diff --git a/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs b/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs
index d5ab2ae8a..5f1273999 100644
--- a/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs
+++ b/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs
@@ -69,7 +69,7 @@ namespace FlaxEditor.Windows.Assets
[EditorDisplay("General"), Tooltip("The base material used to override it's properties")]
public MaterialBase BaseMaterial
{
- get => Window?.Asset?.BaseMaterial;
+ get => Window?.Asset != null ? Window?.Asset.BaseMaterial : null;
set
{
var asset = Window?.Asset;
@@ -101,10 +101,12 @@ namespace FlaxEditor.Windows.Assets
[HideInEditor]
public object[] Values
{
- get => Window?.Asset?.Parameters.Select(x => x.Value).ToArray();
+ get => Window?.Asset != null ? Window?.Asset.Parameters.Select(x => x.Value).ToArray() : null;
set
{
- var parameters = Window?.Asset?.Parameters;
+ if (Window?.Asset == null)
+ return;
+ var parameters = Window?.Asset.Parameters;
if (value != null && parameters != null)
{
if (value.Length != parameters.Length)
@@ -131,9 +133,11 @@ namespace FlaxEditor.Windows.Assets
[HideInEditor]
public FlaxEngine.Object[] ValuesRef
{
- get => Window?.Asset?.Parameters.Select(x => x.Value as FlaxEngine.Object).ToArray();
+ get => Window?.Asset != null ? Window?.Asset.Parameters.Select(x => x.Value as FlaxEngine.Object).ToArray() : null;
set
{
+ if (Window?.Asset == null)
+ return;
var parameters = Window?.Asset?.Parameters;
if (value != null && parameters != null)
{
@@ -293,7 +297,7 @@ namespace FlaxEditor.Windows.Assets
var p = (MaterialParameter)e.Tag;
// Try to get default value (from the base material)
- var pBase = baseMaterial?.GetParameter(p.Name);
+ var pBase = baseMaterial != null ? baseMaterial.GetParameter(p.Name) : null;
if (pBase != null && pBase.ParameterType == p.ParameterType)
{
valueContainer.SetDefaultValue(pBase.Value);
diff --git a/Source/Editor/Windows/Assets/ModelWindow.cs b/Source/Editor/Windows/Assets/ModelWindow.cs
index f70f6a3b5..c2764a5a6 100644
--- a/Source/Editor/Windows/Assets/ModelWindow.cs
+++ b/Source/Editor/Windows/Assets/ModelWindow.cs
@@ -134,7 +134,7 @@ namespace FlaxEditor.Windows.Assets
if (Window._skipEffectsGuiEvents)
return;
- Window._isolateIndex = mesh?.MaterialSlotIndex ?? -1;
+ Window._isolateIndex = mesh != null ? mesh.MaterialSlotIndex : -1;
Window.UpdateEffectsOnAsset();
UpdateEffectsOnUI();
}
@@ -144,7 +144,7 @@ namespace FlaxEditor.Windows.Assets
if (Window._skipEffectsGuiEvents)
return;
- Window._highlightIndex = mesh?.MaterialSlotIndex ?? -1;
+ Window._highlightIndex = mesh != null ? mesh.MaterialSlotIndex : -1;
Window.UpdateEffectsOnAsset();
UpdateEffectsOnUI();
}
@@ -326,7 +326,7 @@ namespace FlaxEditor.Windows.Assets
[EditorOrder(10), EditorDisplay("Materials", EditorDisplayAttribute.InlineStyle)]
public MaterialSlot[] MaterialSlots
{
- get => Asset?.MaterialSlots;
+ get => Asset != null ? Asset.MaterialSlots : null;
set
{
if (Asset != null)
diff --git a/Source/Editor/Windows/Assets/ParticleSystemWindow.cs b/Source/Editor/Windows/Assets/ParticleSystemWindow.cs
index 328369680..17eda1358 100644
--- a/Source/Editor/Windows/Assets/ParticleSystemWindow.cs
+++ b/Source/Editor/Windows/Assets/ParticleSystemWindow.cs
@@ -187,7 +187,7 @@ namespace FlaxEditor.Windows.Assets
base.Initialize(layout);
var emitterTrack = Values[0] as EmitterTrackProxy;
- if (emitterTrack?._effect?.Parameters == null)
+ if (emitterTrack?._effect == null || emitterTrack?._effect.Parameters == null)
return;
var group = layout.Group("Parameters");
diff --git a/Source/Editor/Windows/Assets/SceneAnimationWindow.cs b/Source/Editor/Windows/Assets/SceneAnimationWindow.cs
index 824928743..162944144 100644
--- a/Source/Editor/Windows/Assets/SceneAnimationWindow.cs
+++ b/Source/Editor/Windows/Assets/SceneAnimationWindow.cs
@@ -792,7 +792,7 @@ namespace FlaxEditor.Windows.Assets
{
if (_previewButton.Checked)
return;
- _previewPlayerPicker.Value = _timeline.Player;
+ _previewPlayerPicker.Value = _timeline.Player != null ? _timeline.Player : null;
_cachedPlayerId = _timeline.Player?.ID ?? Guid.Empty;
}
@@ -821,7 +821,7 @@ namespace FlaxEditor.Windows.Assets
if (_timeline.IsModified)
{
var time = _timeline.CurrentTime;
- var isPlaying = _previewPlayer?.IsPlaying ?? false;
+ var isPlaying = _previewPlayer != null ? _previewPlayer.IsPlaying : false;
_timeline.Save(_asset);
if (_previewButton.Checked && _previewPlayer != null)
{
diff --git a/Source/Editor/Windows/Assets/SkinnedModelWindow.cs b/Source/Editor/Windows/Assets/SkinnedModelWindow.cs
index a7ee6e767..d360e5570 100644
--- a/Source/Editor/Windows/Assets/SkinnedModelWindow.cs
+++ b/Source/Editor/Windows/Assets/SkinnedModelWindow.cs
@@ -151,7 +151,7 @@ namespace FlaxEditor.Windows.Assets
if (Window._skipEffectsGuiEvents)
return;
- Window._isolateIndex = mesh?.MaterialSlotIndex ?? -1;
+ Window._isolateIndex = mesh != null ? mesh.MaterialSlotIndex : -1;
Window.UpdateEffectsOnAsset();
UpdateEffectsOnUI();
}
@@ -165,7 +165,7 @@ namespace FlaxEditor.Windows.Assets
if (Window._skipEffectsGuiEvents)
return;
- Window._highlightIndex = mesh?.MaterialSlotIndex ?? -1;
+ Window._highlightIndex = mesh != null ? mesh.MaterialSlotIndex : -1;
Window.UpdateEffectsOnAsset();
UpdateEffectsOnUI();
}
@@ -415,7 +415,7 @@ namespace FlaxEditor.Windows.Assets
[EditorOrder(10), EditorDisplay("Materials", EditorDisplayAttribute.InlineStyle)]
public MaterialSlot[] MaterialSlots
{
- get => Asset?.MaterialSlots;
+ get => Asset != null ? Asset.MaterialSlots : null;
set
{
if (Asset != null)
diff --git a/Source/Editor/Windows/ContentWindow.ContextMenu.cs b/Source/Editor/Windows/ContentWindow.ContextMenu.cs
index 283133688..6923d634d 100644
--- a/Source/Editor/Windows/ContentWindow.ContextMenu.cs
+++ b/Source/Editor/Windows/ContentWindow.ContextMenu.cs
@@ -145,10 +145,9 @@ namespace FlaxEditor.Windows
cm.AddButton("Refresh all thumbnails", RefreshViewItemsThumbnails);
}
- cm.AddSeparator();
-
- if (!isRootFolder)
+ if (!isRootFolder && !(item is ContentFolder projectFolder && projectFolder.Node is ProjectTreeNode))
{
+ cm.AddSeparator();
cm.AddButton("New folder", NewFolder);
}
diff --git a/Source/Editor/Windows/ContentWindow.cs b/Source/Editor/Windows/ContentWindow.cs
index 0f3c12286..c25316e9a 100644
--- a/Source/Editor/Windows/ContentWindow.cs
+++ b/Source/Editor/Windows/ContentWindow.cs
@@ -46,7 +46,7 @@ namespace FlaxEditor.Windows
private TextBox _itemsSearchBox;
private ViewDropdown _viewDropdown;
private SortType _sortType;
- private bool _showEngineFiles = true, _showPluginsFiles = true, _showAllFiles = true;
+ private bool _showEngineFiles = true, _showPluginsFiles = true, _showAllFiles = true, _showGeneratedFiles = false;
private RootContentTreeNode _root;
@@ -106,6 +106,19 @@ namespace FlaxEditor.Windows
}
}
+ internal bool ShowGeneratedFiles
+ {
+ get => _showGeneratedFiles;
+ set
+ {
+ if (_showGeneratedFiles != value)
+ {
+ _showGeneratedFiles = value;
+ RefreshView();
+ }
+ }
+ }
+
internal bool ShowAllFiles
{
get => _showAllFiles;
@@ -129,6 +142,8 @@ namespace FlaxEditor.Windows
Title = "Content";
Icon = editor.Icons.Folder32;
+ FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
+
// Content database events
editor.ContentDatabase.WorkspaceModified += () => _isWorkspaceDirty = true;
editor.ContentDatabase.ItemRemoved += OnContentDatabaseItemRemoved;
@@ -314,6 +329,12 @@ namespace FlaxEditor.Windows
b.Checked = ShowPluginsFiles;
b.CloseMenuOnClick = false;
b.AutoCheck = true;
+
+ b = show.ContextMenu.AddButton("Generated files", () => ShowGeneratedFiles = !ShowGeneratedFiles);
+ b.TooltipText = "Shows generated files";
+ b.Checked = ShowGeneratedFiles;
+ b.CloseMenuOnClick = false;
+ b.AutoCheck = true;
b = show.ContextMenu.AddButton("All files", () => ShowAllFiles = !ShowAllFiles);
b.TooltipText = "Shows all files including other than assets and source code";
@@ -520,7 +541,7 @@ namespace FlaxEditor.Windows
}
// Cache data
- string extension = Path.GetExtension(item.Path);
+ string extension = item.IsFolder ? "" : Path.GetExtension(item.Path);
var newPath = StringUtils.CombinePaths(item.ParentFolder.Path, newShortName + extension);
// Check if was renaming mock element
@@ -626,7 +647,7 @@ namespace FlaxEditor.Windows
// Delete items
for (int i = 0; i < toDelete.Count; i++)
- Editor.ContentDatabase.Delete(toDelete[i]);
+ Editor.ContentDatabase.Delete(toDelete[i], true);
RefreshView();
}
@@ -722,7 +743,12 @@ namespace FlaxEditor.Windows
{
var item = Editor.ContentDatabase.Find(sourcePath);
if (item != null)
- Editor.ContentDatabase.Copy(item, Path.Combine(CurrentViewFolder.Path, item.FileName));
+ {
+ var newPath = StringUtils.NormalizePath(Path.Combine(CurrentViewFolder.Path, item.FileName));
+ if (sourcePath.Equals(newPath))
+ newPath = GetClonedAssetPath(item);
+ Editor.ContentDatabase.Copy(item, newPath);
+ }
else
importFiles.Add(sourcePath);
}
@@ -969,6 +995,8 @@ namespace FlaxEditor.Windows
var items = target.Folder.Children;
if (!_showAllFiles)
items = items.Where(x => !(x is FileItem)).ToList();
+ if (!_showGeneratedFiles)
+ items = items.Where(x => !(x.Path.EndsWith(".Gen.cs", StringComparison.Ordinal) || x.Path.EndsWith(".Gen.h", StringComparison.Ordinal) || x.Path.EndsWith(".Gen.cpp", StringComparison.Ordinal) || x.Path.EndsWith(".csproj", StringComparison.Ordinal) || x.Path.Contains(".CSharp"))).ToList();
_view.ShowItems(items, _sortType, false, true);
}
}
@@ -1145,6 +1173,7 @@ namespace FlaxEditor.Windows
writer.WriteAttributeString("ShowEngineFiles", ShowEngineFiles.ToString());
writer.WriteAttributeString("ShowPluginsFiles", ShowPluginsFiles.ToString());
writer.WriteAttributeString("ShowAllFiles", ShowAllFiles.ToString());
+ writer.WriteAttributeString("ShowGeneratedFiles", ShowGeneratedFiles.ToString());
writer.WriteAttributeString("ViewType", _view.ViewType.ToString());
}
@@ -1162,6 +1191,8 @@ namespace FlaxEditor.Windows
ShowPluginsFiles = value2;
if (bool.TryParse(node.GetAttribute("ShowAllFiles"), out value2))
ShowAllFiles = value2;
+ if (bool.TryParse(node.GetAttribute("ShowGeneratedFiles"), out value2))
+ ShowGeneratedFiles = value2;
if (Enum.TryParse(node.GetAttribute("ViewType"), out ContentViewType viewType))
_view.ViewType = viewType;
}
diff --git a/Source/Editor/Windows/DebugLogWindow.cs b/Source/Editor/Windows/DebugLogWindow.cs
index 49b03ede1..ab0c07ec5 100644
--- a/Source/Editor/Windows/DebugLogWindow.cs
+++ b/Source/Editor/Windows/DebugLogWindow.cs
@@ -317,6 +317,7 @@ namespace FlaxEditor.Windows
Title = "Debug Log";
Icon = IconInfo;
OnEditorOptionsChanged(Editor.Options.Options);
+ FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
// Toolstrip
var toolstrip = new ToolStrip(22.0f)
@@ -544,7 +545,7 @@ namespace FlaxEditor.Windows
if (noLocation)
{
desc.LocationFile = match.Groups[2].Value;
- int.TryParse(match.Groups[5].Value, out desc.LocationLine);
+ int.TryParse(match.Groups[4].Value, out desc.LocationLine);
noLocation = false;
}
fineStackTrace.AppendLine(match.Groups[0].Value);
@@ -573,7 +574,7 @@ namespace FlaxEditor.Windows
if (match.Success)
{
desc.LocationFile = match.Groups[2].Value;
- int.TryParse(match.Groups[3].Value, out desc.LocationLine);
+ int.TryParse(match.Groups[4].Value, out desc.LocationLine);
}
}
diff --git a/Source/Editor/Windows/EditorOptionsWindow.cs b/Source/Editor/Windows/EditorOptionsWindow.cs
index 2942f98c0..d53d4f632 100644
--- a/Source/Editor/Windows/EditorOptionsWindow.cs
+++ b/Source/Editor/Windows/EditorOptionsWindow.cs
@@ -216,5 +216,36 @@ namespace FlaxEditor.Windows
base.OnDestroy();
}
+
+ ///
+ protected override bool OnClosing(ClosingReason reason)
+ {
+ // Block closing only on user events
+ if (reason == ClosingReason.User)
+ {
+ // Check if asset has been edited and not saved (and still has linked item)
+ if (_isDataDirty && _options != null)
+ {
+ // Ask user for further action
+ var result = MessageBox.Show(
+ "Editor options have been edited. Save before closing?",
+ "Save before closing?",
+ MessageBoxButtons.YesNoCancel
+ );
+ if (result == DialogResult.OK || result == DialogResult.Yes)
+ {
+ // Save and close
+ SaveData();
+ }
+ else if (result == DialogResult.Cancel || result == DialogResult.Abort)
+ {
+ // Cancel closing
+ return true;
+ }
+ }
+ }
+
+ return base.OnClosing(reason);
+ }
}
}
diff --git a/Source/Editor/Windows/EditorWindow.cs b/Source/Editor/Windows/EditorWindow.cs
index 1ff0363f1..ff0673c11 100644
--- a/Source/Editor/Windows/EditorWindow.cs
+++ b/Source/Editor/Windows/EditorWindow.cs
@@ -192,6 +192,13 @@ namespace FlaxEditor.Windows
///
public override bool OnKeyDown(KeyboardKeys key)
{
+ // Prevent closing the editor window when using RMB + Ctrl + W to slow down the camera flight
+ if (Editor.Options.Options.Input.CloseTab.Process(this, key))
+ {
+ if (Root.GetMouseButton(MouseButton.Right))
+ return true;
+ }
+
if (base.OnKeyDown(key))
return true;
@@ -207,7 +214,8 @@ namespace FlaxEditor.Windows
case KeyboardKeys.Tab:
if (CanUseNavigation && Root != null)
{
- Root.Navigate(NavDirection.Next);
+ bool shiftDown = Root.GetKey(KeyboardKeys.Shift);
+ Root.Navigate(shiftDown ? NavDirection.Previous : NavDirection.Next);
return true;
}
break;
diff --git a/Source/Editor/Windows/GameWindow.cs b/Source/Editor/Windows/GameWindow.cs
index 513542fdc..bbdf763fb 100644
--- a/Source/Editor/Windows/GameWindow.cs
+++ b/Source/Editor/Windows/GameWindow.cs
@@ -271,6 +271,8 @@ namespace FlaxEditor.Windows
Title = "Game";
AutoFocus = true;
+ FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
+
var task = MainRenderTask.Instance;
// Setup viewport
@@ -302,10 +304,6 @@ namespace FlaxEditor.Windows
// Link editor options
Editor.Options.OptionsChanged += OnOptionsChanged;
OnOptionsChanged(Editor.Options.Options);
-
- InputActions.Add(options => options.Play, Editor.Simulation.DelegatePlayOrStopPlayInEditor);
- InputActions.Add(options => options.Pause, Editor.Simulation.RequestResumeOrPause);
- InputActions.Add(options => options.StepFrame, Editor.Simulation.RequestPlayOneFrame);
}
private void ChangeViewportRatio(ViewportScaleOptions v)
diff --git a/Source/Editor/Windows/OutputLogWindow.cs b/Source/Editor/Windows/OutputLogWindow.cs
index 0b2249a33..1d188a32c 100644
--- a/Source/Editor/Windows/OutputLogWindow.cs
+++ b/Source/Editor/Windows/OutputLogWindow.cs
@@ -150,6 +150,7 @@ namespace FlaxEditor.Windows
{
Title = "Output Log";
ClipChildren = false;
+ FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
// Setup UI
_viewDropdown = new Button(2, 2, 40.0f, TextBoxBase.DefaultHeight)
@@ -159,7 +160,7 @@ namespace FlaxEditor.Windows
Parent = this,
};
_viewDropdown.Clicked += OnViewButtonClicked;
- _searchBox = new SearchBox(false, _viewDropdown.Right + 2, 2, Width - _viewDropdown.Right - 2 - _scrollSize)
+ _searchBox = new SearchBox(false, _viewDropdown.Right + 2, 2, Width - _viewDropdown.Right - 4)
{
Parent = this,
};
@@ -170,11 +171,12 @@ namespace FlaxEditor.Windows
Maximum = 0,
};
_hScroll.ValueChanged += OnHScrollValueChanged;
- _vScroll = new VScrollBar(this, Width - _scrollSize, Height, _scrollSize)
+ _vScroll = new VScrollBar(this, Width - _scrollSize, Height - _viewDropdown.Height - 2, _scrollSize)
{
ThumbThickness = 10,
Maximum = 0,
};
+ _vScroll.Y += _viewDropdown.Height + 2;
_vScroll.ValueChanged += OnVScrollValueChanged;
_output = new OutputTextBox
{
@@ -408,7 +410,7 @@ namespace FlaxEditor.Windows
if (_output != null)
{
- _searchBox.Width = Width - _viewDropdown.Right - 2 - _scrollSize;
+ _searchBox.Width = Width - _viewDropdown.Right - 4;
_output.Size = new Float2(_vScroll.X - 2, _hScroll.Y - 4 - _viewDropdown.Bottom);
}
}
diff --git a/Source/Editor/Windows/Profiler/CPU.cs b/Source/Editor/Windows/Profiler/CPU.cs
index 36fbf21f4..fd4061276 100644
--- a/Source/Editor/Windows/Profiler/CPU.cs
+++ b/Source/Editor/Windows/Profiler/CPU.cs
@@ -429,21 +429,8 @@ namespace FlaxEditor.Windows.Profiler
private void UpdateTable(ref ViewRange viewRange)
{
_table.IsLayoutLocked = true;
- int idx = 0;
- while (_table.Children.Count > idx)
- {
- var child = _table.Children[idx];
- if (child is Row row)
- {
- _tableRowsCache.Add(row);
- child.Parent = null;
- }
- else
- {
- idx++;
- }
- }
+ RecycleTableRows(_table, _tableRowsCache);
UpdateTableInner(ref viewRange);
_table.UnlockChildrenRecursive();
diff --git a/Source/Editor/Windows/Profiler/GPU.cs b/Source/Editor/Windows/Profiler/GPU.cs
index 2cf75a9aa..4ed18691a 100644
--- a/Source/Editor/Windows/Profiler/GPU.cs
+++ b/Source/Editor/Windows/Profiler/GPU.cs
@@ -298,21 +298,7 @@ namespace FlaxEditor.Windows.Profiler
private void UpdateTable()
{
_table.IsLayoutLocked = true;
- int idx = 0;
- while (_table.Children.Count > idx)
- {
- var child = _table.Children[idx];
- if (child is Row row)
- {
- _tableRowsCache.Add(row);
- child.Parent = null;
- }
- else
- {
- idx++;
- }
- }
- _table.LockChildrenRecursive();
+ RecycleTableRows(_table, _tableRowsCache);
UpdateTableInner();
diff --git a/Source/Editor/Windows/Profiler/Network.cs b/Source/Editor/Windows/Profiler/Network.cs
index f0b93a03c..dbee0e8e7 100644
--- a/Source/Editor/Windows/Profiler/Network.cs
+++ b/Source/Editor/Windows/Profiler/Network.cs
@@ -1,8 +1,32 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
+using System;
+using System.Collections.Generic;
+using FlaxEditor.GUI;
using FlaxEngine;
using FlaxEngine.GUI;
+namespace FlaxEngine
+{
+ partial class ProfilingTools
+ {
+ partial struct NetworkEventStat
+ {
+ ///
+ /// Gets the event name.
+ ///
+ public unsafe string Name
+ {
+ get
+ {
+ fixed (byte* name = Name0)
+ return System.Runtime.InteropServices.Marshal.PtrToStringAnsi(new IntPtr(name));
+ }
+ }
+ }
+ }
+}
+
namespace FlaxEditor.Windows.Profiler
{
///
@@ -13,6 +37,10 @@ namespace FlaxEditor.Windows.Profiler
{
private readonly SingleChart _dataSentChart;
private readonly SingleChart _dataReceivedChart;
+ private readonly Table _tableRpc;
+ private readonly Table _tableRep;
+ private SamplesBuffer _events;
+ private List _tableRowsCache;
private FlaxEngine.Networking.NetworkDriverStats _prevStats;
public Network()
@@ -48,11 +76,10 @@ namespace FlaxEditor.Windows.Profiler
Parent = layout,
};
_dataReceivedChart.SelectedSampleChanged += OnSelectedSampleChanged;
- }
- private static string FormatSampleBytes(float v)
- {
- return Utilities.Utils.FormatBytesCount((ulong)v);
+ // Tables
+ _tableRpc = InitTable(layout, "RPC Name");
+ _tableRep = InitTable(layout, "Replication Name");
}
///
@@ -60,21 +87,30 @@ namespace FlaxEditor.Windows.Profiler
{
_dataSentChart.Clear();
_dataReceivedChart.Clear();
+ _events?.Clear();
}
///
public override void Update(ref SharedUpdateData sharedData)
{
- var peer = FlaxEngine.Networking.NetworkManager.Peer;
- if (peer == null)
+ // Gather peer stats
+ var peers = FlaxEngine.Networking.NetworkPeer.Peers;
+ var stats = new FlaxEngine.Networking.NetworkDriverStats();
+ foreach (var peer in peers)
{
- _prevStats = new FlaxEngine.Networking.NetworkDriverStats();
- return;
+ var peerStats = peer.NetworkDriver.GetStats();
+ stats.TotalDataSent += peerStats.TotalDataSent;
+ stats.TotalDataReceived += peerStats.TotalDataReceived;
}
- var stats = peer.NetworkDriver.GetStats();
_dataSentChart.AddSample(Mathf.Max((long)stats.TotalDataSent - (long)_prevStats.TotalDataSent, 0));
_dataReceivedChart.AddSample(Mathf.Max((long)stats.TotalDataReceived - (long)_prevStats.TotalDataReceived, 0));
_prevStats = stats;
+
+ // Gather network events
+ var events = ProfilingTools.EventsNetwork;
+ if (_events == null)
+ _events = new SamplesBuffer();
+ _events.Add(events);
}
///
@@ -82,6 +118,159 @@ namespace FlaxEditor.Windows.Profiler
{
_dataSentChart.SelectedSampleIndex = selectedFrame;
_dataReceivedChart.SelectedSampleIndex = selectedFrame;
+
+ // Update events tables
+ if (_events != null)
+ {
+ if (_tableRowsCache == null)
+ _tableRowsCache = new List();
+ _tableRpc.IsLayoutLocked = true;
+ _tableRep.IsLayoutLocked = true;
+ RecycleTableRows(_tableRpc, _tableRowsCache);
+ RecycleTableRows(_tableRep, _tableRowsCache);
+
+ var events = _events.Get(selectedFrame);
+ var rowCount = Int2.Zero;
+ if (events != null && events.Length != 0)
+ {
+ var rowColor2 = Style.Current.Background * 1.4f;
+ for (int i = 0; i < events.Length; i++)
+ {
+ var e = events[i];
+ var name = e.Name;
+ var isRpc = name.Contains("::", StringComparison.Ordinal);
+
+ Row row;
+ if (_tableRowsCache.Count != 0)
+ {
+ var last = _tableRowsCache.Count - 1;
+ row = _tableRowsCache[last];
+ _tableRowsCache.RemoveAt(last);
+ }
+ else
+ {
+ row = new Row
+ {
+ Values = new object[5],
+ };
+ }
+ {
+ // Name
+ row.Values[0] = name;
+
+ // Count
+ row.Values[1] = (int)e.Count;
+
+ // Data Size
+ row.Values[2] = (int)e.DataSize;
+
+ // Message Size
+ row.Values[3] = (int)e.MessageSize;
+
+ // Receivers
+ row.Values[4] = (float)e.Receivers / (float)e.Count;
+ }
+
+ var table = isRpc ? _tableRpc : _tableRep;
+ row.Width = table.Width;
+ row.BackgroundColor = rowCount[isRpc ? 0 : 1] % 2 == 0 ? rowColor2 : Color.Transparent;
+ row.Parent = table;
+ if (isRpc)
+ rowCount.X++;
+ else
+ rowCount.Y++;
+ }
+ }
+
+ _tableRpc.Visible = rowCount.X != 0;
+ _tableRep.Visible = rowCount.Y != 0;
+ _tableRpc.Children.Sort(SortRows);
+ _tableRep.Children.Sort(SortRows);
+
+ _tableRpc.UnlockChildrenRecursive();
+ _tableRpc.PerformLayout();
+ _tableRep.UnlockChildrenRecursive();
+ _tableRep.PerformLayout();
+ }
+ }
+
+ ///
+ public override void OnDestroy()
+ {
+ _tableRowsCache?.Clear();
+
+ base.OnDestroy();
+ }
+
+ private static Table InitTable(ContainerControl parent, string name)
+ {
+ var headerColor = Style.Current.LightBackground;
+ var table = new Table
+ {
+ Columns = new[]
+ {
+ new ColumnDefinition
+ {
+ UseExpandCollapseMode = true,
+ CellAlignment = TextAlignment.Near,
+ Title = name,
+ TitleBackgroundColor = headerColor,
+ },
+ new ColumnDefinition
+ {
+ Title = "Count",
+ TitleBackgroundColor = headerColor,
+ },
+ new ColumnDefinition
+ {
+ Title = "Data Size",
+ TitleBackgroundColor = headerColor,
+ FormatValue = FormatCellBytes,
+ },
+ new ColumnDefinition
+ {
+ Title = "Message Size",
+ TitleBackgroundColor = headerColor,
+ FormatValue = FormatCellBytes,
+ },
+ new ColumnDefinition
+ {
+ Title = "Receivers",
+ TitleBackgroundColor = headerColor,
+ },
+ },
+ Splits = new[]
+ {
+ 0.40f,
+ 0.15f,
+ 0.15f,
+ 0.15f,
+ 0.15f,
+ },
+ Parent = parent,
+ };
+ return table;
+ }
+
+ private static string FormatSampleBytes(float v)
+ {
+ return Utilities.Utils.FormatBytesCount((ulong)v);
+ }
+
+ private static string FormatCellBytes(object x)
+ {
+ return Utilities.Utils.FormatBytesCount((int)x);
+ }
+
+ private static int SortRows(Control x, Control y)
+ {
+ if (x is Row xRow && y is Row yRow)
+ {
+ var xDataSize = (int)xRow.Values[2];
+ var yDataSize = (int)yRow.Values[2];
+ return yDataSize - xDataSize;
+ }
+ return 0;
}
}
}
diff --git a/Source/Editor/Windows/Profiler/ProfilerMode.cs b/Source/Editor/Windows/Profiler/ProfilerMode.cs
index 0cc1a39ee..b8d2f0c4c 100644
--- a/Source/Editor/Windows/Profiler/ProfilerMode.cs
+++ b/Source/Editor/Windows/Profiler/ProfilerMode.cs
@@ -1,6 +1,8 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
+using System.Collections.Generic;
+using FlaxEditor.GUI;
using FlaxEditor.GUI.Tabs;
using FlaxEngine;
@@ -135,5 +137,28 @@ namespace FlaxEditor.Windows.Profiler
{
SelectedSampleChanged?.Invoke(frameIndex);
}
+
+ ///
+ /// Recycles all table rows to be reused.
+ ///
+ /// The table.
+ /// The output cache.
+ protected static void RecycleTableRows(Table table, List rowsCache)
+ {
+ int idx = 0;
+ while (table.Children.Count > idx)
+ {
+ var child = table.Children[idx];
+ if (child is Row row)
+ {
+ rowsCache.Add(row);
+ child.Parent = null;
+ }
+ else
+ {
+ idx++;
+ }
+ }
+ }
}
}
diff --git a/Source/Editor/Windows/Profiler/ProfilerWindow.cs b/Source/Editor/Windows/Profiler/ProfilerWindow.cs
index f5a5c6f86..f97e943ad 100644
--- a/Source/Editor/Windows/Profiler/ProfilerWindow.cs
+++ b/Source/Editor/Windows/Profiler/ProfilerWindow.cs
@@ -93,7 +93,7 @@ namespace FlaxEditor.Windows.Profiler
_liveRecordingButton = toolstrip.AddButton(editor.Icons.Play64);
_liveRecordingButton.LinkTooltip("Live profiling events recording");
_liveRecordingButton.AutoCheck = true;
- _liveRecordingButton.Clicked += () => _liveRecordingButton.Icon = LiveRecording ? editor.Icons.Stop64 : editor.Icons.Play64;
+ _liveRecordingButton.Clicked += OnLiveRecordingChanged;
_clearButton = toolstrip.AddButton(editor.Icons.Rotate32, Clear);
_clearButton.LinkTooltip("Clear data");
toolstrip.AddSeparator();
@@ -116,6 +116,16 @@ namespace FlaxEditor.Windows.Profiler
Parent = this
};
_tabs.SelectedTabChanged += OnSelectedTabChanged;
+
+ FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
+ InputActions.Bindings.RemoveAll(x => x.Callback == this.FocusOrShow);
+ InputActions.Add(options => options.ProfilerWindow, Hide);
+ }
+
+ private void OnLiveRecordingChanged()
+ {
+ _liveRecordingButton.Icon = LiveRecording ? Editor.Icons.Stop64 : Editor.Icons.Play64;
+ ProfilingTools.Enabled = LiveRecording;
}
///
diff --git a/Source/Editor/Windows/Profiler/SamplesBuffer.cs b/Source/Editor/Windows/Profiler/SamplesBuffer.cs
index abc99cfd5..999156dca 100644
--- a/Source/Editor/Windows/Profiler/SamplesBuffer.cs
+++ b/Source/Editor/Windows/Profiler/SamplesBuffer.cs
@@ -49,6 +49,8 @@ namespace FlaxEditor.Windows.Profiler
/// The sample value
public T Get(int index)
{
+ if (index >= _data.Length || _data.Length == 0)
+ return default;
return index == -1 ? _data[_count - 1] : _data[index];
}
diff --git a/Source/Editor/Windows/SceneEditorWindow.cs b/Source/Editor/Windows/SceneEditorWindow.cs
index 72ff3be33..04cce47e8 100644
--- a/Source/Editor/Windows/SceneEditorWindow.cs
+++ b/Source/Editor/Windows/SceneEditorWindow.cs
@@ -19,28 +19,7 @@ namespace FlaxEditor.Windows
protected SceneEditorWindow(Editor editor, bool hideOnClose, ScrollBars scrollBars)
: base(editor, hideOnClose, scrollBars)
{
- // Setup input actions
- InputActions.Add(options => options.Save, Editor.SaveAll);
- InputActions.Add(options => options.Undo, () =>
- {
- Editor.PerformUndo();
- Focus();
- });
- InputActions.Add(options => options.Redo, () =>
- {
- Editor.PerformRedo();
- Focus();
- });
- InputActions.Add(options => options.Cut, Editor.SceneEditing.Cut);
- InputActions.Add(options => options.Copy, Editor.SceneEditing.Copy);
- InputActions.Add(options => options.Paste, Editor.SceneEditing.Paste);
- InputActions.Add(options => options.Duplicate, Editor.SceneEditing.Duplicate);
- InputActions.Add(options => options.SelectAll, Editor.SceneEditing.SelectAllScenes);
- InputActions.Add(options => options.Delete, Editor.SceneEditing.Delete);
- InputActions.Add(options => options.Search, () => Editor.Windows.SceneWin.Search());
- InputActions.Add(options => options.Play, Editor.Simulation.DelegatePlayOrStopPlayInEditor);
- InputActions.Add(options => options.Pause, Editor.Simulation.RequestResumeOrPause);
- InputActions.Add(options => options.StepFrame, Editor.Simulation.RequestPlayOneFrame);
+ FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
}
}
}
diff --git a/Source/Editor/Windows/SceneTreeWindow.ContextMenu.cs b/Source/Editor/Windows/SceneTreeWindow.ContextMenu.cs
index e48e59f80..63d110368 100644
--- a/Source/Editor/Windows/SceneTreeWindow.ContextMenu.cs
+++ b/Source/Editor/Windows/SceneTreeWindow.ContextMenu.cs
@@ -26,6 +26,7 @@ namespace FlaxEditor.Windows
bool hasSthSelected = Editor.SceneEditing.HasSthSelected;
bool isSingleActorSelected = Editor.SceneEditing.SelectionCount == 1 && Editor.SceneEditing.Selection[0] is ActorNode;
bool canEditScene = Editor.StateMachine.CurrentState.CanEditScene && Level.IsAnySceneLoaded;
+ var inputOptions = Editor.Options.Options.Input;
// Create popup
@@ -44,17 +45,17 @@ namespace FlaxEditor.Windows
if (hasSthSelected)
{
- contextMenu.AddButton(Editor.Windows.EditWin.IsPilotActorActive ? "Stop piloting actor" : "Pilot actor", Editor.UI.PilotActor);
+ contextMenu.AddButton(Editor.Windows.EditWin.IsPilotActorActive ? "Stop piloting actor" : "Pilot actor", inputOptions.PilotActor, Editor.UI.PilotActor);
}
contextMenu.AddSeparator();
// Basic editing options
- b = contextMenu.AddButton("Rename", Rename);
+ b = contextMenu.AddButton("Rename", inputOptions.Rename, Rename);
b.Enabled = isSingleActorSelected;
- b = contextMenu.AddButton("Duplicate", Editor.SceneEditing.Duplicate);
+ b = contextMenu.AddButton("Duplicate", inputOptions.Duplicate, Editor.SceneEditing.Duplicate);
b.Enabled = hasSthSelected;
if (isSingleActorSelected)
@@ -116,17 +117,17 @@ namespace FlaxEditor.Windows
}
}
}
- b = contextMenu.AddButton("Delete", Editor.SceneEditing.Delete);
+ b = contextMenu.AddButton("Delete", inputOptions.Delete, Editor.SceneEditing.Delete);
b.Enabled = hasSthSelected;
contextMenu.AddSeparator();
- b = contextMenu.AddButton("Copy", Editor.SceneEditing.Copy);
+ b = contextMenu.AddButton("Copy", inputOptions.Copy, Editor.SceneEditing.Copy);
b.Enabled = hasSthSelected;
- contextMenu.AddButton("Paste", Editor.SceneEditing.Paste);
+ contextMenu.AddButton("Paste", inputOptions.Paste, Editor.SceneEditing.Paste);
- b = contextMenu.AddButton("Cut", Editor.SceneEditing.Cut);
+ b = contextMenu.AddButton("Cut", inputOptions.Cut, Editor.SceneEditing.Cut);
b.Enabled = canEditScene;
// Prefab options
diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs
index 609f98f83..fba052269 100644
--- a/Source/Editor/Windows/SceneTreeWindow.cs
+++ b/Source/Editor/Windows/SceneTreeWindow.cs
@@ -173,6 +173,9 @@ namespace FlaxEditor.Windows
// Spawn it
Editor.SceneEditing.Spawn(actor, parentActor);
+
+ Editor.SceneEditing.Select(actor);
+ Rename();
}
///
diff --git a/Source/Editor/Windows/SplashScreen.cpp b/Source/Editor/Windows/SplashScreen.cpp
index 7cf7a7f78..d2371a540 100644
--- a/Source/Editor/Windows/SplashScreen.cpp
+++ b/Source/Editor/Windows/SplashScreen.cpp
@@ -18,21 +18,21 @@ const Char* SplashScreenQuotes[] =
TEXT("Loading"),
TEXT("Unloading"),
TEXT("Reloading"),
- TEXT("Reloading gun"),
+ TEXT("Downloading more RAM"),
TEXT("Consuming your RAM"),
TEXT("Burning your CPU"),
- TEXT("#BetterThanUnity"),
TEXT("Rendering buttons"),
TEXT("Collecting crash data"),
- TEXT("Downloading porn"),
#if PLATFORM_WINDOWS
- TEXT("Removing 'C:\\Windows\\'"),
+ TEXT("We're getting everything ready for you."),
#elif PLATFORM_LINUX
- TEXT("Time to switch to Windows?"),
- TEXT("Installing Windows 10"),
+ TEXT("Try it on a Raspberry"),
+ TEXT("Trying to exit vim"),
+ TEXT("Sudo flax --loadproject"),
#elif PLATFORM_MAC
- TEXT("Hacking your iPhone"),
+ TEXT("don't compare Macbooks to oranges."),
TEXT("Why does macbook heat up?\nBecause it doesn't have windows"),
+ TEXT("Starting Direc... um, Vulkan renderer."),
#endif
TEXT("Kappa!"),
TEXT("How you doin'?"),
@@ -40,12 +40,10 @@ const Char* SplashScreenQuotes[] =
TEXT("Bond. James Bond."),
TEXT("To infinity and beyond!"),
TEXT("Houston, we have a problem"),
- TEXT("NotImplementedEngineException"),
TEXT("Made in Poland"),
TEXT("We like you"),
TEXT("Compiling the compiler"),
TEXT("Flax it up!"),
- TEXT("Fun fact: Fortnite runs on Flax"),
TEXT("Toss a coin to your Witcher!!!"),
TEXT("Holy Moly!"),
TEXT("Just Read the Instructions"),
@@ -60,7 +58,6 @@ const Char* SplashScreenQuotes[] =
TEXT("They see me loadin'"),
TEXT("Loadin' loadin' and loadin' loadin'"),
TEXT("Procedurally generating buttons"),
- TEXT("Out of Memory Exception!"),
TEXT("Running Big Bang simulation"),
TEXT("Calculating infinity"),
TEXT("Dividing infinity by zero"),
@@ -70,10 +67,7 @@ const Char* SplashScreenQuotes[] =
TEXT("Whatever you do, do it well.\n~Walt Disney"),
TEXT("Here's Johnny!"),
TEXT("Did you see that? No... I don't think so"),
- TEXT("Collecting unreal power"),
TEXT("Stay safe, friend"),
- TEXT("trolololololololololololo"),
- TEXT("xD"),
TEXT("Come to the dark side"),
TEXT("Flax Facts: This is a loading screen"),
TEXT("Don't Stop Me Now"),
@@ -81,61 +75,58 @@ const Char* SplashScreenQuotes[] =
TEXT("Made with Flax"),
TEXT("This is the way"),
TEXT("The quick brown fox jumps over the lazy dog"),
- TEXT("Hit The Road Jack"),
TEXT("You have 7 lives left"),
TEXT("May the Force be with you"),
TEXT("A martini. Shaken, not stirred"),
TEXT("Hasta la vista, baby"),
TEXT("Winter is coming"),
- TEXT("You know nothing, Jon Snow"),
TEXT("Create something awesome!"),
TEXT("Well Polished Engine"),
TEXT("Error 404: Joke Not Found"),
TEXT("Rushing B"),
TEXT("Putting pineapple on pizza"),
- TEXT("Loading Simulation"),
+ TEXT("Entering the Matrix"),
TEXT("Get ready for a surprise!"),
TEXT("Coffee is my fuel"),
- TEXT("Installing a free copy of Cyberpunk 2077"),
TEXT("With great power comes great electricity bill"),
TEXT("Flax was made in the same city as Witcher 3"),
TEXT("So JavaScript is a scripting version of Java"),
TEXT("Good things take time.\n~Someone"),
- TEXT("Get shit done"),
TEXT("Hold Tight! Loading Flax"),
TEXT("That's one small step for a man,\none giant leap for mankind"),
TEXT("Remember to save your work frequently"),
TEXT("In case of fire:\ngit commit, git push, leave building"),
TEXT("Keep calm and make games"),
TEXT("You're breathtaking!!!"),
- TEXT("Do regular dogs see police dogs & think,\nOh no it's a cop?"),
- TEXT("Dear Santa,\nDefine naughty."),
TEXT("Blah, blah"),
TEXT("My PRECIOUS!!!!"),
TEXT("YOU SHALL NOT PASS!"),
TEXT("You have my bow.\nAnd my axe!"),
TEXT("To the bridge of Khazad-dum."),
TEXT("One ring to rule them all.\nOne ring to find them."),
- TEXT("Ladies and gentelman, we got him"),
- TEXT("Cyberpunk of game engines"),
TEXT("That's what she said"),
- TEXT("Compiling Shaders (93,788)"),
+ TEXT("We could be compiling shaders here"),
TEXT("Hello There"),
TEXT("BAGUETTE"),
- TEXT("All we had to do was follow the damn train, CJ"),
TEXT("Here we go again"),
TEXT("@everyone"),
TEXT("Potato"),
TEXT("Python is a programming snek"),
TEXT("Flax will start when pigs will fly"),
- TEXT("I'm the android sent by CyberLife"),
- TEXT("Fancy-ass ray tracing, rtx on, lighting"),
TEXT("ZOINKS"),
TEXT("Scooby dooby doo"),
TEXT("You shall not load!"),
TEXT("The roof, the roof, the roof is on fire!"),
- TEXT("I've seen better documentation...\nFrom ransomware gangs!"),
TEXT("Slava Ukraini!"),
+ TEXT("RTX off... for now!"),
+ TEXT("Increasing Fiber count"),
+ TEXT("Now this is podracing!"),
+ TEXT("Weird flax, but ok"),
+ TEXT("Reticulating Splines"),
+ TEXT("Discombobulating"),
+ TEXT("Who is signing all these integers?!"),
+ TEXT("Flax fact: Flax was called Celelej once."),
+ TEXT("Changing text overflow setti-"),
};
SplashScreen::~SplashScreen()
diff --git a/Source/Editor/Windows/ToolboxWindow.cs b/Source/Editor/Windows/ToolboxWindow.cs
index 3df4d3527..b747149c5 100644
--- a/Source/Editor/Windows/ToolboxWindow.cs
+++ b/Source/Editor/Windows/ToolboxWindow.cs
@@ -353,6 +353,8 @@ namespace FlaxEditor.Windows
: base(editor, true, ScrollBars.None)
{
Title = "Toolbox";
+
+ FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
}
///
diff --git a/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.cpp b/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.cpp
index fa7999ce0..8fef8e6d3 100644
--- a/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.cpp
+++ b/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.cpp
@@ -905,7 +905,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
MException ex(exception);
ex.Log(LogType::Error, TEXT("Property"));
}
- else if (!MCore::Type::IsPointer(valueType))
+ else if (!MCore::Type::IsPointer(valueType) && !MCore::Type::IsReference(valueType))
{
if (boxed)
Platform::MemoryCopy(value, MCore::Object::Unbox(boxed), valueSize);
diff --git a/Source/Engine/Content/Assets/MaterialInstance.cpp b/Source/Engine/Content/Assets/MaterialInstance.cpp
index 7581692e1..3bf0c54cd 100644
--- a/Source/Engine/Content/Assets/MaterialInstance.cpp
+++ b/Source/Engine/Content/Assets/MaterialInstance.cpp
@@ -205,8 +205,6 @@ void MaterialInstance::Bind(BindParameters& params)
Asset::LoadResult MaterialInstance::load()
{
- ASSERT(_baseMaterial == nullptr);
-
// Get main chunk
auto chunk0 = GetChunk(0);
if (chunk0 == nullptr || chunk0->IsMissing())
@@ -229,6 +227,7 @@ Asset::LoadResult MaterialInstance::load()
else
{
// Clear parameters if has no material loaded
+ _baseMaterial = nullptr;
Params.Dispose();
ParamsChanged();
}
diff --git a/Source/Engine/ContentImporters/ImportShader.cpp b/Source/Engine/ContentImporters/ImportShader.cpp
index 9cfb1242c..bf5b5581d 100644
--- a/Source/Engine/ContentImporters/ImportShader.cpp
+++ b/Source/Engine/ContentImporters/ImportShader.cpp
@@ -32,14 +32,21 @@ CreateAssetResult ImportShader::Import(CreateAssetContext& context)
LOG(Warning, "Empty shader source file.");
return CreateAssetResult::Error;
}
+
+ // Ensure the source code has an empty line at the end (expected by glslang)
+ auto sourceCodeChunkSize = sourceCodeSize + 1;
+ if (sourceCodeText[sourceCodeSize - 1] != '\n')
+ sourceCodeChunkSize++;
+
const auto& sourceCodeChunk = context.Data.Header.Chunks[SourceCodeChunk];
- sourceCodeChunk->Data.Allocate(sourceCodeSize + 1);
+ sourceCodeChunk->Data.Allocate(sourceCodeChunkSize);
const auto sourceCode = sourceCodeChunk->Get();
Platform::MemoryCopy(sourceCode, sourceCodeText.Get(), sourceCodeSize);
+ sourceCode[sourceCodeChunkSize - 2] = '\n';
// Encrypt source code
- Encryption::EncryptBytes(sourceCode, sourceCodeSize);
- sourceCode[sourceCodeSize] = 0;
+ Encryption::EncryptBytes(sourceCode, sourceCodeChunkSize - 1);
+ sourceCode[sourceCodeChunkSize - 1] = 0;
// Set Custom Data with Header
ShaderStorage::Header20 shaderHeader;
diff --git a/Source/Engine/Core/Log.cpp b/Source/Engine/Core/Log.cpp
index fea72bfe8..e3d97e149 100644
--- a/Source/Engine/Core/Log.cpp
+++ b/Source/Engine/Core/Log.cpp
@@ -223,10 +223,10 @@ void Log::Logger::ProcessLogMessage(LogType type, const StringView& msg, fmt_fla
else
{
//w.append(msg.Get(), msg.Get() + msg.Length());
- fmt_flax::format(w, TEXT("{}"), (const Char*)msg.Get());
+ fmt_flax::format(w, TEXT("{}"), msg);
}
#else
- fmt_flax::format(w, TEXT("{}"), (const Char*)msg.Get());
+ fmt_flax::format(w, TEXT("{}"), msg);
#endif
}
@@ -251,19 +251,13 @@ void Log::Logger::Write(LogType type, const StringView& msg)
OnError(type, msg);
}
- // Check if need to show message box with that log message
- if (type == LogType::Fatal)
- {
+ // Ensure the error gets written to the disk
+ if (type == LogType::Fatal || type == LogType::Error)
Flush();
- // Process message further
- if (type == LogType::Fatal)
- Platform::Fatal(msg);
- else if (type == LogType::Error)
- Platform::Error(msg);
- else
- Platform::Info(msg);
- }
+ // Check if need to show message box with that log message
+ if (type == LogType::Fatal)
+ Platform::Fatal(msg);
}
const Char* ToString(LogType e)
diff --git a/Source/Engine/Core/Math/Vector2.cs b/Source/Engine/Core/Math/Vector2.cs
index 2af365638..568c51764 100644
--- a/Source/Engine/Core/Math/Vector2.cs
+++ b/Source/Engine/Core/Math/Vector2.cs
@@ -58,6 +58,7 @@ using Mathr = FlaxEngine.Mathf;
*/
using System;
using System.Globalization;
+using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -953,6 +954,91 @@ namespace FlaxEngine
return result;
}
+ ///
+ /// Performs a gradual change of a vector towards a specified target over time
+ ///
+ /// Current vector.
+ /// Target vector.
+ /// Used to store the current velocity.
+ /// Determines the approximate time it should take to reach the target vector.
+ /// Defines the upper limit on the speed of the Smooth Damp.
+ public static Vector2 SmoothDamp(Vector2 current, Vector2 target, ref Vector2 currentVelocity, float smoothTime, float maxSpeed)
+ {
+ return SmoothDamp(current, target, ref currentVelocity, smoothTime, maxSpeed, Time.DeltaTime);
+ }
+
+ ///
+ /// Performs a gradual change of a vector towards a specified target over time
+ ///
+ /// Current vector.
+ /// Target vector.
+ /// Used to store the current velocity.
+ /// Determines the approximate time it should take to reach the target vector.
+ public static Vector2 SmoothDamp(Vector2 current, Vector2 target, ref Vector2 currentVelocity, float smoothTime)
+ {
+ return SmoothDamp(current, target, ref currentVelocity, smoothTime, float.PositiveInfinity, Time.DeltaTime);
+ }
+
+ ///
+ /// Performs a gradual change of a vector towards a specified target over time
+ ///
+ /// Current vector.
+ /// Target vector.
+ /// Used to store the current velocity.
+ /// Determines the approximate time it should take to reach the target vector.
+ /// Defines the upper limit on the speed of the Smooth Damp.
+ /// Delta Time, represents the time elapsed since last frame.
+ public static Vector2 SmoothDamp(Vector2 current, Vector2 target, ref Vector2 currentVelocity, float smoothTime, [DefaultValue("float.PositiveInfinity")] float maxSpeed, [DefaultValue("Time.DeltaTime")] float deltaTime)
+ {
+ smoothTime = Mathf.Max(0.0001f, smoothTime);
+ Real a = 2f / smoothTime;
+ Real b = a * deltaTime;
+ Real e = 1f / (1f + b + 0.48f * b * b + 0.235f * b * b * b);
+
+ Real change_x = current.X - target.X;
+ Real change_y = current.Y - target.Y;
+ Vector2 originalTo = target;
+
+ Real maxChangeSpeed = maxSpeed * smoothTime;
+ Real changeSq = maxChangeSpeed * maxChangeSpeed;
+ Real sqrDist = change_x * change_x + change_y * change_y;
+ if (sqrDist > changeSq)
+ {
+ var dist = (Real)Math.Sqrt(sqrDist);
+ change_x = change_x / dist * maxChangeSpeed;
+ change_y = change_y / dist * maxChangeSpeed;
+ }
+
+ target.X = current.X - change_x;
+ target.Y = current.Y - change_y;
+
+ Real temp_x = (currentVelocity.X + a * change_x) * deltaTime;
+ Real temp_y = (currentVelocity.Y + a * change_y) * deltaTime;
+
+ currentVelocity.X = (currentVelocity.X - a * temp_x) * e;
+ currentVelocity.Y = (currentVelocity.Y - a * temp_y) * e;
+
+ Real output_x = target.X + (change_x + temp_x) * e;
+ Real output_y = target.Y + (change_y + temp_y) * e;
+
+ Real x1 = originalTo.X - current.X;
+ Real y1 = originalTo.Y - current.Y;
+
+ Real x2 = output_x - originalTo.X;
+ Real y2 = output_y - originalTo.Y;
+
+ if (x1 * x2 + y1 * y2 > 0)
+ {
+ output_x = originalTo.X;
+ output_y = originalTo.Y;
+
+ currentVelocity.X = (output_x - originalTo.X) / deltaTime;
+ currentVelocity.Y = (output_y - originalTo.Y) / deltaTime;
+ }
+
+ return new Vector2(output_x, output_y);
+ }
+
///
/// Performs a cubic interpolation between two vectors.
///
diff --git a/Source/Engine/Core/Math/Vector3.cs b/Source/Engine/Core/Math/Vector3.cs
index 4442d3334..59d1f63db 100644
--- a/Source/Engine/Core/Math/Vector3.cs
+++ b/Source/Engine/Core/Math/Vector3.cs
@@ -58,6 +58,7 @@ using Mathr = FlaxEngine.Mathf;
*/
using System;
using System.Globalization;
+using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -1042,6 +1043,103 @@ namespace FlaxEngine
return result;
}
+ ///
+ /// Performs a gradual change of a vector towards a specified target over time
+ ///
+ /// Current vector.
+ /// Target vector.
+ /// Used to store the current velocity.
+ /// Determines the approximate time it should take to reach the target vector.
+ /// Defines the upper limit on the speed of the Smooth Damp.
+ public static Vector3 SmoothDamp(Vector3 current, Vector3 target, ref Vector3 currentVelocity, float smoothTime, float maxSpeed)
+ {
+ return SmoothDamp(current, target, ref currentVelocity, smoothTime, maxSpeed, Time.DeltaTime);
+ }
+
+ ///
+ /// Performs a gradual change of a vector towards a specified target over time
+ ///
+ /// Current vector.
+ /// Target vector.
+ /// Used to store the current velocity.
+ /// Determines the approximate time it should take to reach the target vector.
+ public static Vector3 SmoothDamp(Vector3 current, Vector3 target, ref Vector3 currentVelocity, float smoothTime)
+ {
+ return SmoothDamp(current, target, ref currentVelocity, smoothTime, float.PositiveInfinity, Time.DeltaTime);
+ }
+
+ ///
+ /// Performs a gradual change of a vector towards a specified target over time
+ ///
+ /// Current vector.
+ /// Target vector.
+ /// Used to store the current velocity.
+ /// Determines the approximate time it should take to reach the target vector.
+ /// Defines the upper limit on the speed of the Smooth Damp.
+ /// Delta Time, represents the time elapsed since last frame.
+ public static Vector3 SmoothDamp(Vector3 current, Vector3 target, ref Vector3 currentVelocity, float smoothTime, [DefaultValue("float.PositiveInfinity")] float maxSpeed, [DefaultValue("Time.DeltaTime")] float deltaTime)
+ {
+ smoothTime = Mathf.Max(0.0001f, smoothTime);
+ Real a = 2f / smoothTime;
+ Real b = a * deltaTime;
+ Real e = 1f / (1f + b + 0.48f * b * b + 0.235f * b * b * b);
+
+ Real change_x = current.X - target.X;
+ Real change_y = current.Y - target.Y;
+ Real change_z = current.Z - target.Z;
+
+ Vector3 originalTo = target;
+
+ Real maxChangeSpeed = maxSpeed * smoothTime;
+ Real changeSq = maxChangeSpeed * maxChangeSpeed;
+ Real sqrLen = change_x * change_x + change_y * change_y + change_z * change_z;
+ if (sqrLen > changeSq)
+ {
+ var len = (Real)Math.Sqrt(sqrLen);
+ change_x = change_x / len * maxChangeSpeed;
+ change_y = change_y / len * maxChangeSpeed;
+ change_z = change_z / len * maxChangeSpeed;
+ }
+
+ target.X = current.X - change_x;
+ target.Y = current.Y - change_y;
+ target.Z = current.Z - change_z;
+
+ Real temp_x = (currentVelocity.X + a * change_x) * deltaTime;
+ Real temp_y = (currentVelocity.Y + a * change_y) * deltaTime;
+ Real temp_z = (currentVelocity.Z + a * change_z) * deltaTime;
+
+ currentVelocity.X = (currentVelocity.X - a * temp_x) * e;
+ currentVelocity.Y = (currentVelocity.Y - a * temp_y) * e;
+ currentVelocity.Z = (currentVelocity.Z - a * temp_z) * e;
+
+ Real output_x = target.X + (change_x + temp_x) * e;
+ Real output_y = target.Y + (change_y + temp_y) * e;
+ Real output_z = target.Z + (change_z + temp_z) * e;
+
+ Real x1 = originalTo.X - current.X;
+ Real y1 = originalTo.Y - current.Y;
+ Real z1 = originalTo.Z - current.Z;
+
+ Real x2 = output_x - originalTo.X;
+ Real y2 = output_y - originalTo.Y;
+ Real z2 = output_z - originalTo.Z;
+
+ if (x1 * x2 + y1 * y2 + z1 * z2 > 0)
+ {
+ output_x = originalTo.X;
+ output_y = originalTo.Y;
+ output_z = originalTo.Z;
+
+ currentVelocity.X = (output_x - originalTo.X) / deltaTime;
+ currentVelocity.Y = (output_y - originalTo.Y) / deltaTime;
+ currentVelocity.Z = (output_z - originalTo.Z) / deltaTime;
+ }
+
+ return new Vector3(output_x, output_y, output_z);
+ }
+
+
///
/// Performs a cubic interpolation between two vectors.
///
diff --git a/Source/Engine/Core/Types/String.cpp b/Source/Engine/Core/Types/String.cpp
index e53f04af7..dab000873 100644
--- a/Source/Engine/Core/Types/String.cpp
+++ b/Source/Engine/Core/Types/String.cpp
@@ -72,7 +72,7 @@ void String::Set(const char* chars, int32 length)
}
_length = length;
}
- if (chars)
+ if (chars && length)
StringUtils::ConvertANSI2UTF16(chars, _data, length, _length);
}
@@ -298,8 +298,10 @@ String String::TrimTrailing() const
end--;
}
- ASSERT_LOW_LAYER(end >= start);
- return Substring(start, end - start + 1);
+ const int32 count = end - start + 1;
+ if (start >= 0 && start + count <= Length() && count >= 0)
+ return String(_data + start, count);
+ return Empty;
}
String& String::operator/=(const Char* str)
diff --git a/Source/Engine/Engine/Engine.cpp b/Source/Engine/Engine/Engine.cpp
index bafcd30b3..ec56861ba 100644
--- a/Source/Engine/Engine/Engine.cpp
+++ b/Source/Engine/Engine/Engine.cpp
@@ -102,9 +102,6 @@ int32 Engine::Main(const Char* cmdLine)
Platform::SetHighDpiAwarenessEnabled(!CommandLine::Options.LowDPI.IsTrue());
Time::StartupTime = DateTime::Now();
-#if COMPILE_WITH_PROFILER
- ProfilerCPU::Enabled = true;
-#endif
Globals::StartupFolder = Globals::BinariesFolder = Platform::GetMainDirectory();
#if USE_EDITOR
Globals::StartupFolder /= TEXT("../../../..");
diff --git a/Source/Engine/Engine/NativeInterop.Invoker.cs b/Source/Engine/Engine/NativeInterop.Invoker.cs
index 381e6dac0..36d7f2e03 100644
--- a/Source/Engine/Engine/NativeInterop.Invoker.cs
+++ b/Source/Engine/Engine/NativeInterop.Invoker.cs
@@ -84,7 +84,7 @@ namespace FlaxEngine.Interop
internal static IntPtr MarshalReturnValueType(ref Type returnValue)
{
- return returnValue != null ? ManagedHandle.ToIntPtr(GetTypeGCHandle(returnValue)) : IntPtr.Zero;
+ return returnValue != null ? ManagedHandle.ToIntPtr(GetTypeManagedHandle(returnValue)) : IntPtr.Zero;
}
internal static IntPtr MarshalReturnValueArray(ref TRet returnValue)
@@ -162,8 +162,8 @@ namespace FlaxEngine.Interop
return ManagedHandle.ToIntPtr((ManagedHandle)(object)returnObject);
if (returnType == typeof(bool))
return (bool)returnObject ? boolTruePtr : boolFalsePtr;
- if (returnType == typeof(Type))
- return ManagedHandle.ToIntPtr(GetTypeGCHandle(Unsafe.As(returnObject)));
+ if (returnType == typeof(Type) || returnType == typeof(TypeHolder))
+ return ManagedHandle.ToIntPtr(GetTypeManagedHandle(Unsafe.As(returnObject)));
if (returnType.IsArray && ArrayFactory.GetMarshalledType(returnType.GetElementType()) == returnType.GetElementType())
return ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(Unsafe.As(returnObject)), GCHandleType.Weak);
if (returnType.IsArray)
@@ -186,8 +186,8 @@ namespace FlaxEngine.Interop
return (IntPtr)(object)returnObject;
if (returnType == typeof(ManagedHandle))
return ManagedHandle.ToIntPtr((ManagedHandle)(object)returnObject);
- if (returnType == typeof(Type))
- return returnObject != null ? ManagedHandle.ToIntPtr(GetTypeGCHandle(Unsafe.As(returnObject))) : IntPtr.Zero;
+ if (returnType == typeof(Type) || returnType == typeof(TypeHolder))
+ return returnObject != null ? ManagedHandle.ToIntPtr(GetTypeManagedHandle(Unsafe.As(returnObject))) : IntPtr.Zero;
if (returnType.IsArray)
{
var elementType = returnType.GetElementType();
diff --git a/Source/Engine/Engine/NativeInterop.Marshallers.cs b/Source/Engine/Engine/NativeInterop.Marshallers.cs
index 74d6e6bad..58aa95a2f 100644
--- a/Source/Engine/Engine/NativeInterop.Marshallers.cs
+++ b/Source/Engine/Engine/NativeInterop.Marshallers.cs
@@ -32,6 +32,7 @@ namespace FlaxEngine.Interop
public static class NativeToManaged
{
public static object ConvertToManaged(IntPtr unmanaged) => unmanaged == IntPtr.Zero ? null : ManagedHandle.FromIntPtr(unmanaged).Target;
+ public static IntPtr ConvertToUnmanaged(object managed) => managed != null ? ManagedHandle.ToIntPtr(managed, GCHandleType.Weak) : IntPtr.Zero;
public static void Free(IntPtr unmanaged)
{
@@ -44,6 +45,7 @@ namespace FlaxEngine.Interop
#endif
public static class ManagedToNative
{
+ public static object ConvertToManaged(IntPtr unmanaged) => unmanaged == IntPtr.Zero ? null : ManagedHandle.FromIntPtr(unmanaged).Target;
public static IntPtr ConvertToUnmanaged(object managed) => managed != null ? ManagedHandle.ToIntPtr(managed, GCHandleType.Weak) : IntPtr.Zero;
public static void Free(IntPtr unmanaged)
@@ -117,13 +119,13 @@ namespace FlaxEngine.Interop
[CustomMarshaller(typeof(Type), MarshalMode.Default, typeof(SystemTypeMarshaller))]
public static class SystemTypeMarshaller
{
- public static Type ConvertToManaged(IntPtr unmanaged) => Unsafe.As(ManagedHandleMarshaller.ConvertToManaged(unmanaged));
+ public static Type ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As(ManagedHandleMarshaller.ConvertToManaged(unmanaged)).type : null;
public static IntPtr ConvertToUnmanaged(Type managed)
{
if (managed == null)
return IntPtr.Zero;
- ManagedHandle handle = NativeInterop.GetTypeGCHandle(managed);
+ ManagedHandle handle = NativeInterop.GetTypeManagedHandle(managed);
return ManagedHandle.ToIntPtr(handle);
}
@@ -147,29 +149,16 @@ namespace FlaxEngine.Interop
#if FLAX_EDITOR
[HideInEditor]
#endif
- [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedIn, typeof(ObjectMarshaller.ManagedToNative))]
- [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedOut, typeof(ObjectMarshaller.ManagedToNative))]
- [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementIn, typeof(ObjectMarshaller.ManagedToNative))]
- [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedOut, typeof(ObjectMarshaller.NativeToManaged))]
- [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedIn, typeof(ObjectMarshaller.NativeToManaged))]
- [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementOut, typeof(ObjectMarshaller.NativeToManaged))]
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedIn, typeof(ObjectMarshaller))]
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedOut, typeof(ObjectMarshaller))]
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementIn, typeof(ObjectMarshaller))]
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ManagedToUnmanagedOut, typeof(ObjectMarshaller))]
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.UnmanagedToManagedIn, typeof(ObjectMarshaller))]
+ [CustomMarshaller(typeof(FlaxEngine.Object), MarshalMode.ElementOut, typeof(ObjectMarshaller))]
public static class ObjectMarshaller
{
-#if FLAX_EDITOR
- [HideInEditor]
-#endif
- public static class NativeToManaged
- {
- public static FlaxEngine.Object ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As(ManagedHandle.FromIntPtr(unmanaged).Target) : null;
- }
-
-#if FLAX_EDITOR
- [HideInEditor]
-#endif
- public static class ManagedToNative
- {
- public static IntPtr ConvertToUnmanaged(FlaxEngine.Object managed) => Unsafe.As