Merge branch 'FlaxEngine:master' into visject_grid_snap

This commit is contained in:
Menotdan
2023-10-01 23:32:21 -04:00
committed by GitHub
238 changed files with 5708 additions and 2953 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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.",

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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`

View File

@@ -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;
}

View File

@@ -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));

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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),
};

View File

@@ -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();

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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));
}
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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";

View File

@@ -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>

View File

@@ -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;

View File

@@ -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);

View File

@@ -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();

View File

@@ -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 />

View File

@@ -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;

View File

@@ -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--;
}

View File

@@ -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)

View File

@@ -129,6 +129,7 @@ namespace FlaxEditor.Modules
else
{
Editor.UI.UpdateProgress(string.Empty, 0);
Editor.UI.UpdateStatusBar();
}
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 />

View File

@@ -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

View File

@@ -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(),

View File

@@ -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;

View File

@@ -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)

View File

@@ -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();
}

View File

@@ -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 },

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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>

View File

@@ -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;
}

View File

@@ -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()

View File

@@ -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()

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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)

View File

@@ -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 />

View File

@@ -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
};

View File

@@ -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);

View File

@@ -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);

View File

@@ -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)

View File

@@ -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");

View File

@@ -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)
{

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;

View File

@@ -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)

View File

@@ -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);
}
}

View File

@@ -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();

View File

@@ -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();

View File

@@ -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;
}
}
}

View File

@@ -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++;
}
}
}
}
}

View File

@@ -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>

View File

@@ -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];
}

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -173,6 +173,9 @@ namespace FlaxEditor.Windows
// Spawn it
Editor.SceneEditing.Spawn(actor, parentActor);
Editor.SceneEditing.Select(actor);
Rename();
}
/// <summary>

View File

@@ -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()

View File

@@ -353,6 +353,8 @@ namespace FlaxEditor.Windows
: base(editor, true, ScrollBars.None)
{
Title = "Toolbox";
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
}
/// <inheritdoc />

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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)

View File

@@ -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>

View File

@@ -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>

View File

@@ -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)

View File

@@ -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("../../../..");

View File

@@ -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();

View File

@@ -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

View File

@@ -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

View File

@@ -181,6 +181,11 @@ void Screen::SetGameWindowMode(GameWindowMode windowMode)
#endif
}
Window* Screen::GetMainWindow()
{
return Engine::MainWindow;
}
void ScreenService::Update()
{
#if USE_EDITOR

View File

@@ -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();
};

View File

@@ -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++;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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