Merge branch 'FlaxEngine:master' into visject_grid_snap
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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.",
|
||||
|
||||
@@ -291,6 +291,8 @@
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=lightmaps/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Linearize/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=lods/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Marshallable/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=marshallers/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=mclass/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=memcpy/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=metalness/@EntryIndexedValue">True</s:Boolean>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
private DragHandlers _dragHandlers;
|
||||
private DragScriptItems _dragScripts;
|
||||
private DragAssets _dragAssets;
|
||||
private Button _addScriptsButton;
|
||||
|
||||
/// <summary>
|
||||
/// 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;
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DisplayStyle Style => DisplayStyle.Inline;
|
||||
@@ -20,23 +22,30 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var dropdownElement = layout.Custom<Dropdown>();
|
||||
_dropdown = dropdownElement.CustomControl;
|
||||
var names = new List<LocalizedString>();
|
||||
LinkedLabel.SetupContextMenu += OnSetupContextMenu;
|
||||
var comboBoxElement = layout.ComboBox();
|
||||
_comboBox = comboBoxElement.ComboBox;
|
||||
var names = new List<string>();
|
||||
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));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DisplayStyle Style => DisplayStyle.Inline;
|
||||
@@ -77,23 +90,30 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
var dropdownElement = layout.Custom<Dropdown>();
|
||||
_dropdown = dropdownElement.CustomControl;
|
||||
var names = new List<LocalizedString>();
|
||||
LinkedLabel.SetupContextMenu += OnSetupContextMenu;
|
||||
var comboBoxElement = layout.ComboBox();
|
||||
_comboBox = comboBoxElement.ComboBox;
|
||||
var names = new List<string>();
|
||||
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));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Tag>)
|
||||
else if (Values[0] is List<Tag> || Values.Type.Type == typeof(List<Tag>))
|
||||
SetValue(new List<Tag>(value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bakes all environmental probes in the scene.
|
||||
/// </summary>
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds CSG for all open scenes.
|
||||
/// </summary>
|
||||
public void BuildCSG()
|
||||
{
|
||||
var scenes = Level.Scenes;
|
||||
scenes.ToList().ForEach(x => x.BuildCSG(0));
|
||||
Scene.MarkSceneEdited(scenes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds Nav mesh for all open scenes.
|
||||
/// </summary>
|
||||
public void BuildNavMesh()
|
||||
{
|
||||
var scenes = Level.Scenes;
|
||||
scenes.ToList().ForEach(x => Navigation.BuildNavMesh(x, 0));
|
||||
Scene.MarkSceneEdited(scenes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds SDF for all static models in the scene.
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the button.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="binding">The input binding.</param>
|
||||
/// <param name="clicked">On button clicked event.</param>
|
||||
/// <returns>Created context menu item control.</returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the child menu (with that name).
|
||||
/// </summary>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace FlaxEditor.GUI.Timeline
|
||||
/// </summary>
|
||||
public SceneAnimationPlayer Player
|
||||
{
|
||||
get => _player;
|
||||
get => _player != null ? _player : null;
|
||||
set
|
||||
{
|
||||
if (_player == value)
|
||||
@@ -268,7 +268,7 @@ namespace FlaxEditor.GUI.Timeline
|
||||
/// <inheritdoc />
|
||||
public override void OnSeek(int frame)
|
||||
{
|
||||
if (_player?.Animation)
|
||||
if (_player != null && _player.Animation)
|
||||
{
|
||||
_player.Animation.WaitForLoaded();
|
||||
_player.Time = frame / _player.Animation.FramesPerSecond;
|
||||
|
||||
@@ -643,7 +643,8 @@ namespace FlaxEditor.Modules
|
||||
/// Deletes the specified item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
public void Delete(ContentItem item)
|
||||
/// <param name="deletedByUser">If the file was deleted by the user and not outside the editor.</param>
|
||||
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--;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -129,6 +129,7 @@ namespace FlaxEditor.Modules
|
||||
else
|
||||
{
|
||||
Editor.UI.UpdateProgress(string.Empty, 0);
|
||||
Editor.UI.UpdateStatusBar();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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<KeyboardKeys, bool> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes this input binding to check if state matches.
|
||||
/// </summary>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -165,20 +213,20 @@ namespace FlaxEditor.Options
|
||||
/// <returns>True if input has been processed, otherwise false.</returns>
|
||||
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;
|
||||
/// <summary>
|
||||
/// Processes this input binding to check if state matches.
|
||||
/// </summary>
|
||||
/// <param name="window">The input providing window.</param>
|
||||
/// <returns>True if input has been processed, otherwise false.</returns>
|
||||
public bool Process(Window window)
|
||||
{
|
||||
return window.GetKey(Key) && ProcessModifiers(window);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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<CodeEditor*>* 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<CodeEditor*>* 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<CodeEditor*>* 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<CodeEditor*>* output)
|
||||
TEXT("flatpak run com.jetbrains.Rider"));
|
||||
#endif
|
||||
|
||||
for (auto directory : subDirectories)
|
||||
#if PLATFORM_MAC
|
||||
String applicationSupportFolder;
|
||||
FileSystem::GetSpecialFolderPath(SpecialFolder::ProgramData, applicationSupportFolder);
|
||||
|
||||
Array<String> 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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a point intersects a connection
|
||||
/// </summary>
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -69,6 +69,11 @@ namespace FlaxEditor.Surface
|
||||
/// </summary>
|
||||
protected bool _rightMouseDown;
|
||||
|
||||
/// <summary>
|
||||
/// The middle mouse down flag.
|
||||
/// </summary>
|
||||
protected bool _middleMouseDown;
|
||||
|
||||
/// <summary>
|
||||
/// The left mouse down position.
|
||||
/// </summary>
|
||||
@@ -79,6 +84,11 @@ namespace FlaxEditor.Surface
|
||||
/// </summary>
|
||||
protected Float2 _rightMouseDownPos = Float2.Minimum;
|
||||
|
||||
/// <summary>
|
||||
/// The middle mouse down position.
|
||||
/// </summary>
|
||||
protected Float2 _middleMouseDownPos = Float2.Minimum;
|
||||
|
||||
/// <summary>
|
||||
/// The mouse position.
|
||||
/// </summary>
|
||||
@@ -912,7 +922,7 @@ namespace FlaxEditor.Surface
|
||||
{
|
||||
return _context.FindNode(id);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds the undo action to be batched (eg. if multiple undo actions is performed in a sequence during single update).
|
||||
/// </summary>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -544,7 +544,7 @@ namespace FlaxEditor.Tools
|
||||
public override bool IsControllingMouse => IsPainting;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override BoundingSphere FocusBounds => _selectedModel?.Sphere ?? base.FocusBounds;
|
||||
public override BoundingSphere FocusBounds => _selectedModel != null ? _selectedModel.Sphere : base.FocusBounds;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(float dt)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds global input actions for the window.
|
||||
/// </summary>
|
||||
/// <param name="window">The editor window.</param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increases or decreases the camera movement speed.
|
||||
/// </summary>
|
||||
/// <param name="step">The stepping direction for speed adjustment.</param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -194,6 +194,7 @@ namespace FlaxEditor.Viewport
|
||||
{
|
||||
_editor = editor;
|
||||
_dragAssets = new DragAssets<DragDropEventArgs>(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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace FlaxEditor.Viewport.Previews
|
||||
/// </summary>
|
||||
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
|
||||
/// </summary>
|
||||
public bool ShowOrigin
|
||||
{
|
||||
get => _originModel?.IsActive ?? false;
|
||||
get => _originModel != null ? _originModel.IsActive : false;
|
||||
set
|
||||
{
|
||||
if (value == ShowOrigin)
|
||||
|
||||
@@ -500,7 +500,7 @@ namespace FlaxEditor.Viewport.Previews
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -549,7 +549,7 @@ namespace FlaxEditor.Viewport.Previews
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -604,7 +604,7 @@ namespace FlaxEditor.Viewport.Previews
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -659,7 +659,7 @@ namespace FlaxEditor.Viewport.Previews
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -216,5 +216,36 @@ namespace FlaxEditor.Windows
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +192,13 @@ namespace FlaxEditor.Windows
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the event name.
|
||||
/// </summary>
|
||||
public unsafe string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
fixed (byte* name = Name0)
|
||||
return System.Runtime.InteropServices.Marshal.PtrToStringAnsi(new IntPtr(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace FlaxEditor.Windows.Profiler
|
||||
{
|
||||
/// <summary>
|
||||
@@ -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<ProfilingTools.NetworkEventStat[]> _events;
|
||||
private List<Row> _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");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -60,21 +87,30 @@ namespace FlaxEditor.Windows.Profiler
|
||||
{
|
||||
_dataSentChart.Clear();
|
||||
_dataReceivedChart.Clear();
|
||||
_events?.Clear();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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<ProfilingTools.NetworkEventStat[]>();
|
||||
_events.Add(events);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -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<Row>();
|
||||
_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();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recycles all table rows to be reused.
|
||||
/// </summary>
|
||||
/// <param name="table">The table.</param>
|
||||
/// <param name="rowsCache">The output cache.</param>
|
||||
protected static void RecycleTableRows(Table table, List<Row> 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -49,6 +49,8 @@ namespace FlaxEditor.Windows.Profiler
|
||||
/// <returns>The sample value</returns>
|
||||
public T Get(int index)
|
||||
{
|
||||
if (index >= _data.Length || _data.Length == 0)
|
||||
return default;
|
||||
return index == -1 ? _data[_count - 1] : _data[index];
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -173,6 +173,9 @@ namespace FlaxEditor.Windows
|
||||
|
||||
// Spawn it
|
||||
Editor.SceneEditing.Spawn(actor, parentActor);
|
||||
|
||||
Editor.SceneEditing.Select(actor);
|
||||
Rename();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -353,6 +353,8 @@ namespace FlaxEditor.Windows
|
||||
: base(editor, true, ScrollBars.None)
|
||||
{
|
||||
Title = "Toolbox";
|
||||
|
||||
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a gradual change of a vector towards a specified target over time
|
||||
/// </summary>
|
||||
/// <param name="current">Current vector.</param>
|
||||
/// <param name="target">Target vector.</param>
|
||||
/// <param name="currentVelocity">Used to store the current velocity.</param>
|
||||
/// <param name="smoothTime">Determines the approximate time it should take to reach the target vector.</param>
|
||||
/// <param name="maxSpeed">Defines the upper limit on the speed of the Smooth Damp.</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a gradual change of a vector towards a specified target over time
|
||||
/// </summary>
|
||||
/// <param name="current">Current vector.</param>
|
||||
/// <param name="target">Target vector.</param>
|
||||
/// <param name="currentVelocity">Used to store the current velocity.</param>
|
||||
/// <param name="smoothTime">Determines the approximate time it should take to reach the target vector.</param>
|
||||
public static Vector2 SmoothDamp(Vector2 current, Vector2 target, ref Vector2 currentVelocity, float smoothTime)
|
||||
{
|
||||
return SmoothDamp(current, target, ref currentVelocity, smoothTime, float.PositiveInfinity, Time.DeltaTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a gradual change of a vector towards a specified target over time
|
||||
/// </summary>
|
||||
/// <param name="current">Current vector.</param>
|
||||
/// <param name="target">Target vector.</param>
|
||||
/// <param name="currentVelocity">Used to store the current velocity.</param>
|
||||
/// <param name="smoothTime">Determines the approximate time it should take to reach the target vector.</param>
|
||||
/// <param name="maxSpeed">Defines the upper limit on the speed of the Smooth Damp.</param>
|
||||
/// <param name="deltaTime">Delta Time, represents the time elapsed since last frame.</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a cubic interpolation between two vectors.
|
||||
/// </summary>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a gradual change of a vector towards a specified target over time
|
||||
/// </summary>
|
||||
/// <param name="current">Current vector.</param>
|
||||
/// <param name="target">Target vector.</param>
|
||||
/// <param name="currentVelocity">Used to store the current velocity.</param>
|
||||
/// <param name="smoothTime">Determines the approximate time it should take to reach the target vector.</param>
|
||||
/// <param name="maxSpeed">Defines the upper limit on the speed of the Smooth Damp.</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a gradual change of a vector towards a specified target over time
|
||||
/// </summary>
|
||||
/// <param name="current">Current vector.</param>
|
||||
/// <param name="target">Target vector.</param>
|
||||
/// <param name="currentVelocity">Used to store the current velocity.</param>
|
||||
/// <param name="smoothTime">Determines the approximate time it should take to reach the target vector.</param>
|
||||
public static Vector3 SmoothDamp(Vector3 current, Vector3 target, ref Vector3 currentVelocity, float smoothTime)
|
||||
{
|
||||
return SmoothDamp(current, target, ref currentVelocity, smoothTime, float.PositiveInfinity, Time.DeltaTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a gradual change of a vector towards a specified target over time
|
||||
/// </summary>
|
||||
/// <param name="current">Current vector.</param>
|
||||
/// <param name="target">Target vector.</param>
|
||||
/// <param name="currentVelocity">Used to store the current velocity.</param>
|
||||
/// <param name="smoothTime">Determines the approximate time it should take to reach the target vector.</param>
|
||||
/// <param name="maxSpeed">Defines the upper limit on the speed of the Smooth Damp.</param>
|
||||
/// <param name="deltaTime">Delta Time, represents the time elapsed since last frame.</param>
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Performs a cubic interpolation between two vectors.
|
||||
/// </summary>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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("../../../..");
|
||||
|
||||
@@ -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<TRet>(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<Type>(returnObject)));
|
||||
if (returnType == typeof(Type) || returnType == typeof(TypeHolder))
|
||||
return ManagedHandle.ToIntPtr(GetTypeManagedHandle(Unsafe.As<Type>(returnObject)));
|
||||
if (returnType.IsArray && ArrayFactory.GetMarshalledType(returnType.GetElementType()) == returnType.GetElementType())
|
||||
return ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(Unsafe.As<Array>(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<Type>(returnObject))) : IntPtr.Zero;
|
||||
if (returnType == typeof(Type) || returnType == typeof(TypeHolder))
|
||||
return returnObject != null ? ManagedHandle.ToIntPtr(GetTypeManagedHandle(Unsafe.As<Type>(returnObject))) : IntPtr.Zero;
|
||||
if (returnType.IsArray)
|
||||
{
|
||||
var elementType = returnType.GetElementType();
|
||||
|
||||
@@ -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<Type>(ManagedHandleMarshaller.ConvertToManaged(unmanaged));
|
||||
public static Type ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As<FlaxEngine.Interop.NativeInterop.TypeHolder>(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<FlaxEngine.Object>(ManagedHandle.FromIntPtr(unmanaged).Target) : null;
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
[HideInEditor]
|
||||
#endif
|
||||
public static class ManagedToNative
|
||||
{
|
||||
public static IntPtr ConvertToUnmanaged(FlaxEngine.Object managed) => Unsafe.As<object>(managed) != null ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero;
|
||||
}
|
||||
public static FlaxEngine.Object ConvertToManaged(IntPtr unmanaged) => unmanaged != IntPtr.Zero ? Unsafe.As<FlaxEngine.Object>(ManagedHandle.FromIntPtr(unmanaged).Target) : null;
|
||||
public static IntPtr ConvertToUnmanaged(FlaxEngine.Object managed) => Unsafe.As<object>(managed) != null ? ManagedHandle.ToIntPtr(managed) : IntPtr.Zero;
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
@@ -342,6 +331,7 @@ namespace FlaxEngine.Interop
|
||||
public static class NativeToManaged
|
||||
{
|
||||
public static Dictionary<T, U> ConvertToManaged(IntPtr unmanaged) => DictionaryMarshaller<T, U>.ToManaged(unmanaged);
|
||||
public static IntPtr ConvertToUnmanaged(Dictionary<T, U> managed) => DictionaryMarshaller<T, U>.ToNative(managed, GCHandleType.Weak);
|
||||
public static void Free(IntPtr unmanaged) => DictionaryMarshaller<T, U>.Free(unmanaged);
|
||||
}
|
||||
|
||||
@@ -350,8 +340,8 @@ namespace FlaxEngine.Interop
|
||||
#endif
|
||||
public static class ManagedToNative
|
||||
{
|
||||
public static Dictionary<T, U> ConvertToManaged(IntPtr unmanaged) => DictionaryMarshaller<T, U>.ToManaged(unmanaged);
|
||||
public static IntPtr ConvertToUnmanaged(Dictionary<T, U> managed) => DictionaryMarshaller<T, U>.ToNative(managed, GCHandleType.Weak);
|
||||
|
||||
public static void Free(IntPtr unmanaged)
|
||||
{
|
||||
//DictionaryMarshaller<T, U>.Free(unmanaged); // No need to free weak handles
|
||||
@@ -425,6 +415,28 @@ namespace FlaxEngine.Interop
|
||||
return new T[numElements];
|
||||
}
|
||||
|
||||
public static TUnmanagedElement* AllocateContainerForUnmanagedElements(T[] managed, out int numElements)
|
||||
{
|
||||
if (managed is null)
|
||||
{
|
||||
numElements = 0;
|
||||
return null;
|
||||
}
|
||||
numElements = managed.Length;
|
||||
(ManagedHandle managedArrayHandle, _) = ManagedArray.AllocatePooledArray<TUnmanagedElement>(managed.Length);
|
||||
return (TUnmanagedElement*)ManagedHandle.ToIntPtr(managedArrayHandle);
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed) => managed;
|
||||
|
||||
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(TUnmanagedElement* unmanaged)
|
||||
{
|
||||
if (unmanaged == null)
|
||||
return Span<TUnmanagedElement>.Empty;
|
||||
ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(new IntPtr(unmanaged)).Target);
|
||||
return managedArray.ToSpan<TUnmanagedElement>();
|
||||
}
|
||||
|
||||
public static Span<T> GetManagedValuesDestination(T[] managed) => managed;
|
||||
|
||||
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(TUnmanagedElement* unmanaged, int numElements)
|
||||
@@ -591,6 +603,7 @@ namespace FlaxEngine.Interop
|
||||
public static class NativeToManaged
|
||||
{
|
||||
public static string ConvertToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
|
||||
public static unsafe IntPtr ConvertToUnmanaged(string managed) => managed == null ? IntPtr.Zero : ManagedHandle.ToIntPtr(managed, GCHandleType.Weak);
|
||||
public static void Free(IntPtr unmanaged) => ManagedString.Free(unmanaged);
|
||||
}
|
||||
|
||||
@@ -599,11 +612,8 @@ namespace FlaxEngine.Interop
|
||||
#endif
|
||||
public static class ManagedToNative
|
||||
{
|
||||
public static unsafe IntPtr ConvertToUnmanaged(string managed)
|
||||
{
|
||||
return managed == null ? IntPtr.Zero : ManagedHandle.ToIntPtr(managed, GCHandleType.Weak);
|
||||
}
|
||||
|
||||
public static string ConvertToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
|
||||
public static unsafe IntPtr ConvertToUnmanaged(string managed) => managed == null ? IntPtr.Zero : ManagedHandle.ToIntPtr(managed, GCHandleType.Weak);
|
||||
public static void Free(IntPtr unmanaged)
|
||||
{
|
||||
//ManagedString.Free(unmanaged); // No need to free weak handles
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace FlaxEngine.Interop
|
||||
internal struct NativeClassDefinitions
|
||||
{
|
||||
internal ManagedHandle typeHandle;
|
||||
internal IntPtr nativePointer;
|
||||
internal IntPtr name;
|
||||
internal IntPtr fullname;
|
||||
internal IntPtr @namespace;
|
||||
@@ -40,6 +41,7 @@ namespace FlaxEngine.Interop
|
||||
internal IntPtr name;
|
||||
internal ManagedHandle fieldHandle;
|
||||
internal ManagedHandle fieldTypeHandle;
|
||||
internal int fieldOffset;
|
||||
internal uint fieldAttributes;
|
||||
}
|
||||
|
||||
@@ -139,6 +141,9 @@ namespace FlaxEngine.Interop
|
||||
|
||||
unsafe partial class NativeInterop
|
||||
{
|
||||
[LibraryImport("FlaxEngine", EntryPoint = "NativeInterop_CreateClass", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(Interop.StringMarshaller))]
|
||||
internal static partial void NativeInterop_CreateClass(ref NativeClassDefinitions managedClass, ManagedHandle assemblyHandle);
|
||||
|
||||
internal enum MTypes : uint
|
||||
{
|
||||
End = 0x00,
|
||||
@@ -184,7 +189,7 @@ namespace FlaxEngine.Interop
|
||||
{
|
||||
string moduleName = Marshal.PtrToStringAnsi(moduleNamePtr);
|
||||
string modulePath = Marshal.PtrToStringAnsi(modulePathPtr);
|
||||
nativeLibraryPaths[moduleName] = modulePath;
|
||||
libraryPaths[moduleName] = modulePath;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
@@ -205,46 +210,8 @@ namespace FlaxEngine.Interop
|
||||
NativeMemory.AlignedFree(ptr);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void GetManagedClasses(ManagedHandle assemblyHandle, NativeClassDefinitions** managedClasses, int* managedClassCount)
|
||||
private static Assembly GetOwningAssembly(Type type)
|
||||
{
|
||||
Assembly assembly = Unsafe.As<Assembly>(assemblyHandle.Target);
|
||||
var assemblyTypes = GetAssemblyTypes(assembly);
|
||||
|
||||
NativeClassDefinitions* arr = (NativeClassDefinitions*)NativeAlloc(assemblyTypes.Length, Unsafe.SizeOf<NativeClassDefinitions>());
|
||||
|
||||
for (int i = 0; i < assemblyTypes.Length; i++)
|
||||
{
|
||||
var type = assemblyTypes[i];
|
||||
IntPtr ptr = IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf<NativeClassDefinitions>() * i);
|
||||
var managedClass = new NativeClassDefinitions
|
||||
{
|
||||
typeHandle = GetTypeGCHandle(type),
|
||||
name = NativeAllocStringAnsi(type.Name),
|
||||
fullname = NativeAllocStringAnsi(type.GetTypeName()),
|
||||
@namespace = NativeAllocStringAnsi(type.Namespace ?? ""),
|
||||
typeAttributes = (uint)type.Attributes,
|
||||
};
|
||||
Unsafe.Write(ptr.ToPointer(), managedClass);
|
||||
}
|
||||
|
||||
*managedClasses = arr;
|
||||
*managedClassCount = assemblyTypes.Length;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void GetManagedClassFromType(ManagedHandle typeHandle, NativeClassDefinitions* managedClass, ManagedHandle* assemblyHandle)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
*managedClass = new NativeClassDefinitions
|
||||
{
|
||||
typeHandle = GetTypeGCHandle(type),
|
||||
name = NativeAllocStringAnsi(type.Name),
|
||||
fullname = NativeAllocStringAnsi(type.GetTypeName()),
|
||||
@namespace = NativeAllocStringAnsi(type.Namespace ?? ""),
|
||||
typeAttributes = (uint)type.Attributes,
|
||||
};
|
||||
|
||||
Assembly assembly = null;
|
||||
if (type.IsGenericType && !type.Assembly.IsCollectible)
|
||||
{
|
||||
@@ -261,14 +228,87 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
if (assembly == null)
|
||||
assembly = type.Assembly;
|
||||
return assembly;
|
||||
}
|
||||
|
||||
*assemblyHandle = GetAssemblyHandle(assembly);
|
||||
private static NativeClassDefinitions CreateNativeClassDefinitions(Type type, out ManagedHandle assemblyHandle)
|
||||
{
|
||||
assemblyHandle = GetAssemblyHandle(GetOwningAssembly(type));
|
||||
return CreateNativeClassDefinitions(type);
|
||||
}
|
||||
|
||||
private static NativeClassDefinitions CreateNativeClassDefinitions(Type type)
|
||||
{
|
||||
return new NativeClassDefinitions()
|
||||
{
|
||||
typeHandle = RegisterType(type).handle,
|
||||
name = NativeAllocStringAnsi(type.Name),
|
||||
fullname = NativeAllocStringAnsi(type.GetTypeName()),
|
||||
@namespace = NativeAllocStringAnsi(type.Namespace ?? ""),
|
||||
typeAttributes = (uint)type.Attributes,
|
||||
};
|
||||
}
|
||||
|
||||
private static NativeClassDefinitions CreateNativeClassDefinitions(Type type, ManagedHandle typeHandle, out ManagedHandle assemblyHandle)
|
||||
{
|
||||
assemblyHandle = GetAssemblyHandle(GetOwningAssembly(type));
|
||||
return new NativeClassDefinitions()
|
||||
{
|
||||
typeHandle = typeHandle,
|
||||
name = NativeAllocStringAnsi(type.Name),
|
||||
fullname = NativeAllocStringAnsi(type.GetTypeName()),
|
||||
@namespace = NativeAllocStringAnsi(type.Namespace ?? ""),
|
||||
typeAttributes = (uint)type.Attributes,
|
||||
};
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void GetManagedClasses(ManagedHandle assemblyHandle, NativeClassDefinitions** managedClasses, int* managedClassCount)
|
||||
{
|
||||
Assembly assembly = Unsafe.As<Assembly>(assemblyHandle.Target);
|
||||
Type[] assemblyTypes = GetAssemblyTypes(assembly);
|
||||
|
||||
*managedClasses = (NativeClassDefinitions*)NativeAlloc(assemblyTypes.Length, Unsafe.SizeOf<NativeClassDefinitions>());
|
||||
*managedClassCount = assemblyTypes.Length;
|
||||
Span<NativeClassDefinitions> span = new Span<NativeClassDefinitions>(*managedClasses, assemblyTypes.Length);
|
||||
for (int i = 0; i < assemblyTypes.Length; i++)
|
||||
{
|
||||
Type type = assemblyTypes[i];
|
||||
ref var managedClass = ref span[i];
|
||||
managedClass = CreateNativeClassDefinitions(type);
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void RegisterManagedClassNativePointers(NativeClassDefinitions** managedClasses, int managedClassCount)
|
||||
{
|
||||
Span<NativeClassDefinitions> span = new Span<NativeClassDefinitions>(Unsafe.Read<IntPtr>(managedClasses).ToPointer(), managedClassCount);
|
||||
foreach (ref NativeClassDefinitions managedClass in span)
|
||||
{
|
||||
TypeHolder typeHolder = Unsafe.As<TypeHolder>(managedClass.typeHandle.Target);
|
||||
typeHolder.managedClassPointer = managedClass.nativePointer;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void GetManagedClassFromType(ManagedHandle typeHandle, NativeClassDefinitions* managedClass, ManagedHandle* assemblyHandle)
|
||||
{
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
*managedClass = CreateNativeClassDefinitions(type, out ManagedHandle handle);
|
||||
*assemblyHandle = handle;
|
||||
}
|
||||
|
||||
private static void RegisterNativeClassFromType(TypeHolder typeHolder, ManagedHandle typeHandle)
|
||||
{
|
||||
NativeClassDefinitions managedClass = CreateNativeClassDefinitions(typeHolder.type, typeHandle, out ManagedHandle assemblyHandle);
|
||||
NativeInterop_CreateClass(ref managedClass, assemblyHandle);
|
||||
typeHolder.managedClassPointer = managedClass.nativePointer;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void GetClassMethods(ManagedHandle typeHandle, NativeMethodDefinitions** classMethods, int* classMethodsCount)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
|
||||
var methods = new List<MethodInfo>();
|
||||
var staticMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
|
||||
@@ -296,8 +336,8 @@ namespace FlaxEngine.Interop
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void GetClassFields(ManagedHandle typeHandle, NativeFieldDefinitions** classFields, int* classFieldsCount)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
var fields = type.GetFields(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
|
||||
NativeFieldDefinitions* arr = (NativeFieldDefinitions*)NativeAlloc(fields.Length, Unsafe.SizeOf<NativeFieldDefinitions>());
|
||||
for (int i = 0; i < fields.Length; i++)
|
||||
@@ -318,7 +358,8 @@ namespace FlaxEngine.Interop
|
||||
{
|
||||
name = NativeAllocStringAnsi(fieldHolder.field.Name),
|
||||
fieldHandle = fieldHandle,
|
||||
fieldTypeHandle = GetTypeGCHandle(fieldHolder.field.FieldType),
|
||||
fieldTypeHandle = GetTypeManagedHandle(fieldHolder.field.FieldType),
|
||||
fieldOffset = fieldHolder.fieldOffset,
|
||||
fieldAttributes = (uint)fieldHolder.field.Attributes,
|
||||
};
|
||||
Unsafe.Write(IntPtr.Add(new IntPtr(arr), Unsafe.SizeOf<NativeFieldDefinitions>() * i).ToPointer(), classField);
|
||||
@@ -330,8 +371,8 @@ namespace FlaxEngine.Interop
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void GetClassProperties(ManagedHandle typeHandle, NativePropertyDefinitions** classProperties, int* classPropertiesCount)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
var properties = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
|
||||
var arr = (NativePropertyDefinitions*)NativeAlloc(properties.Length, Unsafe.SizeOf<NativePropertyDefinitions>());
|
||||
for (int i = 0; i < properties.Length; i++)
|
||||
@@ -364,7 +405,7 @@ namespace FlaxEngine.Interop
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void GetClassAttributes(ManagedHandle typeHandle, ManagedHandle** classAttributes, int* classAttributesCount)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
object[] attributeValues = type.GetCustomAttributes(false);
|
||||
|
||||
ManagedHandle* arr = (ManagedHandle*)NativeAlloc(attributeValues.Length, Unsafe.SizeOf<ManagedHandle>());
|
||||
@@ -384,13 +425,13 @@ namespace FlaxEngine.Interop
|
||||
[UnmanagedCallersOnly]
|
||||
internal static ManagedHandle GetCustomAttribute(ManagedHandle typeHandle, ManagedHandle attributeHandle)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
var attributes = type.GetCustomAttributes(false);
|
||||
object attrib;
|
||||
if (attributeHandle.IsAllocated)
|
||||
{
|
||||
// Check for certain attribute type
|
||||
Type attributeType = Unsafe.As<Type>(attributeHandle.Target);
|
||||
Type attributeType = Unsafe.As<TypeHolder>(attributeHandle.Target);
|
||||
attrib = attributes.FirstOrDefault(x => x.GetType() == attributeType);
|
||||
}
|
||||
else
|
||||
@@ -413,7 +454,7 @@ namespace FlaxEngine.Interop
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void GetClassInterfaces(ManagedHandle typeHandle, IntPtr* classInterfaces, int* classInterfacesCount)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
Type[] interfaces = type.GetInterfaces();
|
||||
|
||||
// Match mono_class_get_interfaces which doesn't return interfaces from base class
|
||||
@@ -465,7 +506,7 @@ namespace FlaxEngine.Interop
|
||||
IntPtr arr = (IntPtr)NativeAlloc(interfaces.Length, IntPtr.Size);
|
||||
for (int i = 0; i < interfaces.Length; i++)
|
||||
{
|
||||
ManagedHandle handle = GetTypeGCHandle(interfaces[i]);
|
||||
ManagedHandle handle = GetTypeManagedHandle(interfaces[i]);
|
||||
Unsafe.Write<ManagedHandle>(IntPtr.Add(arr, IntPtr.Size * i).ToPointer(), handle);
|
||||
}
|
||||
*classInterfaces = arr;
|
||||
@@ -477,7 +518,7 @@ namespace FlaxEngine.Interop
|
||||
{
|
||||
MethodHolder methodHolder = Unsafe.As<MethodHolder>(methodHandle.Target);
|
||||
Type returnType = methodHolder.returnType;
|
||||
return GetTypeGCHandle(returnType);
|
||||
return GetTypeManagedHandle(returnType);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
@@ -488,7 +529,7 @@ namespace FlaxEngine.Interop
|
||||
IntPtr arr = (IntPtr)NativeAlloc(methodHolder.parameterTypes.Length, IntPtr.Size);
|
||||
for (int i = 0; i < methodHolder.parameterTypes.Length; i++)
|
||||
{
|
||||
ManagedHandle typeHandle = GetTypeGCHandle(methodHolder.parameterTypes[i]);
|
||||
ManagedHandle typeHandle = GetTypeManagedHandle(methodHolder.parameterTypes[i]);
|
||||
Unsafe.Write<ManagedHandle>(IntPtr.Add(new IntPtr(arr), IntPtr.Size * i).ToPointer(), typeHandle);
|
||||
}
|
||||
*typeHandles = arr;
|
||||
@@ -509,22 +550,15 @@ namespace FlaxEngine.Interop
|
||||
[UnmanagedCallersOnly]
|
||||
internal static ManagedHandle NewObject(ManagedHandle typeHandle)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
if (type.IsAbstract)
|
||||
{
|
||||
// Dotnet doesn't allow to instantiate abstract type thus allow to use generated mock class usage (eg. for Script or GPUResource) for generated abstract types
|
||||
var abstractWrapper = type.GetNestedType("AbstractWrapper", BindingFlags.NonPublic);
|
||||
if (abstractWrapper != null)
|
||||
type = abstractWrapper;
|
||||
}
|
||||
object value = RuntimeHelpers.GetUninitializedObject(type);
|
||||
TypeHolder typeHolder = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
object value = typeHolder.CreateObject();
|
||||
return ManagedHandle.Alloc(value);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static ManagedHandle NewArray(ManagedHandle typeHandle, long size)
|
||||
{
|
||||
Type elementType = Unsafe.As<Type>(typeHandle.Target);
|
||||
Type elementType = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
Type marshalledType = ArrayFactory.GetMarshalledType(elementType);
|
||||
Type arrayType = ArrayFactory.GetArrayType(elementType);
|
||||
if (marshalledType.IsValueType)
|
||||
@@ -543,9 +577,9 @@ namespace FlaxEngine.Interop
|
||||
[UnmanagedCallersOnly]
|
||||
internal static ManagedHandle GetArrayTypeFromElementType(ManagedHandle elementTypeHandle)
|
||||
{
|
||||
Type elementType = Unsafe.As<Type>(elementTypeHandle.Target);
|
||||
Type elementType = Unsafe.As<TypeHolder>(elementTypeHandle.Target);
|
||||
Type classType = ArrayFactory.GetArrayType(elementType);
|
||||
return GetTypeGCHandle(classType);
|
||||
return GetTypeManagedHandle(classType);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
@@ -559,6 +593,19 @@ namespace FlaxEngine.Interop
|
||||
return managedArray.Pointer;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static IntPtr GetArray(ManagedHandle handle)
|
||||
{
|
||||
if (!handle.IsAllocated)
|
||||
return IntPtr.Zero;
|
||||
object value = handle.Target;
|
||||
if (value is ManagedArray)
|
||||
return (IntPtr)handle;
|
||||
if (value is Array)
|
||||
return Invoker.MarshalReturnValueGeneric(value.GetType(), value);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static int GetArrayLength(ManagedHandle arrayHandle)
|
||||
{
|
||||
@@ -593,7 +640,7 @@ namespace FlaxEngine.Interop
|
||||
Type classType = obj.GetType();
|
||||
if (classType == typeof(ManagedArray))
|
||||
classType = ((ManagedArray)obj).ArrayType;
|
||||
return GetTypeGCHandle(classType);
|
||||
return GetTypeManagedHandle(classType);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
@@ -634,7 +681,7 @@ namespace FlaxEngine.Interop
|
||||
[UnmanagedCallersOnly]
|
||||
internal static ManagedHandle BoxValue(ManagedHandle typeHandle, IntPtr valuePtr)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
object value = MarshalToManaged(valuePtr, type);
|
||||
return ManagedHandle.Alloc(value, GCHandleType.Weak);
|
||||
}
|
||||
@@ -677,6 +724,14 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static IntPtr GetObjectClass(ManagedHandle objectHandle)
|
||||
{
|
||||
object obj = objectHandle.Target;
|
||||
TypeHolder typeHolder = GetTypeHolder(obj.GetType());
|
||||
return typeHolder.managedClassPointer;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static IntPtr InvokeMethod(ManagedHandle instanceHandle, ManagedHandle methodHandle, IntPtr paramPtr, IntPtr exceptionPtr)
|
||||
{
|
||||
@@ -693,7 +748,7 @@ namespace FlaxEngine.Interop
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (exceptionPtr != IntPtr.Zero)
|
||||
Marshal.WriteIntPtr(exceptionPtr, ManagedHandle.ToIntPtr(exception, GCHandleType.Weak));
|
||||
Unsafe.Write<IntPtr>(exceptionPtr.ToPointer(), ManagedHandle.ToIntPtr(exception, GCHandleType.Weak));
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
return returnValue;
|
||||
@@ -708,7 +763,7 @@ namespace FlaxEngine.Interop
|
||||
|
||||
for (int i = 0; i < numParams; i++)
|
||||
{
|
||||
IntPtr nativePtr = Marshal.ReadIntPtr(IntPtr.Add(paramPtr, sizeof(IntPtr) * i));
|
||||
IntPtr nativePtr = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * i)).ToPointer());
|
||||
methodParameters[i] = MarshalToManaged(nativePtr, methodHolder.parameterTypes[i]);
|
||||
}
|
||||
|
||||
@@ -724,7 +779,7 @@ namespace FlaxEngine.Interop
|
||||
realException = exception.InnerException;
|
||||
|
||||
if (exceptionPtr != IntPtr.Zero)
|
||||
Marshal.WriteIntPtr(exceptionPtr, ManagedHandle.ToIntPtr(realException, GCHandleType.Weak));
|
||||
Unsafe.Write<IntPtr>(exceptionPtr.ToPointer(), ManagedHandle.ToIntPtr(realException, GCHandleType.Weak));
|
||||
else
|
||||
throw realException;
|
||||
return IntPtr.Zero;
|
||||
@@ -736,7 +791,7 @@ namespace FlaxEngine.Interop
|
||||
Type parameterType = methodHolder.parameterTypes[i];
|
||||
if (parameterType.IsByRef)
|
||||
{
|
||||
IntPtr nativePtr = Marshal.ReadIntPtr(IntPtr.Add(paramPtr, sizeof(IntPtr) * i));
|
||||
IntPtr nativePtr = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * i)).ToPointer());
|
||||
MarshalToNative(methodParameters[i], nativePtr, parameterType.GetElementType());
|
||||
}
|
||||
}
|
||||
@@ -790,7 +845,7 @@ namespace FlaxEngine.Interop
|
||||
internal static int FieldGetOffset(ManagedHandle fieldHandle)
|
||||
{
|
||||
FieldHolder field = Unsafe.As<FieldHolder>(fieldHandle.Target);
|
||||
return (int)Marshal.OffsetOf(field.field.DeclaringType, field.field.Name);
|
||||
return field.fieldOffset;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
@@ -798,14 +853,47 @@ namespace FlaxEngine.Interop
|
||||
{
|
||||
object fieldOwner = fieldOwnerHandle.Target;
|
||||
FieldHolder field = Unsafe.As<FieldHolder>(fieldHandle.Target);
|
||||
field.toNativeMarshaller(field.field, fieldOwner, valuePtr, out int fieldOffset);
|
||||
field.toNativeMarshaller(field.field, field.fieldOffset, fieldOwner, valuePtr, out int fieldSize);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void FieldGetValueReference(ManagedHandle fieldOwnerHandle, ManagedHandle fieldHandle, IntPtr valuePtr)
|
||||
{
|
||||
object fieldOwner = fieldOwnerHandle.Target;
|
||||
FieldHolder field = Unsafe.As<FieldHolder>(fieldHandle.Target);
|
||||
if (fieldOwner.GetType().IsValueType)
|
||||
{
|
||||
ref IntPtr fieldRef = ref FieldHelper.GetValueTypeFieldReference<object, IntPtr>(field.fieldOffset, ref fieldOwner);
|
||||
Unsafe.Write<IntPtr>(valuePtr.ToPointer(), fieldRef);
|
||||
}
|
||||
else
|
||||
{
|
||||
ref IntPtr fieldRef = ref FieldHelper.GetReferenceTypeFieldReference<object, IntPtr>(field.fieldOffset, ref fieldOwner);
|
||||
Unsafe.Write<IntPtr>(valuePtr.ToPointer(), fieldRef);
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void FieldGetValueReferenceWithOffset(ManagedHandle fieldOwnerHandle, int fieldOffset, IntPtr valuePtr)
|
||||
{
|
||||
object fieldOwner = fieldOwnerHandle.Target;
|
||||
if (fieldOwner.GetType().IsValueType)
|
||||
{
|
||||
ref IntPtr fieldRef = ref FieldHelper.GetValueTypeFieldReference<object, IntPtr>(fieldOffset, ref fieldOwner);
|
||||
Unsafe.Write<IntPtr>(valuePtr.ToPointer(), fieldRef);
|
||||
}
|
||||
else
|
||||
{
|
||||
ref IntPtr fieldRef = ref FieldHelper.GetReferenceTypeFieldReference<object, IntPtr>(fieldOffset, ref fieldOwner);
|
||||
Unsafe.Write<IntPtr>(valuePtr.ToPointer(), fieldRef);
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static IntPtr FieldGetValueBoxed(ManagedHandle fieldOwnerHandle, ManagedHandle fieldHandle)
|
||||
{
|
||||
object fieldOwner = fieldOwnerHandle.Target;
|
||||
FieldHolder field = Unsafe.As<FieldHolder>(fieldHandle.Target);
|
||||
object fieldOwner = field.field.IsStatic ? null : fieldOwnerHandle.Target;
|
||||
object fieldValue = field.field.GetValue(fieldOwner);
|
||||
return Invoker.MarshalReturnValueGeneric(field.field.FieldType, fieldValue);
|
||||
}
|
||||
@@ -826,7 +914,15 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static ManagedHandle LoadAssemblyImage(IntPtr assemblyPathPtr, IntPtr* assemblyName, IntPtr* assemblyFullName)
|
||||
internal static void GetAssemblyName(ManagedHandle assemblyHandle, IntPtr* assemblyName, IntPtr* assemblyFullName)
|
||||
{
|
||||
Assembly assembly = Unsafe.As<Assembly>(assemblyHandle.Target);
|
||||
*assemblyName = NativeAllocStringAnsi(assembly.GetName().Name);
|
||||
*assemblyFullName = NativeAllocStringAnsi(assembly.FullName);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static ManagedHandle LoadAssemblyImage(IntPtr assemblyPathPtr)
|
||||
{
|
||||
if (!firstAssemblyLoaded)
|
||||
{
|
||||
@@ -834,55 +930,55 @@ namespace FlaxEngine.Interop
|
||||
firstAssemblyLoaded = true;
|
||||
|
||||
Assembly flaxEngineAssembly = AssemblyLoadContext.Default.Assemblies.First(x => x.GetName().Name == "FlaxEngine.CSharp");
|
||||
*assemblyName = NativeAllocStringAnsi(flaxEngineAssembly.GetName().Name);
|
||||
*assemblyFullName = NativeAllocStringAnsi(flaxEngineAssembly.FullName);
|
||||
return GetAssemblyHandle(flaxEngineAssembly);
|
||||
}
|
||||
try
|
||||
{
|
||||
string assemblyPath = Marshal.PtrToStringUni(assemblyPathPtr);
|
||||
|
||||
string assemblyPath = Marshal.PtrToStringAnsi(assemblyPathPtr);
|
||||
|
||||
Assembly assembly;
|
||||
Assembly assembly;
|
||||
#if FLAX_EDITOR
|
||||
// Load assembly from loaded bytes to prevent file locking in Editor
|
||||
var assemblyBytes = File.ReadAllBytes(assemblyPath);
|
||||
using MemoryStream stream = new MemoryStream(assemblyBytes);
|
||||
var pdbPath = Path.ChangeExtension(assemblyPath, "pdb");
|
||||
if (File.Exists(pdbPath))
|
||||
{
|
||||
// Load including debug symbols
|
||||
using FileStream pdbStream = new FileStream(Path.ChangeExtension(assemblyPath, "pdb"), FileMode.Open);
|
||||
assembly = scriptingAssemblyLoadContext.LoadFromStream(stream, pdbStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
assembly = scriptingAssemblyLoadContext.LoadFromStream(stream);
|
||||
}
|
||||
// Load assembly from loaded bytes to prevent file locking in Editor
|
||||
var assemblyBytes = File.ReadAllBytes(assemblyPath);
|
||||
using MemoryStream stream = new MemoryStream(assemblyBytes);
|
||||
var pdbPath = Path.ChangeExtension(assemblyPath, "pdb");
|
||||
if (File.Exists(pdbPath))
|
||||
{
|
||||
// Load including debug symbols
|
||||
using FileStream pdbStream = new FileStream(Path.ChangeExtension(assemblyPath, "pdb"), FileMode.Open);
|
||||
assembly = scriptingAssemblyLoadContext.LoadFromStream(stream, pdbStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
assembly = scriptingAssemblyLoadContext.LoadFromStream(stream);
|
||||
}
|
||||
#else
|
||||
// Load assembly from file
|
||||
assembly = scriptingAssemblyLoadContext.LoadFromAssemblyPath(assemblyPath);
|
||||
// Load assembly from file
|
||||
assembly = scriptingAssemblyLoadContext.LoadFromAssemblyPath(assemblyPath);
|
||||
#endif
|
||||
if (assembly == null)
|
||||
return new ManagedHandle();
|
||||
NativeLibrary.SetDllImportResolver(assembly, NativeLibraryImportResolver);
|
||||
if (assembly == null)
|
||||
return new ManagedHandle();
|
||||
NativeLibrary.SetDllImportResolver(assembly, NativeLibraryImportResolver);
|
||||
|
||||
// Assemblies loaded via streams have no Location: https://github.com/dotnet/runtime/issues/12822
|
||||
AssemblyLocations.Add(assembly.FullName, assemblyPath);
|
||||
// Assemblies loaded via streams have no Location: https://github.com/dotnet/runtime/issues/12822
|
||||
AssemblyLocations.Add(assembly.FullName, assemblyPath);
|
||||
|
||||
*assemblyName = NativeAllocStringAnsi(assembly.GetName().Name);
|
||||
*assemblyFullName = NativeAllocStringAnsi(assembly.FullName);
|
||||
return GetAssemblyHandle(assembly);
|
||||
return GetAssemblyHandle(assembly);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
}
|
||||
return new ManagedHandle();
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static ManagedHandle GetAssemblyByName(IntPtr namePtr, IntPtr* assemblyName, IntPtr* assemblyFullName)
|
||||
internal static ManagedHandle GetAssemblyByName(IntPtr namePtr)
|
||||
{
|
||||
string name = Marshal.PtrToStringAnsi(namePtr);
|
||||
Assembly assembly = Utils.GetAssemblies().FirstOrDefault(x => x.GetName().Name == name);
|
||||
if (assembly == null)
|
||||
return new ManagedHandle();
|
||||
|
||||
*assemblyName = NativeAllocStringAnsi(assembly.GetName().Name);
|
||||
*assemblyFullName = NativeAllocStringAnsi(assembly.FullName);
|
||||
return GetAssemblyHandle(assembly);
|
||||
}
|
||||
|
||||
@@ -909,7 +1005,7 @@ namespace FlaxEngine.Interop
|
||||
loadedNativeLibraries.Remove(nativeLibraryName);
|
||||
}
|
||||
if (nativeLibraryName != null)
|
||||
nativeLibraryPaths.Remove(nativeLibraryName);
|
||||
libraryPaths.Remove(nativeLibraryName);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
@@ -921,9 +1017,9 @@ namespace FlaxEngine.Interop
|
||||
|
||||
// Release all references in collectible ALC
|
||||
cachedDelegatesCollectible.Clear();
|
||||
foreach (var pair in typeHandleCacheCollectible)
|
||||
pair.Value.Free();
|
||||
typeHandleCacheCollectible.Clear();
|
||||
foreach (var pair in managedTypesCollectible)
|
||||
pair.Value.handle.Free();
|
||||
managedTypesCollectible.Clear();
|
||||
foreach (var handle in methodHandlesCollectible)
|
||||
handle.Free();
|
||||
methodHandlesCollectible.Clear();
|
||||
@@ -953,7 +1049,7 @@ namespace FlaxEngine.Interop
|
||||
[UnmanagedCallersOnly]
|
||||
internal static int NativeSizeOf(ManagedHandle typeHandle)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
Type nativeType = GetInternalType(type) ?? type;
|
||||
if (nativeType == typeof(Version))
|
||||
nativeType = typeof(NativeVersion);
|
||||
@@ -971,8 +1067,8 @@ namespace FlaxEngine.Interop
|
||||
if (typeHandle == otherTypeHandle)
|
||||
return 1;
|
||||
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
Type otherType = Unsafe.As<Type>(otherTypeHandle.Target);
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
Type otherType = Unsafe.As<TypeHolder>(otherTypeHandle.Target);
|
||||
|
||||
if (type == otherType)
|
||||
return 1;
|
||||
@@ -989,37 +1085,39 @@ namespace FlaxEngine.Interop
|
||||
[UnmanagedCallersOnly]
|
||||
internal static byte TypeIsAssignableFrom(ManagedHandle typeHandle, ManagedHandle otherTypeHandle)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
Type otherType = Unsafe.As<Type>(otherTypeHandle.Target);
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
Type otherType = Unsafe.As<TypeHolder>(otherTypeHandle.Target);
|
||||
return (byte)(type.IsAssignableFrom(otherType) ? 1 : 0);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static byte TypeIsValueType(ManagedHandle typeHandle)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
return (byte)(type.IsValueType ? 1 : 0);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static byte TypeIsEnum(ManagedHandle typeHandle)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
return (byte)(type.IsEnum ? 1 : 0);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static ManagedHandle GetClassParent(ManagedHandle typeHandle)
|
||||
internal static IntPtr GetClassParent(ManagedHandle typeHandle)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
return GetTypeGCHandle(type.BaseType);
|
||||
TypeHolder typeHolder = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
TypeHolder baseTypeHolder = GetTypeHolder(typeHolder.type.BaseType);
|
||||
return baseTypeHolder.managedClassPointer;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static ManagedHandle GetElementClass(ManagedHandle typeHandle)
|
||||
internal static IntPtr GetElementClass(ManagedHandle typeHandle)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
return GetTypeGCHandle(type.GetElementType());
|
||||
TypeHolder typeHolder = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
TypeHolder elementTypeHolder = GetTypeHolder(typeHolder.type.GetElementType());
|
||||
return elementTypeHolder.managedClassPointer;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
@@ -1110,32 +1208,35 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static ManagedHandle GetTypeClass(ManagedHandle typeHandle)
|
||||
internal static IntPtr GetTypeClass(ManagedHandle typeHandle)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
if (type.IsByRef)
|
||||
type = type.GetElementType(); // Drop reference type (&) to get actual value type
|
||||
return GetTypeGCHandle(type);
|
||||
TypeHolder typeHolder = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
if (typeHolder.type.IsByRef)
|
||||
{
|
||||
// Drop reference type (&) to get actual value type
|
||||
return GetTypeHolder(typeHolder.type.GetElementType()).managedClassPointer;
|
||||
}
|
||||
return typeHolder.managedClassPointer;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static bool GetTypeIsPointer(ManagedHandle typeHandle)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
return type.IsPointer;
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static bool GetTypeIsReference(ManagedHandle typeHandle)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
return type.IsByRef;
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
return !type.IsValueType; // Maybe also type.IsByRef?
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static uint GetTypeMTypesEnum(ManagedHandle typeHandle)
|
||||
{
|
||||
Type type = Unsafe.As<Type>(typeHandle.Target);
|
||||
Type type = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||
if (type.IsByRef)
|
||||
type = type.GetElementType(); // Drop reference type (&) to get actual value type
|
||||
MTypes monoType;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -181,6 +181,11 @@ void Screen::SetGameWindowMode(GameWindowMode windowMode)
|
||||
#endif
|
||||
}
|
||||
|
||||
Window* Screen::GetMainWindow()
|
||||
{
|
||||
return Engine::MainWindow;
|
||||
}
|
||||
|
||||
void ScreenService::Update()
|
||||
{
|
||||
#if USE_EDITOR
|
||||
|
||||
@@ -96,4 +96,10 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(Screen);
|
||||
/// </remarks>
|
||||
/// <param name="windowMode">The window mode.</param>
|
||||
API_PROPERTY() static void SetGameWindowMode(GameWindowMode windowMode);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the main window.
|
||||
/// </summary>
|
||||
/// <returns>The current window. Will be null if fails.</returns>
|
||||
API_PROPERTY() static Window* GetMainWindow();
|
||||
};
|
||||
|
||||
@@ -76,11 +76,11 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
|
||||
// Set reflection probe data
|
||||
EnvironmentProbe* probe = nullptr;
|
||||
// TODO: optimize env probe searching for a transparent material - use spatial cache for renderer to find it
|
||||
const Vector3 drawCallOrigin = drawCall.ObjectPosition + view.Origin;
|
||||
const BoundingSphere objectBoundsWorld(drawCall.ObjectPosition + view.Origin, drawCall.ObjectRadius);
|
||||
for (int32 i = 0; i < cache->EnvironmentProbes.Count(); i++)
|
||||
{
|
||||
const auto p = cache->EnvironmentProbes[i];
|
||||
if (p->GetSphere().Contains(drawCallOrigin) != ContainmentType::Disjoint)
|
||||
if (CollisionsHelper::SphereIntersectsSphere(objectBoundsWorld, p->GetSphere()))
|
||||
{
|
||||
probe = p;
|
||||
break;
|
||||
@@ -99,10 +99,12 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
|
||||
|
||||
// Set local lights
|
||||
data.LocalLightsCount = 0;
|
||||
const BoundingSphere objectBounds(drawCall.ObjectPosition, drawCall.ObjectRadius);
|
||||
// TODO: optimize lights searching for a transparent material - use spatial cache for renderer to find it
|
||||
for (int32 i = 0; i < cache->PointLights.Count() && data.LocalLightsCount < MaxLocalLights; i++)
|
||||
{
|
||||
const auto& light = cache->PointLights[i];
|
||||
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.ObjectPosition) != ContainmentType::Disjoint)
|
||||
if (CollisionsHelper::SphereIntersectsSphere(objectBounds, BoundingSphere(light.Position, light.Radius)))
|
||||
{
|
||||
light.SetupLightData(&data.LocalLights[data.LocalLightsCount], false);
|
||||
data.LocalLightsCount++;
|
||||
@@ -111,7 +113,7 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
|
||||
for (int32 i = 0; i < cache->SpotLights.Count() && data.LocalLightsCount < MaxLocalLights; i++)
|
||||
{
|
||||
const auto& light = cache->SpotLights[i];
|
||||
if (BoundingSphere(light.Position, light.Radius).Contains(drawCall.ObjectPosition) != ContainmentType::Disjoint)
|
||||
if (CollisionsHelper::SphereIntersectsSphere(objectBounds, BoundingSphere(light.Position, light.Radius)))
|
||||
{
|
||||
light.SetupLightData(&data.LocalLights[data.LocalLightsCount], false);
|
||||
data.LocalLightsCount++;
|
||||
|
||||
@@ -429,6 +429,7 @@ void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, cons
|
||||
drawCall.Material = material;
|
||||
drawCall.World = world;
|
||||
drawCall.ObjectPosition = drawCall.World.GetTranslation();
|
||||
drawCall.ObjectRadius = _sphere.Radius * drawCall.World.GetScaleVector().GetAbsolute().MaxValue();
|
||||
drawCall.Surface.GeometrySize = _box.GetSize();
|
||||
drawCall.Surface.PrevWorld = world;
|
||||
drawCall.Surface.Lightmap = nullptr;
|
||||
@@ -495,6 +496,7 @@ void Mesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float
|
||||
drawCall.Material = material;
|
||||
drawCall.World = *info.World;
|
||||
drawCall.ObjectPosition = drawCall.World.GetTranslation();
|
||||
drawCall.ObjectRadius = info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition?
|
||||
drawCall.Surface.GeometrySize = _box.GetSize();
|
||||
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
|
||||
drawCall.Surface.Lightmap = (info.Flags & StaticFlags::Lightmap) != StaticFlags::None ? info.Lightmap : nullptr;
|
||||
@@ -555,6 +557,7 @@ void Mesh::Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& in
|
||||
drawCall.Material = material;
|
||||
drawCall.World = *info.World;
|
||||
drawCall.ObjectPosition = drawCall.World.GetTranslation();
|
||||
drawCall.ObjectRadius = info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition?
|
||||
drawCall.Surface.GeometrySize = _box.GetSize();
|
||||
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
|
||||
drawCall.Surface.Lightmap = (info.Flags & StaticFlags::Lightmap) != StaticFlags::None ? info.Lightmap : nullptr;
|
||||
|
||||
@@ -198,6 +198,7 @@ void SkinnedMesh::Draw(const RenderContext& renderContext, const DrawInfo& info,
|
||||
drawCall.Material = material;
|
||||
drawCall.World = *info.World;
|
||||
drawCall.ObjectPosition = drawCall.World.GetTranslation();
|
||||
drawCall.ObjectRadius = info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition?
|
||||
drawCall.Surface.GeometrySize = _box.GetSize();
|
||||
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
|
||||
drawCall.Surface.Lightmap = nullptr;
|
||||
@@ -258,6 +259,7 @@ void SkinnedMesh::Draw(const RenderContextBatch& renderContextBatch, const DrawI
|
||||
drawCall.Material = material;
|
||||
drawCall.World = *info.World;
|
||||
drawCall.ObjectPosition = drawCall.World.GetTranslation();
|
||||
drawCall.ObjectRadius = info.Bounds.Radius; // TODO: should it be kept in sync with ObjectPosition?
|
||||
drawCall.Surface.GeometrySize = _box.GetSize();
|
||||
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
|
||||
drawCall.Surface.Lightmap = nullptr;
|
||||
|
||||
@@ -120,7 +120,7 @@ bool GPUShader::Create(MemoryReadStream& stream)
|
||||
GPUShaderProgram* shader = CreateGPUShaderProgram(type, initializer, cache, cacheSize, stream);
|
||||
if (shader == nullptr)
|
||||
{
|
||||
LOG(Warning, "Failed to create shader program.");
|
||||
LOG(Error, "Failed to create {} Shader program '{}'.", ::ToString(type), String(initializer.Name));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ bool GPUBufferDX11::OnInit()
|
||||
data.SysMemPitch = bufferDesc.ByteWidth;
|
||||
data.SysMemSlicePitch = 0;
|
||||
}
|
||||
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateBuffer(&bufferDesc, _desc.InitData ? &data : nullptr, &_resource));
|
||||
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateBuffer(&bufferDesc, _desc.InitData ? &data : nullptr, &_resource));
|
||||
|
||||
// Set state
|
||||
DX_SET_DEBUG_NAME(_resource, GetName());
|
||||
@@ -135,7 +135,7 @@ bool GPUBufferDX11::OnInit()
|
||||
srvDesc.Buffer.NumElements = numElements;
|
||||
}
|
||||
ID3D11ShaderResourceView* srv;
|
||||
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateShaderResourceView(_resource, &srvDesc, &srv));
|
||||
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateShaderResourceView(_resource, &srvDesc, &srv));
|
||||
_view.SetSRV(srv);
|
||||
}
|
||||
if (useUAV)
|
||||
@@ -156,7 +156,7 @@ bool GPUBufferDX11::OnInit()
|
||||
else
|
||||
uavDesc.Format = RenderToolsDX::ToDxgiFormat(PixelFormatExtensions::FindUnorderedAccessFormat(_desc.Format));
|
||||
ID3D11UnorderedAccessView* uav;
|
||||
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateUnorderedAccessView(_resource, &uavDesc, &uav));
|
||||
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateUnorderedAccessView(_resource, &uavDesc, &uav));
|
||||
_view.SetUAV(uav);
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ GPUDevice* GPUDeviceDX11::Create()
|
||||
if (tempAdapter && TryCreateDevice(tempAdapter, maxAllowedFeatureLevel, &adapter.MaxFeatureLevel))
|
||||
{
|
||||
adapter.Index = index;
|
||||
VALIDATE_DIRECTX_RESULT(tempAdapter->GetDesc(&adapter.Description));
|
||||
VALIDATE_DIRECTX_CALL(tempAdapter->GetDesc(&adapter.Description));
|
||||
uint32 outputs = RenderToolsDX::CountAdapterOutputs(tempAdapter);
|
||||
|
||||
LOG(Info, "Adapter {1}: '{0}', DirectX {2}", adapter.Description.Description, index, RenderToolsDX::GetFeatureLevelString(adapter.MaxFeatureLevel));
|
||||
@@ -163,7 +163,7 @@ GPUDevice* GPUDeviceDX11::Create()
|
||||
if (tempAdapter && TryCreateDevice(tempAdapter, maxAllowedFeatureLevel, &adapter.MaxFeatureLevel))
|
||||
{
|
||||
DXGI_ADAPTER_DESC desc;
|
||||
VALIDATE_DIRECTX_RESULT(tempAdapter->GetDesc(&desc));
|
||||
VALIDATE_DIRECTX_CALL(tempAdapter->GetDesc(&desc));
|
||||
for (int i = 0; i < adapters.Count(); i++)
|
||||
{
|
||||
if (adapters[i].Description.AdapterLuid.LowPart == desc.AdapterLuid.LowPart &&
|
||||
@@ -274,7 +274,7 @@ ID3D11BlendState* GPUDeviceDX11::GetBlendState(const BlendingMode& blending)
|
||||
#endif
|
||||
|
||||
// Create object
|
||||
VALIDATE_DIRECTX_RESULT(_device->CreateBlendState(&desc, &blendState));
|
||||
VALIDATE_DIRECTX_CALL(_device->CreateBlendState(&desc, &blendState));
|
||||
|
||||
// Cache blend state
|
||||
BlendStates.Add(blending, blendState);
|
||||
@@ -333,7 +333,7 @@ bool GPUDeviceDX11::Init()
|
||||
// Create DirectX device
|
||||
D3D_FEATURE_LEVEL createdFeatureLevel = static_cast<D3D_FEATURE_LEVEL>(0);
|
||||
auto targetFeatureLevel = GetD3DFeatureLevel();
|
||||
VALIDATE_DIRECTX_RESULT(D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, flags, &targetFeatureLevel, 1, D3D11_SDK_VERSION, &_device, &createdFeatureLevel, &_imContext));
|
||||
VALIDATE_DIRECTX_CALL(D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, flags, &targetFeatureLevel, 1, D3D11_SDK_VERSION, &_device, &createdFeatureLevel, &_imContext));
|
||||
|
||||
// Validate result
|
||||
ASSERT(_device);
|
||||
@@ -409,7 +409,7 @@ bool GPUDeviceDX11::Init()
|
||||
// Init debug layer
|
||||
#if GPU_ENABLE_DIAGNOSTICS
|
||||
ComPtr<ID3D11InfoQueue> infoQueue;
|
||||
VALIDATE_DIRECTX_RESULT(_device->QueryInterface(IID_PPV_ARGS(&infoQueue)));
|
||||
VALIDATE_DIRECTX_CALL(_device->QueryInterface(IID_PPV_ARGS(&infoQueue)));
|
||||
if (infoQueue)
|
||||
{
|
||||
D3D11_INFO_QUEUE_FILTER filter;
|
||||
@@ -457,7 +457,7 @@ bool GPUDeviceDX11::Init()
|
||||
samplerDesc.MinLOD = 0;
|
||||
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
|
||||
result = _device->CreateSamplerState(&samplerDesc, &_samplerLinearClamp);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
|
||||
|
||||
// Point Clamp
|
||||
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
@@ -467,7 +467,7 @@ bool GPUDeviceDX11::Init()
|
||||
samplerDesc.MinLOD = 0;
|
||||
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
|
||||
result = _device->CreateSamplerState(&samplerDesc, &_samplerPointClamp);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
|
||||
|
||||
// Linear Wrap
|
||||
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
@@ -477,7 +477,7 @@ bool GPUDeviceDX11::Init()
|
||||
samplerDesc.MinLOD = 0;
|
||||
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
|
||||
result = _device->CreateSamplerState(&samplerDesc, &_samplerLinearWrap);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
|
||||
|
||||
// Point Wrap
|
||||
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
@@ -487,7 +487,7 @@ bool GPUDeviceDX11::Init()
|
||||
samplerDesc.MinLOD = 0;
|
||||
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
|
||||
result = _device->CreateSamplerState(&samplerDesc, &_samplerPointWrap);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
|
||||
|
||||
// Shadow
|
||||
samplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT;
|
||||
@@ -500,7 +500,7 @@ bool GPUDeviceDX11::Init()
|
||||
samplerDesc.MinLOD = 0;
|
||||
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
|
||||
result = _device->CreateSamplerState(&samplerDesc, &_samplerShadow);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
|
||||
|
||||
// Shadow PCF
|
||||
samplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR;
|
||||
@@ -514,7 +514,7 @@ bool GPUDeviceDX11::Init()
|
||||
samplerDesc.MinLOD = 0;
|
||||
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
|
||||
result = _device->CreateSamplerState(&samplerDesc, &_samplerShadowPCF);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
|
||||
}
|
||||
|
||||
// Rasterizer States
|
||||
@@ -534,7 +534,7 @@ bool GPUDeviceDX11::Init()
|
||||
rDesc.AntialiasedLineEnable = !!wireframe; \
|
||||
rDesc.DepthClipEnable = !!depthClip; \
|
||||
result = _device->CreateRasterizerState(&rDesc, &RasterizerStates[index]); \
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result)
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, true)
|
||||
CREATE_RASTERIZER_STATE(CullMode::Normal, D3D11_CULL_BACK, false, false);
|
||||
CREATE_RASTERIZER_STATE(CullMode::Inverted, D3D11_CULL_FRONT, false, false);
|
||||
CREATE_RASTERIZER_STATE(CullMode::TwoSided, D3D11_CULL_NONE, false, false);
|
||||
@@ -568,7 +568,7 @@ bool GPUDeviceDX11::Init()
|
||||
dsDesc.DepthFunc = (D3D11_COMPARISON_FUNC)depthFunc; \
|
||||
index = (int32)depthFunc + (depthEnable ? 0 : 9) + (depthWrite ? 0 : 18); \
|
||||
HRESULT result = _device->CreateDepthStencilState(&dsDesc, &DepthStencilStates[index]); \
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result); }
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, true); }
|
||||
CREATE_DEPTH_STENCIL_STATE(false, false);
|
||||
CREATE_DEPTH_STENCIL_STATE(false, true);
|
||||
CREATE_DEPTH_STENCIL_STATE(true, true);
|
||||
@@ -666,7 +666,7 @@ void GPUDeviceDX11::DrawEnd()
|
||||
#if GPU_ENABLE_DIAGNOSTICS
|
||||
// Flush debug messages queue
|
||||
ComPtr<ID3D11InfoQueue> infoQueue;
|
||||
VALIDATE_DIRECTX_RESULT(_device->QueryInterface(IID_PPV_ARGS(&infoQueue)));
|
||||
VALIDATE_DIRECTX_CALL(_device->QueryInterface(IID_PPV_ARGS(&infoQueue)));
|
||||
if (infoQueue)
|
||||
{
|
||||
Array<uint8> data;
|
||||
|
||||
@@ -106,7 +106,7 @@ bool GPUSamplerDX11::OnInit()
|
||||
samplerDesc.MinLOD = _desc.MinMipLevel;
|
||||
samplerDesc.MaxLOD = _desc.MaxMipLevel;
|
||||
HRESULT result = _device->GetDevice()->CreateSamplerState(&samplerDesc, &SamplerState);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
|
||||
ASSERT(SamplerState != nullptr);
|
||||
_memoryUsage = sizeof(D3D11_SAMPLER_DESC);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const GPUShaderProgramInitializer& initializer, byte* cacheBytes, uint32 cacheSize, MemoryReadStream& stream)
|
||||
{
|
||||
GPUShaderProgram* shader = nullptr;
|
||||
HRESULT result;
|
||||
switch (type)
|
||||
{
|
||||
case ShaderStage::Vertex:
|
||||
@@ -90,12 +91,13 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
|
||||
if (inputLayoutSize > 0)
|
||||
{
|
||||
// Create input layout
|
||||
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateInputLayout(inputLayoutDesc, inputLayoutSize, cacheBytes, cacheSize, &inputLayout));
|
||||
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateInputLayout(inputLayoutDesc, inputLayoutSize, cacheBytes, cacheSize, &inputLayout));
|
||||
}
|
||||
|
||||
// Create shader
|
||||
ID3D11VertexShader* buffer = nullptr;
|
||||
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateVertexShader(cacheBytes, cacheSize, nullptr, &buffer));
|
||||
result = _device->GetDevice()->CreateVertexShader(cacheBytes, cacheSize, nullptr, &buffer);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
|
||||
|
||||
// Create object
|
||||
shader = New<GPUShaderProgramVSDX11>(initializer, buffer, inputLayout, inputLayoutSize);
|
||||
@@ -109,7 +111,8 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
|
||||
|
||||
// Create shader
|
||||
ID3D11HullShader* buffer = nullptr;
|
||||
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateHullShader(cacheBytes, cacheSize, nullptr, &buffer));
|
||||
result = _device->GetDevice()->CreateHullShader(cacheBytes, cacheSize, nullptr, &buffer);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
|
||||
|
||||
// Create object
|
||||
shader = New<GPUShaderProgramHSDX11>(initializer, buffer, controlPointsCount);
|
||||
@@ -119,7 +122,8 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
|
||||
{
|
||||
// Create shader
|
||||
ID3D11DomainShader* buffer = nullptr;
|
||||
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateDomainShader(cacheBytes, cacheSize, nullptr, &buffer));
|
||||
result = _device->GetDevice()->CreateDomainShader(cacheBytes, cacheSize, nullptr, &buffer);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
|
||||
|
||||
// Create object
|
||||
shader = New<GPUShaderProgramDSDX11>(initializer, buffer);
|
||||
@@ -129,7 +133,8 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
|
||||
{
|
||||
// Create shader
|
||||
ID3D11GeometryShader* buffer = nullptr;
|
||||
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateGeometryShader(cacheBytes, cacheSize, nullptr, &buffer));
|
||||
result = _device->GetDevice()->CreateGeometryShader(cacheBytes, cacheSize, nullptr, &buffer);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
|
||||
|
||||
// Create object
|
||||
shader = New<GPUShaderProgramGSDX11>(initializer, buffer);
|
||||
@@ -139,7 +144,8 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
|
||||
{
|
||||
// Create shader
|
||||
ID3D11PixelShader* buffer = nullptr;
|
||||
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreatePixelShader(cacheBytes, cacheSize, nullptr, &buffer));
|
||||
result = _device->GetDevice()->CreatePixelShader(cacheBytes, cacheSize, nullptr, &buffer);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
|
||||
|
||||
// Create object
|
||||
shader = New<GPUShaderProgramPSDX11>(initializer, buffer);
|
||||
@@ -149,7 +155,8 @@ GPUShaderProgram* GPUShaderDX11::CreateGPUShaderProgram(ShaderStage type, const
|
||||
{
|
||||
// Create shader
|
||||
ID3D11ComputeShader* buffer = nullptr;
|
||||
VALIDATE_DIRECTX_RESULT(_device->GetDevice()->CreateComputeShader(cacheBytes, cacheSize, nullptr, &buffer));
|
||||
result = _device->GetDevice()->CreateComputeShader(cacheBytes, cacheSize, nullptr, &buffer);
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, nullptr);
|
||||
|
||||
// Create object
|
||||
shader = New<GPUShaderProgramCSDX11>(initializer, buffer);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user