diff --git a/.github/workflows/build_linux.todo b/.github/workflows/build_linux.todo
new file mode 100644
index 000000000..9c3b21624
--- /dev/null
+++ b/.github/workflows/build_linux.todo
@@ -0,0 +1,19 @@
+name: Build Linux
+on: [push, pull_request]
+
+jobs:
+
+ # Game
+ game-linux:
+ name: Game (Linux, Release x64)
+ runs-on: "ubuntu-20.04"
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@v2
+ - name: Checkout LFS
+ run: |
+ git lfs version
+ git lfs pull
+ - name: Build
+ run: |
+ ./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Release -buildtargets=FlaxGame
diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml
new file mode 100644
index 000000000..690d6747b
--- /dev/null
+++ b/.github/workflows/build_windows.yml
@@ -0,0 +1,34 @@
+name: Build Windows
+on: [push, pull_request]
+
+jobs:
+
+ # Editor
+ editor-windows:
+ name: Editor (Windows, Development x64)
+ runs-on: "windows-latest"
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@v2
+ - name: Checkout LFS
+ run: |
+ git lfs version
+ git lfs pull
+ - name: Build
+ run: |
+ .\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=x64 -platform=Windows -configuration=Development -buildtargets=FlaxEditor
+
+ # Game
+ game-windows:
+ name: Game (Windows, Release x64)
+ runs-on: "windows-latest"
+ steps:
+ - name: Checkout repo
+ uses: actions/checkout@v2
+ - name: Checkout LFS
+ run: |
+ git lfs version
+ git lfs pull
+ - name: Build
+ run: |
+ .\Development\Scripts\Windows\CallBuildTool.bat -build -log -arch=x64 -platform=Windows -configuration=Release -buildtargets=FlaxGame
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 000000000..236fa6d67
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,34 @@
+# How to contribute to the FlaxEngine
+
+For any questions, suggestions or help join our discord!
+
+
+
+Want to see whats planned for Flax?
+
+Go check out our [Trello](https://trello.com/b/NQjLXRCP/flax-roadmap).
+
+## **Found a bug?**
+
+* Avoid opening any new issues without having checked if your problem has already been reported. If there are no currently open issues that fit your problem's description, feel free to [add it](https://github.com/FlaxEngine/FlaxEngine/issues/new).
+
+* When writing an issue make sure to include a clear title and description as well as having filled out all the necessary information, depending on the severity of the issue also include the necessary log files and minidump.
+
+* Try to following the given template when writing a new issue if possible.
+
+## **Want to contribute?**
+
+* Fork the FlaxEngine, create a new branch and push your changes there. Then, create a pull request.
+
+* When creating a PR for fixing an issue/bug make sure to describe as to what led to the fix for better understanding, for small and obvious fixes this is not really needed.
+ However make sure to mention the relevant issue where it was first reported if possible.
+
+* For feature PR's the first thing you should evaluate is the value of your contribution, as in, what would it bring to this engine? Is it really required?
+ If its a small change you could preferably suggest it to us on our discord, else feel free to open up a PR for it.
+
+* Ensure when creating a PR that your contribution is well explained with a adequate description and title.
+
+* Generally, good code quality is expected, make sure your contribution works as intended and is appropriately commented where necessary.
+
+
+Thank you for taking interest in contributing to Flax!
diff --git a/Content/Editor/Primitives/Plane.flax b/Content/Editor/Primitives/Plane.flax
index bf2052f02..1e5eaf76b 100644
--- a/Content/Editor/Primitives/Plane.flax
+++ b/Content/Editor/Primitives/Plane.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:8ab6d87b9f36f4ad231f38f415223130eea7b411be7ff8fd174b6ff7790258fb
-size 2232
+oid sha256:5683a761f198d01d7189490d526b55e393eb01fffbd6761fb969d11067b3db73
+size 2277
diff --git a/Content/Shaders/BakeLightmap.flax b/Content/Shaders/BakeLightmap.flax
index 6e813205f..fac992469 100644
--- a/Content/Shaders/BakeLightmap.flax
+++ b/Content/Shaders/BakeLightmap.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:17295767d488dc2b64a1794ceda8b4d68f20dd2c5f1a8fdbe6f7940a070f9724
+oid sha256:cc4b141137661d995ff571191150c5997fa6f6576572b5c2281c395a12772d7c
size 16095
diff --git a/Content/Shaders/BitonicSort.flax b/Content/Shaders/BitonicSort.flax
index c8a9e901c..1d5b8a581 100644
--- a/Content/Shaders/BitonicSort.flax
+++ b/Content/Shaders/BitonicSort.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c8371a1f4e0631e69f6dc6dbb8e11c8618351a7083293078270d60599f739e9f
-size 6725
+oid sha256:f46a61cf8d5183230176e661a51208bfeece16cc7238655f406288ff448af64e
+size 6721
diff --git a/Development/Scripts/Linux/CallBuildTool.sh b/Development/Scripts/Linux/CallBuildTool.sh
old mode 100644
new mode 100755
index 3b4568918..1a8affe20
--- a/Development/Scripts/Linux/CallBuildTool.sh
+++ b/Development/Scripts/Linux/CallBuildTool.sh
@@ -3,6 +3,12 @@
set -e
+testfilesize=$(wc -c < 'Source/Logo.png')
+if [ $testfilesize -le 1000 ]; then
+ echo "CallBuildTool ERROR: Repository was not cloned using Git LFS" 1>&2
+ exit 1
+fi
+
# Compile the build tool.
xbuild /nologo /verbosity:quiet "Source/Tools/Flax.Build/Flax.Build.csproj" /property:Configuration=Release /property:Platform=AnyCPU /target:Build
diff --git a/Development/Scripts/Windows/CallBuildTool.bat b/Development/Scripts/Windows/CallBuildTool.bat
index 4d9124776..c9729cf55 100644
--- a/Development/Scripts/Windows/CallBuildTool.bat
+++ b/Development/Scripts/Windows/CallBuildTool.bat
@@ -4,6 +4,10 @@ rem Copyright (c) 2012-2020 Wojciech Figat. All rights reserved.
if not exist "Development\Scripts\Windows\GetMSBuildPath.bat" goto Error_InvalidLocation
+for %%I in (Source\Logo.png) do if %%~zI LSS 2000 (
+ goto Error_MissingLFS
+)
+
call "Development\Scripts\Windows\GetMSBuildPath.bat"
if errorlevel 1 goto Error_NoVisualStudioEnvironment
@@ -33,6 +37,9 @@ Binaries\Tools\Flax.Build.exe %*
if errorlevel 1 goto Error_FlaxBuildFailed
exit /B 0
+:Error_MissingLFS
+echo CallBuildTool ERROR: Repository was not cloned using Git LFS
+goto Exit
:Error_InvalidLocation
echo CallBuildTool ERROR: The script is in invalid directory.
goto Exit
diff --git a/Flax.flaxproj b/Flax.flaxproj
index 26fb340ba..0c2683afb 100644
--- a/Flax.flaxproj
+++ b/Flax.flaxproj
@@ -3,7 +3,7 @@
"Version": {
"Major": 1,
"Minor": 0,
- "Build": 6215
+ "Build": 6216
},
"Company": "Flax",
"Copyright": "Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.",
diff --git a/GenerateProjectFiles.bat b/GenerateProjectFiles.bat
index 5db8aaf55..aeeac1c67 100644
--- a/GenerateProjectFiles.bat
+++ b/GenerateProjectFiles.bat
@@ -16,6 +16,7 @@ exit /B 0
:BuildToolFailed
echo Flax.Build tool failed.
+pause
goto Exit
:Exit
diff --git a/GenerateProjectFiles.sh b/GenerateProjectFiles.sh
old mode 100644
new mode 100755
diff --git a/PackagePlatforms.sh b/PackagePlatforms.sh
old mode 100644
new mode 100755
diff --git a/README.md b/README.md
index 1ad9f7ce4..9c5b83aae 100644
--- a/README.md
+++ b/README.md
@@ -26,6 +26,10 @@ This repository contains full source code of the Flax (excluding NDA-protected p
Follow the instructions below to compile and run the engine from source.
+## Flax plugin for Visual Studio
+
+Flax Visual Studio extension provides better programming workflow, C# scripts debugging functionality and allows to attach to running engine instance to debug C# source. This extension is available to download [here](https://marketplace.visualstudio.com/items?itemName=Flax.FlaxVS).
+
## Windows
* Install Visual Studio 2015 or newer
@@ -34,7 +38,8 @@ Follow the instructions below to compile and run the engine from source.
* Clone repo (with LFS)
* Run **GenerateProjectFiles.bat**
* Open `Flax.sln` and set solution configuration to **Editor.Development** and solution platform to **Win64**
-* Compile Flax project (hit F7 key)
+* Set Flax or FlaxEngine as startup project
+* Compile Flax project (hit F7 or CTRL+Shift+B)
* Run Flax (hit F5 key)
## Linux
@@ -49,10 +54,6 @@ Follow the instructions below to compile and run the engine from source.
* Open workspace with Visual Code
* Build and run
-# Flax plugin for Visual Studio
-
-Flax Visual Studio extension provides better programming workflow, C# scripts debugging functionality and allows to attach to running engine instance to debug C# source. This extension is available to download [here](https://marketplace.visualstudio.com/items?itemName=Flax.FlaxVS).
-
## Workspace directory
- **Binaries/** - executable files
diff --git a/Source/Editor/Content/Import/ModelImportEntry.cs b/Source/Editor/Content/Import/ModelImportEntry.cs
index e7cbe96ea..37525e6d3 100644
--- a/Source/Editor/Content/Import/ModelImportEntry.cs
+++ b/Source/Editor/Content/Import/ModelImportEntry.cs
@@ -262,9 +262,9 @@ namespace FlaxEditor.Content.Import
public int BaseLOD { get; set; } = 0;
///
- /// The amount of LODs to include in the model (all reaming ones starting from Base LOD will be generated).
+ /// The amount of LODs to include in the model (all remaining ones starting from Base LOD will be generated).
///
- [EditorOrder(1120), DefaultValue(4), Limit(1, Model.MaxLODs), EditorDisplay("Level Of Detail", "LOD Count"), Tooltip("The amount of LODs to include in the model (all reaming ones starting from Base LOD will be generated).")]
+ [EditorOrder(1120), DefaultValue(4), Limit(1, Model.MaxLODs), EditorDisplay("Level Of Detail", "LOD Count"), Tooltip("The amount of LODs to include in the model (all remaining ones starting from Base LOD will be generated).")]
public int LODCount { get; set; } = 4;
///
diff --git a/Source/Editor/Content/Proxy/PrefabProxy.cs b/Source/Editor/Content/Proxy/PrefabProxy.cs
index 39d77f25c..276bc0d30 100644
--- a/Source/Editor/Content/Proxy/PrefabProxy.cs
+++ b/Source/Editor/Content/Proxy/PrefabProxy.cs
@@ -162,8 +162,7 @@ namespace FlaxEditor.Content
// Auto fit actor to camera
float targetSize = 30.0f;
- BoundingBox bounds;
- Editor.GetActorEditorBox(_preview.Instance, out bounds);
+ Editor.GetActorEditorBox(_preview.Instance, out var bounds);
float maxSize = Mathf.Max(0.001f, bounds.Size.MaxValue);
_preview.Instance.Scale = new Vector3(targetSize / maxSize);
_preview.Instance.Position = Vector3.Zero;
@@ -175,6 +174,7 @@ namespace FlaxEditor.Content
///
public override void OnThumbnailDrawEnd(ThumbnailRequest request, ContainerControl guiRoot)
{
+ _preview.RemoveChildren();
_preview.Prefab = null;
_preview.Parent = null;
}
diff --git a/Source/Editor/Content/Tree/ContentTreeNode.cs b/Source/Editor/Content/Tree/ContentTreeNode.cs
index 7df407e08..4370bc8e7 100644
--- a/Source/Editor/Content/Tree/ContentTreeNode.cs
+++ b/Source/Editor/Content/Tree/ContentTreeNode.cs
@@ -295,7 +295,8 @@ namespace FlaxEditor.Content
StartRenaming();
return true;
case KeyboardKeys.Delete:
- Editor.Instance.Windows.ContentWin.Delete(Folder);
+ if (Folder.Exists)
+ Editor.Instance.Windows.ContentWin.Delete(Folder);
return true;
}
if (RootWindow.GetKey(KeyboardKeys.Control))
@@ -303,7 +304,8 @@ namespace FlaxEditor.Content
switch (key)
{
case KeyboardKeys.D:
- Editor.Instance.Windows.ContentWin.Duplicate(Folder);
+ if (Folder.Exists)
+ Editor.Instance.Windows.ContentWin.Duplicate(Folder);
return true;
}
}
diff --git a/Source/Editor/Cooker/Platform/Android/AndroidPlatformTools.cpp b/Source/Editor/Cooker/Platform/Android/AndroidPlatformTools.cpp
index bce6aa860..b4365b4bd 100644
--- a/Source/Editor/Cooker/Platform/Android/AndroidPlatformTools.cpp
+++ b/Source/Editor/Cooker/Platform/Android/AndroidPlatformTools.cpp
@@ -141,7 +141,7 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
const auto c = packageName[i];
if (c != '_' && c != '.' && !StringUtils::IsAlnum(c))
{
- LOG(Error, "Android Package Name \'{0}\' contains invalid chaarcter. Only letters, numbers, dots and underscore characters are allowed.", packageName);
+ LOG(Error, "Android Package Name \'{0}\' contains invalid character. Only letters, numbers, dots and underscore characters are allowed.", packageName);
return true;
}
}
diff --git a/Source/Editor/Cooker/Platform/UWP/UWPPlatformTools.cpp b/Source/Editor/Cooker/Platform/UWP/UWPPlatformTools.cpp
index f6c846fed..d9d2fe612 100644
--- a/Source/Editor/Cooker/Platform/UWP/UWPPlatformTools.cpp
+++ b/Source/Editor/Cooker/Platform/UWP/UWPPlatformTools.cpp
@@ -24,7 +24,7 @@ bool UWPPlatformTools::OnScriptsStepDone(CookingData& data)
const String assembliesPath = data.OutputPath;
if (FileSystem::CopyFile(assembliesPath / TEXT("Newtonsoft.Json.dll"), customBinPath))
{
- data.Error(TEXT("Failed to copy deloy custom assembly."));
+ data.Error(TEXT("Failed to copy deploy custom assembly."));
return true;
}
FileSystem::DeleteFile(assembliesPath / TEXT("Newtonsoft.Json.pdb"));
diff --git a/Source/Editor/Cooker/PlatformTools.h b/Source/Editor/Cooker/PlatformTools.h
index 28f6346ca..c98c008bc 100644
--- a/Source/Editor/Cooker/PlatformTools.h
+++ b/Source/Editor/Cooker/PlatformTools.h
@@ -48,7 +48,7 @@ public:
///
/// Gets the value indicating whenever platform requires AOT.
///
- /// True if platform uses AOT and needs C# assemblies to be be precompiled, otherwise false.
+ /// True if platform uses AOT and needs C# assemblies to be precompiled, otherwise false.
virtual bool UseAOT() const
{
return false;
diff --git a/Source/Editor/Cooker/Steps/ValidateStep.cpp b/Source/Editor/Cooker/Steps/ValidateStep.cpp
index 219301544..fdebca0a7 100644
--- a/Source/Editor/Cooker/Steps/ValidateStep.cpp
+++ b/Source/Editor/Cooker/Steps/ValidateStep.cpp
@@ -60,7 +60,7 @@ bool ValidateStep::Perform(CookingData& data)
AssetInfo info;
if (!Content::GetAssetInfo(GameSettings::FirstScene, info))
{
- data.Error(TEXT("Missing first scene."));
+ data.Error(TEXT("Missing first scene. Set it in the game settings."));
return true;
}
}
diff --git a/Source/Editor/CustomEditors/CustomEditorsUtil.cs b/Source/Editor/CustomEditors/CustomEditorsUtil.cs
index 2f97da333..9b83dd820 100644
--- a/Source/Editor/CustomEditors/CustomEditorsUtil.cs
+++ b/Source/Editor/CustomEditors/CustomEditorsUtil.cs
@@ -71,7 +71,7 @@ namespace FlaxEditor.CustomEditors
// Space before word starting with uppercase letter
if (char.IsUpper(c) && i > 0)
{
- if (i + 2 < length && !char.IsUpper(name[i + 1]) && !char.IsUpper(name[i + 2]))
+ if (i + 1 < length && !char.IsUpper(name[i + 1]))
sb.Append(' ');
}
// Space instead of underscore
diff --git a/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs b/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs
index 44a273ee4..6c825f46d 100644
--- a/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs
+++ b/Source/Editor/CustomEditors/Dedicated/LayersMatrixEditor.cs
@@ -76,7 +76,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
upperRightCell.AddChild(new Label
{
Height = labelsHeight,
- Text = layerNames[layerIndex],
+ Text = layerNames[layerNames.Length - layerIndex - 1],
HorizontalAlignment = TextAlignment.Near,
});
bottomLeftCell.AddChild(new Label
diff --git a/Source/Editor/CustomEditors/Editors/ActorStaticFlagsEditor.cs b/Source/Editor/CustomEditors/Editors/ActorStaticFlagsEditor.cs
index 86dd45812..cf649552a 100644
--- a/Source/Editor/CustomEditors/Editors/ActorStaticFlagsEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/ActorStaticFlagsEditor.cs
@@ -23,7 +23,7 @@ namespace FlaxEditor.CustomEditors.Editors
///
protected override void OnValueChanged()
{
- var value = (StaticFlags)element.EnumComboBox.EnumTypeValue;
+ var value = (StaticFlags)element.ComboBox.EnumTypeValue;
// If selected is single actor that has children, ask if apply flags to the sub objects as well
if (Values.IsSingleObject && (StaticFlags)Values[0] != value && ParentEditor.Values[0] is Actor actor && actor.HasChildren)
diff --git a/Source/Editor/CustomEditors/Editors/EnumEditor.cs b/Source/Editor/CustomEditors/Editors/EnumEditor.cs
index e277324e5..7954e18bf 100644
--- a/Source/Editor/CustomEditors/Editors/EnumEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/EnumEditor.cs
@@ -40,7 +40,7 @@ namespace FlaxEditor.CustomEditors.Editors
{
var enumType = Values.Type.Type != typeof(object) || Values[0] == null ? TypeUtils.GetType(Values.Type) : Values[0].GetType();
element = layout.Enum(enumType, null, mode);
- element.EnumComboBox.ValueChanged += OnValueChanged;
+ element.ComboBox.ValueChanged += OnValueChanged;
}
}
@@ -49,7 +49,7 @@ namespace FlaxEditor.CustomEditors.Editors
///
protected virtual void OnValueChanged()
{
- SetValue(element.EnumComboBox.EnumTypeValue);
+ SetValue(element.ComboBox.EnumTypeValue);
}
///
@@ -63,7 +63,7 @@ namespace FlaxEditor.CustomEditors.Editors
}
else
{
- element.EnumComboBox.EnumTypeValue = Values[0];
+ element.ComboBox.EnumTypeValue = Values[0];
}
}
}
diff --git a/Source/Editor/CustomEditors/Elements/EnumElement.cs b/Source/Editor/CustomEditors/Elements/EnumElement.cs
index 27b4dfdb9..be4085f40 100644
--- a/Source/Editor/CustomEditors/Elements/EnumElement.cs
+++ b/Source/Editor/CustomEditors/Elements/EnumElement.cs
@@ -16,7 +16,7 @@ namespace FlaxEditor.CustomEditors.Elements
///
/// The combo box used to show enum values.
///
- public EnumComboBox EnumComboBox;
+ public EnumComboBox ComboBox;
///
/// Initializes a new instance of the class.
@@ -26,10 +26,10 @@ namespace FlaxEditor.CustomEditors.Elements
/// The formatting mode.
public EnumElement(Type type, EnumComboBox.BuildEntriesDelegate customBuildEntriesDelegate = null, EnumDisplayAttribute.FormatMode formatMode = EnumDisplayAttribute.FormatMode.Default)
{
- EnumComboBox = new EnumComboBox(type, customBuildEntriesDelegate, formatMode);
+ ComboBox = new EnumComboBox(type, customBuildEntriesDelegate, formatMode);
}
///
- public override Control Control => EnumComboBox;
+ public override Control Control => ComboBox;
}
}
diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs
index 59810043d..f81f81ddd 100644
--- a/Source/Editor/Editor.cs
+++ b/Source/Editor/Editor.cs
@@ -254,7 +254,7 @@ namespace FlaxEditor
if (loadingPreview != null)
{
// Link it to the prefab preview to see it in the editor
- loadingPreview.customControlLinked = control.Control;
+ loadingPreview.customControlLinked = control;
return loadingPreview;
}
return null;
diff --git a/Source/Editor/Editor.h b/Source/Editor/Editor.h
index 761e4b059..8c56043d9 100644
--- a/Source/Editor/Editor.h
+++ b/Source/Editor/Editor.h
@@ -43,7 +43,7 @@ public:
public:
///
- /// The flag used to determine if a project was used with the older engine version last time it was opened. Some cached data should be regenerated to prevent version difference issues. The version number comparision is based on major and minor part of the version. Build number is ignored.
+ /// The flag used to determine if a project was used with the older engine version last time it was opened. Some cached data should be regenerated to prevent version difference issues. The version number comparison is based on major and minor part of the version. Build number is ignored.
///
static bool IsOldProjectOpened;
diff --git a/Source/Editor/GUI/AssetPicker.cs b/Source/Editor/GUI/AssetPicker.cs
index 63c1276ab..db012ab1e 100644
--- a/Source/Editor/GUI/AssetPicker.cs
+++ b/Source/Editor/GUI/AssetPicker.cs
@@ -355,12 +355,10 @@ namespace FlaxEditor.GUI
_mousePos = location;
// Check if start drag drop
- if (_isMouseDown && Vector2.Distance(location, _mouseDownPos) > 10.0f)
+ if (_isMouseDown && Vector2.Distance(location, _mouseDownPos) > 10.0f && IconRect.Contains(_mouseDownPos))
{
- // Clear flag
- _isMouseDown = false;
-
// Do the drag
+ _isMouseDown = false;
DoDrag();
}
@@ -370,35 +368,35 @@ namespace FlaxEditor.GUI
///
public override bool OnMouseUp(Vector2 location, MouseButton button)
{
- if (button == MouseButton.Left)
+ if (button == MouseButton.Left && _isMouseDown)
{
_isMouseDown = false;
- }
- // Buttons logic
- if (Button1Rect.Contains(location))
- {
- // Show asset picker popup
- Focus();
- AssetSearchPopup.Show(this, Button1Rect.BottomLeft, IsValid, assetItem =>
+ // Buttons logic
+ if (Button1Rect.Contains(location))
{
- SelectedItem = assetItem;
- RootWindow.Focus();
+ // Show asset picker popup
Focus();
- });
- }
- else if (_selected != null || _selectedItem != null)
- {
- if (Button2Rect.Contains(location) && _selectedItem != null)
- {
- // Select asset
- Editor.Instance.Windows.ContentWin.Select(_selectedItem);
+ AssetSearchPopup.Show(this, Button1Rect.BottomLeft, IsValid, assetItem =>
+ {
+ SelectedItem = assetItem;
+ RootWindow.Focus();
+ Focus();
+ });
}
- else if (Button3Rect.Contains(location))
+ else if (_selected != null || _selectedItem != null)
{
- // Deselect asset
- Focus();
- SelectedItem = null;
+ if (Button2Rect.Contains(location) && _selectedItem != null)
+ {
+ // Select asset
+ Editor.Instance.Windows.ContentWin.Select(_selectedItem);
+ }
+ else if (Button3Rect.Contains(location))
+ {
+ // Deselect asset
+ Focus();
+ SelectedItem = null;
+ }
}
}
@@ -409,8 +407,7 @@ namespace FlaxEditor.GUI
///
public override bool OnMouseDown(Vector2 location, MouseButton button)
{
- // Set flag for dragging asset
- if (button == MouseButton.Left && IconRect.Contains(location))
+ if (button == MouseButton.Left)
{
_isMouseDown = true;
_mouseDownPos = location;
diff --git a/Source/Editor/GUI/CurveEditor.cs b/Source/Editor/GUI/CurveEditor.cs
index 8840a7f06..cef9a9dec 100644
--- a/Source/Editor/GUI/CurveEditor.cs
+++ b/Source/Editor/GUI/CurveEditor.cs
@@ -221,7 +221,7 @@ namespace FlaxEditor.GUI
}
///
- /// Filters teh given value using the the .
+ /// Filters the given value using the .
///
/// The mode.
/// The value to process.
diff --git a/Source/Editor/GUI/Dialogs/Dialog.cs b/Source/Editor/GUI/Dialogs/Dialog.cs
index b8897b2e1..173dd9128 100644
--- a/Source/Editor/GUI/Dialogs/Dialog.cs
+++ b/Source/Editor/GUI/Dialogs/Dialog.cs
@@ -186,7 +186,7 @@ namespace FlaxEditor.GUI.Dialogs
// Clean up
_window = null;
- // Check if any thead is blocked during ShowDialog, then wait for it
+ // Check if any thread is blocked during ShowDialog, then wait for it
bool wait = true;
while (wait)
{
diff --git a/Source/Editor/GUI/Docking/DockWindow.cs b/Source/Editor/GUI/Docking/DockWindow.cs
index aa6d94ca8..56c78efed 100644
--- a/Source/Editor/GUI/Docking/DockWindow.cs
+++ b/Source/Editor/GUI/Docking/DockWindow.cs
@@ -307,6 +307,14 @@ namespace FlaxEditor.GUI.Docking
_dockedTo?.SelectTab(this, autoFocus);
}
+ ///
+ /// Brings the window to the front of the Z order.
+ ///
+ public void BringToFront()
+ {
+ _dockedTo?.RootWindow?.BringToFront();
+ }
+
internal void OnUnlinkInternal()
{
OnUnlink();
@@ -412,6 +420,7 @@ namespace FlaxEditor.GUI.Docking
base.Focus();
SelectTab();
+ BringToFront();
}
///
diff --git a/Source/Editor/GUI/Docking/MasterDockPanel.cs b/Source/Editor/GUI/Docking/MasterDockPanel.cs
index f7acdbed4..a560de195 100644
--- a/Source/Editor/GUI/Docking/MasterDockPanel.cs
+++ b/Source/Editor/GUI/Docking/MasterDockPanel.cs
@@ -64,7 +64,7 @@ namespace FlaxEditor.GUI.Docking
for (int i = 0; i < childPanels.Length; i++)
childPanels[i].Dispose();
- // Delete reaming controls (except tabs proxy)
+ // Delete remaining controls (except tabs proxy)
if (TabsProxy != null)
TabsProxy.Parent = null;
DisposeChildren();
diff --git a/Source/Editor/GUI/Input/SliderControl.cs b/Source/Editor/GUI/Input/SliderControl.cs
index 90288cfd0..77e8a5da8 100644
--- a/Source/Editor/GUI/Input/SliderControl.cs
+++ b/Source/Editor/GUI/Input/SliderControl.cs
@@ -168,6 +168,7 @@ namespace FlaxEditor.GUI.Input
{
if (button == MouseButton.Left)
{
+ Focus();
float mousePosition = location.X;
if (_thumbRect.Contains(ref location))
@@ -208,7 +209,6 @@ namespace FlaxEditor.GUI.Input
{
if (button == MouseButton.Left && _isSliding)
{
- // End sliding
EndSliding();
return true;
}
diff --git a/Source/Editor/GUI/Input/UIntValueBox.cs b/Source/Editor/GUI/Input/UIntValueBox.cs
index 9f1b2c1f4..d691be116 100644
--- a/Source/Editor/GUI/Input/UIntValueBox.cs
+++ b/Source/Editor/GUI/Input/UIntValueBox.cs
@@ -143,6 +143,8 @@ namespace FlaxEditor.GUI.Input
try
{
var value = ShuntingYard.Parse(Text);
+ if (value < 0)
+ value = 0;
Value = (uint)value;
}
catch (Exception ex)
diff --git a/Source/Editor/GUI/Input/ValueBox.cs b/Source/Editor/GUI/Input/ValueBox.cs
index 8ee1c3887..d34acd17b 100644
--- a/Source/Editor/GUI/Input/ValueBox.cs
+++ b/Source/Editor/GUI/Input/ValueBox.cs
@@ -49,6 +49,11 @@ namespace FlaxEditor.GUI.Input
///
protected T _startSlideValue;
+ ///
+ /// The text cached on editing start. Used to compare with the end result to detect changes.
+ ///
+ protected string _startEditText;
+
private Vector2 _startSlideLocation;
///
@@ -257,11 +262,23 @@ namespace FlaxEditor.GUI.Input
return base.OnMouseUp(location, button);
}
+ ///
+ protected override void OnEditBegin()
+ {
+ base.OnEditBegin();
+
+ _startEditText = _text;
+ }
+
///
protected override void OnEditEnd()
{
- // Update value
- TryGetValue();
+ if (_startEditText != _text)
+ {
+ // Update value
+ TryGetValue();
+ }
+ _startEditText = null;
base.OnEditEnd();
}
diff --git a/Source/Editor/GUI/Table.cs b/Source/Editor/GUI/Table.cs
index e070cba17..cca26cadc 100644
--- a/Source/Editor/GUI/Table.cs
+++ b/Source/Editor/GUI/Table.cs
@@ -120,7 +120,7 @@ namespace FlaxEditor.GUI
///
/// Draws the column.
///
- /// The the header area rectangle.
+ /// The header area rectangle.
/// The zero-based index of the column.
protected virtual void DrawColumn(ref Rectangle rect, int columnIndex)
{
diff --git a/Source/Editor/GUI/Timeline/GUI/KeyframesEditor.cs b/Source/Editor/GUI/Timeline/GUI/KeyframesEditor.cs
index abd3e78a8..a12a71e21 100644
--- a/Source/Editor/GUI/Timeline/GUI/KeyframesEditor.cs
+++ b/Source/Editor/GUI/Timeline/GUI/KeyframesEditor.cs
@@ -401,7 +401,7 @@ namespace FlaxEditor.GUI
}
///
- /// Converts the input point from editor editor contents control space into the keyframes time/value coordinates.
+ /// Converts the input point from editor contents control space into the keyframes time/value coordinates.
///
/// The point.
/// The keyframes contents area bounds.
diff --git a/Source/Editor/GUI/Timeline/Track.cs b/Source/Editor/GUI/Timeline/Track.cs
index 4f5278251..6ba8191d6 100644
--- a/Source/Editor/GUI/Timeline/Track.cs
+++ b/Source/Editor/GUI/Timeline/Track.cs
@@ -16,6 +16,7 @@ namespace FlaxEditor.GUI.Timeline
/// The Timeline track that contains a header and custom timeline events/media.
///
///
+ [HideInEditor]
public class Track : ContainerControl
{
///
diff --git a/Source/Editor/GUI/Timeline/Tracks/MemberTrack.cs b/Source/Editor/GUI/Timeline/Tracks/MemberTrack.cs
index 57de46ee4..250fb73c3 100644
--- a/Source/Editor/GUI/Timeline/Tracks/MemberTrack.cs
+++ b/Source/Editor/GUI/Timeline/Tracks/MemberTrack.cs
@@ -179,7 +179,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
}
///
- /// Evaluates the member value value at the specified time.
+ /// Evaluates the member value at the specified time.
///
/// The time to evaluate the member at.
/// The member value at provided time.
diff --git a/Source/Editor/GUI/Tree/TreeNode.cs b/Source/Editor/GUI/Tree/TreeNode.cs
index 727da3edd..f7e5f115a 100644
--- a/Source/Editor/GUI/Tree/TreeNode.cs
+++ b/Source/Editor/GUI/Tree/TreeNode.cs
@@ -21,7 +21,7 @@ namespace FlaxEditor.GUI.Tree
///
/// The default node offset on Y axis.
///
- public const float DefaultNodeOffsetY = 1;
+ public const float DefaultNodeOffsetY = 0;
private Tree _tree;
@@ -539,7 +539,7 @@ namespace FlaxEditor.GUI.Tree
{
if (new Rectangle(_headerRect.X, _headerRect.Y - DefaultDragInsertPositionMargin - DefaultNodeOffsetY, _headerRect.Width, DefaultDragInsertPositionMargin * 2.0f).Contains(location))
_dragOverMode = DragItemPositioning.Above;
- else if (IsCollapsed && new Rectangle(_headerRect.X, _headerRect.Bottom - DefaultDragInsertPositionMargin, _headerRect.Width, DefaultDragInsertPositionMargin * 2.0f).Contains(location))
+ else if ((IsCollapsed || !HasAnyVisibleChild) && new Rectangle(_headerRect.X, _headerRect.Bottom - DefaultDragInsertPositionMargin, _headerRect.Width, DefaultDragInsertPositionMargin * 2.0f).Contains(location))
_dragOverMode = DragItemPositioning.Below;
else
_dragOverMode = DragItemPositioning.At;
diff --git a/Source/Editor/Gizmo/GizmosCollection.cs b/Source/Editor/Gizmo/GizmosCollection.cs
index a246aeeb0..5530a41a3 100644
--- a/Source/Editor/Gizmo/GizmosCollection.cs
+++ b/Source/Editor/Gizmo/GizmosCollection.cs
@@ -7,7 +7,7 @@ using FlaxEngine;
namespace FlaxEditor.Gizmo
{
///
- /// Represents collection of Gizmo tools where one is active and in use.
+ /// Represents collection of gizmo tools where one is active and in use.
///
///
[HideInEditor]
diff --git a/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs b/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs
index 8f871c635..0a11ecd77 100644
--- a/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs
+++ b/Source/Editor/Gizmo/TransformGizmoBase.Draw.cs
@@ -45,7 +45,7 @@ namespace FlaxEditor.Gizmo
)
{
// Error
- Platform.Fatal("Failed to load Transform Gizmo resources.");
+ Platform.Fatal("Failed to load transform gizmo resources.");
}
}
diff --git a/Source/Editor/Gizmo/TransformGizmoBase.Settings.cs b/Source/Editor/Gizmo/TransformGizmoBase.Settings.cs
index 786e001e6..2955fe6d7 100644
--- a/Source/Editor/Gizmo/TransformGizmoBase.Settings.cs
+++ b/Source/Editor/Gizmo/TransformGizmoBase.Settings.cs
@@ -104,7 +104,7 @@ namespace FlaxEditor.Gizmo
public Axis ActiveAxis => _activeAxis;
///
- /// Gets or sts the current gizmo mode.
+ /// Gets or sets the current gizmo mode.
///
public Mode ActiveMode
{
diff --git a/Source/Editor/Gizmo/TransformGizmoBase.cs b/Source/Editor/Gizmo/TransformGizmoBase.cs
index 87dcb6fa8..014143685 100644
--- a/Source/Editor/Gizmo/TransformGizmoBase.cs
+++ b/Source/Editor/Gizmo/TransformGizmoBase.cs
@@ -151,7 +151,7 @@ namespace FlaxEditor.Gizmo
// Set positions of the gizmo
UpdateGizmoPosition();
- // Scale Gizmo to fit on-screen
+ // Scale gizmo to fit on-screen
Vector3 vLength = Owner.ViewPosition - Position;
float gizmoSize = Editor.Instance.Options.Options.Visual.GizmoSize;
_screenScale = vLength.Length / GizmoScaleFactor * gizmoSize;
@@ -196,12 +196,10 @@ namespace FlaxEditor.Gizmo
private void UpdateTranslateScale()
{
bool isScaling = _activeMode == Mode.Scale;
-
Vector3 delta = Vector3.Zero;
Ray ray = Owner.MouseRay;
- Matrix invRotationMatrix;
- Matrix.Invert(ref _rotationMatrix, out invRotationMatrix);
+ Matrix.Invert(ref _rotationMatrix, out var invRotationMatrix);
ray.Position = Vector3.Transform(ray.Position, invRotationMatrix);
Vector3.TransformNormal(ref ray.Direction, ref invRotationMatrix, out ray.Direction);
@@ -211,9 +209,7 @@ namespace FlaxEditor.Gizmo
case Axis.X:
{
var plane = new Plane(Vector3.Backward, Vector3.Transform(Position, invRotationMatrix).Z);
-
- float intersection;
- if (ray.Intersects(ref plane, out intersection))
+ if (ray.Intersects(ref plane, out float intersection))
{
_intersectPosition = ray.Position + ray.Direction * intersection;
if (_lastIntersectionPosition != Vector3.Zero)
@@ -222,18 +218,14 @@ namespace FlaxEditor.Gizmo
? new Vector3(_tDelta.X, 0, 0)
: new Vector3(_tDelta.X, _tDelta.Y, 0);
}
-
break;
}
-
case Axis.Z:
case Axis.YZ:
case Axis.Y:
{
var plane = new Plane(Vector3.Left, Vector3.Transform(Position, invRotationMatrix).X);
-
- float intersection;
- if (ray.Intersects(ref plane, out intersection))
+ if (ray.Intersects(ref plane, out float intersection))
{
_intersectPosition = ray.Position + ray.Direction * intersection;
if (_lastIntersectionPosition != Vector3.Zero)
@@ -251,41 +243,31 @@ namespace FlaxEditor.Gizmo
break;
}
}
-
break;
}
-
case Axis.ZX:
{
var plane = new Plane(Vector3.Down, Vector3.Transform(Position, invRotationMatrix).Y);
-
- float intersection;
- if (ray.Intersects(ref plane, out intersection))
+ if (ray.Intersects(ref plane, out float intersection))
{
_intersectPosition = ray.Position + ray.Direction * intersection;
if (_lastIntersectionPosition != Vector3.Zero)
_tDelta = _intersectPosition - _lastIntersectionPosition;
delta = new Vector3(_tDelta.X, 0, _tDelta.Z);
}
-
break;
}
-
case Axis.Center:
{
- Vector3 gizmoToView = Position - Owner.ViewPosition;
+ var gizmoToView = Position - Owner.ViewPosition;
var plane = new Plane(-Vector3.Normalize(gizmoToView), gizmoToView.Length);
-
- float intersection;
- if (ray.Intersects(ref plane, out intersection))
+ if (ray.Intersects(ref plane, out float intersection))
{
_intersectPosition = ray.Position + ray.Direction * intersection;
if (_lastIntersectionPosition != Vector3.Zero)
_tDelta = _intersectPosition - _lastIntersectionPosition;
}
-
delta = _tDelta;
-
break;
}
}
@@ -299,14 +281,11 @@ namespace FlaxEditor.Gizmo
if ((isScaling ? ScaleSnapEnabled : TranslationSnapEnable) || Owner.UseSnapping)
{
float snapValue = isScaling ? ScaleSnapValue : TranslationSnapValue;
-
_translationScaleSnapDelta += delta;
-
delta = new Vector3(
(int)(_translationScaleSnapDelta.X / snapValue) * snapValue,
(int)(_translationScaleSnapDelta.Y / snapValue) * snapValue,
(int)(_translationScaleSnapDelta.Z / snapValue) * snapValue);
-
_translationScaleSnapDelta -= delta;
}
@@ -318,7 +297,30 @@ namespace FlaxEditor.Gizmo
}
else if (_activeMode == Mode.Scale)
{
- // Apply Scale
+ // Scale
+ if (_activeTransformSpace == TransformSpace.World && _activeAxis != Axis.Center)
+ {
+ var deltaLocal = delta;
+ Quaternion orientation = GetSelectedObject(0).Orientation;
+ delta = Vector3.Transform(delta, orientation);
+
+ // Fix axis sign of delta movement for rotated object in some cases (eg. rotated object by 90 deg on Y axis and scale in world space with Red/X axis)
+ switch (_activeAxis)
+ {
+ case Axis.X:
+ if (deltaLocal.X < 0)
+ delta *= -1;
+ break;
+ case Axis.Y:
+ if (deltaLocal.Y < 0)
+ delta *= -1;
+ break;
+ case Axis.Z:
+ if (deltaLocal.Z < 0)
+ delta *= -1;
+ break;
+ }
+ }
_scaleDelta = delta;
}
}
@@ -382,7 +384,7 @@ namespace FlaxEditor.Gizmo
// Snap to ground
if (_activeAxis == Axis.None && SelectionCount != 0 && Owner.SnapToGround)
{
- if (Physics.RayCast(Position, Vector3.Down, out var hit, float.MaxValue, int.MaxValue, false))
+ if (Physics.RayCast(Position, Vector3.Down, out var hit, float.MaxValue, uint.MaxValue, false))
{
StartTransforming();
var translationDelta = hit.Point - Position;
@@ -408,7 +410,6 @@ namespace FlaxEditor.Gizmo
case Mode.Translate:
UpdateTranslateScale();
break;
-
case Mode.Rotate:
UpdateRotate(dt);
break;
@@ -437,7 +438,7 @@ namespace FlaxEditor.Gizmo
translationDelta = _translationDelta;
_translationDelta = Vector3.Zero;
- // Prevent from moving objects too far away, like to different galaxy or sth
+ // Prevent from moving objects too far away, like to a different galaxy or sth
Vector3 prevMoveDelta = _accMoveDelta;
_accMoveDelta += _translationDelta;
if (_accMoveDelta.Length > Owner.ViewFarPlane * 0.7f)
diff --git a/Source/Editor/History/HistoryStack.cs b/Source/Editor/History/HistoryStack.cs
index c7a63efc4..e2d828ce9 100644
--- a/Source/Editor/History/HistoryStack.cs
+++ b/Source/Editor/History/HistoryStack.cs
@@ -74,7 +74,7 @@ namespace FlaxEditor.History
_reverseActions.PushBack(reverse[i]);
}
- // Cleanup reaming actions
+ // Cleanup remaining actions
for (int i = _historyActionsLimit; i < history.Length; i++)
{
history[i].Dispose();
diff --git a/Source/Editor/Modules/ContentFindingModule.cs b/Source/Editor/Modules/ContentFindingModule.cs
index 88b5832af..9be15e0d1 100644
--- a/Source/Editor/Modules/ContentFindingModule.cs
+++ b/Source/Editor/Modules/ContentFindingModule.cs
@@ -108,7 +108,7 @@ namespace FlaxEditor.Modules
///
/// Removes a quick action by name.
///
- /// Thr action's name.
+ /// The action's name.
/// True when it succeed, false if there is no Quick Action with this name.
public bool RemoveQuickAction(string name)
{
diff --git a/Source/Editor/Modules/ContentImportingModule.cs b/Source/Editor/Modules/ContentImportingModule.cs
index 03f434b9c..0c934f130 100644
--- a/Source/Editor/Modules/ContentImportingModule.cs
+++ b/Source/Editor/Modules/ContentImportingModule.cs
@@ -410,7 +410,7 @@ namespace FlaxEditor.Modules
{
if (request.Settings != null && entry.TryOverrideSettings(request.Settings))
{
- // Use overriden settings
+ // Use overridden settings
}
else if (!request.SkipSettingsDialog)
{
diff --git a/Source/Editor/Modules/WindowsModule.cs b/Source/Editor/Modules/WindowsModule.cs
index 9b80b664c..a8058b9d8 100644
--- a/Source/Editor/Modules/WindowsModule.cs
+++ b/Source/Editor/Modules/WindowsModule.cs
@@ -276,8 +276,8 @@ namespace FlaxEditor.Modules
// Get metadata
int version = int.Parse(root.Attributes["Version"].Value, CultureInfo.InvariantCulture);
var virtualDesktopBounds = Platform.VirtualDesktopBounds;
- var virtualDesktopSafeLeftCorner = virtualDesktopBounds.Location + new Vector2(0, 23); // 23 is a window strip size
- var virtualDesktopSafeRightCorner = virtualDesktopBounds.BottomRight - new Vector2(50, 50); // apply some safe area
+ var virtualDesktopSafeLeftCorner = virtualDesktopBounds.Location;
+ var virtualDesktopSafeRightCorner = virtualDesktopBounds.BottomRight;
switch (version)
{
@@ -971,7 +971,7 @@ namespace FlaxEditor.Modules
}
#region Window Events
-
+
private void OnEditorStateChanged()
{
for (int i = 0; i < Windows.Count; i++)
diff --git a/Source/Editor/Options/InputBinding.cs b/Source/Editor/Options/InputBinding.cs
index e28e8fa0c..eddd76882 100644
--- a/Source/Editor/Options/InputBinding.cs
+++ b/Source/Editor/Options/InputBinding.cs
@@ -143,7 +143,31 @@ namespace FlaxEditor.Options
{
var root = control.Root;
- if (root.GetKeyDown(Key))
+ if (root.GetKey(Key))
+ {
+ if (Modifier1 == KeyboardKeys.None || root.GetKey(Modifier1))
+ {
+ if (Modifier2 == KeyboardKeys.None || root.GetKey(Modifier2))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ ///
+ /// Processes this input binding to check if state matches.
+ ///
+ /// The input providing control.
+ /// The input key.
+ /// True if input has been processed, otherwise false.
+ public bool Process(Control control, KeyboardKeys key)
+ {
+ var root = control.Root;
+
+ if (key == Key)
{
if (Modifier1 == KeyboardKeys.None || root.GetKey(Modifier1))
{
@@ -435,16 +459,10 @@ namespace FlaxEditor.Options
for (int i = 0; i < _bindings.Count; i++)
{
var binding = _bindings[i].Binder(options);
- if (binding.Key == key)
+ if (binding.Process(control, key))
{
- if (binding.Modifier1 == KeyboardKeys.None || root.GetKey(binding.Modifier1))
- {
- if (binding.Modifier2 == KeyboardKeys.None || root.GetKey(binding.Modifier2))
- {
- _bindings[i].Callback();
- return true;
- }
- }
+ _bindings[i].Callback();
+ return true;
}
}
diff --git a/Source/Editor/Options/OptionsModule.cs b/Source/Editor/Options/OptionsModule.cs
index 7c0cd11da..3c501de85 100644
--- a/Source/Editor/Options/OptionsModule.cs
+++ b/Source/Editor/Options/OptionsModule.cs
@@ -41,7 +41,7 @@ namespace FlaxEditor.Options
private readonly Dictionary _customSettings = new Dictionary();
///
- /// Gets the custom settings factories. Each entry defines the custom settings type identified by teh given key name. The value si a factory function that returns the default options fpr a given type.
+ /// Gets the custom settings factories. Each entry defines the custom settings type identified by the given key name. The value is a factory function that returns the default options for a given type.
///
public IReadOnlyDictionary CustomSettings => _customSettings;
diff --git a/Source/Editor/Options/ViewportOptions.cs b/Source/Editor/Options/ViewportOptions.cs
index 6e1f8a9d6..5558ac89d 100644
--- a/Source/Editor/Options/ViewportOptions.cs
+++ b/Source/Editor/Options/ViewportOptions.cs
@@ -45,5 +45,12 @@ namespace FlaxEditor.Options
[DefaultValue(60.0f), Limit(35.0f, 160.0f, 0.1f)]
[EditorDisplay("Defaults", "Default Field Of View"), EditorOrder(140), Tooltip("The default field of view angle (in degrees) for the viewport camera.")]
public float DefaultFieldOfView { get; set; } = 60.0f;
+
+ ///
+ /// Gets or sets if the panning direction is inverted for the viewport camera.
+ ///
+ [DefaultValue(false)]
+ [EditorDisplay("Defaults"), EditorOrder(150), Tooltip( "Invert the panning direction for the viewport camera." )]
+ public bool DefaultInvertPanning { get; set; } = false;
}
}
diff --git a/Source/Editor/Progress/ProgressHandler.cs b/Source/Editor/Progress/ProgressHandler.cs
index da2782d16..958612e51 100644
--- a/Source/Editor/Progress/ProgressHandler.cs
+++ b/Source/Editor/Progress/ProgressHandler.cs
@@ -79,7 +79,7 @@ namespace FlaxEditor.Progress
}
///
- /// Called when progress action gets updated (changed nfo text or progress value).
+ /// Called when progress action gets updated (changed info text or progress value).
///
/// The progress (normalized to range [0;1]).
/// The information text.
diff --git a/Source/Editor/ProjectInfo.cpp b/Source/Editor/ProjectInfo.cpp
index 0f916241e..47782ab9d 100644
--- a/Source/Editor/ProjectInfo.cpp
+++ b/Source/Editor/ProjectInfo.cpp
@@ -204,7 +204,7 @@ bool ProjectInfo::LoadProject(const String& projectPath)
reference.Project = Load(referencePath);
if (reference.Project == nullptr)
{
- LOG(Error, "Faield to load referenced project ({0}, from {1})", reference.Name, referencePath);
+ LOG(Error, "Failed to load referenced project ({0}, from {1})", reference.Name, referencePath);
return true;
}
}
@@ -277,7 +277,7 @@ bool ProjectInfo::LoadOldProject(const String& projectPath)
flaxReference.Project = Load(Globals::StartupFolder / TEXT("Flax.flaxproj"));
if (!flaxReference.Project)
{
- ShowProjectLoadError(TEXT("Failed to load Flax Engien project."), projectPath);
+ ShowProjectLoadError(TEXT("Failed to load Flax Engine project."), projectPath);
return true;
}
diff --git a/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioConnection.cpp b/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioConnection.cpp
index d73c5279a..54ba119f2 100644
--- a/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioConnection.cpp
+++ b/Source/Editor/Scripting/CodeEditors/VisualStudio/VisualStudioConnection.cpp
@@ -49,7 +49,7 @@ public:
{
if (dwRejectType == SERVERCALL_RETRYLATER)
{
- // Retry immediatey
+ // Retry immediately
return 99;
}
diff --git a/Source/Editor/Scripting/ScriptsBuilder.cpp b/Source/Editor/Scripting/ScriptsBuilder.cpp
index 7d581fa8a..7cced3e36 100644
--- a/Source/Editor/Scripting/ScriptsBuilder.cpp
+++ b/Source/Editor/Scripting/ScriptsBuilder.cpp
@@ -567,7 +567,7 @@ bool ScriptsBuilderService::Init()
LOG(Warning, "Missing EditorTarget property in opened project, using deducted target name {0}", Editor::Project->EditorTarget);
}
- // Remove any reaming files from previous Editor run hot-reloads
+ // Remove any remaining files from previous Editor run hot-reloads
const Char *target, *platform, *architecture, *configuration;
ScriptsBuilder::GetBinariesConfiguration(target, platform, architecture, configuration);
if (target)
diff --git a/Source/Editor/Surface/AnimGraphSurface.cs b/Source/Editor/Surface/AnimGraphSurface.cs
index 8621ed257..abffc4432 100644
--- a/Source/Editor/Surface/AnimGraphSurface.cs
+++ b/Source/Editor/Surface/AnimGraphSurface.cs
@@ -65,8 +65,8 @@ namespace FlaxEditor.Surface
NodeElementArchetype.Factory.Output(0, "Length", typeof(float), 0),
NodeElementArchetype.Factory.Output(1, "Time", typeof(float), 1),
NodeElementArchetype.Factory.Output(2, "Normalized Time", typeof(float), 2),
- NodeElementArchetype.Factory.Output(3, "Reaming Time", typeof(float), 3),
- NodeElementArchetype.Factory.Output(4, "Reaming Normalized Time", typeof(float), 4),
+ NodeElementArchetype.Factory.Output(3, "Remaining Time", typeof(float), 3),
+ NodeElementArchetype.Factory.Output(4, "Remaining Normalized Time", typeof(float), 4),
}
},
}
diff --git a/Source/Editor/Surface/Archetypes/Animation.StateMachine.cs b/Source/Editor/Surface/Archetypes/Animation.StateMachine.cs
index 9f9e21f4f..2faa9feef 100644
--- a/Source/Editor/Surface/Archetypes/Animation.StateMachine.cs
+++ b/Source/Editor/Surface/Archetypes/Animation.StateMachine.cs
@@ -1046,7 +1046,7 @@ namespace FlaxEditor.Surface.Archetypes
startPos += nrm;
endPos += nrm;
- // Swap fo the other arrow
+ // Swap to the other arrow
if (!diff)
{
var tmp = startPos;
diff --git a/Source/Editor/Surface/Archetypes/Animation.cs b/Source/Editor/Surface/Archetypes/Animation.cs
index b27fb9bd6..15096e696 100644
--- a/Source/Editor/Surface/Archetypes/Animation.cs
+++ b/Source/Editor/Surface/Archetypes/Animation.cs
@@ -764,8 +764,8 @@ namespace FlaxEditor.Surface.Archetypes
NodeElementArchetype.Factory.Output(0, "Length", typeof(float), 0),
NodeElementArchetype.Factory.Output(1, "Time", typeof(float), 1),
NodeElementArchetype.Factory.Output(2, "Normalized Time", typeof(float), 2),
- NodeElementArchetype.Factory.Output(3, "Reaming Time", typeof(float), 3),
- NodeElementArchetype.Factory.Output(4, "Reaming Normalized Time", typeof(float), 4),
+ NodeElementArchetype.Factory.Output(3, "Remaining Time", typeof(float), 3),
+ NodeElementArchetype.Factory.Output(4, "Remaining Normalized Time", typeof(float), 4),
}
},
new NodeArchetype
@@ -791,7 +791,7 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Transform Node (local space)",
Description = "Transforms the skeleton node",
Flags = NodeFlags.AnimGraph,
- Size = new Vector2(270, 130),
+ Size = new Vector2(280, 130),
DefaultValues = new object[]
{
string.Empty,
@@ -816,7 +816,7 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Transform Node (model space)",
Description = "Transforms the skeleton node",
Flags = NodeFlags.AnimGraph,
- Size = new Vector2(270, 130),
+ Size = new Vector2(280, 130),
DefaultValues = new object[]
{
string.Empty,
@@ -872,7 +872,7 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Get Node Transform (model space)",
Description = "Samples the skeleton node transformation (in model space)",
Flags = NodeFlags.AnimGraph,
- Size = new Vector2(250, 40),
+ Size = new Vector2(324, 40),
DefaultValues = new object[]
{
string.Empty,
@@ -880,7 +880,7 @@ namespace FlaxEditor.Surface.Archetypes
Elements = new[]
{
NodeElementArchetype.Factory.Input(0, string.Empty, true, typeof(void), 0),
- NodeElementArchetype.Factory.SkeletonNodeNameSelect(40, Surface.Constants.LayoutOffsetY * 1, 120, 0),
+ NodeElementArchetype.Factory.SkeletonNodeNameSelect(40, Surface.Constants.LayoutOffsetY * 1, 160, 0),
NodeElementArchetype.Factory.Text(0, Surface.Constants.LayoutOffsetY * 1, "Node:"),
NodeElementArchetype.Factory.Output(0, "Transform", typeof(Transform), 1),
}
@@ -903,7 +903,7 @@ namespace FlaxEditor.Surface.Archetypes
NodeElementArchetype.Factory.Input(0, string.Empty, true, typeof(void), 1),
NodeElementArchetype.Factory.Input(1, "Target", true, typeof(Vector3), 2),
NodeElementArchetype.Factory.Input(2, "Weight", true, typeof(float), 3, 1),
- NodeElementArchetype.Factory.SkeletonNodeNameSelect(40, Surface.Constants.LayoutOffsetY * 3, 120, 0),
+ NodeElementArchetype.Factory.SkeletonNodeNameSelect(40, Surface.Constants.LayoutOffsetY * 3, 160, 0),
NodeElementArchetype.Factory.Text(0, Surface.Constants.LayoutOffsetY * 3, "Node:"),
}
},
@@ -913,7 +913,7 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Get Node Transform (local space)",
Description = "Samples the skeleton node transformation (in local space)",
Flags = NodeFlags.AnimGraph,
- Size = new Vector2(250, 40),
+ Size = new Vector2(316, 40),
DefaultValues = new object[]
{
string.Empty,
diff --git a/Source/Editor/Surface/Archetypes/Constants.cs b/Source/Editor/Surface/Archetypes/Constants.cs
index 63cec366b..3ae9d6a8a 100644
--- a/Source/Editor/Surface/Archetypes/Constants.cs
+++ b/Source/Editor/Surface/Archetypes/Constants.cs
@@ -379,7 +379,7 @@ namespace FlaxEditor.Surface.Archetypes
Elements = new[]
{
NodeElementArchetype.Factory.Output(0, "Value", typeof(uint), 0),
- NodeElementArchetype.Factory.Integer(0, 0, 0)
+ NodeElementArchetype.Factory.UnsignedInteger(0, 0, 0, -1, 0, int.MaxValue)
}
},
};
diff --git a/Source/Editor/Surface/Archetypes/Function.cs b/Source/Editor/Surface/Archetypes/Function.cs
index 7c4963072..9f7e3757a 100644
--- a/Source/Editor/Surface/Archetypes/Function.cs
+++ b/Source/Editor/Surface/Archetypes/Function.cs
@@ -867,8 +867,15 @@ namespace FlaxEditor.Surface.Archetypes
for (int i = 0; i < signature.Params.Length; i++)
{
ref var param = ref signature.Params[i];
- if (param.Type != memberParameters[i].Type || param.IsOut != memberParameters[i].IsOut)
+ ref var paramMember = ref memberParameters[i];
+ if (param.Type != paramMember.Type || param.IsOut != paramMember.IsOut)
{
+ // Special case: param.Type is serialized as just a type while paramMember.Type might be a reference for output parameters (eg. `out Int32` vs `out Int32&`)
+ var paramMemberTypeName = paramMember.Type.TypeName;
+ if (param.IsOut && param.IsOut == paramMember.IsOut && paramMember.Type.IsReference && !param.Type.IsReference &&
+ paramMemberTypeName.Substring(0, paramMemberTypeName.Length - 1) == param.Type.TypeName)
+ continue;
+
isInvalid = true;
break;
}
@@ -1176,7 +1183,7 @@ namespace FlaxEditor.Surface.Archetypes
[EditorOrder(0), Tooltip("The name of the parameter."), ExpandGroups]
public string Name;
- [EditorOrder(1), Tooltip("The type fo the parameter value.")]
+ [EditorOrder(1), Tooltip("The type for the parameter value.")]
[TypeReference(typeof(object), nameof(IsTypeValid))]
public ScriptType Type;
@@ -1547,7 +1554,7 @@ namespace FlaxEditor.Surface.Archetypes
// Check if return type has been changed
if (_signature.ReturnType != prevReturnType)
{
- // Update all return nodes used by this function to match teh new type
+ // Update all return nodes used by this function to match the new type
var usedNodes = DepthFirstTraversal(false);
var hasAnyReturnNode = false;
foreach (var node in usedNodes)
diff --git a/Source/Editor/Surface/Archetypes/Material.cs b/Source/Editor/Surface/Archetypes/Material.cs
index a007db7d7..ceb9921cb 100644
--- a/Source/Editor/Surface/Archetypes/Material.cs
+++ b/Source/Editor/Surface/Archetypes/Material.cs
@@ -642,6 +642,179 @@ namespace FlaxEditor.Surface.Archetypes
NodeElementArchetype.Factory.Output(0, "XYZ", typeof(Vector3), 0),
}
},
+ new NodeArchetype
+ {
+ TypeID = 26,
+ Title = "Blend Normals",
+ Description = "Blend two normal maps to create a single normal map",
+ Flags = NodeFlags.MaterialGraph,
+ Size = new Vector2(170, 40),
+ ConnectionsHints = ConnectionsHint.Vector,
+ Elements = new[]
+ {
+ NodeElementArchetype.Factory.Input(0, "Base Normal", true, typeof(Vector3), 0),
+ NodeElementArchetype.Factory.Input(1, "Additional Normal", true, typeof(Vector3), 1),
+ NodeElementArchetype.Factory.Output(0, "Result", typeof(Vector3), 2)
+ }
+ },
+ new NodeArchetype
+ {
+ TypeID = 27,
+ Title = "Rotator",
+ Description = "Rotates UV coordinates according to a scalar angle (0-1)",
+ Flags = NodeFlags.MaterialGraph,
+ Size = new Vector2(150, 55),
+ Elements = new[]
+ {
+ NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Vector2), 0),
+ NodeElementArchetype.Factory.Input(1, "Center", true, typeof(Vector2), 1),
+ NodeElementArchetype.Factory.Input(2, "Rotation Angle", true, typeof(float), 2),
+ NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Vector2), 3),
+ }
+ },
+ new NodeArchetype
+ {
+ TypeID = 28,
+ Title = "Sphere Mask",
+ Description = "Creates a sphere mask",
+ Flags = NodeFlags.MaterialGraph,
+ Size = new Vector2(150, 100),
+ ConnectionsHints = ConnectionsHint.Vector,
+ IndependentBoxes = new[]
+ {
+ 0,
+ 1
+ },
+ DefaultValues = new object[]
+ {
+ 0.3f,
+ 0.5f,
+ false
+ },
+ Elements = new[]
+ {
+ NodeElementArchetype.Factory.Input(0, "A", true, null, 0),
+ NodeElementArchetype.Factory.Input(1, "B", true, null, 1),
+ NodeElementArchetype.Factory.Input(2, "Radius", true, typeof(float), 2, 0),
+ NodeElementArchetype.Factory.Input(3, "Hardness", true, typeof(float), 3, 1),
+ NodeElementArchetype.Factory.Input(4, "Invert", true, typeof(bool), 4, 2),
+ NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 5),
+ }
+ },
+ new NodeArchetype
+ {
+ TypeID = 29,
+ Title = "UV Tiling & Offset",
+ Description = "Takes UVs and applies tiling and offset",
+ Flags = NodeFlags.MaterialGraph,
+ Size = new Vector2(175, 60),
+ DefaultValues = new object[]
+ {
+ Vector2.One,
+ Vector2.Zero
+ },
+ Elements = new[]
+ {
+ NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Vector2), 0),
+ NodeElementArchetype.Factory.Input(1, "Tiling", true, typeof(Vector2), 1, 0),
+ NodeElementArchetype.Factory.Input(2, "Offset", true, typeof(Vector2), 2, 1),
+ NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Vector2), 3),
+ }
+ },
+ new NodeArchetype
+ {
+ TypeID = 30,
+ Title = "DDX",
+ Description = "Returns the partial derivative of the specified value with respect to the screen-space x-coordinate",
+ Flags = NodeFlags.MaterialGraph,
+ Size = new Vector2(90, 25),
+ ConnectionsHints = ConnectionsHint.Numeric,
+ IndependentBoxes = new[] { 0 },
+ DependentBoxes = new[] { 1 },
+ Elements = new[]
+ {
+ NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
+ NodeElementArchetype.Factory.Output(0, string.Empty, null, 1),
+ }
+ },
+ new NodeArchetype
+ {
+ TypeID = 31,
+ Title = "DDY",
+ Description = "Returns the partial derivative of the specified value with respect to the screen-space y-coordinate",
+ Flags = NodeFlags.MaterialGraph,
+ Size = new Vector2(90, 25),
+ ConnectionsHints = ConnectionsHint.Numeric,
+ IndependentBoxes = new[] { 0 },
+ DependentBoxes = new[] { 1 },
+ Elements = new[]
+ {
+ NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
+ NodeElementArchetype.Factory.Output(0, string.Empty, null, 1),
+ }
+ },
+ new NodeArchetype
+ {
+ TypeID = 32,
+ Title = "Sign",
+ Description = "Returns -1 if value is less than zero; 0 if value equals zero; and 1 if value is greater than zero",
+ Flags = NodeFlags.MaterialGraph,
+ Size = new Vector2(90, 25),
+ ConnectionsHints = ConnectionsHint.Numeric,
+ IndependentBoxes = new[] { 0 },
+ Elements = new[]
+ {
+ NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
+ NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 1),
+ }
+ },
+ new NodeArchetype
+ {
+ TypeID = 33,
+ Title = "Any",
+ Description = "True if any components of value are non-zero; otherwise, false",
+ Flags = NodeFlags.MaterialGraph,
+ Size = new Vector2(90, 25),
+ ConnectionsHints = ConnectionsHint.Numeric,
+ IndependentBoxes = new[] { 0 },
+ Elements = new[]
+ {
+ NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
+ NodeElementArchetype.Factory.Output(0, string.Empty, typeof(bool), 1),
+ }
+ },
+ new NodeArchetype
+ {
+ TypeID = 34,
+ Title = "All",
+ Description = "Determines if all components of the specified value are non-zero",
+ Flags = NodeFlags.MaterialGraph,
+ Size = new Vector2(90, 25),
+ ConnectionsHints = ConnectionsHint.Numeric,
+ IndependentBoxes = new[] { 0 },
+ Elements = new[]
+ {
+ NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
+ NodeElementArchetype.Factory.Output(0, string.Empty, typeof(bool), 1),
+ }
+ },
+ new NodeArchetype
+ {
+ TypeID = 35,
+ Title = "Black Body",
+ Description = "Simulates black body radiation via a given temperature in kelvin",
+ Flags = NodeFlags.MaterialGraph,
+ Size = new Vector2(120, 25),
+ DefaultValues = new object[]
+ {
+ 0.0f,
+ },
+ Elements = new[]
+ {
+ NodeElementArchetype.Factory.Input(0, "Temp", true, typeof(float), 0, 0),
+ NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Vector3), 1),
+ }
+ },
};
}
}
diff --git a/Source/Editor/Surface/Archetypes/Math.cs b/Source/Editor/Surface/Archetypes/Math.cs
index 92ae69a12..7416ea498 100644
--- a/Source/Editor/Surface/Archetypes/Math.cs
+++ b/Source/Editor/Surface/Archetypes/Math.cs
@@ -404,6 +404,29 @@ namespace FlaxEditor.Surface.Archetypes
NodeElementArchetype.Factory.Output(0, "A | B", null, 2),
}
},
+ new NodeArchetype
+ {
+ TypeID = 48,
+ Title = "Remap",
+ Description = "Remaps a value from one range to another, so for example having 25 in a range of 0 to 100 being remapped to 0 to 1 would return 0.25",
+ Flags = NodeFlags.AllGraphs,
+ Size = new Vector2(175, 75),
+ DefaultValues = new object[]
+ {
+ 25.0f,
+ new Vector2(0.0f, 100.0f),
+ new Vector2(0.0f, 1.0f),
+ false
+ },
+ Elements = new[]
+ {
+ NodeElementArchetype.Factory.Input(0, "Value", true, typeof(float), 0, 0),
+ NodeElementArchetype.Factory.Input(1, "In Range", true, typeof(Vector2), 1, 1),
+ NodeElementArchetype.Factory.Input(2, "Out Range", true, typeof(Vector2), 2, 2),
+ NodeElementArchetype.Factory.Input(3, "Clamp", true, typeof(bool), 3, 3),
+ NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 4),
+ }
+ },
};
}
}
diff --git a/Source/Editor/Surface/Archetypes/Packing.cs b/Source/Editor/Surface/Archetypes/Packing.cs
index 04f3819ea..f5b466ab3 100644
--- a/Source/Editor/Surface/Archetypes/Packing.cs
+++ b/Source/Editor/Surface/Archetypes/Packing.cs
@@ -486,7 +486,7 @@ namespace FlaxEditor.Surface.Archetypes
Description = "Unpack X component from Vector",
Flags = NodeFlags.AllGraphs,
ConnectionsHints = ConnectionsHint.Vector,
- Size = new Vector2(160, 30),
+ Size = new Vector2(110, 30),
Elements = new[]
{
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
@@ -500,7 +500,7 @@ namespace FlaxEditor.Surface.Archetypes
Description = "Unpack Y component from Vector",
Flags = NodeFlags.AllGraphs,
ConnectionsHints = ConnectionsHint.Vector,
- Size = new Vector2(160, 30),
+ Size = new Vector2(110, 30),
Elements = new[]
{
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
@@ -514,7 +514,7 @@ namespace FlaxEditor.Surface.Archetypes
Description = "Unpack Z component from Vector",
Flags = NodeFlags.AllGraphs,
ConnectionsHints = ConnectionsHint.Vector,
- Size = new Vector2(160, 30),
+ Size = new Vector2(110, 30),
Elements = new[]
{
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
@@ -528,7 +528,7 @@ namespace FlaxEditor.Surface.Archetypes
Description = "Unpack W component from Vector",
Flags = NodeFlags.AllGraphs,
ConnectionsHints = ConnectionsHint.Vector,
- Size = new Vector2(160, 30),
+ Size = new Vector2(110, 30),
Elements = new[]
{
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
@@ -544,7 +544,7 @@ namespace FlaxEditor.Surface.Archetypes
Description = "Unpack XY components from Vector",
Flags = NodeFlags.AllGraphs,
ConnectionsHints = ConnectionsHint.Vector,
- Size = new Vector2(160, 30),
+ Size = new Vector2(110, 30),
Elements = new[]
{
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
@@ -558,7 +558,7 @@ namespace FlaxEditor.Surface.Archetypes
Description = "Unpack XZ components from Vector",
Flags = NodeFlags.AllGraphs,
ConnectionsHints = ConnectionsHint.Vector,
- Size = new Vector2(160, 30),
+ Size = new Vector2(110, 30),
Elements = new[]
{
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
@@ -572,7 +572,7 @@ namespace FlaxEditor.Surface.Archetypes
Description = "Unpack YZ components from Vector",
Flags = NodeFlags.AllGraphs,
ConnectionsHints = ConnectionsHint.Vector,
- Size = new Vector2(160, 30),
+ Size = new Vector2(110, 30),
Elements = new[]
{
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
@@ -588,7 +588,7 @@ namespace FlaxEditor.Surface.Archetypes
Description = "Unpack XYZ components from Vector",
Flags = NodeFlags.AllGraphs,
ConnectionsHints = ConnectionsHint.Vector,
- Size = new Vector2(160, 30),
+ Size = new Vector2(110, 30),
Elements = new[]
{
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
diff --git a/Source/Editor/Surface/Archetypes/Parameters.cs b/Source/Editor/Surface/Archetypes/Parameters.cs
index 43048d19d..5332b3475 100644
--- a/Source/Editor/Surface/Archetypes/Parameters.cs
+++ b/Source/Editor/Surface/Archetypes/Parameters.cs
@@ -32,7 +32,7 @@ namespace FlaxEditor.Surface.Archetypes
public Dictionary Prototypes = DefaultPrototypes;
///
- /// The default prototypes for thr node elements to use for the given parameter type.
+ /// The default prototypes for the node elements to use for the given parameter type.
///
public static readonly Dictionary DefaultPrototypes = new Dictionary
{
diff --git a/Source/Editor/Surface/Archetypes/Particles.cs b/Source/Editor/Surface/Archetypes/Particles.cs
index 4d72bfa7b..1f3ee8ce6 100644
--- a/Source/Editor/Surface/Archetypes/Particles.cs
+++ b/Source/Editor/Surface/Archetypes/Particles.cs
@@ -338,7 +338,7 @@ namespace FlaxEditor.Surface.Archetypes
Size = new Vector2(300, 600),
DefaultValues = new object[]
{
- 500, // Capacity
+ 1000, // Capacity
(int)ParticlesSimulationMode.Default, // Simulation Mode
(int)ParticlesSimulationSpace.Local, // Simulation Space
true, // Enable Pooling
diff --git a/Source/Editor/Surface/Elements/Box.cs b/Source/Editor/Surface/Elements/Box.cs
index 886ab1e37..b8d88741f 100644
--- a/Source/Editor/Surface/Elements/Box.cs
+++ b/Source/Editor/Surface/Elements/Box.cs
@@ -97,7 +97,7 @@ namespace FlaxEditor.Surface.Elements
var connections = Connections.ToArray();
for (int i = 0; i < connections.Length; i++)
{
- var targetBox = Connections[i];
+ var targetBox = connections[i];
// Break connection
Connections.Remove(targetBox);
@@ -565,7 +565,28 @@ namespace FlaxEditor.Surface.Elements
{
_isMouseDown = false;
if (Surface.CanEdit)
- Surface.ConnectingStart(this);
+ {
+ if (!IsOutput && HasSingleConnection)
+ {
+ var connectedBox = Connections[0];
+ if (Surface.Undo != null)
+ {
+ var action = new ConnectBoxesAction((InputBox)this, (OutputBox)connectedBox, false);
+ BreakConnection(connectedBox);
+ action.End();
+ Surface.Undo.AddAction(action);
+ }
+ else
+ {
+ BreakConnection(connectedBox);
+ }
+ Surface.ConnectingStart(connectedBox);
+ }
+ else
+ {
+ Surface.ConnectingStart(this);
+ }
+ }
}
base.OnMouseLeave();
}
diff --git a/Source/Editor/Surface/Elements/SkeletonNodeNameSelectElement.cs b/Source/Editor/Surface/Elements/SkeletonNodeNameSelectElement.cs
index 0d8d676c7..4321eabd0 100644
--- a/Source/Editor/Surface/Elements/SkeletonNodeNameSelectElement.cs
+++ b/Source/Editor/Surface/Elements/SkeletonNodeNameSelectElement.cs
@@ -32,8 +32,8 @@ namespace FlaxEditor.Surface.Elements
}
set
{
- if (!string.IsNullOrEmpty(value))
- SelectedIndex = _nodeNameToIndex[value];
+ if (!string.IsNullOrEmpty(value) && _nodeNameToIndex.TryGetValue(value, out var index))
+ SelectedIndex = index;
else
SelectedIndex = -1;
}
@@ -60,8 +60,8 @@ namespace FlaxEditor.Surface.Elements
{
_selectedIndices.Clear();
var selectedNode = (string)ParentNode.Values[Archetype.ValueIndex];
- if (!string.IsNullOrEmpty(selectedNode))
- _selectedIndices.Add(_nodeNameToIndex[selectedNode]);
+ if (!string.IsNullOrEmpty(selectedNode) && _nodeNameToIndex.TryGetValue(selectedNode, out var index))
+ _selectedIndices.Add(index);
OnSelectedIndexChanged();
}
@@ -92,7 +92,7 @@ namespace FlaxEditor.Surface.Elements
{
sb.Clear();
var node = nodes[nodeIndex];
- _nodeNameToIndex.Add(node.Name, nodeIndex);
+ _nodeNameToIndex[node.Name] = nodeIndex;
int parent = node.ParentIndex;
while (parent != -1)
{
diff --git a/Source/Editor/Surface/Elements/UnsignedIntegerValue.cs b/Source/Editor/Surface/Elements/UnsignedIntegerValue.cs
index 9668105f1..a1822a268 100644
--- a/Source/Editor/Surface/Elements/UnsignedIntegerValue.cs
+++ b/Source/Editor/Surface/Elements/UnsignedIntegerValue.cs
@@ -85,7 +85,7 @@ namespace FlaxEditor.Surface.Elements
else if (value is Vector4 valueVec4)
result = (uint)(arch.BoxID == 0 ? valueVec4.X : arch.BoxID == 1 ? valueVec4.Y : arch.BoxID == 2 ? valueVec4.Z : valueVec4.W);
else
- result = 0;
+ result = 0u;
return result;
}
diff --git a/Source/Editor/Surface/NodeElementArchetype.cs b/Source/Editor/Surface/NodeElementArchetype.cs
index 07ea35875..cc2f41106 100644
--- a/Source/Editor/Surface/NodeElementArchetype.cs
+++ b/Source/Editor/Surface/NodeElementArchetype.cs
@@ -239,6 +239,32 @@ namespace FlaxEditor.Surface
};
}
+ ///
+ /// Creates new Unsigned Integer value element description.
+ ///
+ /// The x location (in node area space).
+ /// The y location (in node area space).
+ /// The index of the node variable linked as the input. Useful to make a physical connection between input box and default value for it.
+ /// The index of the component to edit. For vectors this can be set to modify only single component of it. Eg. for vec2 value component set to 1 will edit only Y component. Default value -1 will be used to edit whole value.
+ /// The minimum value range.
+ /// The maximum value range.
+ /// The archetype.
+ public static NodeElementArchetype UnsignedInteger(float x, float y, int valueIndex = -1, int component = -1, uint valueMin = 0, uint valueMax = 1000000)
+ {
+ return new NodeElementArchetype
+ {
+ Type = NodeElementType.UnsignedIntegerValue,
+ Position = new Vector2(Constants.NodeMarginX + x, Constants.NodeMarginY + Constants.NodeHeaderSize + y),
+ Text = null,
+ Single = false,
+ ValueIndex = valueIndex,
+ ValueMin = valueMin,
+ ValueMax = valueMax,
+ BoxID = -1,
+ ConnectionsType = ScriptType.Null
+ };
+ }
+
///
/// Creates new Float value element description.
///
diff --git a/Source/Editor/Surface/NodeElementType.cs b/Source/Editor/Surface/NodeElementType.cs
index 48b2356dd..f104b234c 100644
--- a/Source/Editor/Surface/NodeElementType.cs
+++ b/Source/Editor/Surface/NodeElementType.cs
@@ -94,5 +94,10 @@ namespace FlaxEditor.Surface
/// The actor picker.
///
Actor = 19,
+
+ ///
+ /// The unsigned integer value.
+ ///
+ UnsignedIntegerValue = 20,
}
}
diff --git a/Source/Editor/Surface/SurfaceNode.cs b/Source/Editor/Surface/SurfaceNode.cs
index cf39384ce..abbd6a6a0 100644
--- a/Source/Editor/Surface/SurfaceNode.cs
+++ b/Source/Editor/Surface/SurfaceNode.cs
@@ -185,9 +185,9 @@ namespace FlaxEditor.Surface
var rightWidth = 40.0f;
var boxLabelFont = Style.Current.FontSmall;
var titleLabelFont = Style.Current.FontLarge;
- for (int i = 0; i < Elements.Count; i++)
+ for (int i = 0; i < Children.Count; i++)
{
- if (Elements[i] is InputBox inputBox)
+ if (Children[i] is InputBox inputBox)
{
var boxWidth = boxLabelFont.MeasureText(inputBox.Text).X + 20;
if (inputBox.DefaultValueEditor != null)
@@ -195,15 +195,23 @@ namespace FlaxEditor.Surface
leftWidth = Mathf.Max(leftWidth, boxWidth);
leftHeight = Mathf.Max(leftHeight, inputBox.Archetype.Position.Y - Constants.NodeMarginY - Constants.NodeHeaderSize + 20.0f);
}
- else if (Elements[i] is OutputBox outputBox)
+ else if (Children[i] is OutputBox outputBox)
{
rightWidth = Mathf.Max(rightWidth, boxLabelFont.MeasureText(outputBox.Text).X + 20);
rightHeight = Mathf.Max(rightHeight, outputBox.Archetype.Position.Y - Constants.NodeMarginY - Constants.NodeHeaderSize + 20.0f);
}
- else if (Elements[i] is Control control)
+ else if (Children[i] is Control control)
{
- width = Mathf.Max(width, control.Width + 10);
- height = Mathf.Max(height, control.Height + 10);
+ if (control.AnchorPreset == AnchorPresets.TopLeft)
+ {
+ width = Mathf.Max(width, control.Right + 4 - Constants.NodeMarginX);
+ height = Mathf.Max(height, control.Bottom + 4 - Constants.NodeMarginY - Constants.NodeHeaderSize);
+ }
+ else
+ {
+ width = Mathf.Max(width, control.Width + 4);
+ height = Mathf.Max(height, control.Height + 4);
+ }
}
}
width = Mathf.Max(width, leftWidth + rightWidth + 10);
@@ -267,6 +275,9 @@ namespace FlaxEditor.Surface
case NodeElementType.Actor:
element = new ActorSelect(this, arch);
break;
+ case NodeElementType.UnsignedIntegerValue:
+ element = new UnsignedIntegerValue(this, arch);
+ break;
//default: throw new NotImplementedException("Unknown node element type: " + arch.Type);
}
if (element != null)
@@ -303,12 +314,16 @@ namespace FlaxEditor.Surface
{
if (type == ScriptType.Null)
type = new ScriptType(typeof(object));
+
+ // Try to reuse box
var box = GetBox(id);
if ((isOut && box is InputBox) || (!isOut && box is OutputBox))
{
box.Dispose();
box = null;
}
+
+ // Create new if missing
if (box == null)
{
if (isOut)
@@ -319,10 +334,15 @@ namespace FlaxEditor.Surface
}
else
{
+ // Sync properties for exiting box
box.Text = text;
box.CurrentType = type;
box.Y = Constants.NodeMarginY + Constants.NodeHeaderSize + yLevel * Constants.LayoutOffsetY;
}
+
+ // Update box
+ box.OnConnectionsChanged();
+
return box;
}
diff --git a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs
index 6b38ffdfc..c2b0d1887 100644
--- a/Source/Editor/Surface/VisjectSurface.ContextMenu.cs
+++ b/Source/Editor/Surface/VisjectSurface.ContextMenu.cs
@@ -15,6 +15,7 @@ namespace FlaxEditor.Surface
{
private ContextMenuButton _cmCopyButton;
private ContextMenuButton _cmDuplicateButton;
+ private ContextMenuButton _cmFormatNodesConnectionButton;
private ContextMenuButton _cmRemoveNodeConnectionsButton;
private ContextMenuButton _cmRemoveBoxConnectionsButton;
private readonly Vector2 ContextMenuOffset = new Vector2(5);
@@ -216,6 +217,13 @@ namespace FlaxEditor.Surface
}
}).Enabled = Nodes.Any(x => x.Breakpoint.Set && x.Breakpoint.Enabled);
}
+ menu.AddSeparator();
+
+ _cmFormatNodesConnectionButton = menu.AddButton("Format node(s)", () =>
+ {
+ FormatGraph(SelectedNodes);
+ });
+ _cmFormatNodesConnectionButton.Enabled = HasNodesSelection;
menu.AddSeparator();
_cmRemoveNodeConnectionsButton = menu.AddButton("Remove all connections to that node(s)", () =>
diff --git a/Source/Editor/Surface/VisjectSurface.DragDrop.cs b/Source/Editor/Surface/VisjectSurface.DragDrop.cs
index 323ef8510..422198f5b 100644
--- a/Source/Editor/Surface/VisjectSurface.DragDrop.cs
+++ b/Source/Editor/Surface/VisjectSurface.DragDrop.cs
@@ -107,7 +107,7 @@ namespace FlaxEditor.Surface
/// Validates the parameter drag operation.
///
/// Name of the parameter.
- /// Tre if can drag that parameter, otherwise false.
+ /// True if can drag that parameter, otherwise false.
protected virtual bool ValidateDragParameter(string parameterName)
{
return GetParameter(parameterName) != null;
diff --git a/Source/Editor/Surface/VisjectSurface.Formatting.cs b/Source/Editor/Surface/VisjectSurface.Formatting.cs
new file mode 100644
index 000000000..848f79157
--- /dev/null
+++ b/Source/Editor/Surface/VisjectSurface.Formatting.cs
@@ -0,0 +1,287 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using FlaxEngine;
+using FlaxEditor.Surface.Elements;
+using FlaxEditor.Surface.Undo;
+
+namespace FlaxEditor.Surface
+{
+ public partial class VisjectSurface
+ {
+ // Reference https://github.com/stefnotch/xnode-graph-formatter/blob/812e08e71c7b9b7eb0810dbdfb0a9a1034da6941/Assets/Examples/MathGraph/Editor/MathGraphEditor.cs
+
+ private class NodeFormattingData
+ {
+ ///
+ /// Starting from 0 at the main nodes
+ ///
+ public int Layer;
+
+ ///
+ /// Position in the layer
+ ///
+ public int Offset;
+
+ ///
+ /// How far the subtree needs to be moved additionally
+ ///
+ public int SubtreeOffset;
+ }
+
+ ///
+ /// Formats a graph where the nodes can be disjointed.
+ /// Uses the Sugiyama method
+ ///
+ /// List of nodes
+ protected void FormatGraph(List nodes)
+ {
+ if (nodes.Count <= 1 || !CanEdit) return;
+
+ var nodesToVisit = new HashSet(nodes);
+
+ // While we haven't formatted every node
+ while (nodesToVisit.Count > 0)
+ {
+ // Run a search in both directions
+ var connectedNodes = new List();
+ var queue = new Queue();
+
+ var startNode = nodesToVisit.First();
+ nodesToVisit.Remove(startNode);
+ queue.Enqueue(startNode);
+
+ while (queue.Count > 0)
+ {
+ var node = queue.Dequeue();
+ connectedNodes.Add(node);
+
+ for (int i = 0; i < node.Elements.Count; i++)
+ {
+ if (node.Elements[i] is Box box)
+ {
+ for (int j = 0; j < box.Connections.Count; j++)
+ {
+ if (nodesToVisit.Contains(box.Connections[j].ParentNode))
+ {
+ nodesToVisit.Remove(box.Connections[j].ParentNode);
+ queue.Enqueue(box.Connections[j].ParentNode);
+ }
+ }
+
+ }
+ }
+ }
+
+ FormatConnectedGraph(connectedNodes);
+ }
+ }
+
+ ///
+ /// Formats a graph where all nodes are connected
+ ///
+ /// List of connected nodes
+ protected void FormatConnectedGraph(List nodes)
+ {
+ if (nodes.Count <= 1 || !CanEdit) return;
+
+ var boundingBox = GetNodesBounds(nodes);
+
+ var nodeData = nodes.ToDictionary(n => n, n => new NodeFormattingData { });
+
+ // Rightmost nodes with none of our nodes to the right of them
+ var endNodes = nodes
+ .Where(n => !n.GetBoxes().Any(b => b.IsOutput && b.Connections.Any(c => nodeData.ContainsKey(c.ParentNode))))
+ .OrderBy(n => n.Top) // Keep their relative order
+ .ToList();
+
+ // Longest path layering
+ int maxLayer = SetLayers(nodeData, endNodes);
+
+ // Set the vertical offsets
+ int maxOffset = SetOffsets(nodeData, endNodes, maxLayer);
+
+ // Layout the nodes
+
+ // Get the largest nodes in the Y and X direction
+ float[] widths = new float[maxLayer + 1];
+ float[] heights = new float[maxOffset + 1];
+ for (int i = 0; i < nodes.Count; i++)
+ {
+ if (nodeData.TryGetValue(nodes[i], out var data))
+ {
+ if (nodes[i].Width > widths[data.Layer])
+ {
+ widths[data.Layer] = nodes[i].Width;
+ }
+ if (nodes[i].Height > heights[data.Offset])
+ {
+ heights[data.Offset] = nodes[i].Height;
+ }
+ }
+ }
+
+ Vector2 minDistanceBetweenNodes = new Vector2(30, 30);
+
+ // Figure out the node positions (aligned to a grid)
+ float[] nodeXPositions = new float[widths.Length];
+ for (int i = 1; i < widths.Length; i++)
+ {
+ // Go from right to left (backwards) through the nodes
+ nodeXPositions[i] = nodeXPositions[i - 1] + minDistanceBetweenNodes.X + widths[i];
+ }
+
+ float[] nodeYPositions = new float[heights.Length];
+ for (int i = 1; i < heights.Length; i++)
+ {
+ // Go from top to bottom through the nodes
+ nodeYPositions[i] = nodeYPositions[i - 1] + heights[i - 1] + minDistanceBetweenNodes.Y;
+ }
+
+ // Set the node positions
+ var undoActions = new List();
+ var topRightPosition = endNodes[0].Location;
+ for (int i = 0; i < nodes.Count; i++)
+ {
+ if (nodeData.TryGetValue(nodes[i], out var data))
+ {
+ Vector2 newLocation = new Vector2(-nodeXPositions[data.Layer], nodeYPositions[data.Offset]) + topRightPosition;
+ Vector2 locationDelta = newLocation - nodes[i].Location;
+ nodes[i].Location = newLocation;
+
+ if (Undo != null)
+ undoActions.Add(new MoveNodesAction(Context, new[] { nodes[i].ID }, locationDelta));
+ }
+ }
+
+ MarkAsEdited(false);
+ Undo?.AddAction(new MultiUndoAction(undoActions, "Format nodes"));
+ }
+
+ ///
+ /// Assigns a layer to every node
+ ///
+ /// The exta node data
+ /// The end nodes
+ /// The number of the maximum layer
+ private int SetLayers(Dictionary nodeData, List endNodes)
+ {
+ // Longest path layering
+ int maxLayer = 0;
+ var stack = new Stack(endNodes);
+
+ while (stack.Count > 0)
+ {
+ var node = stack.Pop();
+ int layer = nodeData[node].Layer;
+
+ for (int i = 0; i < node.Elements.Count; i++)
+ {
+ if (node.Elements[i] is InputBox box && box.HasAnyConnection)
+ {
+ var childNode = box.Connections[0].ParentNode;
+
+ if (nodeData.TryGetValue(childNode, out var data))
+ {
+ int nodeLayer = Math.Max(data.Layer, layer + 1);
+ data.Layer = nodeLayer;
+ if (nodeLayer > maxLayer)
+ {
+ maxLayer = nodeLayer;
+ }
+
+ stack.Push(childNode);
+ }
+ }
+ }
+ }
+ return maxLayer;
+ }
+
+
+ ///
+ /// Sets the node offsets
+ ///
+ /// The exta node data
+ /// The end nodes
+ /// The number of the maximum layer
+ /// The number of the maximum offset
+ private int SetOffsets(Dictionary nodeData, List endNodes, int maxLayer)
+ {
+ int maxOffset = 0;
+
+ // Keeps track of the largest offset (Y axis) for every layer
+ int[] offsets = new int[maxLayer + 1];
+
+ var visitedNodes = new HashSet();
+
+ void SetOffsets(SurfaceNode node, NodeFormattingData straightParentData)
+ {
+ if (!nodeData.TryGetValue(node, out var data)) return;
+
+ // If we realize that the current node would collide with an already existing node in this layer
+ if (data.Layer >= 0 && offsets[data.Layer] > data.Offset)
+ {
+ // Move the entire sub-tree down
+ straightParentData.SubtreeOffset = Math.Max(straightParentData.SubtreeOffset, offsets[data.Layer] - data.Offset);
+ }
+
+ // Keeps track of the offset of the last direct child we visited
+ int childOffset = data.Offset;
+ bool straightChild = true;
+
+ // Run the algorithm for every child
+ for (int i = 0; i < node.Elements.Count; i++)
+ {
+ if (node.Elements[i] is InputBox box && box.HasAnyConnection)
+ {
+ var childNode = box.Connections[0].ParentNode;
+ if (!visitedNodes.Contains(childNode) && nodeData.TryGetValue(childNode, out var childData))
+ {
+ visitedNodes.Add(childNode);
+ childData.Offset = childOffset;
+ SetOffsets(childNode, straightChild ? straightParentData : childData);
+ childOffset = childData.Offset + 1;
+ straightChild = false;
+ }
+ }
+ }
+
+ if (data.Layer >= 0)
+ {
+ // When coming out of the recursion, apply the extra subtree offsets
+ data.Offset += straightParentData.SubtreeOffset;
+ if (data.Offset > maxOffset)
+ {
+ maxOffset = data.Offset;
+ }
+ offsets[data.Layer] = data.Offset + 1;
+ }
+ }
+
+ {
+ // An imaginary final node
+ var endNodeData = new NodeFormattingData { Layer = -1 };
+ int childOffset = 0;
+ bool straightChild = true;
+
+ for (int i = 0; i < endNodes.Count; i++)
+ {
+ if (nodeData.TryGetValue(endNodes[i], out var childData))
+ {
+ visitedNodes.Add(endNodes[i]);
+ childData.Offset = childOffset;
+ SetOffsets(endNodes[i], straightChild ? endNodeData : childData);
+ childOffset = childData.Offset + 1;
+ straightChild = false;
+ }
+ }
+ }
+
+ return maxOffset;
+ }
+
+ }
+}
diff --git a/Source/Editor/Surface/VisjectSurface.Input.cs b/Source/Editor/Surface/VisjectSurface.Input.cs
index 68966370c..dec89e143 100644
--- a/Source/Editor/Surface/VisjectSurface.Input.cs
+++ b/Source/Editor/Surface/VisjectSurface.Input.cs
@@ -24,7 +24,9 @@ namespace FlaxEditor.Surface
private class InputBracket
{
+ private readonly float DefaultWidth = 120f;
private readonly Margin _padding = new Margin(10f);
+
public Box Box { get; }
public Vector2 EndBracketPosition { get; }
public List Nodes { get; } = new List();
@@ -33,7 +35,7 @@ namespace FlaxEditor.Surface
public InputBracket(Box box, Vector2 nodePosition)
{
Box = box;
- EndBracketPosition = nodePosition;
+ EndBracketPosition = nodePosition + new Vector2(DefaultWidth, 0);
Update();
}
@@ -47,11 +49,10 @@ namespace FlaxEditor.Surface
}
else
{
- area = new Rectangle(EndBracketPosition, new Vector2(120f, 80f));
+ area = new Rectangle(EndBracketPosition, new Vector2(DefaultWidth, 80f));
}
_padding.ExpandRectangle(ref area);
- Vector2 endPoint = area.Location + new Vector2(area.Width, area.Height / 2f);
- Vector2 offset = EndBracketPosition - endPoint;
+ Vector2 offset = EndBracketPosition - area.UpperRight;
area.Location += offset;
Area = area;
if (!offset.IsZero)
@@ -99,18 +100,6 @@ namespace FlaxEditor.Surface
///
public event Window.MouseWheelDelegate CustomMouseWheel;
- ///
- /// Gets the node under the mouse location.
- ///
- /// The node or null if no intersection.
- public SurfaceNode GetNodeUnderMouse()
- {
- var pos = _rootControl.PointFromParent(ref _mousePos);
- if (_rootControl.GetChildAt(pos) is SurfaceNode node)
- return node;
- return null;
- }
-
///
/// Gets the control under the mouse location.
///
@@ -118,9 +107,7 @@ namespace FlaxEditor.Surface
public SurfaceControl GetControlUnderMouse()
{
var pos = _rootControl.PointFromParent(ref _mousePos);
- if (_rootControl.GetChildAtRecursive(pos) is SurfaceControl control)
- return control;
- return null;
+ return _rootControl.GetChildAt(pos) as SurfaceControl;
}
private void UpdateSelectionRectangle()
@@ -464,15 +451,7 @@ namespace FlaxEditor.Surface
{
// Check if any control is under the mouse
_cmStartPos = location;
- if (controlUnderMouse != null)
- {
- if (!HasNodesSelection)
- Select(controlUnderMouse);
-
- // Show secondary context menu
- ShowSecondaryCM(_cmStartPos, controlUnderMouse);
- }
- else
+ if (controlUnderMouse == null)
{
// Show primary context menu
ShowPrimaryMenu(_cmStartPos);
@@ -708,31 +687,38 @@ namespace FlaxEditor.Surface
private Vector2 FindEmptySpace(Box box)
{
- int boxIndex = 0;
+ Vector2 distanceBetweenNodes = new Vector2(30, 30);
var node = box.ParentNode;
+
+ // Same height as node
+ float yLocation = node.Top;
+
for (int i = 0; i < node.Elements.Count; i++)
{
- // Box on the same side above the current box
if (node.Elements[i] is Box nodeBox && nodeBox.IsOutput == box.IsOutput && nodeBox.Y < box.Y)
{
- boxIndex++;
+ // Below connected node
+ yLocation = Mathf.Max(yLocation, nodeBox.ParentNode.Bottom + distanceBetweenNodes.Y);
}
}
+
// TODO: Dodge the other nodes
- Vector2 distanceBetweenNodes = new Vector2(40, 20);
- const float NodeHeight = 120;
+ float xLocation = node.Location.X;
+ if (box.IsOutput)
+ {
+ xLocation += node.Width + distanceBetweenNodes.X;
+ }
+ else
+ {
+ xLocation += -120 - distanceBetweenNodes.X;
+ }
- float direction = box.IsOutput ? 1 : -1;
-
- Vector2 newNodeLocation = node.Location +
- new Vector2(
- (node.Width + distanceBetweenNodes.X) * direction,
- boxIndex * (NodeHeight + distanceBetweenNodes.Y)
- );
-
- return newNodeLocation;
+ return new Vector2(
+ xLocation,
+ yLocation
+ );
}
}
}
diff --git a/Source/Editor/Surface/VisualScriptSurface.cs b/Source/Editor/Surface/VisualScriptSurface.cs
index ccabc8f2f..5a5a2e250 100644
--- a/Source/Editor/Surface/VisualScriptSurface.cs
+++ b/Source/Editor/Surface/VisualScriptSurface.cs
@@ -71,7 +71,7 @@ namespace FlaxEditor.Surface
// Check if has cached groups
if (_cache.Count != 0)
{
- // Check if context menu doesn;t have the recent cached groups
+ // Check if context menu doesn't have the recent cached groups
if (!contextMenu.Groups.Any(g => g.Archetype.Tag is int asInt && asInt == _version))
{
var groups = contextMenu.Groups.Where(g => g.Archetype.Tag is int).ToArray();
diff --git a/Source/Editor/Tools/Foliage/FoliageTab.cs b/Source/Editor/Tools/Foliage/FoliageTab.cs
index 9dbb17e88..fe4120035 100644
--- a/Source/Editor/Tools/Foliage/FoliageTab.cs
+++ b/Source/Editor/Tools/Foliage/FoliageTab.cs
@@ -21,6 +21,7 @@ namespace FlaxEditor.Tools.Foliage
private readonly Tabs _modes;
private readonly ContainerControl _noFoliagePanel;
private int _selectedFoliageTypeIndex = -1;
+ private Button _createNewFoliage;
///
/// The editor instance.
@@ -99,6 +100,7 @@ namespace FlaxEditor.Tools.Foliage
public FoliageTab(SpriteHandle icon, Editor editor)
: base(string.Empty, icon)
{
+ Level.SceneLoaded += OnSceneLoaded;
Editor = editor;
Editor.SceneEditing.SelectionChanged += OnSelectionChanged;
@@ -135,14 +137,31 @@ namespace FlaxEditor.Tools.Foliage
Offsets = Margin.Zero,
Parent = _noFoliagePanel
};
- var noFoliageButton = new Button
+ _createNewFoliage = new Button
{
Text = "Create new foliage",
AnchorPreset = AnchorPresets.MiddleCenter,
Offsets = new Margin(-60, 120, -12, 24),
Parent = _noFoliagePanel,
+ Enabled = false
};
- noFoliageButton.Clicked += OnCreateNewFoliageClicked;
+ _createNewFoliage.Clicked += OnCreateNewFoliageClicked;
+ }
+
+ private void OnSceneLoaded(Scene arg1, Guid arg2)
+ {
+ _createNewFoliage.Enabled = true;
+
+ Level.SceneUnloaded += OnSceneUnloaded;
+ Level.SceneLoaded -= OnSceneLoaded;
+ }
+
+ private void OnSceneUnloaded(Scene arg1, Guid arg2)
+ {
+ _createNewFoliage.Enabled = false;
+
+ Level.SceneLoaded += OnSceneLoaded;
+ Level.SceneUnloaded -= OnSceneUnloaded;
}
private void OnSelected(Tab tab)
@@ -248,5 +267,16 @@ namespace FlaxEditor.Tools.Foliage
{
SelectedFoliageTypesChanged?.Invoke();
}
+
+ ///
+ public override void OnDestroy()
+ {
+ if (_createNewFoliage.Enabled)
+ Level.SceneUnloaded -= OnSceneUnloaded;
+ else
+ Level.SceneLoaded -= OnSceneLoaded;
+
+ base.OnDestroy();
+ }
}
}
diff --git a/Source/Editor/Tools/Foliage/FoliageTools.cpp b/Source/Editor/Tools/Foliage/FoliageTools.cpp
index a0cbf8e14..3354be0b3 100644
--- a/Source/Editor/Tools/Foliage/FoliageTools.cpp
+++ b/Source/Editor/Tools/Foliage/FoliageTools.cpp
@@ -67,7 +67,7 @@ struct GeometryLookup
static bool Search(Actor* actor, GeometryLookup& lookup)
{
// Early out if object is not intersecting with the foliage brush bounds
- if (!actor->GetBox().Intersects(lookup.Brush))
+ if (!actor->GetIsActive() || !actor->GetBox().Intersects(lookup.Brush))
return true;
const auto brush = lookup.Brush;
diff --git a/Source/Editor/Tools/Terrain/CarveTab.cs b/Source/Editor/Tools/Terrain/CarveTab.cs
index a3a65c52a..e7b880414 100644
--- a/Source/Editor/Tools/Terrain/CarveTab.cs
+++ b/Source/Editor/Tools/Terrain/CarveTab.cs
@@ -18,6 +18,7 @@ namespace FlaxEditor.Tools.Terrain
{
private readonly Tabs _modes;
private readonly ContainerControl _noTerrainPanel;
+ private readonly Button _createTerrainButton;
///
/// The editor instance.
@@ -57,6 +58,7 @@ namespace FlaxEditor.Tools.Terrain
public CarveTab(SpriteHandle icon, Editor editor)
: base(string.Empty, icon)
{
+ Level.SceneLoaded += OnSceneLoaded;
Editor = editor;
Editor.SceneEditing.SelectionChanged += OnSelectionChanged;
@@ -93,14 +95,31 @@ namespace FlaxEditor.Tools.Terrain
Offsets = Margin.Zero,
Parent = _noTerrainPanel
};
- var noTerrainButton = new Button
+ _createTerrainButton = new Button
{
Text = "Create new terrain",
AnchorPreset = AnchorPresets.MiddleCenter,
Offsets = new Margin(-60, 120, -12, 24),
- Parent = _noTerrainPanel
+ Parent = _noTerrainPanel,
+ Enabled = false
};
- noTerrainButton.Clicked += OnCreateNewTerrainClicked;
+ _createTerrainButton.Clicked += OnCreateNewTerrainClicked;
+ }
+
+ private void OnSceneLoaded(Scene arg1, Guid arg2)
+ {
+ _createTerrainButton.Enabled = true;
+
+ Level.SceneUnloaded += OnSceneUnloaded;
+ Level.SceneLoaded -= OnSceneLoaded;
+ }
+
+ private void OnSceneUnloaded(Scene arg1, Guid arg2)
+ {
+ _createTerrainButton.Enabled = false;
+
+ Level.SceneLoaded += OnSceneLoaded;
+ Level.SceneUnloaded -= OnSceneUnloaded;
}
private void OnSelected(Tab tab)
@@ -183,5 +202,16 @@ namespace FlaxEditor.Tools.Terrain
default: throw new IndexOutOfRangeException("Invalid carve tab mode.");
}
}
+
+ ///
+ public override void OnDestroy()
+ {
+ if (_createTerrainButton.Enabled)
+ Level.SceneUnloaded -= OnSceneUnloaded;
+ else
+ Level.SceneLoaded -= OnSceneLoaded;
+
+ base.OnDestroy();
+ }
}
}
diff --git a/Source/Editor/Tools/Terrain/Paint/Mode.cs b/Source/Editor/Tools/Terrain/Paint/Mode.cs
index 1a1373d05..e53071aa3 100644
--- a/Source/Editor/Tools/Terrain/Paint/Mode.cs
+++ b/Source/Editor/Tools/Terrain/Paint/Mode.cs
@@ -33,7 +33,7 @@ namespace FlaxEditor.Tools.Terrain.Paint
}
///
- /// The tool strength (normalized to range 0-1). Defines the intensity of the paint operation to make it stronger or mre subtle.
+ /// The tool strength (normalized to range 0-1). Defines the intensity of the paint operation to make it stronger or more subtle.
///
[EditorOrder(0), Limit(0, 10, 0.01f), Tooltip("The tool strength (normalized to range 0-1). Defines the intensity of the paint operation to make it stronger or more subtle.")]
public float Strength = 1.0f;
diff --git a/Source/Editor/Tools/Terrain/Sculpt/Mode.cs b/Source/Editor/Tools/Terrain/Sculpt/Mode.cs
index 14fbe0175..eb32b3934 100644
--- a/Source/Editor/Tools/Terrain/Sculpt/Mode.cs
+++ b/Source/Editor/Tools/Terrain/Sculpt/Mode.cs
@@ -33,7 +33,7 @@ namespace FlaxEditor.Tools.Terrain.Sculpt
}
///
- /// The tool strength (normalized to range 0-1). Defines the intensity of the sculpt operation to make it stronger or mre subtle.
+ /// The tool strength (normalized to range 0-1). Defines the intensity of the sculpt operation to make it stronger or more subtle.
///
[EditorOrder(0), Limit(0, 6, 0.01f), Tooltip("The tool strength (normalized to range 0-1). Defines the intensity of the sculpt operation to make it stronger or more subtle.")]
public float Strength = 1.2f;
diff --git a/Source/Editor/Tools/Terrain/TerrainTools.cpp b/Source/Editor/Tools/Terrain/TerrainTools.cpp
index 6bf4f8fd4..e89b5e3e9 100644
--- a/Source/Editor/Tools/Terrain/TerrainTools.cpp
+++ b/Source/Editor/Tools/Terrain/TerrainTools.cpp
@@ -2,7 +2,7 @@
#include "TerrainTools.h"
#include "Engine/Core/Cache.h"
-#include "Engine/Core/Math/VectorInt.h"
+#include "Engine/Core/Math/Int2.h"
#include "Engine/Core/Math/Color32.h"
#include "Engine/Core/Collections/CollectionPoolCache.h"
#include "Engine/Terrain/TerrainPatch.h"
diff --git a/Source/Editor/Tools/VertexPainting.cs b/Source/Editor/Tools/VertexPainting.cs
index c130370e7..29d9daedc 100644
--- a/Source/Editor/Tools/VertexPainting.cs
+++ b/Source/Editor/Tools/VertexPainting.cs
@@ -49,7 +49,7 @@ namespace FlaxEditor.Tools
set => Tab._gizmoMode.BrushStrength = value;
}
- [EditorOrder(20), EditorDisplay("Brush"), Limit(0.0f, 1.0f, 0.01f), Tooltip("The falloff parameter fo the brush. Adjusts the paint strength for the vertices that are far from the brush center. Use lower values to make painting smoother and softer.")]
+ [EditorOrder(20), EditorDisplay("Brush"), Limit(0.0f, 1.0f, 0.01f), Tooltip("The falloff parameter for the brush. Adjusts the paint strength for the vertices that are far from the brush center. Use lower values to make painting smoother and softer.")]
public float BrushFalloff
{
get => Tab._gizmoMode.BrushFalloff;
diff --git a/Source/Editor/Utilities/EditorUtilities.cpp b/Source/Editor/Utilities/EditorUtilities.cpp
index 1571c39d1..538b78173 100644
--- a/Source/Editor/Utilities/EditorUtilities.cpp
+++ b/Source/Editor/Utilities/EditorUtilities.cpp
@@ -6,10 +6,8 @@
#include "Engine/Core/Log.h"
#include "Engine/Graphics/Textures/TextureData.h"
#include "Engine/Graphics/PixelFormatExtensions.h"
-#include "Engine/Serialization/FileReadStream.h"
#include "Engine/Tools/TextureTool/TextureTool.h"
#include "Engine/Core/Math/Color32.h"
-#include "Engine/Core/Math/VectorInt.h"
#include "Engine/Core/Config/GameSettings.h"
#include "Engine/Content/Content.h"
#include "Engine/Content/AssetReference.h"
@@ -247,7 +245,7 @@ void UpdateIconData(uint8* iconData, const TextureData* icon)
iconTexSize = Math::RoundUpToPowerOf2(width);
}
- // Try to pick a proper mip (requrie the same size)
+ // Try to pick a proper mip (require the same size)
const TextureMipData* srcPixels = nullptr;
int32 mipLevels = icon->GetMipLevels();
for (int32 mipIndex = 0; mipIndex < mipLevels; mipIndex++)
@@ -743,6 +741,59 @@ bool EditorUtilities::GenerateCertificate(const String& name, const String& outp
return false;
}
+bool EditorUtilities::IsInvalidPathChar(Char c)
+{
+ char illegalChars[] =
+ {
+ '?',
+ '\\',
+ '/',
+ '\"',
+ '<',
+ '>',
+ '|',
+ ':',
+ '*',
+ '\u0001',
+ '\u0002',
+ '\u0003',
+ '\u0004',
+ '\u0005',
+ '\u0006',
+ '\a',
+ '\b',
+ '\t',
+ '\n',
+ '\v',
+ '\f',
+ '\r',
+ '\u000E',
+ '\u000F',
+ '\u0010',
+ '\u0011',
+ '\u0012',
+ '\u0013',
+ '\u0014',
+ '\u0015',
+ '\u0016',
+ '\u0017',
+ '\u0018',
+ '\u0019',
+ '\u001A',
+ '\u001B',
+ '\u001C',
+ '\u001D',
+ '\u001E',
+ '\u001F'
+ };
+ for (auto i : illegalChars)
+ {
+ if (c == i)
+ return true;
+ }
+ return false;
+}
+
bool EditorUtilities::ReplaceInFiles(const String& folderPath, const Char* searchPattern, DirectorySearchOption searchOption, const String& findWhat, const String& replaceWith)
{
Array files;
diff --git a/Source/Editor/Utilities/EditorUtilities.h b/Source/Editor/Utilities/EditorUtilities.h
index 236d10e6f..a5f129c1b 100644
--- a/Source/Editor/Utilities/EditorUtilities.h
+++ b/Source/Editor/Utilities/EditorUtilities.h
@@ -42,6 +42,13 @@ public:
public:
+ ///
+ /// Determines whether the specified path character is invalid.
+ ///
+ /// The path character.
+ /// true if the given character cannot be used as a path because it is illegal character; otherwise, false.
+ static bool IsInvalidPathChar(Char c);
+
///
/// Replaces the given text with other one in the files.
///
diff --git a/Source/Editor/Utilities/ObjectSnapshot.cs b/Source/Editor/Utilities/ObjectSnapshot.cs
index a64ddf306..8f29d1145 100644
--- a/Source/Editor/Utilities/ObjectSnapshot.cs
+++ b/Source/Editor/Utilities/ObjectSnapshot.cs
@@ -251,7 +251,7 @@ namespace FlaxEditor.Utilities
var list = new List();
#if DEBUG_OBJECT_SNAPSHOT_COMPARISION
- Debug.Logger.LogHandler.LogWrite(LogType.Warning, "-------------- Comparision --------------");
+ Debug.Logger.LogHandler.LogWrite(LogType.Warning, "-------------- Comparison --------------");
#endif
for (int i = _members.Count - 1; i >= 0; i--)
{
diff --git a/Source/Editor/Utilities/ShuntingYardParser.cs b/Source/Editor/Utilities/ShuntingYardParser.cs
index dfd83b1f8..a07026d1c 100644
--- a/Source/Editor/Utilities/ShuntingYardParser.cs
+++ b/Source/Editor/Utilities/ShuntingYardParser.cs
@@ -126,7 +126,7 @@ namespace FlaxEditor.Utilities
///
/// The first operator.
/// The second operator.
- /// The comparision result.
+ /// The comparison result.
private static bool CompareOperators(string oper1, string oper2)
{
var op1 = Operators[oper1];
@@ -193,6 +193,7 @@ namespace FlaxEditor.Utilities
{
case 'x':
case 'X':
+ {
// Hexadecimal value
i++;
token.Clear();
@@ -200,22 +201,35 @@ namespace FlaxEditor.Utilities
throw new ParsingException("invalid hexadecimal number");
while (i + 1 < text.Length && StringUtils.IsHexDigit(text[i + 1]))
{
- i++;
- token.Append(text[i]);
+ token.Append(text[++i]);
}
var value = ulong.Parse(token.ToString(), NumberStyles.HexNumber);
token.Clear();
token.Append(value.ToString());
break;
+ }
default:
+ {
// Decimal value
while (i + 1 < text.Length && DetermineType(text[i + 1]) == TokenType.Number)
{
- i++;
- token.Append(text[i]);
+ token.Append(text[++i]);
+ }
+
+ // Exponential notation
+ if (i + 2 < text.Length && (text[i + 1] == 'e' || text[i + 1] == 'E'))
+ {
+ token.Append(text[++i]);
+ if (text[i + 1] == '-' || text[i + 1] == '+')
+ token.Append(text[++i]);
+ while (i + 1 < text.Length && DetermineType(text[i + 1]) == TokenType.Number)
+ {
+ token.Append(text[++i]);
+ }
}
break;
}
+ }
}
// Discard solo '-'
diff --git a/Source/Editor/Utilities/Utils.cs b/Source/Editor/Utilities/Utils.cs
index 5f1636239..26c5ec92b 100644
--- a/Source/Editor/Utilities/Utils.cs
+++ b/Source/Editor/Utilities/Utils.cs
@@ -532,6 +532,8 @@ namespace FlaxEditor.Utilities
break;
case VariantType.Enum:
case VariantType.Structure:
+ case VariantType.ManagedObject:
+ case VariantType.Typename:
stream.Write(int.MaxValue);
stream.WriteStrAnsi(type.FullName, 77);
break;
@@ -742,6 +744,7 @@ namespace FlaxEditor.Utilities
case VariantType.Array: return new ScriptType(typeof(object[]));
case VariantType.Dictionary: return new ScriptType(typeof(Dictionary
/// The target object bounds.
/// The margin distance scale of the orbit radius.
- public void SerArcBallView(BoundingBox objectBounds, float marginDistanceScale = 2.0f)
+ public void SetArcBallView(BoundingBox objectBounds, float marginDistanceScale = 2.0f)
{
- SerArcBallView(BoundingSphere.FromBox(objectBounds), marginDistanceScale);
+ SetArcBallView(BoundingSphere.FromBox(objectBounds), marginDistanceScale);
}
///
@@ -42,18 +42,18 @@ namespace FlaxEditor.Viewport.Cameras
///
/// The target object bounds.
/// The margin distance scale of the orbit radius.
- public void SerArcBallView(BoundingSphere objectBounds, float marginDistanceScale = 2.0f)
+ public void SetArcBallView(BoundingSphere objectBounds, float marginDistanceScale = 2.0f)
{
- SerArcBallView(new Quaternion(-0.08f, -0.92f, 0.31f, -0.23f), objectBounds.Center, objectBounds.Radius * marginDistanceScale);
+ SetArcBallView(new Quaternion(-0.08f, -0.92f, 0.31f, -0.23f), objectBounds.Center, objectBounds.Radius * marginDistanceScale);
}
///
/// Sets view orientation and position to match the arc ball camera style view for the given orbit radius.
///
/// The orbit radius.
- public void SerArcBallView(float orbitRadius)
+ public void SetArcBallView(float orbitRadius)
{
- SerArcBallView(new Quaternion(-0.08f, -0.92f, 0.31f, -0.23f), Vector3.Zero, orbitRadius);
+ SetArcBallView(new Quaternion(-0.08f, -0.92f, 0.31f, -0.23f), Vector3.Zero, orbitRadius);
}
///
@@ -62,7 +62,7 @@ namespace FlaxEditor.Viewport.Cameras
/// The view rotation.
/// The orbit center location.
/// The orbit radius.
- public void SerArcBallView(Quaternion orientation, Vector3 orbitCenter, float orbitRadius)
+ public void SetArcBallView(Quaternion orientation, Vector3 orbitCenter, float orbitRadius)
{
// Rotate
Viewport.ViewOrientation = orientation;
diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs
index 02696f743..a19589c05 100644
--- a/Source/Editor/Viewport/EditorViewport.cs
+++ b/Source/Editor/Viewport/EditorViewport.cs
@@ -138,9 +138,7 @@ namespace FlaxEditor.Viewport
private bool _isControllingMouse;
private int _deltaFilteringStep;
- private Vector2 _startPosMiddle;
- private Vector2 _startPosRight;
- private Vector2 _startPosLeft;
+ private Vector2 _startPos;
private Vector2 _mouseDeltaRightLast;
private Vector2[] _deltaFilteringBuffer = new Vector2[FpsCameraFilteringFrames];
@@ -180,6 +178,7 @@ namespace FlaxEditor.Viewport
private float _orthoSize = 1.0f;
private bool _isOrtho = false;
private float _wheelMovementChangeDeltaSum = 0;
+ private bool _invertPanning;
///
/// Speed of the mouse.
@@ -403,6 +402,15 @@ namespace FlaxEditor.Viewport
set => _isOrtho = value;
}
+ ///
+ /// Gets or sets if the panning direction is inverted.
+ ///
+ public bool InvertPanning
+ {
+ get => _invertPanning;
+ set => _invertPanning = value;
+ }
+
///
/// The input actions collection to processed during user input.
///
@@ -434,6 +442,7 @@ namespace FlaxEditor.Viewport
_nearPlane = options.Viewport.DefaultNearPlane;
_farPlane = options.Viewport.DefaultFarPlane;
_fieldOfView = options.Viewport.DefaultFieldOfView;
+ _invertPanning = options.Viewport.DefaultInvertPanning;
Editor.Instance.Options.OptionsChanged += OnEditorOptionsChanged;
OnEditorOptionsChanged(options);
@@ -454,7 +463,7 @@ namespace FlaxEditor.Viewport
var button = camSpeedCM.AddButton(v.ToString());
button.Tag = v;
}
- camSpeedCM.ButtonClicked += (button) => MovementSpeed = (float)button.Tag;
+ camSpeedCM.ButtonClicked += button => MovementSpeed = (float)button.Tag;
camSpeedCM.VisibleChanged += WidgetCamSpeedShowHide;
camSpeedButton.Parent = camSpeed;
camSpeed.Parent = this;
@@ -515,9 +524,9 @@ namespace FlaxEditor.Viewport
// Orthographic
{
var ortho = ViewWidgetButtonMenu.AddButton("Orthographic");
- var orthoValue = new CheckBox(75, 2, _isOrtho);
+ var orthoValue = new CheckBox(90, 2, _isOrtho);
orthoValue.Parent = ortho;
- orthoValue.StateChanged += (checkBox) =>
+ orthoValue.StateChanged += checkBox =>
{
if (checkBox.Checked != _isOrtho)
{
@@ -528,13 +537,25 @@ namespace FlaxEditor.Viewport
ViewWidgetButtonMenu.VisibleChanged += control => orthoValue.Checked = _isOrtho;
}
+ // Cara Orientation
+ {
+ var cameraView = ViewWidgetButtonMenu.AddChildMenu("Orientation").ContextMenu;
+ for (int i = 0; i < EditorViewportCameraOrientationValues.Length; i++)
+ {
+ var co = EditorViewportCameraOrientationValues[i];
+ var button = cameraView.AddButton(co.Name);
+ button.Tag = co.Orientation;
+ }
+ cameraView.ButtonClicked += button => ViewOrientation = Quaternion.Euler((Vector3)button.Tag);
+ }
+
// Field of View
{
var fov = ViewWidgetButtonMenu.AddButton("Field Of View");
- var fovValue = new FloatValueBox(1, 75, 2, 50.0f, 35.0f, 160.0f, 0.1f);
+ var fovValue = new FloatValueBox(1, 90, 2, 70.0f, 35.0f, 160.0f, 0.1f);
fovValue.Parent = fov;
fovValue.ValueChanged += () => _fieldOfView = fovValue.Value;
- ViewWidgetButtonMenu.VisibleChanged += (control) =>
+ ViewWidgetButtonMenu.VisibleChanged += control =>
{
fov.Visible = !_isOrtho;
fovValue.Value = _fieldOfView;
@@ -544,10 +565,10 @@ namespace FlaxEditor.Viewport
// Ortho Scale
{
var orthoSize = ViewWidgetButtonMenu.AddButton("Ortho Scale");
- var orthoSizeValue = new FloatValueBox(_orthoSize, 75, 2, 50.0f, 0.001f, 100000.0f, 0.01f);
+ var orthoSizeValue = new FloatValueBox(_orthoSize, 90, 2, 70.0f, 0.001f, 100000.0f, 0.01f);
orthoSizeValue.Parent = orthoSize;
orthoSizeValue.ValueChanged += () => _orthoSize = orthoSizeValue.Value;
- ViewWidgetButtonMenu.VisibleChanged += (control) =>
+ ViewWidgetButtonMenu.VisibleChanged += control =>
{
orthoSize.Visible = _isOrtho;
orthoSizeValue.Value = _orthoSize;
@@ -557,7 +578,7 @@ namespace FlaxEditor.Viewport
// Near Plane
{
var nearPlane = ViewWidgetButtonMenu.AddButton("Near Plane");
- var nearPlaneValue = new FloatValueBox(2.0f, 75, 2, 50.0f, 0.001f, 1000.0f);
+ var nearPlaneValue = new FloatValueBox(2.0f, 90, 2, 70.0f, 0.001f, 1000.0f);
nearPlaneValue.Parent = nearPlane;
nearPlaneValue.ValueChanged += () => _nearPlane = nearPlaneValue.Value;
ViewWidgetButtonMenu.VisibleChanged += control => nearPlaneValue.Value = _nearPlane;
@@ -566,7 +587,7 @@ namespace FlaxEditor.Viewport
// Far Plane
{
var farPlane = ViewWidgetButtonMenu.AddButton("Far Plane");
- var farPlaneValue = new FloatValueBox(1000, 75, 2, 50.0f, 10.0f);
+ var farPlaneValue = new FloatValueBox(1000, 90, 2, 70.0f, 10.0f);
farPlaneValue.Parent = farPlane;
farPlaneValue.ValueChanged += () => _farPlane = farPlaneValue.Value;
ViewWidgetButtonMenu.VisibleChanged += control => farPlaneValue.Value = _farPlane;
@@ -575,7 +596,7 @@ namespace FlaxEditor.Viewport
// Brightness
{
var brightness = ViewWidgetButtonMenu.AddButton("Brightness");
- var brightnessValue = new FloatValueBox(1.0f, 75, 2, 50.0f, 0.001f, 10.0f, 0.001f);
+ var brightnessValue = new FloatValueBox(1.0f, 90, 2, 70.0f, 0.001f, 10.0f, 0.001f);
brightnessValue.Parent = brightness;
brightnessValue.ValueChanged += () => Brightness = brightnessValue.Value;
ViewWidgetButtonMenu.VisibleChanged += control => brightnessValue.Value = Brightness;
@@ -584,11 +605,26 @@ namespace FlaxEditor.Viewport
// Resolution
{
var resolution = ViewWidgetButtonMenu.AddButton("Resolution");
- var resolutionValue = new FloatValueBox(1.0f, 75, 2, 50.0f, 0.1f, 4.0f, 0.001f);
+ var resolutionValue = new FloatValueBox(1.0f, 90, 2, 70.0f, 0.1f, 4.0f, 0.001f);
resolutionValue.Parent = resolution;
resolutionValue.ValueChanged += () => ResolutionScale = resolutionValue.Value;
ViewWidgetButtonMenu.VisibleChanged += control => resolutionValue.Value = ResolutionScale;
}
+
+ // Invert Panning
+ {
+ var invert = ViewWidgetButtonMenu.AddButton("Invert Panning");
+ var invertValue = new CheckBox(90, 2, _invertPanning);
+ invertValue.Parent = invert;
+ invertValue.StateChanged += checkBox =>
+ {
+ if (checkBox.Checked != _invertPanning)
+ {
+ _invertPanning = checkBox.Checked;
+ }
+ };
+ ViewWidgetButtonMenu.VisibleChanged += control => invertValue.Checked = _invertPanning;
+ }
}
// Link for task event
@@ -812,7 +848,7 @@ namespace FlaxEditor.Viewport
///
protected virtual void OnLeftMouseButtonDown()
{
- _startPosLeft = _viewMousePos;
+ _startPos = _viewMousePos;
}
///
@@ -827,7 +863,7 @@ namespace FlaxEditor.Viewport
///
protected virtual void OnRightMouseButtonDown()
{
- _startPosRight = _viewMousePos;
+ _startPos = _viewMousePos;
}
///
@@ -842,7 +878,7 @@ namespace FlaxEditor.Viewport
///
protected virtual void OnMiddleMouseButtonDown()
{
- _startPosMiddle = _viewMousePos;
+ _startPos = _viewMousePos;
}
///
@@ -1013,7 +1049,13 @@ namespace FlaxEditor.Viewport
moveDelta *= 0.3f;
// Calculate smooth mouse delta not dependant on viewport size
- Vector2 offset = _viewMousePos - (_input.IsMouseMiddleDown ? _startPosMiddle : _startPosRight);
+
+ Vector2 offset = _viewMousePos - _startPos;
+ if (_input.IsZooming && !_input.IsMouseRightDown && !_input.IsMouseLeftDown && !_input.IsMouseMiddleDown)
+ {
+ offset = Vector2.Zero;
+ }
+
offset.X = offset.X > 0 ? Mathf.Floor(offset.X) : Mathf.Ceil(offset.X);
offset.Y = offset.Y > 0 ? Mathf.Floor(offset.Y) : Mathf.Ceil(offset.Y);
_mouseDeltaRight = offset / size;
@@ -1055,7 +1097,7 @@ namespace FlaxEditor.Viewport
// Move mouse back to the root position
if (centerMouse && (_input.IsMouseRightDown || _input.IsMouseLeftDown || _input.IsMouseMiddleDown))
{
- Vector2 center = PointToWindow(_input.IsMouseMiddleDown ? _startPosMiddle : _startPosRight);
+ Vector2 center = PointToWindow(_startPos);
win.MousePosition = center;
}
}
@@ -1101,11 +1143,11 @@ namespace FlaxEditor.Viewport
if (_input.IsMouseLeftDown)
{
// Calculate smooth mouse delta not dependant on viewport size
- Vector2 offset = _viewMousePos - _startPosLeft;
+ Vector2 offset = _viewMousePos - _startPos;
offset.X = offset.X > 0 ? Mathf.Floor(offset.X) : Mathf.Ceil(offset.X);
offset.Y = offset.Y > 0 ? Mathf.Floor(offset.Y) : Mathf.Ceil(offset.Y);
_mouseDeltaLeft = offset / size;
- _startPosLeft = _viewMousePos;
+ _startPos = _viewMousePos;
}
else
{
@@ -1193,6 +1235,28 @@ namespace FlaxEditor.Viewport
base.OnDestroy();
}
+ private struct CameraOrientation
+ {
+ public readonly string Name;
+ public readonly Vector3 Orientation;
+
+ public CameraOrientation(string name, Vector3 orientation)
+ {
+ Name = name;
+ Orientation = orientation;
+ }
+ }
+
+ private readonly CameraOrientation[] EditorViewportCameraOrientationValues =
+ {
+ new CameraOrientation("Front", new Vector3(0, 0, 0)),
+ new CameraOrientation("Back", new Vector3(0, 180, 0)),
+ new CameraOrientation("Left", new Vector3(0, 90, 0)),
+ new CameraOrientation("Right", new Vector3(0, -90, 0)),
+ new CameraOrientation("Top", new Vector3(-90, 0, 0)),
+ new CameraOrientation("Bottom", new Vector3(90, 0, 0))
+ };
+
private readonly float[] EditorViewportCameraSpeedValues =
{
0.1f,
diff --git a/Source/Editor/Viewport/PrefabWindowViewport.cs b/Source/Editor/Viewport/PrefabWindowViewport.cs
index 94b994ac8..dd6f8fce3 100644
--- a/Source/Editor/Viewport/PrefabWindowViewport.cs
+++ b/Source/Editor/Viewport/PrefabWindowViewport.cs
@@ -485,6 +485,23 @@ namespace FlaxEditor.Viewport
}
}
+ ///
+ public override void Draw()
+ {
+ base.Draw();
+
+ // Selected UI controls outline
+ for (var i = 0; i < _window.Selection.Count; i++)
+ {
+ if (_window.Selection[i].EditableObject is UIControl controlActor && controlActor.Control != null)
+ {
+ var control = controlActor.Control;
+ var bounds = Rectangle.FromPoints(control.PointToParent(this, Vector2.Zero), control.PointToParent(this, control.Size));
+ Render2D.DrawRectangle(bounds, Editor.Instance.Options.Options.Visual.SelectionOutlineColor0, Editor.Instance.Options.Options.Visual.UISelectionOutlineSize);
+ }
+ }
+ }
+
///
protected override void OnLeftMouseButtonUp()
{
diff --git a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs
index 24ae53261..b85895528 100644
--- a/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs
+++ b/Source/Editor/Viewport/Previews/AnimatedModelPreview.cs
@@ -84,7 +84,7 @@ namespace FlaxEditor.Viewport.Previews
// Preview LOD
{
var previewLOD = ViewWidgetButtonMenu.AddButton("Preview LOD");
- var previewLODValue = new IntValueBox(-1, 75, 2, 50.0f, -1, 10, 0.02f);
+ var previewLODValue = new IntValueBox(-1, 90, 2, 70.0f, -1, 10, 0.02f);
previewLODValue.Parent = previewLOD;
previewLODValue.ValueChanged += () => _previewModel.ForcedLOD = previewLODValue.Value;
ViewWidgetButtonMenu.VisibleChanged += control => previewLODValue.Value = _previewModel.ForcedLOD;
diff --git a/Source/Editor/Viewport/Previews/AssetPreview.cs b/Source/Editor/Viewport/Previews/AssetPreview.cs
index 012837f87..9bf3573a1 100644
--- a/Source/Editor/Viewport/Previews/AssetPreview.cs
+++ b/Source/Editor/Viewport/Previews/AssetPreview.cs
@@ -85,7 +85,7 @@ namespace FlaxEditor.Viewport.Previews
var orbitRadius = 200.0f;
if (camera is ArcBallCamera arcBallCamera)
orbitRadius = arcBallCamera.OrbitRadius;
- camera.SerArcBallView(new Quaternion(-0.08f, -0.92f, 0.31f, -0.23f), Vector3.Zero, orbitRadius);
+ camera.SetArcBallView(new Quaternion(-0.08f, -0.92f, 0.31f, -0.23f), Vector3.Zero, orbitRadius);
if (useWidgets)
{
diff --git a/Source/Editor/Viewport/Previews/MaterialPreview.cs b/Source/Editor/Viewport/Previews/MaterialPreview.cs
index a03598193..6ff695b69 100644
--- a/Source/Editor/Viewport/Previews/MaterialPreview.cs
+++ b/Source/Editor/Viewport/Previews/MaterialPreview.cs
@@ -23,6 +23,15 @@ namespace FlaxEditor.Viewport.Previews
"Cone"
};
+ private static readonly Transform[] Transforms =
+ {
+ new Transform(Vector3.Zero, Quaternion.RotationY(Mathf.Pi), new Vector3(0.45f)),
+ new Transform(Vector3.Zero, Quaternion.RotationY(Mathf.Pi), new Vector3(0.45f)),
+ new Transform(Vector3.Zero, Quaternion.Identity, new Vector3(0.45f)),
+ new Transform(Vector3.Zero, Quaternion.RotationY(Mathf.Pi), new Vector3(0.45f)),
+ new Transform(Vector3.Zero, Quaternion.RotationY(Mathf.Pi), new Vector3(0.45f)),
+ };
+
private StaticModel _previewModel;
private Decal _decal;
private Terrain _terrain;
@@ -65,6 +74,7 @@ namespace FlaxEditor.Viewport.Previews
_selectedModelIndex = value;
_previewModel.Model = FlaxEngine.Content.LoadAsyncInternal("Editor/Primitives/" + Models[value]);
+ _previewModel.Transform = Transforms[value];
}
}
@@ -77,7 +87,6 @@ namespace FlaxEditor.Viewport.Previews
{
// Setup preview scene
_previewModel = new StaticModel();
- _previewModel.Transform = new Transform(Vector3.Zero, Quaternion.RotationY(Mathf.Pi), new Vector3(0.45f));
SelectedModelIndex = 0;
// Link actors for rendering
diff --git a/Source/Editor/Viewport/Previews/ModelPreview.cs b/Source/Editor/Viewport/Previews/ModelPreview.cs
index e4789bdb8..aa03d0ee2 100644
--- a/Source/Editor/Viewport/Previews/ModelPreview.cs
+++ b/Source/Editor/Viewport/Previews/ModelPreview.cs
@@ -53,7 +53,7 @@ namespace FlaxEditor.Viewport.Previews
// Preview LOD
{
var previewLOD = ViewWidgetButtonMenu.AddButton("Preview LOD");
- var previewLODValue = new IntValueBox(-1, 75, 2, 50.0f, -1, 10, 0.02f);
+ var previewLODValue = new IntValueBox(-1, 90, 2, 70.0f, -1, 10, 0.02f);
previewLODValue.Parent = previewLOD;
previewLODValue.ValueChanged += () => _previewModel.ForcedLOD = previewLODValue.Value;
ViewWidgetButtonMenu.VisibleChanged += control => previewLODValue.Value = _previewModel.ForcedLOD;
diff --git a/Source/Editor/Viewport/Previews/ParticleEmitterPreview.cs b/Source/Editor/Viewport/Previews/ParticleEmitterPreview.cs
index e7021050b..638c8324c 100644
--- a/Source/Editor/Viewport/Previews/ParticleEmitterPreview.cs
+++ b/Source/Editor/Viewport/Previews/ParticleEmitterPreview.cs
@@ -67,7 +67,7 @@ namespace FlaxEditor.Viewport.Previews
if (useWidgets)
{
var playbackDuration = ViewWidgetButtonMenu.AddButton("Duration");
- var playbackDurationValue = new FloatValueBox(_playbackDuration, 75, 2, 50.0f, 0.1f, 1000000.0f, 0.1f);
+ var playbackDurationValue = new FloatValueBox(_playbackDuration, 90, 2, 70.0f, 0.1f, 1000000.0f, 0.1f);
playbackDurationValue.Parent = playbackDuration;
playbackDurationValue.ValueChanged += () => PlaybackDuration = playbackDurationValue.Value;
ViewWidgetButtonMenu.VisibleChanged += control => playbackDurationValue.Value = PlaybackDuration;
diff --git a/Source/Editor/Viewport/Previews/PrefabPreview.cs b/Source/Editor/Viewport/Previews/PrefabPreview.cs
index d0ed8a0c2..066e98456 100644
--- a/Source/Editor/Viewport/Previews/PrefabPreview.cs
+++ b/Source/Editor/Viewport/Previews/PrefabPreview.cs
@@ -1,7 +1,6 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
using FlaxEngine;
-using FlaxEngine.GUI;
using Object = FlaxEngine.Object;
namespace FlaxEditor.Viewport.Previews
@@ -19,7 +18,7 @@ namespace FlaxEditor.Viewport.Previews
private Prefab _prefab;
private Actor _instance;
- internal Control customControlLinked;
+ internal UIControl customControlLinked;
///
/// Gets or sets the prefab asset to preview.
@@ -29,39 +28,37 @@ namespace FlaxEditor.Viewport.Previews
get => _prefab;
set
{
- if (_prefab != value)
+ if (_prefab == value)
+ return;
+
+ // Unset and cleanup spawned instance
+ if (_instance)
{
- if (_instance)
+ var instance = _instance;
+ Instance = null;
+ Object.Destroy(instance);
+ }
+
+ _prefab = value;
+
+ if (_prefab)
+ {
+ // Load prefab
+ _prefab.WaitForLoaded();
+
+ // Spawn prefab
+ var prevPreview = LoadingPreview;
+ LoadingPreview = this;
+ var instance = PrefabManager.SpawnPrefab(_prefab, null);
+ LoadingPreview = prevPreview;
+ if (instance == null)
{
- if (customControlLinked != null)
- {
- customControlLinked.Parent = null;
- customControlLinked = null;
- }
- Task.RemoveCustomActor(_instance);
- Object.Destroy(_instance);
+ _prefab = null;
+ throw new FlaxException("Failed to spawn a prefab for the preview.");
}
- _prefab = value;
-
- if (_prefab)
- {
- _prefab.WaitForLoaded(); // TODO: use lazy prefab spawning to reduce stalls
-
- var prevPreview = LoadingPreview;
- LoadingPreview = this;
-
- _instance = PrefabManager.SpawnPrefab(_prefab, null);
-
- LoadingPreview = prevPreview;
-
- if (_instance == null)
- {
- _prefab = null;
- throw new FlaxException("Failed to spawn a prefab for the preview.");
- }
- Task.AddCustomActor(_instance);
- }
+ // Set instance
+ Instance = instance;
}
}
}
@@ -72,7 +69,47 @@ namespace FlaxEditor.Viewport.Previews
public Actor Instance
{
get => _instance;
- internal set => _instance = value;
+ internal set
+ {
+ if (_instance == value)
+ return;
+
+ if (_instance)
+ {
+ // Unlink UI control
+ if (customControlLinked)
+ {
+ if (customControlLinked.Control?.Parent == this)
+ customControlLinked.Control.Parent = null;
+ customControlLinked = null;
+ }
+
+ // Remove for the preview
+ Task.RemoveCustomActor(_instance);
+ }
+
+ _instance = value;
+
+ if (_instance)
+ {
+ // Add to the preview
+ Task.AddCustomActor(_instance);
+
+ // Link UI canvases to the preview
+ LinkCanvas(_instance);
+ }
+ }
+ }
+
+ private void LinkCanvas(Actor actor)
+ {
+ if (actor is UICanvas uiCanvas)
+ uiCanvas.EditorOverride(Task, this);
+ var children = actor.ChildrenCount;
+ for (int i = 0; i < children; i++)
+ {
+ LinkCanvas(actor.GetChild(i));
+ }
}
///
@@ -87,7 +124,6 @@ namespace FlaxEditor.Viewport.Previews
///
public override void OnDestroy()
{
- // Cleanup
Prefab = null;
base.OnDestroy();
diff --git a/Source/Editor/Viewport/Previews/TexturePreview.cs b/Source/Editor/Viewport/Previews/TexturePreview.cs
index d1904027a..5e1024609 100644
--- a/Source/Editor/Viewport/Previews/TexturePreview.cs
+++ b/Source/Editor/Viewport/Previews/TexturePreview.cs
@@ -159,13 +159,14 @@ namespace FlaxEditor.Viewport.Previews
float prevScale = _viewScale;
_viewScale = Mathf.Clamp(_viewScale + delta * 0.24f, 0.001f, 20.0f);
- // Move view to make use of the control much more soother
- //float coeff = (prevScale + (_viewScale - prevScale)) / prevScale;
- //_viewPos += (location * coeff - location) / _viewScale;
- //_viewPos += location / _viewScale;
- Vector2 sizeDelta = (_viewScale - prevScale) * _textureRect.Size;
+ // Compensate for the Rectangle.MakeScaled
+ Vector2 sizeDelta = (_viewScale - prevScale) * _textureRect.Size * 0.5f;
_viewPos += sizeDelta * 0.5f;
+ // Move to zoom position
+ Vector2 locationOnTexture = (location - _textureRect.Location) / _textureRect.Size;
+ _viewPos -= sizeDelta * locationOnTexture;
+
return true;
}
diff --git a/Source/Editor/Windows/AboutDialog.cs b/Source/Editor/Windows/AboutDialog.cs
index 03e60f43c..bb320fb87 100644
--- a/Source/Editor/Windows/AboutDialog.cs
+++ b/Source/Editor/Windows/AboutDialog.cs
@@ -115,7 +115,7 @@ namespace FlaxEditor.Windows
{
var thirdPartyPanel = new Panel(ScrollBars.Vertical)
{
- Bounds = new Rectangle(0, topParentControl.Bottom + 4, Width, Height - topParentControl.Bottom - 24),
+ Bounds = new Rectangle(4, topParentControl.Bottom + 4, Width - 8, Height - topParentControl.Bottom - 24),
Parent = this
};
var thirdPartyEntries = new[]
diff --git a/Source/Editor/Windows/Assets/AssetEditorWindow.cs b/Source/Editor/Windows/Assets/AssetEditorWindow.cs
index 756adbe05..8ad655d01 100644
--- a/Source/Editor/Windows/Assets/AssetEditorWindow.cs
+++ b/Source/Editor/Windows/Assets/AssetEditorWindow.cs
@@ -288,7 +288,7 @@ namespace FlaxEditor.Windows.Assets
public abstract class AssetEditorWindowBase : AssetEditorWindow where T : Asset
{
///
- /// Flag set to true if window is is waiting for asset to be loaded (to send or events).
+ /// Flag set to true if window is waiting for asset to be loaded (to send or events).
///
protected bool _isWaitingForLoaded;
@@ -430,7 +430,7 @@ namespace FlaxEditor.Windows.Assets
///
/// Gets the original asset. Note: is the cloned asset for local editing. Use to apply changes to the original asset.
///
- public T OriginalAsset => (T)FlaxEngine.Content.GetAsset(_item.ID);
+ public T OriginalAsset => (T)FlaxEngine.Content.Load(_item.ID);
///
protected ClonedAssetEditorWindowBase(Editor editor, AssetItem item)
diff --git a/Source/Editor/Windows/Assets/JsonAssetWindow.cs b/Source/Editor/Windows/Assets/JsonAssetWindow.cs
index 670414241..da463c501 100644
--- a/Source/Editor/Windows/Assets/JsonAssetWindow.cs
+++ b/Source/Editor/Windows/Assets/JsonAssetWindow.cs
@@ -40,6 +40,12 @@ namespace FlaxEditor.Windows.Assets
_presenter.Modified += MarkAsEdited;
}
+ private void OnScriptsReloadBegin()
+ {
+ Close();
+ ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
+ }
+
///
public override void Save()
{
@@ -76,6 +82,10 @@ namespace FlaxEditor.Windows.Assets
_presenter.Select(_object);
ClearEditedFlag();
+ // Auto-close on scripting reload if json asset is from game scripts (it might be reloaded)
+ if (_object != null && FlaxEngine.Scripting.IsTypeFromGameScripts(_object.GetType()))
+ ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
+
base.OnAssetLoaded();
}
diff --git a/Source/Editor/Windows/Assets/ModelWindow.cs b/Source/Editor/Windows/Assets/ModelWindow.cs
index 9910c6e7a..533c9694c 100644
--- a/Source/Editor/Windows/Assets/ModelWindow.cs
+++ b/Source/Editor/Windows/Assets/ModelWindow.cs
@@ -1004,7 +1004,7 @@ namespace FlaxEditor.Windows.Assets
protected override void OnAssetLoaded()
{
_refreshOnLODsLoaded = true;
- _preview.ViewportCamera.SerArcBallView(Asset.GetBox());
+ _preview.ViewportCamera.SetArcBallView(Asset.GetBox());
UpdateEffectsOnAsset();
// TODO: disable streaming for this model
diff --git a/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs b/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs
index 08621f2ec..bded7e147 100644
--- a/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs
+++ b/Source/Editor/Windows/Assets/PrefabWindow.Hierarchy.cs
@@ -69,6 +69,7 @@ namespace FlaxEditor.Windows.Assets
bool hasSthSelected = Selection.Count > 0;
bool isSingleActorSelected = Selection.Count == 1 && Selection[0] is ActorNode;
bool isRootSelected = isSingleActorSelected && Selection[0] == Graph.Main;
+ bool hasPrefabLink = isSingleActorSelected && (Selection[0] as ActorNode).HasPrefabLink;
// Create popup
@@ -97,7 +98,7 @@ namespace FlaxEditor.Windows.Assets
b.Enabled = hasSthSelected && !isRootSelected;
b = contextMenu.AddButton("Set Root", SetRoot);
- b.Enabled = isSingleActorSelected && !isRootSelected;
+ b.Enabled = isSingleActorSelected && !isRootSelected && hasPrefabLink;
// Prefab options
@@ -108,8 +109,6 @@ namespace FlaxEditor.Windows.Assets
(Selection[0] as ActorNode).CanCreatePrefab &&
Editor.Windows.ContentWin.CurrentViewFolder.CanHaveAssets;
- bool hasPrefabLink = isSingleActorSelected && (Selection[0] as ActorNode).HasPrefabLink;
-
b = contextMenu.AddButton("Select Prefab", Editor.Prefabs.SelectPrefab);
b.Enabled = hasPrefabLink;
diff --git a/Source/Editor/Windows/Assets/PrefabWindow.cs b/Source/Editor/Windows/Assets/PrefabWindow.cs
index a8b3e24a4..4cc7898ee 100644
--- a/Source/Editor/Windows/Assets/PrefabWindow.cs
+++ b/Source/Editor/Windows/Assets/PrefabWindow.cs
@@ -284,6 +284,9 @@ namespace FlaxEditor.Windows.Assets
{
// Simply update changes
Editor.Prefabs.ApplyAll(_viewport.Instance);
+
+ // Refresh properties panel to sync new prefab default values
+ _propertiesEditor.BuildLayout();
}
catch (Exception)
{
diff --git a/Source/Editor/Windows/Assets/SceneAnimationWindow.cs b/Source/Editor/Windows/Assets/SceneAnimationWindow.cs
index cbed724bc..c18edc716 100644
--- a/Source/Editor/Windows/Assets/SceneAnimationWindow.cs
+++ b/Source/Editor/Windows/Assets/SceneAnimationWindow.cs
@@ -277,6 +277,7 @@ namespace FlaxEditor.Windows.Assets
private readonly StagingTexture[] _stagingTextures = new StagingTexture[FrameLatency + 1];
private RenderProgress _progress;
private RenderEditorState _editorState;
+ private GameWindow _gameWindow;
public RenderOptions Options => _options;
@@ -373,6 +374,9 @@ namespace FlaxEditor.Windows.Assets
gameWin.Viewport.Task.PostRender += OnPostRender;
if (!gameWin.Visible)
gameWin.Show();
+ else if (!gameWin.IsFocused)
+ gameWin.Focus();
+ _gameWindow = gameWin;
_warmUpTimeLeft = _options.WarmUpTime;
_animationFrame = 0;
var stagingTextureDesc = GPUTextureDescription.New2D(resolution.X, resolution.Y, gameWin.Viewport.Task.Output.Format, GPUTextureFlags.None);
@@ -385,6 +389,12 @@ namespace FlaxEditor.Windows.Assets
_stagingTextures[i].TaskFrame = -1;
}
_player.Play();
+ if (!_player.IsPlaying)
+ {
+ Editor.LogError("Scene Animation Player failed to start playing.");
+ CancelRendering();
+ return;
+ }
if (_warmUpTimeLeft > 0.0f)
{
// Start warmup time
@@ -438,8 +448,11 @@ namespace FlaxEditor.Windows.Assets
_stagingTextures[i].Texture.ReleaseGPU();
Object.Destroy(ref _stagingTextures[i].Texture);
}
- _progress.End();
- editor.ProgressReporting.UnregisterHandler(_progress);
+ if (_progress != null)
+ {
+ _progress.End();
+ editor.ProgressReporting.UnregisterHandler(_progress);
+ }
if (_editorState != null)
{
editor.StateMachine.GoToState(editor.StateMachine.EditingSceneState);
@@ -452,6 +465,7 @@ namespace FlaxEditor.Windows.Assets
gameWin.Viewport.BackgroundColor = Color.Transparent;
gameWin.Viewport.KeepAspectRatio = false;
gameWin.Viewport.Task.PostRender -= OnPostRender;
+ _gameWindow = null;
_isRendering = false;
_presenter.Panel.Enabled = true;
_presenter.BuildLayoutOnUpdate();
@@ -467,6 +481,11 @@ namespace FlaxEditor.Windows.Assets
{
// Render first frame
_player.Play();
+ if (!_player.IsPlaying)
+ {
+ Editor.LogError("Scene Animation Player failed to start playing.");
+ CancelRendering();
+ }
_warmUpTimeLeft = -1;
_state = States.Render;
}
@@ -490,7 +509,7 @@ namespace FlaxEditor.Windows.Assets
}
if (_player.IsStopped || _player.Time >= _options.EndTime)
{
- // End rendering but perform reaming copies of the staging textures so all data is captured (from GPU to CPU)
+ // End rendering but perform remaining copies of the staging textures so all data is captured (from GPU to CPU)
_state = States.Staging;
break;
}
@@ -503,8 +522,7 @@ namespace FlaxEditor.Windows.Assets
private void OnPostRender(GPUContext context, RenderContext renderContext)
{
- var gameWin = Editor.Instance.Windows.GameWin;
- var task = gameWin.Viewport.Task;
+ var task = _gameWindow.Viewport.Task;
var taskFrame = task.FrameCount;
// Check all staging textures for finished GPU to CPU transfers
@@ -540,7 +558,7 @@ namespace FlaxEditor.Windows.Assets
ref var stagingTexture = ref _stagingTextures[textureIdx];
stagingTexture.AnimationFrame = _animationFrame;
stagingTexture.TaskFrame = taskFrame;
- _options.VideoOutputFormat.RenderFrame(context, ref stagingTexture, _options, gameWin.Viewport.Task.Output);
+ _options.VideoOutputFormat.RenderFrame(context, ref stagingTexture, _options, _gameWindow.Viewport.Task.Output);
// Now wait for the next animation frame to be updated
_state = States.Update;
diff --git a/Source/Editor/Windows/Assets/SkinnedModelWindow.cs b/Source/Editor/Windows/Assets/SkinnedModelWindow.cs
index 2f6c952ba..c599e7e2a 100644
--- a/Source/Editor/Windows/Assets/SkinnedModelWindow.cs
+++ b/Source/Editor/Windows/Assets/SkinnedModelWindow.cs
@@ -1097,7 +1097,7 @@ namespace FlaxEditor.Windows.Assets
protected override void OnAssetLoaded()
{
_refreshOnLODsLoaded = true;
- _preview.ViewportCamera.SerArcBallView(Asset.GetBox());
+ _preview.ViewportCamera.SetArcBallView(Asset.GetBox());
UpdateEffectsOnAsset();
// TODO: disable streaming for this model
diff --git a/Source/Editor/Windows/ContentWindow.ContextMenu.cs b/Source/Editor/Windows/ContentWindow.ContextMenu.cs
index 1b4d2be31..f81220ac4 100644
--- a/Source/Editor/Windows/ContentWindow.ContextMenu.cs
+++ b/Source/Editor/Windows/ContentWindow.ContextMenu.cs
@@ -224,7 +224,7 @@ namespace FlaxEditor.Windows
///
private void ExportSelection()
{
- if(FileSystem.ShowBrowseFolderDialog(Editor.Windows.MainWindow, null, "Select the output folder", out var outputFolder))
+ if (FileSystem.ShowBrowseFolderDialog(Editor.Windows.MainWindow, null, "Select the output folder", out var outputFolder))
return;
var selection = _view.Selection;
diff --git a/Source/Editor/Windows/ContentWindow.cs b/Source/Editor/Windows/ContentWindow.cs
index 66ed50daf..145c0d972 100644
--- a/Source/Editor/Windows/ContentWindow.cs
+++ b/Source/Editor/Windows/ContentWindow.cs
@@ -396,7 +396,7 @@ namespace FlaxEditor.Windows
/// The item to delete.
public void Delete(ContentItem item)
{
- Delete(new List { item });
+ Delete(new List(1) { item });
}
///
@@ -405,36 +405,18 @@ namespace FlaxEditor.Windows
/// The items to delete.
public void Delete(List items)
{
+ if (items.Count == 0) return;
+
// TODO: remove items that depend on different items in the list: use wants to remove `folderA` and `folderA/asset.x`, we should just remove `folderA`
var toDelete = new List(items);
+ string msg = toDelete.Count == 1 ?
+ string.Format("Are you sure to delete \'{0}\'?\nThis action cannot be undone. Files will be deleted permanently.", items[0].Path)
+ : string.Format("Are you sure to delete {0} selected items?\nThis action cannot be undone. Files will be deleted permanently.", items.Count);
+
// Ask user
- if (toDelete.Count == 1)
- {
- // Single item
- if (MessageBox.Show(string.Format("Are you sure to delete \'{0}\'?\nThis action cannot be undone. Files will be deleted permanently.", items[0].Path),
- "Delete asset(s)",
- MessageBoxButtons.OKCancel,
- MessageBoxIcon.Question)
- != DialogResult.OK)
- {
- // Break
- return;
- }
- }
- else
- {
- // Many items
- if (MessageBox.Show(string.Format("Are you sure to delete {0} selected items?\nThis action cannot be undone. Files will be deleted permanently.", items.Count),
- "Delete asset(s)",
- MessageBoxButtons.OKCancel,
- MessageBoxIcon.Question)
- != DialogResult.OK)
- {
- // Break
- return;
- }
- }
+ if (MessageBox.Show(msg, "Delete asset(s)", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) != DialogResult.OK)
+ return;
// Clear navigation
// TODO: just remove invalid locations from the history (those are removed)
diff --git a/Source/Editor/Windows/GameWindow.cs b/Source/Editor/Windows/GameWindow.cs
index a29869825..858f0e0ba 100644
--- a/Source/Editor/Windows/GameWindow.cs
+++ b/Source/Editor/Windows/GameWindow.cs
@@ -222,7 +222,7 @@ namespace FlaxEditor.Windows
private void PlayingStateOnSceneDuplicating()
{
- // Remove reaming GUI controls so loaded scene can add own GUI
+ // Remove remaining GUI controls so loaded scene can add own GUI
//_guiRoot.DisposeChildren();
// Show GUI
@@ -231,7 +231,7 @@ namespace FlaxEditor.Windows
private void PlayingStateOnSceneRestored()
{
- // Remove reaming GUI controls so loaded scene can add own GUI
+ // Remove remaining GUI controls so loaded scene can add own GUI
//_guiRoot.DisposeChildren();
// Hide GUI
@@ -294,7 +294,9 @@ namespace FlaxEditor.Windows
{
if (Editor.Instance.SceneEditing.Selection[i].EditableObject is UIControl controlActor && controlActor.Control != null)
{
- Render2D.DrawRectangle(controlActor.Control.Bounds, Editor.Instance.Options.Options.Visual.SelectionOutlineColor0, Editor.Instance.Options.Options.Visual.UISelectionOutlineSize);
+ var control = controlActor.Control;
+ var bounds = Rectangle.FromPoints(control.PointToParent(_viewport, Vector2.Zero), control.PointToParent(_viewport, control.Size));
+ Render2D.DrawRectangle(bounds, Editor.Instance.Options.Options.Visual.SelectionOutlineColor0, Editor.Instance.Options.Options.Visual.UISelectionOutlineSize);
}
}
@@ -387,6 +389,12 @@ namespace FlaxEditor.Windows
}
}
+ // Prevent closing the game window tab during a play session
+ if (Editor.StateMachine.IsPlayMode && Editor.Options.Options.Input.CloseTab.Process(this, key))
+ {
+ return true;
+ }
+
return base.OnKeyDown(key);
}
diff --git a/Source/Editor/Windows/SplashScreen.cpp b/Source/Editor/Windows/SplashScreen.cpp
index 98578950f..bc92a8d2a 100644
--- a/Source/Editor/Windows/SplashScreen.cpp
+++ b/Source/Editor/Windows/SplashScreen.cpp
@@ -110,6 +110,12 @@ const Char* SplashScreenQuotes[] =
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("Hi There"),
+ TEXT("BAGUETTE"),
};
SplashScreen::~SplashScreen()
diff --git a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp
index 8f43506d2..1a26318a1 100644
--- a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp
+++ b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp
@@ -1489,11 +1489,11 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
case 2:
value = transitionsData.Position / transitionsData.Length;
break;
- // Reaming Time
+ // Remaining Time
case 3:
value = transitionsData.Length - transitionsData.Position;
break;
- // Reaming Normalized Time
+ // Remaining Normalized Time
case 4:
value = 1.0f - (transitionsData.Position / transitionsData.Length);
break;
diff --git a/Source/Engine/Audio/AudioSource.h b/Source/Engine/Audio/AudioSource.h
index ac15b5a4b..2b5b7e9d8 100644
--- a/Source/Engine/Audio/AudioSource.h
+++ b/Source/Engine/Audio/AudioSource.h
@@ -199,7 +199,7 @@ public:
/// Gets the current state of the audio playback (playing/paused/stopped).
///
/// The value.
- API_PROPERTY() FORCE_INLINE States GetState() const
+ API_PROPERTY() FORCE_INLINE AudioSource::States GetState() const
{
return _state;
}
diff --git a/Source/Engine/CSG/CSGMesh.Triangulate.cpp b/Source/Engine/CSG/CSGMesh.Triangulate.cpp
index bb814653b..8a64f4042 100644
--- a/Source/Engine/CSG/CSGMesh.Triangulate.cpp
+++ b/Source/Engine/CSG/CSGMesh.Triangulate.cpp
@@ -22,7 +22,7 @@ bool CSG::Mesh::Triangulate(RawData& data, Array& cacheVB) const
Array surfaceCacheVB(32);
// Cache submeshes by material to lay them down
- // key- brush index, value- direcotry for surafecs (key: surface index, value: list with start vertex per triangle)
+ // key- brush index, value- direcotry for surfaces (key: surface index, value: list with start vertex per triangle)
Dictionary>> polygonsPerBrush(64);
// Build index buffer
@@ -115,8 +115,8 @@ bool CSG::Mesh::Triangulate(RawData& data, Array& cacheVB) const
tangent.Normalize();
// Gram-Schmidt orthogonalize
- Vector3 newTangentUnormalized = tangent - normal * Vector3::Dot(normal, tangent);
- const float length = newTangentUnormalized.Length();
+ Vector3 newTangentUnnormalized = tangent - normal * Vector3::Dot(normal, tangent);
+ const float length = newTangentUnnormalized.Length();
// Workaround to handle degenerated case
if (Math::IsZero(length))
@@ -129,7 +129,7 @@ bool CSG::Mesh::Triangulate(RawData& data, Array& cacheVB) const
}
else
{
- tangent = newTangentUnormalized / length;
+ tangent = newTangentUnnormalized / length;
bitangent.Normalize();
}
@@ -217,12 +217,12 @@ bool CSG::Mesh::Triangulate(RawData& data, Array& cacheVB) const
auto& vertex = cacheVB[triangleStartVertex + k];
Vector3 projected = Vector3::Project(vertex.Position, 0, 0, 1000, 1000, 0, 1, vp);
- Vector2 projectecXY = Vector2(projected);
+ Vector2 projectedXY = Vector2(projected);
- min = Vector2::Min(projectecXY, min);
- max = Vector2::Max(projectecXY, max);
+ min = Vector2::Min(projectedXY, min);
+ max = Vector2::Max(projectedXY, max);
- pointsCache.Add(projectecXY);
+ pointsCache.Add(projectedXY);
}
}
diff --git a/Source/Engine/CSG/CSGMesh.cpp b/Source/Engine/CSG/CSGMesh.cpp
index cc4897d3a..9a885a35d 100644
--- a/Source/Engine/CSG/CSGMesh.cpp
+++ b/Source/Engine/CSG/CSGMesh.cpp
@@ -38,7 +38,7 @@ void CSG::Mesh::PerformOperation(Mesh* other)
{
case Mode::Additive:
{
- // Check if both meshes do not intesect
+ // Check if both meshes do not intersect
if (AABB::IsOutside(_bounds, other->GetBounds())) // TODO: test every sub bounds not whole _bounds
{
// Add vertices to the mesh without any additional calculations
@@ -57,7 +57,7 @@ void CSG::Mesh::PerformOperation(Mesh* other)
case Mode::Subtractive:
{
- // Check if both meshes do not intesect
+ // Check if both meshes do not intersect
if (AABB::IsOutside(_bounds, other->GetBounds())) // TODO: test every sub bounds not whole _bounds
{
// Do nothing
@@ -141,7 +141,7 @@ void CSG::Mesh::intersect(const Mesh* other, PolygonOperation insideOp, PolygonO
// insideOp - operation for polygons being inside the other brush
// outsideOp - operation for polygons being outside the other brush
- // Prevent from redudant action
+ // Prevent from redundant action
if (insideOp == Keep && outsideOp == Keep)
return;
@@ -180,7 +180,7 @@ void CSG::Mesh::intersectSubMesh(const Mesh* other, int32 subMeshIndex, PolygonO
int32 startBrushSurface = brushMeta.StartSurfaceIndex;
int32 endBrushSurface = startBrushSurface + brushMeta.SurfacesCount;
- // Check every polygon (itereate fron end since we can ass new polygons and we don't want to process them)
+ // Check every polygon (iterate from end since we can ass new polygons and we don't want to process them)
for (int32 i = _polygons.Count() - 1; i >= 0; i--)
{
auto& polygon = _polygons[i];
diff --git a/Source/Engine/Content/Assets/ModelBase.h b/Source/Engine/Content/Assets/ModelBase.h
index ebf05570d..89805f3c0 100644
--- a/Source/Engine/Content/Assets/ModelBase.h
+++ b/Source/Engine/Content/Assets/ModelBase.h
@@ -53,7 +53,7 @@ public:
ScopeLock lock(Locker);
const int32 prevCount = MaterialSlots.Count();
- MaterialSlots.Resize(slotsCount);
+ MaterialSlots.Resize(slotsCount, false);
// Initialize slot names
for (int32 i = prevCount; i < slotsCount; i++)
diff --git a/Source/Engine/Content/JsonAsset.h b/Source/Engine/Content/JsonAsset.h
index ce617938d..c74c4a045 100644
--- a/Source/Engine/Content/JsonAsset.h
+++ b/Source/Engine/Content/JsonAsset.h
@@ -75,7 +75,7 @@ protected:
/// Generic type of Json-format asset. It provides the managed representation of this resource data so it can be accessed via C# API.
///
///
-API_CLASS(NoSpawn) class JsonAsset : public JsonAssetBase
+API_CLASS(NoSpawn) class FLAXENGINE_API JsonAsset : public JsonAssetBase
{
DECLARE_ASSET_HEADER(JsonAsset);
diff --git a/Source/Engine/Content/Loading/ContentLoadingManager.cpp b/Source/Engine/Content/Loading/ContentLoadingManager.cpp
index ac2dd8257..6e6ff7a65 100644
--- a/Source/Engine/Content/Loading/ContentLoadingManager.cpp
+++ b/Source/Engine/Content/Loading/ContentLoadingManager.cpp
@@ -208,7 +208,7 @@ void ContentLoadingManagerService::Dispose()
MainThread = nullptr;
ThisThread = nullptr;
- // Cancel all reaming tasks (no chance to execute them)
+ // Cancel all remaining tasks (no chance to execute them)
Tasks.CancelAll();
}
diff --git a/Source/Engine/Content/Utilities/IESLoader.cpp b/Source/Engine/Content/Utilities/IESLoader.cpp
index 0ef7c320a..271ab3d5e 100644
--- a/Source/Engine/Content/Utilities/IESLoader.cpp
+++ b/Source/Engine/Content/Utilities/IESLoader.cpp
@@ -240,7 +240,7 @@ float IESLoader::ExtractInR16(Array& output)
float result = 0.0f;
for (uint32 i = 0; i < hAnglesCount; i++)
result += InterpolateBilinear(static_cast(i), v);
- *out++ = ConvertFloatToHalf(invMaxValue * result / (float)hAnglesCount);
+ *out++ = Float16Compressor::Compress(invMaxValue * result / (float)hAnglesCount);
}
}
diff --git a/Source/Engine/ContentExporters/ExportModel.cpp b/Source/Engine/ContentExporters/ExportModel.cpp
index efc13419b..7fdd011f9 100644
--- a/Source/Engine/ContentExporters/ExportModel.cpp
+++ b/Source/Engine/ContentExporters/ExportModel.cpp
@@ -76,7 +76,7 @@ ExportAssetResult AssetExporters::ExportModel(ExportAssetContext& context)
for (uint32 i = 0; i < vertices; i++)
{
auto v = vb1[i].TexCoord;
- output->WriteTextFormatted("vt {0} {1}\n", ConvertHalfToFloat(v.X), ConvertHalfToFloat(v.Y));
+ output->WriteTextFormatted("vt {0} {1}\n", Float16Compressor::Decompress(v.X), Float16Compressor::Decompress(v.Y));
}
output->WriteChar('\n');
@@ -181,7 +181,7 @@ ExportAssetResult AssetExporters::ExportSkinnedModel(ExportAssetContext& context
for (uint32 i = 0; i < vertices; i++)
{
auto v = vb0[i].TexCoord;
- output->WriteTextFormatted("vt {0} {1}\n", ConvertHalfToFloat(v.X), ConvertHalfToFloat(v.Y));
+ output->WriteTextFormatted("vt {0} {1}\n", Float16Compressor::Decompress(v.X), Float16Compressor::Decompress(v.Y));
}
output->WriteChar('\n');
diff --git a/Source/Engine/ContentImporters/AssetsImportingManager.cpp b/Source/Engine/ContentImporters/AssetsImportingManager.cpp
index 3a39bd64b..f1d048ca5 100644
--- a/Source/Engine/ContentImporters/AssetsImportingManager.cpp
+++ b/Source/Engine/ContentImporters/AssetsImportingManager.cpp
@@ -178,7 +178,7 @@ void CreateAssetContext::ApplyChanges()
// Move file
if (FileSystem::MoveFile(TargetAssetPath, OutputPath, true))
{
- LOG(Warning, "Cannot move imported file to the destination path.");
+ LOG(Warning, "Cannot move imported file {0} to the destination path {1}.", OutputPath, TargetAssetPath);
_applyChangesResult = CreateAssetResult::CannotSaveFile;
return;
}
diff --git a/Source/Engine/Core/Config/LayersTagsSettings.h b/Source/Engine/Core/Config/LayersTagsSettings.h
index 4ed9394fb..c01f915aa 100644
--- a/Source/Engine/Core/Config/LayersTagsSettings.h
+++ b/Source/Engine/Core/Config/LayersTagsSettings.h
@@ -3,6 +3,7 @@
#pragma once
#include "Engine/Core/Config/Settings.h"
+#include "Engine/Serialization/Json.h"
///
/// Layers and objects tags settings.
diff --git a/Source/Engine/Core/Config/Settings.h b/Source/Engine/Core/Config/Settings.h
index 0380c96b3..e21e558fc 100644
--- a/Source/Engine/Core/Config/Settings.h
+++ b/Source/Engine/Core/Config/Settings.h
@@ -9,7 +9,7 @@
///
/// Base class for all global settings containers for the engine. Helps to apply, store and expose properties to c#.
///
-class SettingsBase
+class FLAXENGINE_API SettingsBase
{
public:
diff --git a/Source/Engine/Core/Log.cpp b/Source/Engine/Core/Log.cpp
index 2213672c9..cb73a79e1 100644
--- a/Source/Engine/Core/Log.cpp
+++ b/Source/Engine/Core/Log.cpp
@@ -51,18 +51,18 @@ bool Log::Logger::Init()
{
// Check if there are any files to delete
const int32 maxLogFiles = 20;
- int32 reaming = oldLogs.Count() - maxLogFiles + 1;
- if (reaming > 0)
+ int32 remaining = oldLogs.Count() - maxLogFiles + 1;
+ if (remaining > 0)
{
Sorting::QuickSort(oldLogs.Get(), oldLogs.Count());
// Delete the oldest logs
int32 i = 0;
- while (reaming > 0)
+ while (remaining > 0)
{
FileSystem::DeleteFile(oldLogs[i++]);
filesDeleted++;
- reaming--;
+ remaining--;
}
}
}
diff --git a/Source/Engine/Core/Math/AABB.h b/Source/Engine/Core/Math/AABB.h
index 39e8a5bf6..5853d6597 100644
--- a/Source/Engine/Core/Math/AABB.h
+++ b/Source/Engine/Core/Math/AABB.h
@@ -8,7 +8,7 @@
///
/// Integer axis aligned bounding box
///
-struct AABB
+struct FLAXENGINE_API AABB
{
public:
diff --git a/Source/Engine/Core/Math/BoundingFrustum.h b/Source/Engine/Core/Math/BoundingFrustum.h
index b8b16c412..9052521fc 100644
--- a/Source/Engine/Core/Math/BoundingFrustum.h
+++ b/Source/Engine/Core/Math/BoundingFrustum.h
@@ -10,7 +10,7 @@
///
/// Defines a frustum which can be used in frustum culling, zoom to Extents (zoom to fit) operations, (matrix, frustum, camera) interchange, and many kind of intersection testing.
///
-API_STRUCT(InBuild) struct BoundingFrustum
+API_STRUCT(InBuild) struct FLAXENGINE_API BoundingFrustum
{
private:
diff --git a/Source/Engine/Core/Math/CollisionsHelper.cpp b/Source/Engine/Core/Math/CollisionsHelper.cpp
index 48e7472d1..d485e5fba 100644
--- a/Source/Engine/Core/Math/CollisionsHelper.cpp
+++ b/Source/Engine/Core/Math/CollisionsHelper.cpp
@@ -15,7 +15,7 @@ void CollisionsHelper::ClosestPointPointLine(const Vector2& point, const Vector2
Vector2 n = p1 - p0;
const float length = n.Length();
- if (length < 1e-10)
+ if (length < 1e-10f)
{
// Both points are the same, just give any
result = p0;
@@ -24,7 +24,7 @@ void CollisionsHelper::ClosestPointPointLine(const Vector2& point, const Vector2
n /= length;
const float dot = Vector2::Dot(n, p);
- if (dot <= 0.0)
+ if (dot <= 0.0f)
{
// Before first point
result = p0;
@@ -41,6 +41,45 @@ void CollisionsHelper::ClosestPointPointLine(const Vector2& point, const Vector2
}
}
+Vector2 CollisionsHelper::ClosestPointPointLine(const Vector2& point, const Vector2& p0, const Vector2& p1)
+{
+ Vector2 result;
+ ClosestPointPointLine(point, p0, p1, result);
+ return result;
+}
+
+void CollisionsHelper::ClosestPointPointLine(const Vector3& point, const Vector3& p0, const Vector3& p1, Vector3& result)
+{
+ const Vector3 p = point - p0;
+ Vector3 n = p1 - p0;
+ const float length = n.Length();
+ if (length < 1e-10f)
+ {
+ result = p0;
+ return;
+ }
+ n /= length;
+ const float dot = Vector3::Dot(n, p);
+ if (dot <= 0.0f)
+ {
+ result = p0;
+ return;
+ }
+ if (dot >= length)
+ {
+ result = p1;
+ return;
+ }
+ result = p0 + n * dot;
+}
+
+Vector3 CollisionsHelper::ClosestPointPointLine(const Vector3& point, const Vector3& p0, const Vector3& p1)
+{
+ Vector3 result;
+ ClosestPointPointLine(point, p0, p1, result);
+ return result;
+}
+
void CollisionsHelper::ClosestPointPointTriangle(const Vector3& point, const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3, Vector3& result)
{
// Source: Real-Time Collision Detection by Christer Ericson
@@ -101,6 +140,13 @@ void CollisionsHelper::ClosestPointPointTriangle(const Vector3& point, const Vec
result = vertex1 + ab * v2 + ac * w2; //= u*vertex1 + v*vertex2 + w*vertex3, u = va * denom = 1.0f - v - w
}
+Vector3 CollisionsHelper::ClosestPointPointTriangle(const Vector3& point, const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3)
+{
+ Vector3 result;
+ ClosestPointPointTriangle(point, vertex1, vertex2, vertex3, result);
+ return result;
+}
+
void CollisionsHelper::ClosestPointPlanePoint(const Plane& plane, const Vector3& point, Vector3& result)
{
// Source: Real-Time Collision Detection by Christer Ericson
@@ -112,6 +158,13 @@ void CollisionsHelper::ClosestPointPlanePoint(const Plane& plane, const Vector3&
result = point - t * plane.Normal;
}
+Vector3 CollisionsHelper::ClosestPointPlanePoint(const Plane& plane, const Vector3& point)
+{
+ Vector3 result;
+ ClosestPointPlanePoint(plane, point, result);
+ return result;
+}
+
void CollisionsHelper::ClosestPointBoxPoint(const BoundingBox& box, const Vector3& point, Vector3& result)
{
// Source: Real-Time Collision Detection by Christer Ericson
@@ -122,6 +175,13 @@ void CollisionsHelper::ClosestPointBoxPoint(const BoundingBox& box, const Vector
Vector3::Min(temp, box.Maximum, result);
}
+Vector3 CollisionsHelper::ClosestPointBoxPoint(const BoundingBox& box, const Vector3& point)
+{
+ Vector3 result;
+ ClosestPointBoxPoint(box, point, result);
+ return result;
+}
+
void CollisionsHelper::ClosestPointRectanglePoint(const Rectangle& rect, const Vector2& point, Vector2& result)
{
Vector2 temp, end;
@@ -130,6 +190,13 @@ void CollisionsHelper::ClosestPointRectanglePoint(const Rectangle& rect, const V
Vector2::Min(temp, end, result);
}
+Vector2 CollisionsHelper::ClosestPointRectanglePoint(const Rectangle& rect, const Vector2& point)
+{
+ Vector2 result;
+ ClosestPointRectanglePoint(rect, point, result);
+ return result;
+}
+
void CollisionsHelper::ClosestPointSpherePoint(const BoundingSphere& sphere, const Vector3& point, Vector3& result)
{
// Source: Jorgy343
@@ -147,6 +214,13 @@ void CollisionsHelper::ClosestPointSpherePoint(const BoundingSphere& sphere, con
result += sphere.Center;
}
+Vector3 CollisionsHelper::ClosestPointSpherePoint(const BoundingSphere& sphere, const Vector3& point)
+{
+ Vector3 result;
+ ClosestPointSpherePoint(sphere, point, result);
+ return result;
+}
+
void CollisionsHelper::ClosestPointSphereSphere(const BoundingSphere& sphere1, const BoundingSphere& sphere2, Vector3& result)
{
// Source: Jorgy343
@@ -164,6 +238,13 @@ void CollisionsHelper::ClosestPointSphereSphere(const BoundingSphere& sphere1, c
result += sphere1.Center;
}
+Vector3 CollisionsHelper::ClosestPointSphereSphere(const BoundingSphere& sphere1, const BoundingSphere& sphere2)
+{
+ Vector3 result;
+ ClosestPointSphereSphere(sphere1, sphere2, result);
+ return result;
+}
+
float CollisionsHelper::DistancePlanePoint(const Plane& plane, const Vector3& point)
{
// Source: Real-Time Collision Detection by Christer Ericson
@@ -821,7 +902,6 @@ bool CollisionsHelper::RayIntersectsBox(const Ray& ray, const BoundingBox& box,
d = Math::Abs(size.Z - Math::Abs(localPoint.Z));
if (d < dMin)
{
- dMin = d;
normal = Vector3(0, 0, Math::Sign(localPoint.Z));
}
@@ -990,15 +1070,11 @@ PlaneIntersectionType CollisionsHelper::PlaneIntersectsBox(const Plane& plane, c
min.Z = plane.Normal.Z >= 0.0f ? box.Maximum.Z : box.Minimum.Z;
float distance = Vector3::Dot(plane.Normal, max);
-
if (distance + plane.D > Plane::DistanceEpsilon)
return PlaneIntersectionType::Front;
-
distance = Vector3::Dot(plane.Normal, min);
-
if (distance + plane.D < Plane::DistanceEpsilon)
return PlaneIntersectionType::Back;
-
return PlaneIntersectionType::Intersecting;
}
@@ -1012,10 +1088,8 @@ PlaneIntersectionType CollisionsHelper::PlaneIntersectsSphere(const Plane& plane
if (distance > sphere.Radius)
return PlaneIntersectionType::Front;
-
if (distance < -sphere.Radius)
return PlaneIntersectionType::Back;
-
return PlaneIntersectionType::Intersecting;
}
@@ -1023,13 +1097,10 @@ bool CollisionsHelper::BoxIntersectsBox(const BoundingBox& box1, const BoundingB
{
if (box1.Minimum.X > box2.Maximum.X || box2.Minimum.X > box1.Maximum.X)
return false;
-
if (box1.Minimum.Y > box2.Maximum.Y || box2.Minimum.Y > box1.Maximum.Y)
return false;
-
if (box1.Minimum.Z > box2.Maximum.Z || box2.Minimum.Z > box1.Maximum.Z)
return false;
-
return true;
}
diff --git a/Source/Engine/Core/Math/CollisionsHelper.h b/Source/Engine/Core/Math/CollisionsHelper.h
index 33631a682..4bebf2492 100644
--- a/Source/Engine/Core/Math/CollisionsHelper.h
+++ b/Source/Engine/Core/Math/CollisionsHelper.h
@@ -72,6 +72,33 @@ public:
/// When the method completes, contains the closest point between the two objects.
static void ClosestPointPointLine(const Vector2& point, const Vector2& p0, const Vector2& p1, Vector2& result);
+ ///
+ /// Determines the closest point between a point and a line.
+ ///
+ /// The point to test.
+ /// The line first point.
+ /// The line second point.
+ /// The closest point between the two objects.
+ static Vector2 ClosestPointPointLine(const Vector2& point, const Vector2& p0, const Vector2& p1);
+
+ ///
+ /// Determines the closest point between a point and a line.
+ ///
+ /// The point to test.
+ /// The line first point.
+ /// The line second point.
+ /// When the method completes, contains the closest point between the two objects.
+ static void ClosestPointPointLine(const Vector3& point, const Vector3& p0, const Vector3& p1, Vector3& result);
+
+ ///
+ /// Determines the closest point between a point and a line.
+ ///
+ /// The point to test.
+ /// The line first point.
+ /// The line second point.
+ /// The closest point between the two objects.
+ static Vector3 ClosestPointPointLine(const Vector3& point, const Vector3& p0, const Vector3& p1);
+
///
/// Determines the closest point between a point and a triangle.
///
@@ -82,6 +109,16 @@ public:
/// When the method completes, contains the closest point between the two objects.
static void ClosestPointPointTriangle(const Vector3& point, const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3, Vector3& result);
+ ///
+ /// Determines the closest point between a point and a triangle.
+ ///
+ /// The point to test.
+ /// The first vertex to test.
+ /// The second vertex to test.
+ /// The third vertex to test.
+ /// The closest point between the two objects.
+ static Vector3 ClosestPointPointTriangle(const Vector3& point, const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3);
+
///
/// Determines the closest point between a and a point.
///
@@ -90,6 +127,14 @@ public:
/// When the method completes, contains the closest point between the two objects.
static void ClosestPointPlanePoint(const Plane& plane, const Vector3& point, Vector3& result);
+ ///
+ /// Determines the closest point between a and a point.
+ ///
+ /// The plane to test.
+ /// The point to test.
+ /// The closest point between the two objects.
+ static Vector3 ClosestPointPlanePoint(const Plane& plane, const Vector3& point);
+
///
/// Determines the closest point between a and a point.
///
@@ -98,6 +143,14 @@ public:
/// When the method completes, contains the closest point between the two objects.
static void ClosestPointBoxPoint(const BoundingBox& box, const Vector3& point, Vector3& result);
+ ///
+ /// Determines the closest point between a and a point.
+ ///
+ /// The box to test.
+ /// The point to test.
+ /// The closest point between the two objects.
+ static Vector3 ClosestPointBoxPoint(const BoundingBox& box, const Vector3& point);
+
///
/// Determines the closest point between a and a point.
///
@@ -106,6 +159,14 @@ public:
/// When the method completes, contains the closest point between the two objects.
static void ClosestPointRectanglePoint(const Rectangle& rect, const Vector2& point, Vector2& result);
+ ///
+ /// Determines the closest point between a and a point.
+ ///
+ /// The rectangle to test.
+ /// The point to test.
+ /// The closest point between the two objects.
+ static Vector2 ClosestPointRectanglePoint(const Rectangle& rect, const Vector2& point);
+
///
/// Determines the closest point between a and a point.
///
@@ -114,6 +175,14 @@ public:
/// When the method completes, contains the closest point between the two objects; or, if the point is directly in the center of the sphere, contains .
static void ClosestPointSpherePoint(const BoundingSphere& sphere, const Vector3& point, Vector3& result);
+ ///
+ /// Determines the closest point between a and a point.
+ ///
+ /// The sphere to test.
+ /// The point to test.
+ /// The closest point between the two objects; or, if the point is directly in the center of the sphere, contains .
+ static Vector3 ClosestPointSpherePoint(const BoundingSphere& sphere, const Vector3& point);
+
///
/// Determines the closest point between a and a .
///
@@ -127,6 +196,19 @@ public:
///
static void ClosestPointSphereSphere(const BoundingSphere& sphere1, const BoundingSphere& sphere2, Vector3& result);
+ ///
+ /// Determines the closest point between a and a .
+ ///
+ /// The first sphere to test.
+ /// The second sphere to test.
+ /// The closest point between the two objects; or, if the point is directly in the center of the sphere, contains .
+ ///
+ /// If the two spheres are overlapping, but not directly on top of each other, the closest point
+ /// is the 'closest' point of intersection. This can also be considered is the deepest point of
+ /// intersection.
+ ///
+ static Vector3 ClosestPointSphereSphere(const BoundingSphere& sphere1, const BoundingSphere& sphere2);
+
///
/// Determines the distance between a and a point.
///
diff --git a/Source/Engine/Core/Math/Color.cs b/Source/Engine/Core/Math/Color.cs
index 5aee4c428..a865bde15 100644
--- a/Source/Engine/Core/Math/Color.cs
+++ b/Source/Engine/Core/Math/Color.cs
@@ -280,7 +280,7 @@ namespace FlaxEngine
///
/// The hexadecimal string.
/// Output value.
- /// True if value has benn parsed, otherwise false.
+ /// True if value has been parsed, otherwise false.
public static bool TryParseHex(string hexString, out Color value)
{
value = Black;
diff --git a/Source/Engine/Core/Math/Half.cpp b/Source/Engine/Core/Math/Half.cpp
index 47bf66802..0de29c030 100644
--- a/Source/Engine/Core/Math/Half.cpp
+++ b/Source/Engine/Core/Math/Half.cpp
@@ -18,81 +18,81 @@ Half4 Half4::Zero(0, 0, 0, 0);
Half2::Half2(const Vector2& v)
{
- X = ConvertFloatToHalf(v.X);
- Y = ConvertFloatToHalf(v.Y);
+ X = Float16Compressor::Compress(v.X);
+ Y = Float16Compressor::Compress(v.Y);
}
Vector2 Half2::ToVector2() const
{
return Vector2(
- ConvertHalfToFloat(X),
- ConvertHalfToFloat(Y)
+ Float16Compressor::Decompress(X),
+ Float16Compressor::Decompress(Y)
);
}
Half3::Half3(const Vector3& v)
{
- X = ConvertFloatToHalf(v.X);
- Y = ConvertFloatToHalf(v.Y);
- Z = ConvertFloatToHalf(v.Z);
+ X = Float16Compressor::Compress(v.X);
+ Y = Float16Compressor::Compress(v.Y);
+ Z = Float16Compressor::Compress(v.Z);
}
Vector3 Half3::ToVector3() const
{
return Vector3(
- ConvertHalfToFloat(X),
- ConvertHalfToFloat(Y),
- ConvertHalfToFloat(Z)
+ Float16Compressor::Decompress(X),
+ Float16Compressor::Decompress(Y),
+ Float16Compressor::Decompress(Z)
);
}
Half4::Half4(const Vector4& v)
{
- X = ConvertFloatToHalf(v.X);
- Y = ConvertFloatToHalf(v.Y);
- Z = ConvertFloatToHalf(v.Z);
- W = ConvertFloatToHalf(v.W);
+ X = Float16Compressor::Compress(v.X);
+ Y = Float16Compressor::Compress(v.Y);
+ Z = Float16Compressor::Compress(v.Z);
+ W = Float16Compressor::Compress(v.W);
}
Half4::Half4(const Color& c)
{
- X = ConvertFloatToHalf(c.R);
- Y = ConvertFloatToHalf(c.G);
- Z = ConvertFloatToHalf(c.B);
- W = ConvertFloatToHalf(c.A);
+ X = Float16Compressor::Compress(c.R);
+ Y = Float16Compressor::Compress(c.G);
+ Z = Float16Compressor::Compress(c.B);
+ W = Float16Compressor::Compress(c.A);
}
Half4::Half4(const Rectangle& rect)
{
- X = ConvertFloatToHalf(rect.Location.X);
- Y = ConvertFloatToHalf(rect.Location.Y);
- Z = ConvertFloatToHalf(rect.Size.X);
- W = ConvertFloatToHalf(rect.Size.Y);
+ X = Float16Compressor::Compress(rect.Location.X);
+ Y = Float16Compressor::Compress(rect.Location.Y);
+ Z = Float16Compressor::Compress(rect.Size.X);
+ W = Float16Compressor::Compress(rect.Size.Y);
}
Vector2 Half4::ToVector2() const
{
return Vector2(
- ConvertHalfToFloat(X),
- ConvertHalfToFloat(Y)
+ Float16Compressor::Decompress(X),
+ Float16Compressor::Decompress(Y)
);
}
Vector3 Half4::ToVector3() const
{
return Vector3(
- ConvertHalfToFloat(X),
- ConvertHalfToFloat(Y),
- ConvertHalfToFloat(Z)
+ Float16Compressor::Decompress(X),
+ Float16Compressor::Decompress(Y),
+ Float16Compressor::Decompress(Z)
);
}
Vector4 Half4::ToVector4() const
{
return Vector4(
- ConvertHalfToFloat(X),
- ConvertHalfToFloat(Y),
- ConvertHalfToFloat(Z),
- ConvertHalfToFloat(W)
+ Float16Compressor::Decompress(X),
+ Float16Compressor::Decompress(Y),
+ Float16Compressor::Decompress(Z),
+ Float16Compressor::Decompress(W)
);
}
diff --git a/Source/Engine/Core/Math/Half.h b/Source/Engine/Core/Math/Half.h
index 19059ad0c..e0773b1d4 100644
--- a/Source/Engine/Core/Math/Half.h
+++ b/Source/Engine/Core/Math/Half.h
@@ -11,8 +11,14 @@ typedef uint16 Half;
#define USE_SSE_HALF_CONVERSION 0
-class Float16Compressor
+///
+/// Utility for packing/unpacking floating point value from single precision (32 bit) to half precision (16 bit).
+///
+class FLAXENGINE_API Float16Compressor
{
+ // Reference:
+ // http://www.cs.cmu.edu/~jinlianw/third_party/float16_compressor.hpp
+
union Bits
{
float f;
@@ -22,24 +28,19 @@ class Float16Compressor
static const int shift = 13;
static const int shiftSign = 16;
-
static const int32 infN = 0x7F800000; // flt32 infinity
static const int32 maxN = 0x477FE000; // max flt16 normal as a flt32
static const int32 minN = 0x38800000; // min flt16 normal as a flt32
static const int32 signN = 0x80000000; // flt32 sign bit
-
static const int32 infC = infN >> shift;
static const int32 nanN = (infC + 1) << shift; // minimum flt16 nan as a flt32
static const int32 maxC = maxN >> shift;
static const int32 minC = minN >> shift;
static const int32 signC = signN >> shiftSign; // flt16 sign bit
-
static const int32 mulN = 0x52000000; // (1 << 23) / minN
static const int32 mulC = 0x33800000; // minN / (1 << (23 - shift))
-
static const int32 subC = 0x003FF; // max flt32 subnormal down shifted
static const int32 norC = 0x00400; // min flt32 normal down shifted
-
static const int32 maxD = infC - maxC - 1;
static const int32 minD = minC - subC - 1;
@@ -48,9 +49,9 @@ public:
static Half Compress(const float value)
{
#if USE_SSE_HALF_CONVERSION
- __m128 V1 = _mm_set_ss(value);
- __m128i V2 = _mm_cvtps_ph(V1, 0);
- return static_cast(_mm_cvtsi128_si32(V2));
+ __m128 value1 = _mm_set_ss(value);
+ __m128i value2 = _mm_cvtps_ph(value1, 0);
+ return static_cast(_mm_cvtsi128_si32(value2));
#else
Bits v, s;
v.f = value;
@@ -72,9 +73,9 @@ public:
static float Decompress(const Half value)
{
#if USE_SSE_HALF_CONVERSION
- __m128i V1 = _mm_cvtsi32_si128(static_cast(value));
- __m128 V2 = _mm_cvtph_ps(V1);
- return _mm_cvtss_f32(V2);
+ __m128i value1 = _mm_cvtsi32_si128(static_cast(value));
+ __m128 value2 = _mm_cvtph_ps(value1);
+ return _mm_cvtss_f32(value2);
#else
Bits v;
v.ui = value;
@@ -95,20 +96,10 @@ public:
}
};
-inline float ConvertHalfToFloat(const Half value)
-{
- return Float16Compressor::Decompress(value);
-}
-
-inline Half ConvertFloatToHalf(const float value)
-{
- return Float16Compressor::Compress(value);
-}
-
///
/// Defines a two component vector, using half precision floating point coordinates.
///
-struct Half2
+struct FLAXENGINE_API Half2
{
public:
@@ -145,8 +136,8 @@ public:
/// Y component
Half2(float x, float y)
{
- X = ConvertFloatToHalf(x);
- Y = ConvertFloatToHalf(y);
+ X = Float16Compressor::Compress(x);
+ Y = Float16Compressor::Compress(y);
}
///
@@ -167,7 +158,7 @@ public:
///
/// Defines a three component vector, using half precision floating point coordinates.
///
-struct Half3
+struct FLAXENGINE_API Half3
{
public:
@@ -201,9 +192,9 @@ public:
Half3(const float x, const float y, const float z)
{
- X = ConvertFloatToHalf(x);
- Y = ConvertFloatToHalf(y);
- Z = ConvertFloatToHalf(z);
+ X = Float16Compressor::Compress(x);
+ Y = Float16Compressor::Compress(y);
+ Z = Float16Compressor::Compress(z);
}
Half3(const Vector3& v);
@@ -216,7 +207,7 @@ public:
///
/// Defines a four component vector, using half precision floating point coordinates.
///
-struct Half4
+struct FLAXENGINE_API Half4
{
public:
@@ -255,31 +246,27 @@ public:
Half4(const float x, const float y, const float z)
{
- X = ConvertFloatToHalf(x);
- Y = ConvertFloatToHalf(y);
- Z = ConvertFloatToHalf(z);
+ X = Float16Compressor::Compress(x);
+ Y = Float16Compressor::Compress(y);
+ Z = Float16Compressor::Compress(z);
W = 0;
}
Half4(const float x, const float y, const float z, const float w)
{
- X = ConvertFloatToHalf(x);
- Y = ConvertFloatToHalf(y);
- Z = ConvertFloatToHalf(z);
- W = ConvertFloatToHalf(w);
+ X = Float16Compressor::Compress(x);
+ Y = Float16Compressor::Compress(y);
+ Z = Float16Compressor::Compress(z);
+ W = Float16Compressor::Compress(w);
}
explicit Half4(const Vector4& v);
-
explicit Half4(const Color& c);
-
explicit Half4(const Rectangle& rect);
public:
Vector2 ToVector2() const;
-
Vector3 ToVector3() const;
-
Vector4 ToVector4() const;
};
diff --git a/Source/Engine/Core/Math/Int2.h b/Source/Engine/Core/Math/Int2.h
new file mode 100644
index 000000000..a6038d1b0
--- /dev/null
+++ b/Source/Engine/Core/Math/Int2.h
@@ -0,0 +1,279 @@
+// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+
+#pragma once
+
+#include "Math.h"
+#include "Engine/Core/Formatting.h"
+#include "Engine/Core/Templates.h"
+
+struct Vector2;
+struct Vector3;
+struct Vector4;
+
+///
+/// Two-components vector (32 bit integer type).
+///
+API_STRUCT(InBuild) struct FLAXENGINE_API Int2
+{
+public:
+
+ union
+ {
+ struct
+ {
+ // X component
+ int32 X;
+
+ // Y component
+ int32 Y;
+ };
+
+ // Raw values
+ int32 Raw[2];
+ };
+
+public:
+
+ // Vector with all components equal 0
+ static const Int2 Zero;
+
+ // Vector with all components equal 1
+ static const Int2 One;
+
+public:
+
+ ///
+ /// Empty constructor.
+ ///
+ Int2()
+ {
+ }
+
+ // Init
+ // @param xy Value to assign to the all components
+ Int2(int32 xy)
+ : X(xy)
+ , Y(xy)
+ {
+ }
+
+ // Init
+ // @param x X component value
+ // @param y Y component value
+ Int2(int32 x, int32 y)
+ : X(x)
+ , Y(y)
+ {
+ }
+
+ // Init
+ // @param v Vector to use X and Y components
+ explicit Int2(const Vector2& v);
+
+public:
+
+ String ToString() const;
+
+public:
+
+ // Arithmetic operators with Int2
+
+ Int2 operator+(const Int2& b) const
+ {
+ return Add(*this, b);
+ }
+
+ Int2 operator-(const Int2& b) const
+ {
+ return Subtract(*this, b);
+ }
+
+ Int2 operator*(const Int2& b) const
+ {
+ return Multiply(*this, b);
+ }
+
+ Int2 operator/(const Int2& b) const
+ {
+ return Divide(*this, b);
+ }
+
+ Int2 operator-() const
+ {
+ return Int2(-X, -Y);
+ }
+
+ // op= operators with Int2
+
+ Int2& operator+=(const Int2& b)
+ {
+ *this = Add(*this, b);
+ return *this;
+ }
+
+ Int2& operator-=(const Int2& b)
+ {
+ *this = Subtract(*this, b);
+ return *this;
+ }
+
+ Int2& operator*=(const Int2& b)
+ {
+ *this = Multiply(*this, b);
+ return *this;
+ }
+
+ Int2& operator/=(const Int2& b)
+ {
+ *this = Divide(*this, b);
+ return *this;
+ }
+
+ // Arithmetic operators with int32
+
+ Int2 operator+(int32 b) const
+ {
+ return Add(*this, b);
+ }
+
+ Int2 operator-(int32 b) const
+ {
+ return Subtract(*this, b);
+ }
+
+ Int2 operator*(int32 b) const
+ {
+ return Multiply(*this, b);
+ }
+
+ Int2 operator/(int32 b) const
+ {
+ return Divide(*this, b);
+ }
+
+ // op= operators with int32
+
+ Int2& operator+=(int32 b)
+ {
+ *this = Add(*this, b);
+ return *this;
+ }
+
+ Int2& operator-=(int32 b)
+ {
+ *this = Subtract(*this, b);
+ return *this;
+ }
+
+ Int2& operator*=(int32 b)
+ {
+ *this = Multiply(*this, b);
+ return *this;
+ }
+
+ Int2& operator/=(int32 b)
+ {
+ *this = Divide(*this, b);
+ return *this;
+ }
+
+ // Comparison operators
+
+ bool operator==(const Int2& b) const
+ {
+ return X == b.X && Y == b.Y;
+ }
+
+ bool operator!=(const Int2& b) const
+ {
+ return X != b.X || Y != b.Y;
+ }
+
+ bool operator>(const Int2& b) const
+ {
+ return X > b.X && Y > b.Y;
+ }
+
+ bool operator>=(const Int2& b) const
+ {
+ return X >= b.X && Y >= b.Y;
+ }
+
+ bool operator<(const Int2& b) const
+ {
+ return X < b.X && Y < b.Y;
+ }
+
+ bool operator<=(const Int2& b) const
+ {
+ return X <= b.X && Y <= b.Y;
+ }
+
+public:
+
+ static void Add(const Int2& a, const Int2& b, Int2* result)
+ {
+ result->X = a.X + b.X;
+ result->Y = a.Y + b.Y;
+ }
+
+ static Int2 Add(const Int2& a, const Int2& b)
+ {
+ Int2 result;
+ Add(a, b, &result);
+ return result;
+ }
+
+ static void Subtract(const Int2& a, const Int2& b, Int2* result)
+ {
+ result->X = a.X - b.X;
+ result->Y = a.Y - b.Y;
+ }
+
+ static Int2 Subtract(const Int2& a, const Int2& b)
+ {
+ Int2 result;
+ Subtract(a, b, &result);
+ return result;
+ }
+
+ static Int2 Multiply(const Int2& a, const Int2& b)
+ {
+ return Int2(a.X * b.X, a.Y * b.Y);
+ }
+
+ static Int2 Multiply(const Int2& a, int32 b)
+ {
+ return Int2(a.X * b, a.Y * b);
+ }
+
+ static Int2 Divide(const Int2& a, const Int2& b)
+ {
+ return Int2(a.X / b.X, a.Y / b.Y);
+ }
+
+ static Int2 Divide(const Int2& a, int32 b)
+ {
+ return Int2(a.X / b, a.Y / b);
+ }
+
+ // Creates vector from minimum components of two vectors
+ static Int2 Min(const Int2& a, const Int2& b)
+ {
+ return Int2(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y);
+ }
+
+ // Creates vector from maximum components of two vectors
+ static Int2 Max(const Int2& a, const Int2& b)
+ {
+ return Int2(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y);
+ }
+};
+
+template<>
+struct TIsPODType
+{
+ enum { Value = true };
+};
+
+DEFINE_DEFAULT_FORMATTING(Int2, "X:{0} Y:{1}", v.X, v.Y);
diff --git a/Source/Engine/Core/Math/Int3.h b/Source/Engine/Core/Math/Int3.h
new file mode 100644
index 000000000..6886acc6b
--- /dev/null
+++ b/Source/Engine/Core/Math/Int3.h
@@ -0,0 +1,128 @@
+// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+
+#pragma once
+
+#include "Math.h"
+#include "Engine/Core/Formatting.h"
+#include "Engine/Core/Templates.h"
+
+struct Vector2;
+struct Vector3;
+struct Vector4;
+
+///
+/// Three-components vector (32 bit integer type).
+///
+API_STRUCT(InBuild) struct FLAXENGINE_API Int3
+{
+public:
+
+ union
+ {
+ struct
+ {
+ // X component
+ int32 X;
+
+ // Y component
+ int32 Y;
+
+ // Y component
+ int32 Z;
+ };
+
+ // Raw values
+ int32 Raw[3];
+ };
+
+public:
+
+ // Vector with all components equal 0
+ static const Int3 Zero;
+
+ // Vector with all components equal 1
+ static const Int3 One;
+
+public:
+
+ ///
+ /// Empty constructor.
+ ///
+ Int3()
+ {
+ }
+
+ // Init
+ // @param xy Value to assign to the all components
+ Int3(int32 xyz)
+ : X(xyz)
+ , Y(xyz)
+ , Z(xyz)
+ {
+ }
+
+ // Init
+ // @param x X component value
+ // @param y Y component value
+ // @param z Z component value
+ Int3(int32 x, int32 y, int32 z)
+ : X(x)
+ , Y(y)
+ , Z(z)
+ {
+ }
+
+ // Init
+ // @param v Vector to use X, Y and Z components
+ explicit Int3(const Vector3& v);
+
+public:
+
+ String ToString() const;
+
+public:
+
+ // Returns a vector containing the largest components of the specified vectors
+ // @param a The first source vector
+ // @param b The second source vector
+ // @param result When the method completes, contains an new vector composed of the largest components of the source vectors
+ static Int3 Max(const Int3& a, const Int3& b)
+ {
+ return Int3(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y, a.Z > b.Z ? a.Z : b.Z);
+ }
+
+ // Returns a vector containing the smallest components of the specified vectors
+ // @param a The first source vector
+ // @param b The second source vector
+ // @param result When the method completes, contains an new vector composed of the smallest components of the source vectors
+ static Int3 Min(const Int3& a, const Int3& b)
+ {
+ return Int3(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y, a.Z < b.Z ? a.Z : b.Z);
+ }
+
+ // Returns a vector containing the largest components of the specified vectors
+ // @param a The first source vector
+ // @param b The second source vector
+ // @param result When the method completes, contains an new vector composed of the largest components of the source vectors
+ static void Max(const Int3& a, const Int3& b, Int3* result)
+ {
+ *result = Int3(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y, a.Z > b.Z ? a.Z : b.Z);
+ }
+
+ // Returns a vector containing the smallest components of the specified vectors
+ // @param a The first source vector
+ // @param b The second source vector
+ // @param result When the method completes, contains an new vector composed of the smallest components of the source vectors
+ static void Min(const Int3& a, const Int3& b, Int3* result)
+ {
+ *result = Int3(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y, a.Z < b.Z ? a.Z : b.Z);
+ }
+};
+
+template<>
+struct TIsPODType
+{
+ enum { Value = true };
+};
+
+DEFINE_DEFAULT_FORMATTING(Int3, "X:{0} Y:{1} Z:{2}", v.X, v.Y, v.Z);
diff --git a/Source/Engine/Core/Math/Int4.h b/Source/Engine/Core/Math/Int4.h
new file mode 100644
index 000000000..c8e9eebd8
--- /dev/null
+++ b/Source/Engine/Core/Math/Int4.h
@@ -0,0 +1,134 @@
+// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+
+#pragma once
+
+#include "Math.h"
+#include "Engine/Core/Formatting.h"
+#include "Engine/Core/Templates.h"
+
+struct Vector2;
+struct Vector3;
+struct Vector4;
+
+///
+/// Four-components vector (32 bit integer type).
+///
+API_STRUCT(InBuild) struct FLAXENGINE_API Int4
+{
+public:
+
+ union
+ {
+ struct
+ {
+ // X component
+ int32 X;
+
+ // Y component
+ int32 Y;
+
+ // Z component
+ int32 Z;
+
+ // W component
+ int32 W;
+ };
+
+ // Raw values
+ int32 Raw[4];
+ };
+
+public:
+
+ // Vector with all components equal 0
+ static const Int4 Zero;
+
+ // Vector with all components equal 1
+ static const Int4 One;
+
+public:
+
+ ///
+ /// Empty constructor.
+ ///
+ Int4()
+ {
+ }
+
+ // Init
+ // @param xy Value to assign to the all components
+ Int4(int32 xyzw)
+ : X(xyzw)
+ , Y(xyzw)
+ , Z(xyzw)
+ , W(xyzw)
+ {
+ }
+
+ // Init
+ // @param x X component value
+ // @param y Y component value
+ // @param z Z component value
+ // @param w W component value
+ Int4(int32 x, int32 y, int32 z, int32 w)
+ : X(x)
+ , Y(y)
+ , Z(z)
+ , W(w)
+ {
+ }
+
+ // Init
+ // @param v Vector to use X, Y, Z and W components
+ explicit Int4(const Vector4& v);
+
+public:
+
+ String ToString() const;
+
+public:
+
+ ///
+ /// Returns average arithmetic of all the components
+ ///
+ /// Average arithmetic of all the components
+ float AverageArithmetic() const
+ {
+ return (X + Y + Z + W) * 0.25f;
+ }
+
+ ///
+ /// Gets sum of all vector components values
+ ///
+ /// Sum of X, Y, Z and W
+ int32 SumValues() const
+ {
+ return X + Y + Z + W;
+ }
+
+ ///
+ /// Returns minimum value of all the components
+ ///
+ /// Minimum value
+ int32 MinValue() const
+ {
+ return Math::Min(X, Y, Z, W);
+ }
+
+ ///
+ /// Returns maximum value of all the components
+ ///
+ /// Maximum value
+ int32 MaxValue() const
+ {
+ return Math::Max(X, Y, Z, W);
+ }
+};
+
+template<>
+struct TIsPODType
+{
+ enum { Value = true };
+};
+
+DEFINE_DEFAULT_FORMATTING(Int4, "X:{0} Y:{1} Z:{2} W:{3}", v.X, v.Y, v.Z, v.W);
diff --git a/Source/Engine/Core/Math/Mathf.cs b/Source/Engine/Core/Math/Mathf.cs
index 7286573bf..529bd6ab0 100644
--- a/Source/Engine/Core/Math/Mathf.cs
+++ b/Source/Engine/Core/Math/Mathf.cs
@@ -36,6 +36,11 @@ namespace FlaxEngine
///
public const float PiOverFour = (float)(Math.PI / 4);
+ ///
+ /// A value specifying the golden mean
+ ///
+ public const float GoldenRatio = 1.6180339887f;
+
///
/// Returns the absolute value of f.
///
diff --git a/Source/Engine/Core/Math/Matrix3x3.h b/Source/Engine/Core/Math/Matrix3x3.h
index 3cf690259..b28be5437 100644
--- a/Source/Engine/Core/Math/Matrix3x3.h
+++ b/Source/Engine/Core/Math/Matrix3x3.h
@@ -9,7 +9,7 @@
///
/// Represents a 3x3 mathematical matrix.
///
-API_STRUCT(InBuild) struct Matrix3x3
+API_STRUCT(InBuild) struct FLAXENGINE_API Matrix3x3
{
public:
diff --git a/Source/Engine/Core/Math/OrientedBoundingBox.h b/Source/Engine/Core/Math/OrientedBoundingBox.h
index 03256633d..d19108f84 100644
--- a/Source/Engine/Core/Math/OrientedBoundingBox.h
+++ b/Source/Engine/Core/Math/OrientedBoundingBox.h
@@ -8,7 +8,7 @@
#include "CollisionsHelper.h"
// Oriented Bounding Box (OBB) is a rectangular block, much like an AABB (Bounding Box) but with an arbitrary orientation in 3D space.
-API_STRUCT(InBuild) struct OrientedBoundingBox
+API_STRUCT(InBuild) struct FLAXENGINE_API OrientedBoundingBox
{
public:
diff --git a/Source/Engine/Core/Math/Packed.h b/Source/Engine/Core/Math/Packed.h
index ec666bf61..4f41dac9c 100644
--- a/Source/Engine/Core/Math/Packed.h
+++ b/Source/Engine/Core/Math/Packed.h
@@ -13,7 +13,7 @@ typedef Half Float16;
///
/// Packed vector, layout: R:10 bytes, G:10 bytes, B:10 bytes, A:2 bytes, all values are stored as floats in range [0;1].
///
-struct Float1010102
+struct FLAXENGINE_API Float1010102
{
union
{
@@ -64,7 +64,7 @@ public:
};
// The 3D vector is packed into 32 bits with 11/11/10 bits per floating-point component.
-struct FloatR11G11B10
+struct FLAXENGINE_API FloatR11G11B10
{
union
{
@@ -118,7 +118,7 @@ public:
Vector3 ToVector3() const;
};
-struct RG16UNorm
+struct FLAXENGINE_API RG16UNorm
{
uint16 X, Y;
@@ -131,7 +131,7 @@ struct RG16UNorm
Vector2 ToVector2() const;
};
-struct RGBA16UNorm
+struct FLAXENGINE_API RGBA16UNorm
{
uint16 X, Y, Z, W;
diff --git a/Source/Engine/Core/Math/Plane.h b/Source/Engine/Core/Math/Plane.h
index 2ca34258f..2fbe7438c 100644
--- a/Source/Engine/Core/Math/Plane.h
+++ b/Source/Engine/Core/Math/Plane.h
@@ -8,7 +8,7 @@
///
/// Represents a plane in three dimensional space.
///
-API_STRUCT() struct Plane
+API_STRUCT() struct FLAXENGINE_API Plane
{
DECLARE_SCRIPTING_TYPE_MINIMAL(Plane);
public:
diff --git a/Source/Engine/Core/Math/Ray.h b/Source/Engine/Core/Math/Ray.h
index 56d06a21e..f125cba97 100644
--- a/Source/Engine/Core/Math/Ray.h
+++ b/Source/Engine/Core/Math/Ray.h
@@ -11,7 +11,7 @@ struct Viewport;
///
/// Represents a three dimensional line based on a point in space and a direction.
///
-API_STRUCT() struct Ray
+API_STRUCT() struct FLAXENGINE_API Ray
{
DECLARE_SCRIPTING_TYPE_MINIMAL(Ray);
public:
diff --git a/Source/Engine/Core/Math/Rectangle.h b/Source/Engine/Core/Math/Rectangle.h
index 305ae70e1..f2dcbd20a 100644
--- a/Source/Engine/Core/Math/Rectangle.h
+++ b/Source/Engine/Core/Math/Rectangle.h
@@ -10,7 +10,6 @@
API_STRUCT() struct FLAXENGINE_API Rectangle
{
DECLARE_SCRIPTING_TYPE_MINIMAL(Rectangle);
-public:
///
/// The empty rectangle.
diff --git a/Source/Engine/Core/Math/Transform.h b/Source/Engine/Core/Math/Transform.h
index 3b8cf71b7..ed19efeae 100644
--- a/Source/Engine/Core/Math/Transform.h
+++ b/Source/Engine/Core/Math/Transform.h
@@ -11,10 +11,9 @@ struct Matrix;
///
/// Describes transformation in a 3D space.
///
-API_STRUCT() struct Transform
+API_STRUCT() struct FLAXENGINE_API Transform
{
DECLARE_SCRIPTING_TYPE_MINIMAL(Transform);
-public:
///
/// The translation vector of the transform.
diff --git a/Source/Engine/Core/Math/Triangle.h b/Source/Engine/Core/Math/Triangle.h
index 03f91ece3..b0f7ea09d 100644
--- a/Source/Engine/Core/Math/Triangle.h
+++ b/Source/Engine/Core/Math/Triangle.h
@@ -8,7 +8,7 @@
///
/// Represents a three dimensional triangle.
///
-struct Triangle
+struct FLAXENGINE_API Triangle
{
public:
diff --git a/Source/Engine/Core/Math/Vector2.cpp b/Source/Engine/Core/Math/Vector2.cpp
index 6a0468033..c23e79d19 100644
--- a/Source/Engine/Core/Math/Vector2.cpp
+++ b/Source/Engine/Core/Math/Vector2.cpp
@@ -4,8 +4,8 @@
#include "Vector3.h"
#include "Vector4.h"
#include "Color.h"
+#include "Int2.h"
#include "../Types/String.h"
-#include "VectorInt.h"
static_assert(sizeof(Vector2) == 8, "Invalid Vector2 type size.");
diff --git a/Source/Engine/Core/Math/Vector3.cpp b/Source/Engine/Core/Math/Vector3.cpp
index e3ff349ba..f66bbcbbd 100644
--- a/Source/Engine/Core/Math/Vector3.cpp
+++ b/Source/Engine/Core/Math/Vector3.cpp
@@ -6,7 +6,7 @@
#include "Color.h"
#include "Quaternion.h"
#include "Matrix.h"
-#include "VectorInt.h"
+#include "Int3.h"
#include "../Types/String.h"
static_assert(sizeof(Vector3) == 12, "Invalid Vector3 type size.");
diff --git a/Source/Engine/Core/Math/Vector3.cs b/Source/Engine/Core/Math/Vector3.cs
index db27cf8ed..a57fcb224 100644
--- a/Source/Engine/Core/Math/Vector3.cs
+++ b/Source/Engine/Core/Math/Vector3.cs
@@ -1221,7 +1221,7 @@ namespace FlaxEngine
float dot = Mathf.Clamp(Dot(from.Normalized, to.Normalized), -1F, 1F);
if (Mathf.Abs(dot) > (1F - Mathf.Epsilon))
return dot > 0F ? 0F : 180F;
- return Mathf.Acos(dot) * Mathf.DegreesToRadians;
+ return Mathf.Acos(dot) * Mathf.RadiansToDegrees;
}
///
diff --git a/Source/Engine/Core/Math/Vector4.cpp b/Source/Engine/Core/Math/Vector4.cpp
index 3caaab985..34fa27aac 100644
--- a/Source/Engine/Core/Math/Vector4.cpp
+++ b/Source/Engine/Core/Math/Vector4.cpp
@@ -6,7 +6,7 @@
#include "Color.h"
#include "Matrix.h"
#include "Rectangle.h"
-#include "VectorInt.h"
+#include "Int4.h"
#include "../Types/String.h"
static_assert(sizeof(Vector4) == 16, "Invalid Vector4 type size.");
diff --git a/Source/Engine/Core/Math/VectorInt.h b/Source/Engine/Core/Math/VectorInt.h
index 80804c39a..d9611d615 100644
--- a/Source/Engine/Core/Math/VectorInt.h
+++ b/Source/Engine/Core/Math/VectorInt.h
@@ -2,518 +2,6 @@
#pragma once
-#include "Math.h"
-#include "Engine/Core/Formatting.h"
-#include "Engine/Core/Templates.h"
-
-struct Vector2;
-struct Vector3;
-struct Vector4;
-
-///
-/// Two-components vector (32 bit integer type).
-///
-API_STRUCT(InBuild) struct Int2
-{
-public:
-
- union
- {
- struct
- {
- // X component
- int32 X;
-
- // Y component
- int32 Y;
- };
-
- // Raw values
- int32 Raw[2];
- };
-
-public:
-
- // Vector with all components equal 0
- static const Int2 Zero;
-
- // Vector with all components equal 1
- static const Int2 One;
-
-public:
-
- ///
- /// Empty constructor.
- ///
- Int2()
- {
- }
-
- // Init
- // @param xy Value to assign to the all components
- Int2(int32 xy)
- : X(xy)
- , Y(xy)
- {
- }
-
- // Init
- // @param x X component value
- // @param y Y component value
- Int2(int32 x, int32 y)
- : X(x)
- , Y(y)
- {
- }
-
- // Init
- // @param v Vector to use X and Y components
- explicit Int2(const Vector2& v);
-
-public:
-
- String ToString() const;
-
-public:
-
- // Arithmetic operators with Int2
-
- Int2 operator+(const Int2& b) const
- {
- return Add(*this, b);
- }
-
- Int2 operator-(const Int2& b) const
- {
- return Subtract(*this, b);
- }
-
- Int2 operator*(const Int2& b) const
- {
- return Multiply(*this, b);
- }
-
- Int2 operator/(const Int2& b) const
- {
- return Divide(*this, b);
- }
-
- Int2 operator-() const
- {
- return Int2(-X, -Y);
- }
-
- // op= operators with Int2
-
- Int2& operator+=(const Int2& b)
- {
- *this = Add(*this, b);
- return *this;
- }
-
- Int2& operator-=(const Int2& b)
- {
- *this = Subtract(*this, b);
- return *this;
- }
-
- Int2& operator*=(const Int2& b)
- {
- *this = Multiply(*this, b);
- return *this;
- }
-
- Int2& operator/=(const Int2& b)
- {
- *this = Divide(*this, b);
- return *this;
- }
-
- // Arithmetic operators with int32
-
- Int2 operator+(int32 b) const
- {
- return Add(*this, b);
- }
-
- Int2 operator-(int32 b) const
- {
- return Subtract(*this, b);
- }
-
- Int2 operator*(int32 b) const
- {
- return Multiply(*this, b);
- }
-
- Int2 operator/(int32 b) const
- {
- return Divide(*this, b);
- }
-
- // op= operators with int32
-
- Int2& operator+=(int32 b)
- {
- *this = Add(*this, b);
- return *this;
- }
-
- Int2& operator-=(int32 b)
- {
- *this = Subtract(*this, b);
- return *this;
- }
-
- Int2& operator*=(int32 b)
- {
- *this = Multiply(*this, b);
- return *this;
- }
-
- Int2& operator/=(int32 b)
- {
- *this = Divide(*this, b);
- return *this;
- }
-
- // Comparison operators
-
- bool operator==(const Int2& b) const
- {
- return X == b.X && Y == b.Y;
- }
-
- bool operator!=(const Int2& b) const
- {
- return X != b.X || Y != b.Y;
- }
-
- bool operator>(const Int2& b) const
- {
- return X > b.X && Y > b.Y;
- }
-
- bool operator>=(const Int2& b) const
- {
- return X >= b.X && Y >= b.Y;
- }
-
- bool operator<(const Int2& b) const
- {
- return X < b.X && Y < b.Y;
- }
-
- bool operator<=(const Int2& b) const
- {
- return X <= b.X && Y <= b.Y;
- }
-
-public:
-
- static void Add(const Int2& a, const Int2& b, Int2* result)
- {
- result->X = a.X + b.X;
- result->Y = a.Y + b.Y;
- }
-
- static Int2 Add(const Int2& a, const Int2& b)
- {
- Int2 result;
- Add(a, b, &result);
- return result;
- }
-
- static void Subtract(const Int2& a, const Int2& b, Int2* result)
- {
- result->X = a.X - b.X;
- result->Y = a.Y - b.Y;
- }
-
- static Int2 Subtract(const Int2& a, const Int2& b)
- {
- Int2 result;
- Subtract(a, b, &result);
- return result;
- }
-
- static Int2 Multiply(const Int2& a, const Int2& b)
- {
- return Int2(a.X * b.X, a.Y * b.Y);
- }
-
- static Int2 Multiply(const Int2& a, int32 b)
- {
- return Int2(a.X * b, a.Y * b);
- }
-
- static Int2 Divide(const Int2& a, const Int2& b)
- {
- return Int2(a.X / b.X, a.Y / b.Y);
- }
-
- static Int2 Divide(const Int2& a, int32 b)
- {
- return Int2(a.X / b, a.Y / b);
- }
-
- // Creates vector from minimum components of two vectors
- static Int2 Min(const Int2& a, const Int2& b)
- {
- return Int2(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y);
- }
-
- // Creates vector from maximum components of two vectors
- static Int2 Max(const Int2& a, const Int2& b)
- {
- return Int2(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y);
- }
-};
-
-///
-/// Three-components vector (32 bit integer type).
-///
-API_STRUCT(InBuild) struct Int3
-{
-public:
-
- union
- {
- struct
- {
- // X component
- int32 X;
-
- // Y component
- int32 Y;
-
- // Y component
- int32 Z;
- };
-
- // Raw values
- int32 Raw[3];
- };
-
-public:
-
- // Vector with all components equal 0
- static const Int3 Zero;
-
- // Vector with all components equal 1
- static const Int3 One;
-
-public:
-
- ///
- /// Empty constructor.
- ///
- Int3()
- {
- }
-
- // Init
- // @param xy Value to assign to the all components
- Int3(int32 xyz)
- : X(xyz)
- , Y(xyz)
- , Z(xyz)
- {
- }
-
- // Init
- // @param x X component value
- // @param y Y component value
- // @param z Z component value
- Int3(int32 x, int32 y, int32 z)
- : X(x)
- , Y(y)
- , Z(z)
- {
- }
-
- // Init
- // @param v Vector to use X, Y and Z components
- explicit Int3(const Vector3& v);
-
-public:
-
- String ToString() const;
-
-public:
-
- // Returns a vector containing the largest components of the specified vectors
- // @param a The first source vector
- // @param b The second source vector
- // @param result When the method completes, contains an new vector composed of the largest components of the source vectors
- static Int3 Max(const Int3& a, const Int3& b)
- {
- return Int3(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y, a.Z > b.Z ? a.Z : b.Z);
- }
-
- // Returns a vector containing the smallest components of the specified vectors
- // @param a The first source vector
- // @param b The second source vector
- // @param result When the method completes, contains an new vector composed of the smallest components of the source vectors
- static Int3 Min(const Int3& a, const Int3& b)
- {
- return Int3(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y, a.Z < b.Z ? a.Z : b.Z);
- }
-
- // Returns a vector containing the largest components of the specified vectors
- // @param a The first source vector
- // @param b The second source vector
- // @param result When the method completes, contains an new vector composed of the largest components of the source vectors
- static void Max(const Int3& a, const Int3& b, Int3* result)
- {
- *result = Int3(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y, a.Z > b.Z ? a.Z : b.Z);
- }
-
- // Returns a vector containing the smallest components of the specified vectors
- // @param a The first source vector
- // @param b The second source vector
- // @param result When the method completes, contains an new vector composed of the smallest components of the source vectors
- static void Min(const Int3& a, const Int3& b, Int3* result)
- {
- *result = Int3(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y, a.Z < b.Z ? a.Z : b.Z);
- }
-};
-
-///
-/// Four-components vector (32 bit integer type).
-///
-API_STRUCT(InBuild) struct Int4
-{
-public:
-
- union
- {
- struct
- {
- // X component
- int32 X;
-
- // Y component
- int32 Y;
-
- // Z component
- int32 Z;
-
- // W component
- int32 W;
- };
-
- // Raw values
- int32 Raw[4];
- };
-
-public:
-
- // Vector with all components equal 0
- static const Int4 Zero;
-
- // Vector with all components equal 1
- static const Int4 One;
-
-public:
-
- ///
- /// Empty constructor.
- ///
- Int4()
- {
- }
-
- // Init
- // @param xy Value to assign to the all components
- Int4(int32 xyzw)
- : X(xyzw)
- , Y(xyzw)
- , Z(xyzw)
- , W(xyzw)
- {
- }
-
- // Init
- // @param x X component value
- // @param y Y component value
- // @param z Z component value
- // @param w W component value
- Int4(int32 x, int32 y, int32 z, int32 w)
- : X(x)
- , Y(y)
- , Z(z)
- , W(w)
- {
- }
-
- // Init
- // @param v Vector to use X, Y, Z and W components
- explicit Int4(const Vector4& v);
-
-public:
-
- String ToString() const;
-
-public:
-
- ///
- /// Returns average arithmetic of all the components
- ///
- /// Average arithmetic of all the components
- float AverageArithmetic() const
- {
- return (X + Y + Z + W) * 0.25f;
- }
-
- ///
- /// Gets sum of all vector components values
- ///
- /// Sum of X, Y, Z and W
- int32 SumValues() const
- {
- return X + Y + Z + W;
- }
-
- ///
- /// Returns minimum value of all the components
- ///
- /// Minimum value
- int32 MinValue() const
- {
- return Math::Min(X, Y, Z, W);
- }
-
- ///
- /// Returns maximum value of all the components
- ///
- /// Maximum value
- int32 MaxValue() const
- {
- return Math::Max(X, Y, Z, W);
- }
-};
-
-template<>
-struct TIsPODType
-{
- enum { Value = true };
-};
-
-template<>
-struct TIsPODType
-{
- enum { Value = true };
-};
-
-template<>
-struct TIsPODType
-{
- enum { Value = true };
-};
-
-DEFINE_DEFAULT_FORMATTING(Int2, "X:{0} Y:{1}", v.X, v.Y);
-
-DEFINE_DEFAULT_FORMATTING(Int3, "X:{0} Y:{1} Z:{2}", v.X, v.Y, v.Z);
-
-DEFINE_DEFAULT_FORMATTING(Int4, "X:{0} Y:{1} Z:{2} W:{3}", v.X, v.Y, v.Z, v.W);
+#include "Int2.h"
+#include "Int3.h"
+#include "Int4.h"
diff --git a/Source/Engine/Core/Math/Viewport.h b/Source/Engine/Core/Math/Viewport.h
index 0b5871f2e..e30d085d3 100644
--- a/Source/Engine/Core/Math/Viewport.h
+++ b/Source/Engine/Core/Math/Viewport.h
@@ -10,7 +10,7 @@ struct Matrix;
struct Rectangle;
// Describes the viewport dimensions.
-API_STRUCT(InBuild) struct Viewport
+API_STRUCT(InBuild) struct FLAXENGINE_API Viewport
{
public:
diff --git a/Source/Engine/Core/ObjectsRemovalService.cpp b/Source/Engine/Core/ObjectsRemovalService.cpp
index a36265646..f9d26f808 100644
--- a/Source/Engine/Core/ObjectsRemovalService.cpp
+++ b/Source/Engine/Core/ObjectsRemovalService.cpp
@@ -193,7 +193,7 @@ void ObjectsRemovalServiceService::Dispose()
// Collect new objects
ObjectsRemovalService::Flush();
- // Delete all reaming objects
+ // Delete all remaining objects
{
ScopeLock lock(PoolLocker);
for (auto i = Pool.Begin(); i.IsNotEnd(); ++i)
diff --git a/Source/Engine/Core/Types/Variant.cpp b/Source/Engine/Core/Types/Variant.cpp
index 62c791875..db71c2f77 100644
--- a/Source/Engine/Core/Types/Variant.cpp
+++ b/Source/Engine/Core/Types/Variant.cpp
@@ -2612,7 +2612,8 @@ Variant Variant::Lerp(const Variant& a, const Variant& b, float alpha)
void Variant::AllocStructure()
{
- const ScriptingTypeHandle typeHandle = Scripting::FindScriptingType(StringAnsiView(Type.TypeName));
+ const StringAnsiView typeName(Type.TypeName);
+ const ScriptingTypeHandle typeHandle = Scripting::FindScriptingType(typeName);
if (typeHandle)
{
const ScriptingType& type = typeHandle.GetType();
@@ -2620,8 +2621,26 @@ void Variant::AllocStructure()
AsBlob.Data = Allocator::Allocate(AsBlob.Length);
type.Struct.Ctor(AsBlob.Data);
}
+ else if (typeName == "System.Byte")
+ {
+ // Hack for byte
+ AsBlob.Length = 1;
+ AsBlob.Data = Allocator::Allocate(AsBlob.Length);
+ *((byte*)AsBlob.Data) = 0;
+ }
+ else if (typeName == "System.Int16" || typeName == "System.UInt16")
+ {
+ // Hack for 16bit int
+ AsBlob.Length = 2;
+ AsBlob.Data = Allocator::Allocate(AsBlob.Length);
+ *((int16*)AsBlob.Data) = 0;
+ }
else
{
+ if (typeName.Length() != 0)
+ {
+ LOG(Warning, "Missing scripting type \'{0}\'", String(typeName.Get()));
+ }
AsBlob.Data = nullptr;
AsBlob.Length = 0;
}
@@ -2637,6 +2656,10 @@ void Variant::CopyStructure(void* src)
auto& type = typeHandle.GetType();
type.Struct.Copy(AsBlob.Data, src);
}
+ else
+ {
+ Platform::MemoryCopy(AsBlob.Data, src, AsBlob.Length);
+ }
}
}
diff --git a/Source/Engine/Debug/DebugDraw.cpp b/Source/Engine/Debug/DebugDraw.cpp
index 457c90411..f954cd7cb 100644
--- a/Source/Engine/Debug/DebugDraw.cpp
+++ b/Source/Engine/Debug/DebugDraw.cpp
@@ -19,6 +19,7 @@
#include "Engine/Graphics/RenderBuffers.h"
#include "Engine/Animations/AnimationUtils.h"
#include "Engine/Profiler/Profiler.h"
+#include "Engine/Debug/DebugLog.h"
// Debug draw service configuration
#define DEBUG_DRAW_INITIAL_VB_CAPACITY (4 * 1024)
@@ -629,7 +630,11 @@ void DebugDraw::DrawLine(const Vector3& start, const Vector3& end, const Color&
void DebugDraw::DrawLines(const Span& lines, const Matrix& transform, const Color& color, float duration, bool depthTest)
{
- ASSERT(lines.Length() % 2 == 0);
+ if (lines.Length() % 2 != 0)
+ {
+ DebugLog::ThrowException("Cannot draw debug lines with uneven amount of items in array");
+ return;
+ }
// Create draw call entry
DebugLine l = { Vector3::Zero, Vector3::Zero, Color32(color), duration };
@@ -637,10 +642,12 @@ void DebugDraw::DrawLines(const Span& lines, const Matrix& transform, c
// Add lines
const Vector3* p = lines.Get();
Array* list;
- if (depthTest)
+
+ if (depthTest)
list = duration > 0 ? &DebugDrawDepthTest.DefaultLines : &DebugDrawDepthTest.OneFrameLines;
else
list = duration > 0 ? &DebugDrawDefault.DefaultLines : &DebugDrawDefault.OneFrameLines;
+
list->EnsureCapacity(list->Count() + lines.Length());
for (int32 i = 0; i < lines.Length(); i += 2)
{
diff --git a/Source/Engine/Debug/Exception.h b/Source/Engine/Debug/Exception.h
index 481c78589..5bef7aa55 100644
--- a/Source/Engine/Debug/Exception.h
+++ b/Source/Engine/Debug/Exception.h
@@ -36,7 +36,7 @@ namespace Log
///
/// Additional information that help describe error
Exception(const String& additionalInfo)
- : Exception(TEXT("An exception has occured."), additionalInfo)
+ : Exception(TEXT("An exception has occurred."), additionalInfo)
{
}
diff --git a/Source/Engine/Engine/Engine.cpp b/Source/Engine/Engine/Engine.cpp
index ebf268957..140f1b4a0 100644
--- a/Source/Engine/Engine/Engine.cpp
+++ b/Source/Engine/Engine/Engine.cpp
@@ -463,7 +463,7 @@ void Engine::OnExit()
LOG_FLUSH();
- // Kill all reaming threads
+ // Kill all remaining threads
ThreadRegistry::KillEmAll();
// Cleanup
diff --git a/Source/Engine/Graphics/Enums.h b/Source/Engine/Graphics/Enums.h
index 20836b300..8aa88756a 100644
--- a/Source/Engine/Graphics/Enums.h
+++ b/Source/Engine/Graphics/Enums.h
@@ -985,7 +985,7 @@ API_ENUM() enum class TessellationMethod
enum class ShaderFlags : uint32
{
///
- /// The default set fo flags.
+ /// The default set for flags.
///
Default = 0,
diff --git a/Source/Engine/Graphics/GPUBuffer.h b/Source/Engine/Graphics/GPUBuffer.h
index 84611419e..97be261a4 100644
--- a/Source/Engine/Graphics/GPUBuffer.h
+++ b/Source/Engine/Graphics/GPUBuffer.h
@@ -215,7 +215,7 @@ public:
/// Gets a CPU pointer to the resource by mapping its contents. Denies the GPU access to that resource.
///
/// The map operation mode.
- /// The pointer ot the mapped CPU buffer with resource data or null if failed.
+ /// The pointer of the mapped CPU buffer with resource data or null if failed.
API_FUNCTION() virtual void* Map(GPUResourceMapMode mode) = 0;
///
diff --git a/Source/Engine/Graphics/GPUDevice.cpp b/Source/Engine/Graphics/GPUDevice.cpp
index a5195ff50..47ec6d3a6 100644
--- a/Source/Engine/Graphics/GPUDevice.cpp
+++ b/Source/Engine/Graphics/GPUDevice.cpp
@@ -239,7 +239,7 @@ void GPUDevice::preDispose()
SAFE_DELETE_GPU_RESOURCE(_res->FullscreenTriangleVB);
// Release GPU resources memory and unlink from device
- // Note: after that noe GPU resources should be used/created, only deleted
+ // Note: after that no GPU resources should be used/created, only deleted
Resources.OnDeviceDispose();
}
diff --git a/Source/Engine/Graphics/GPULimits.h b/Source/Engine/Graphics/GPULimits.h
index 485f5d866..b50714fcd 100644
--- a/Source/Engine/Graphics/GPULimits.h
+++ b/Source/Engine/Graphics/GPULimits.h
@@ -174,10 +174,10 @@ API_ENUM(Attributes="Flags") enum class FormatSupport : int32
DECLARE_ENUM_OPERATORS(FormatSupport);
// Helper macro to check if given format does not support a given set of feature flags
-#define FORMAT_FEATURES_ARE_NOT_SUPPORTED(formatSupport, formatSupportFlags) ((formatSupport & formatSupportFlags) != static_cast(formatSupportFlags))
+#define FORMAT_FEATURES_ARE_NOT_SUPPORTED(formatSupport, formatSupportFlags) ((formatSupport & (formatSupportFlags)) != static_cast(formatSupportFlags))
// Helper macro to check if given format does support a given set of feature flags
-#define FORMAT_FEATURES_ARE_SUPPORTED(formatSupport, formatSupportFlags) ((formatSupport & formatSupportFlags) == static_cast(formatSupportFlags))
+#define FORMAT_FEATURES_ARE_SUPPORTED(formatSupport, formatSupportFlags) ((formatSupport & (formatSupportFlags)) == static_cast(formatSupportFlags))
///
/// The features exposed for a particular format.
diff --git a/Source/Engine/Graphics/GPUSwapChain.cpp b/Source/Engine/Graphics/GPUSwapChain.cpp
index 347fa6e46..68b1486ad 100644
--- a/Source/Engine/Graphics/GPUSwapChain.cpp
+++ b/Source/Engine/Graphics/GPUSwapChain.cpp
@@ -39,7 +39,7 @@ Task* GPUSwapChain::DownloadDataAsync(TextureData& result)
{
if (_downloadTask)
{
- LOG(Warning, "Can download window backuffer data ony once at the time.");
+ LOG(Warning, "Can download window backuffer data only once at the time.");
return nullptr;
}
diff --git a/Source/Engine/Graphics/Graphics.cpp b/Source/Engine/Graphics/Graphics.cpp
index 21b506ef1..69170dca0 100644
--- a/Source/Engine/Graphics/Graphics.cpp
+++ b/Source/Engine/Graphics/Graphics.cpp
@@ -49,6 +49,9 @@ GraphicsService GraphicsServiceInstance;
void Graphics::DisposeDevice()
{
+ // Clean any danging pointer to last task (might stay if engine is disposing after crash)
+ GPUDevice::Instance->CurrentTask = nullptr;
+
if (GPUDevice::Instance)
{
GPUDevice::Instance->Dispose();
diff --git a/Source/Engine/Graphics/Materials/IMaterial.h b/Source/Engine/Graphics/Materials/IMaterial.h
index 8d5590354..09796c04b 100644
--- a/Source/Engine/Graphics/Materials/IMaterial.h
+++ b/Source/Engine/Graphics/Materials/IMaterial.h
@@ -108,7 +108,7 @@ public:
///
/// Gets the mask of render passes supported by this material.
///
- /// The drw passes supported by this material.
+ /// The draw passes supported by this material.
virtual DrawPass GetDrawModes() const
{
return DrawPass::None;
diff --git a/Source/Engine/Graphics/Mesh.cs b/Source/Engine/Graphics/Mesh.cs
index f639bff8f..f96b4ce63 100644
--- a/Source/Engine/Graphics/Mesh.cs
+++ b/Source/Engine/Graphics/Mesh.cs
@@ -117,7 +117,7 @@ namespace FlaxEngine
/// Mesh data will be cached and uploaded to the GPU with a delay.
///
/// The mesh vertices positions. Cannot be null.
- /// The mesh index buffer (triangles). Uses 32-bit stride buffer. Cannot be null.
+ /// The mesh index buffer (clockwise triangles). Uses 32-bit stride buffer. Cannot be null.
/// The normal vectors (per vertex).
/// The normal vectors (per vertex). Use null to compute them from normal vectors.
/// The texture coordinates (per vertex).
@@ -163,7 +163,7 @@ namespace FlaxEngine
/// Mesh data will be cached and uploaded to the GPU with a delay.
///
/// The mesh vertices positions. Cannot be null.
- /// The mesh index buffer (triangles). Uses 32-bit stride buffer. Cannot be null.
+ /// The mesh index buffer (clockwise triangles). Uses 32-bit stride buffer. Cannot be null.
/// The normal vectors (per vertex).
/// The normal vectors (per vertex). Use null to compute them from normal vectors.
/// The texture coordinates (per vertex).
@@ -210,7 +210,7 @@ namespace FlaxEngine
/// Mesh data will be cached and uploaded to the GPU with a delay.
///
/// The mesh vertices positions. Cannot be null.
- /// The mesh index buffer (triangles). Uses 16-bit stride buffer. Cannot be null.
+ /// The mesh index buffer (clockwise triangles). Uses 16-bit stride buffer. Cannot be null.
/// The normal vectors (per vertex).
/// The tangent vectors (per vertex). Use null to compute them from normal vectors.
/// The texture coordinates (per vertex).
@@ -257,7 +257,7 @@ namespace FlaxEngine
/// Mesh data will be cached and uploaded to the GPU with a delay.
///
/// The mesh vertices positions. Cannot be null.
- /// The mesh index buffer (triangles). Uses 16-bit stride buffer. Cannot be null.
+ /// The mesh index buffer (clockwise triangles). Uses 16-bit stride buffer. Cannot be null.
/// The normal vectors (per vertex).
/// The tangent vectors (per vertex). Use null to compute them from normal vectors.
/// The texture coordinates (per vertex).
@@ -435,7 +435,7 @@ namespace FlaxEngine
/// Downloads the third vertex buffer that contains mesh vertices data. To download data from GPU set to true and call this method from the thread other than main thread (see ).
///
///
- /// If mesh has no vertex colors (stored in vertex buffer 2) the the returned value is null.
+ /// If mesh has no vertex colors (stored in vertex buffer 2) the returned value is null.
///
/// If set to true the data will be downloaded from the GPU, otherwise it can be loaded from the drive (source asset file) or from memory (if cached). Downloading mesh from GPU requires this call to be made from the other thread than main thread. Virtual assets are always downloaded from GPU memory due to lack of dedicated storage container for the asset data.
/// The gathered data or null if mesh has no vertex colors.
diff --git a/Source/Engine/Graphics/Models/Mesh.cpp b/Source/Engine/Graphics/Models/Mesh.cpp
index 0ba51b2d7..444d60540 100644
--- a/Source/Engine/Graphics/Models/Mesh.cpp
+++ b/Source/Engine/Graphics/Models/Mesh.cpp
@@ -10,6 +10,127 @@
#include "Engine/Serialization/MemoryReadStream.h"
#include
+namespace
+{
+ template
+ bool UpdateMesh(Mesh* mesh, uint32 vertexCount, uint32 triangleCount, Vector3* vertices, IndexType* triangles, Vector3* normals, Vector3* tangents, Vector2* uvs, Color32* colors)
+ {
+ auto model = mesh->GetModel();
+ CHECK_RETURN(model && model->IsVirtual(), true);
+ CHECK_RETURN(triangles && vertices, true);
+
+ // Pack mesh data into vertex buffers
+ Array vb1;
+ Array vb2;
+ vb1.Resize(vertexCount);
+ if (normals)
+ {
+ if (tangents)
+ {
+ for (uint32 i = 0; i < vertexCount; i++)
+ {
+ const Vector3 normal = normals[i];
+ const Vector3 tangent = tangents[i];
+
+ // Calculate bitangent sign
+ Vector3 bitangent = Vector3::Normalize(Vector3::Cross(normal, tangent));
+ byte sign = static_cast(Vector3::Dot(Vector3::Cross(bitangent, normal), tangent) < 0.0f ? 1 : 0);
+
+ // Set tangent frame
+ vb1[i].Tangent = Float1010102(tangent * 0.5f + 0.5f, sign);
+ vb1[i].Normal = Float1010102(normal * 0.5f + 0.5f, 0);
+ }
+ }
+ else
+ {
+ for (uint32 i = 0; i < vertexCount; i++)
+ {
+ const Vector3 normal = normals[i];
+
+ // Calculate tangent
+ Vector3 c1 = Vector3::Cross(normal, Vector3::UnitZ);
+ Vector3 c2 = Vector3::Cross(normal, Vector3::UnitY);
+ Vector3 tangent;
+ if (c1.LengthSquared() > c2.LengthSquared())
+ tangent = c1;
+ else
+ tangent = c2;
+
+ // Calculate bitangent sign
+ Vector3 bitangent = Vector3::Normalize(Vector3::Cross(normal, tangent));
+ byte sign = static_cast(Vector3::Dot(Vector3::Cross(bitangent, normal), tangent) < 0.0f ? 1 : 0);
+
+ // Set tangent frame
+ vb1[i].Tangent = Float1010102(tangent * 0.5f + 0.5f, sign);
+ vb1[i].Normal = Float1010102(normal * 0.5f + 0.5f, 0);
+ }
+ }
+ }
+ else
+ {
+ // Set default tangent frame
+ const auto n = Float1010102(Vector3::UnitZ);
+ const auto t = Float1010102(Vector3::UnitX);
+ for (uint32 i = 0; i < vertexCount; i++)
+ {
+ vb1[i].Normal = n;
+ vb1[i].Tangent = t;
+ }
+ }
+ if (uvs)
+ {
+ for (uint32 i = 0; i < vertexCount; i++)
+ vb1[i].TexCoord = Half2(uvs[i]);
+ }
+ else
+ {
+ auto v = Half2(0, 0);
+ for (uint32 i = 0; i < vertexCount; i++)
+ vb1[i].TexCoord = v;
+ }
+ {
+ auto v = Half2(0, 0);
+ for (uint32 i = 0; i < vertexCount; i++)
+ vb1[i].LightmapUVs = v;
+ }
+ if (colors)
+ {
+ vb2.Resize(vertexCount);
+ for (uint32 i = 0; i < vertexCount; i++)
+ vb2[i].Color = colors[i];
+ }
+
+ return mesh->UpdateMesh(vertexCount, triangleCount, (VB0ElementType*)vertices, vb1.Get(), vb2.HasItems() ? vb2.Get() : nullptr, triangles);
+ }
+
+ template
+ bool UpdateMesh(Mesh* mesh, uint32 vertexCount, uint32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj)
+ {
+ ASSERT((uint32)mono_array_length(verticesObj) >= vertexCount);
+ ASSERT((uint32)mono_array_length(trianglesObj) / 3 >= triangleCount);
+ auto vertices = (Vector3*)(void*)mono_array_addr_with_size(verticesObj, sizeof(Vector3), 0);
+ auto triangles = (IndexType*)(void*)mono_array_addr_with_size(trianglesObj, sizeof(IndexType), 0);
+ const auto normals = normalsObj ? (Vector3*)(void*)mono_array_addr_with_size(normalsObj, sizeof(Vector3), 0) : nullptr;
+ const auto tangents = tangentsObj ? (Vector3*)(void*)mono_array_addr_with_size(tangentsObj, sizeof(Vector3), 0) : nullptr;
+ const auto uvs = uvObj ? (Vector2*)(void*)mono_array_addr_with_size(uvObj, sizeof(Vector2), 0) : nullptr;
+ const auto colors = colorsObj ? (Color32*)(void*)mono_array_addr_with_size(colorsObj, sizeof(Color32), 0) : nullptr;
+ return UpdateMesh(mesh, vertexCount, triangleCount, vertices, triangles, normals, tangents, uvs, colors);
+ }
+
+ template
+ bool UpdateTriangles(Mesh* mesh, int32 triangleCount, MonoArray* trianglesObj)
+ {
+ const auto model = mesh->GetModel();
+ ASSERT(model && model->IsVirtual() && trianglesObj);
+
+ // Get buffer data
+ ASSERT((int32)mono_array_length(trianglesObj) / 3 >= triangleCount);
+ auto ib = (IndexType*)(void*)mono_array_addr_with_size(trianglesObj, sizeof(IndexType), 0);
+
+ return mesh->UpdateTriangles(triangleCount, ib);
+ }
+}
+
bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, void* ib, bool use16BitIndices)
{
Unload();
@@ -31,6 +152,16 @@ bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType*
return failed;
}
+bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint16* triangles, Vector3* normals, Vector3* tangents, Vector2* uvs, Color32* colors)
+{
+ return ::UpdateMesh(this, vertexCount, triangleCount, vertices, triangles, normals, tangents, uvs, colors);
+}
+
+bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint32* triangles, Vector3* normals, Vector3* tangents, Vector2* uvs, Color32* colors)
+{
+ return ::UpdateMesh(this, vertexCount, triangleCount, vertices, triangles, normals, tangents, uvs, colors);
+}
+
bool Mesh::UpdateTriangles(uint32 triangleCount, void* ib, bool use16BitIndices)
{
// Cache data
@@ -384,108 +515,9 @@ ScriptingObject* Mesh::GetParentModel()
return _model;
}
-template
-bool UpdateMesh(Mesh* mesh, uint32 vertexCount, uint32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj)
-{
- auto model = mesh->GetModel();
- ASSERT(model && model->IsVirtual() && verticesObj && trianglesObj);
-
- // Get buffers data
- ASSERT((uint32)mono_array_length(verticesObj) >= vertexCount);
- ASSERT((uint32)mono_array_length(trianglesObj) / 3 >= triangleCount);
- auto vb0 = (Vector3*)(void*)mono_array_addr_with_size(verticesObj, sizeof(Vector3), 0);
- auto ib = (IndexType*)(void*)mono_array_addr_with_size(trianglesObj, sizeof(IndexType), 0);
- Array vb1;
- Array vb2;
- vb1.Resize(vertexCount);
- if (normalsObj)
- {
- const auto normals = (Vector3*)(void*)mono_array_addr_with_size(normalsObj, sizeof(Vector3), 0);
- if (tangentsObj)
- {
- const auto tangents = (Vector3*)(void*)mono_array_addr_with_size(tangentsObj, sizeof(Vector3), 0);
- for (uint32 i = 0; i < vertexCount; i++)
- {
- // Peek normal and tangent
- const Vector3 normal = normals[i];
- const Vector3 tangent = tangents[i];
-
- // Calculate bitangent sign
- Vector3 bitangent = Vector3::Normalize(Vector3::Cross(normal, tangent));
- byte sign = static_cast(Vector3::Dot(Vector3::Cross(bitangent, normal), tangent) < 0.0f ? 1 : 0);
-
- // Set tangent frame
- vb1[i].Tangent = Float1010102(tangent * 0.5f + 0.5f, sign);
- vb1[i].Normal = Float1010102(normal * 0.5f + 0.5f, 0);
- }
- }
- else
- {
- for (uint32 i = 0; i < vertexCount; i++)
- {
- // Peek normal
- const Vector3 normal = normals[i];
-
- // Calculate tangent
- Vector3 c1 = Vector3::Cross(normal, Vector3::UnitZ);
- Vector3 c2 = Vector3::Cross(normal, Vector3::UnitY);
- Vector3 tangent;
- if (c1.LengthSquared() > c2.LengthSquared())
- tangent = c1;
- else
- tangent = c2;
-
- // Calculate bitangent sign
- Vector3 bitangent = Vector3::Normalize(Vector3::Cross(normal, tangent));
- byte sign = static_cast(Vector3::Dot(Vector3::Cross(bitangent, normal), tangent) < 0.0f ? 1 : 0);
-
- // Set tangent frame
- vb1[i].Tangent = Float1010102(tangent * 0.5f + 0.5f, sign);
- vb1[i].Normal = Float1010102(normal * 0.5f + 0.5f, 0);
- }
- }
- }
- else
- {
- const auto n = Float1010102(Vector3::UnitZ);
- const auto t = Float1010102(Vector3::UnitX);
- for (uint32 i = 0; i < vertexCount; i++)
- {
- vb1[i].Normal = n;
- vb1[i].Tangent = t;
- }
- }
- if (uvObj)
- {
- const auto uvs = (Vector2*)(void*)mono_array_addr_with_size(uvObj, sizeof(Vector2), 0);
- for (uint32 i = 0; i < vertexCount; i++)
- vb1[i].TexCoord = Half2(uvs[i]);
- }
- else
- {
- auto v = Half2(0, 0);
- for (uint32 i = 0; i < vertexCount; i++)
- vb1[i].TexCoord = v;
- }
- {
- auto v = Half2(0, 0);
- for (uint32 i = 0; i < vertexCount; i++)
- vb1[i].LightmapUVs = v;
- }
- if (colorsObj)
- {
- vb2.Resize(vertexCount);
- const auto colors = (Color32*)(void*)mono_array_addr_with_size(colorsObj, sizeof(Color32), 0);
- for (uint32 i = 0; i < vertexCount; i++)
- vb2[i].Color = colors[i];
- }
-
- return mesh->UpdateMesh(vertexCount, triangleCount, (VB0ElementType*)vb0, vb1.Get(), vb2.HasItems() ? vb2.Get() : nullptr, ib);
-}
-
bool Mesh::UpdateMeshInt(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj)
{
- return ::UpdateMesh(this, (uint32)vertexCount, (uint32)triangleCount, verticesObj, trianglesObj, normalsObj, tangentsObj, uvObj, colorsObj);
+ return ::UpdateMesh(this, (uint32)vertexCount, (uint32)triangleCount, verticesObj, trianglesObj, normalsObj, tangentsObj, uvObj, colorsObj);
}
bool Mesh::UpdateMeshUShort(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj)
@@ -493,22 +525,9 @@ bool Mesh::UpdateMeshUShort(int32 vertexCount, int32 triangleCount, MonoArray* v
return ::UpdateMesh(this, (uint32)vertexCount, (uint32)triangleCount, verticesObj, trianglesObj, normalsObj, tangentsObj, uvObj, colorsObj);
}
-template
-bool UpdateTriangles(Mesh* mesh, int32 triangleCount, MonoArray* trianglesObj)
-{
- auto model = mesh->GetModel();
- ASSERT(model && model->IsVirtual() && trianglesObj);
-
- // Get buffer data
- ASSERT((int32)mono_array_length(trianglesObj) / 3 >= triangleCount);
- auto ib = (IndexType*)(void*)mono_array_addr_with_size(trianglesObj, sizeof(IndexType), 0);
-
- return mesh->UpdateTriangles(triangleCount, ib);
-}
-
bool Mesh::UpdateTrianglesInt(int32 triangleCount, MonoArray* trianglesObj)
{
- return ::UpdateTriangles(this, triangleCount, trianglesObj);
+ return ::UpdateTriangles(this, triangleCount, trianglesObj);
}
bool Mesh::UpdateTrianglesUShort(int32 triangleCount, MonoArray* trianglesObj)
diff --git a/Source/Engine/Graphics/Models/Mesh.h b/Source/Engine/Graphics/Models/Mesh.h
index c8311a1f3..80d566fa3 100644
--- a/Source/Engine/Graphics/Models/Mesh.h
+++ b/Source/Engine/Graphics/Models/Mesh.h
@@ -216,9 +216,9 @@ public:
/// The first vertex buffer data.
/// The second vertex buffer data.
/// The third vertex buffer data.
- /// The index buffer.
+ /// The index buffer in clockwise order.
/// True if failed, otherwise false.
- FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, int32* ib)
+ FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, uint32* ib)
{
return UpdateMesh(vertexCount, triangleCount, vb0, vb1, vb2, ib, false);
}
@@ -231,7 +231,7 @@ public:
/// The first vertex buffer data.
/// The second vertex buffer data.
/// The third vertex buffer data.
- /// The index buffer.
+ /// The index buffer in clockwise order.
/// True if failed, otherwise false.
FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, uint16* ib)
{
@@ -240,17 +240,51 @@ public:
///
/// Updates the model mesh (used by the virtual models created with Init rather than Load).
+ /// Can be used only for virtual assets (see and ).
+ /// Mesh data will be cached and uploaded to the GPU with a delay.
///
/// The amount of vertices in the vertex buffer.
/// The amount of triangles in the index buffer.
/// The first vertex buffer data.
/// The second vertex buffer data.
/// The third vertex buffer data.
- /// The index buffer.
+ /// The index buffer in clockwise order.
/// True if index buffer uses 16-bit index buffer, otherwise 32-bit.
/// True if failed, otherwise false.
bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, void* ib, bool use16BitIndices);
+ ///
+ /// Updates the model mesh (used by the virtual models created with Init rather than Load).
+ /// Can be used only for virtual assets (see and ).
+ /// Mesh data will be cached and uploaded to the GPU with a delay.
+ ///
+ /// The amount of vertices in the vertex buffer.
+ /// The amount of triangles in the index buffer.
+ /// The mesh vertices positions. Cannot be null.
+ /// The mesh index buffer (clockwise triangles). Uses 32-bit stride buffer. Cannot be null.
+ /// The normal vectors (per vertex).
+ /// The normal vectors (per vertex). Use null to compute them from normal vectors.
+ /// The texture coordinates (per vertex).
+ /// The vertex colors (per vertex).
+ /// True if failed, otherwise false.
+ bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint16* triangles, Vector3* normals = nullptr, Vector3* tangents = nullptr, Vector2* uvs = nullptr, Color32* colors = nullptr);
+
+ ///
+ /// Updates the model mesh (used by the virtual models created with Init rather than Load).
+ /// Can be used only for virtual assets (see and ).
+ /// Mesh data will be cached and uploaded to the GPU with a delay.
+ ///
+ /// The amount of vertices in the vertex buffer.
+ /// The amount of triangles in the index buffer.
+ /// The mesh vertices positions. Cannot be null.
+ /// The mesh index buffer (clockwise triangles). Uses 32-bit stride buffer. Cannot be null.
+ /// The normal vectors (per vertex).
+ /// The normal vectors (per vertex). Use null to compute them from normal vectors.
+ /// The texture coordinates (per vertex).
+ /// The vertex colors (per vertex).
+ /// True if failed, otherwise false.
+ bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint32* triangles, Vector3* normals = nullptr, Vector3* tangents = nullptr, Vector2* uvs = nullptr, Color32* colors = nullptr);
+
public:
///
@@ -259,7 +293,7 @@ public:
/// The amount of triangles in the index buffer.
/// The index buffer.
/// True if failed, otherwise false.
- FORCE_INLINE bool UpdateTriangles(uint32 triangleCount, int32* ib)
+ FORCE_INLINE bool UpdateTriangles(uint32 triangleCount, uint32* ib)
{
return UpdateTriangles(triangleCount, ib, false);
}
diff --git a/Source/Engine/Graphics/Models/ModelData.Tool.cpp b/Source/Engine/Graphics/Models/ModelData.Tool.cpp
index ee1b219dd..ee0fcb348 100644
--- a/Source/Engine/Graphics/Models/ModelData.Tool.cpp
+++ b/Source/Engine/Graphics/Models/ModelData.Tool.cpp
@@ -791,7 +791,7 @@ void MeshData::ImproveCacheLocality()
Allocator::Free(piCandidates);
const auto endTime = Platform::GetTimeSeconds();
- LOG(Info, "Cache relevant optimzie for {0} vertices and {1} indices. Average output ACMR is {2}. Time: {3}s", vertexCount, indexCount, (float)iCacheMisses / indexCount / 3, Utilities::RoundTo2DecimalPlaces(endTime - startTime));
+ LOG(Info, "Cache relevant optimize for {0} vertices and {1} indices. Average output ACMR is {2}. Time: {3}s", vertexCount, indexCount, (float)iCacheMisses / indexCount / 3, Utilities::RoundTo2DecimalPlaces(endTime - startTime));
}
float MeshData::CalculateTrianglesArea() const
diff --git a/Source/Engine/Graphics/Models/ModelData.h b/Source/Engine/Graphics/Models/ModelData.h
index 1e4b59d0a..a3bb47fcc 100644
--- a/Source/Engine/Graphics/Models/ModelData.h
+++ b/Source/Engine/Graphics/Models/ModelData.h
@@ -5,7 +5,7 @@
#include "Engine/Core/Common.h"
#include "Engine/Core/Math/BoundingSphere.h"
#include "Engine/Core/Math/BoundingBox.h"
-#include "Engine/Core/Math/VectorInt.h"
+#include "Engine/Core/Math/Int4.h"
#include "Engine/Serialization/Stream.h"
#include "Engine/Graphics/Enums.h"
#include "Types.h"
diff --git a/Source/Engine/Graphics/Models/SkinnedMesh.h b/Source/Engine/Graphics/Models/SkinnedMesh.h
index 2c168980b..bbdf38014 100644
--- a/Source/Engine/Graphics/Models/SkinnedMesh.h
+++ b/Source/Engine/Graphics/Models/SkinnedMesh.h
@@ -163,7 +163,7 @@ public:
/// The amount of vertices in the vertex buffer.
/// The amount of triangles in the index buffer.
/// The vertex buffer data.
- /// The index buffer.
+ /// The index buffer in clockwise order.
/// True if failed, otherwise false.
FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0SkinnedElementType* vb, int32* ib)
{
@@ -176,7 +176,7 @@ public:
/// The amount of vertices in the vertex buffer.
/// The amount of triangles in the index buffer.
/// The vertex buffer data.
- /// The index buffer.
+ /// The index buffer, clockwise order.
/// True if failed, otherwise false.
FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0SkinnedElementType* vb, uint16* ib)
{
@@ -189,7 +189,7 @@ public:
/// The amount of vertices in the vertex buffer.
/// The amount of triangles in the index buffer.
/// The vertex buffer data.
- /// The index buffer.
+ /// The index buffer in clockwise order.
/// True if index buffer uses 16-bit index buffer, otherwise 32-bit.
/// True if failed, otherwise false.
bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0SkinnedElementType* vb, void* ib, bool use16BitIndices);
diff --git a/Source/Engine/Graphics/Models/Types.h b/Source/Engine/Graphics/Models/Types.h
index 248988243..9a95b8815 100644
--- a/Source/Engine/Graphics/Models/Types.h
+++ b/Source/Engine/Graphics/Models/Types.h
@@ -9,7 +9,7 @@
#include "Engine/Core/Math/Vector4.h"
#include "Engine/Core/Math/Color.h"
#include "Engine/Core/Math/Color32.h"
-#include "Engine/Core/Math/VectorInt.h"
+#include "Engine/Core/Math/Int4.h"
class Model;
class SkinnedModel;
diff --git a/Source/Engine/Graphics/PostProcessSettings.h b/Source/Engine/Graphics/PostProcessSettings.h
index 4279cfc9b..400deb3c1 100644
--- a/Source/Engine/Graphics/PostProcessSettings.h
+++ b/Source/Engine/Graphics/PostProcessSettings.h
@@ -387,7 +387,7 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(ToneMappingSettings);
float WhiteTemperature = 6500.0f;
///
- /// Adjusts the white balance temperature tint for the scene by adjusting the cyan and magenta color ranges. Ideally, this setting should be used once you've adjusted the white balance temporature to get accurate colors. Under some light temperatures, the colors may appear to be more yellow or blue. This can be used to balance the resulting color to look more natural. The default value is `0`.
+ /// Adjusts the white balance temperature tint for the scene by adjusting the cyan and magenta color ranges. Ideally, this setting should be used once you've adjusted the white balance temperature to get accurate colors. Under some light temperatures, the colors may appear to be more yellow or blue. This can be used to balance the resulting color to look more natural. The default value is `0`.
///
API_FIELD(Attributes="DefaultValue(0.0f), Limit(-1, 1, 0.001f), EditorOrder(1), PostProcessSetting((int)ToneMappingSettingsOverride.WhiteTint)")
float WhiteTint = 0.0f;
diff --git a/Source/Engine/Graphics/RenderTargetPool.cpp b/Source/Engine/Graphics/RenderTargetPool.cpp
index 109ff8de9..a9db0283d 100644
--- a/Source/Engine/Graphics/RenderTargetPool.cpp
+++ b/Source/Engine/Graphics/RenderTargetPool.cpp
@@ -108,5 +108,5 @@ void RenderTargetPool::Release(GPUTexture* rt)
}
}
- LOG(Error, "Trying to release temporary render target which has not been registred in service!");
+ LOG(Error, "Trying to release temporary render target which has not been registered in service!");
}
diff --git a/Source/Engine/Graphics/RenderTask.cpp b/Source/Engine/Graphics/RenderTask.cpp
index e3e261c96..405e0fe45 100644
--- a/Source/Engine/Graphics/RenderTask.cpp
+++ b/Source/Engine/Graphics/RenderTask.cpp
@@ -260,6 +260,11 @@ void SceneRenderTask::OnCollectDrawCalls(RenderContext& renderContext)
CollectDrawCalls(renderContext);
}
+void SceneRenderTask::OnPreRender(GPUContext* context, RenderContext& renderContext)
+{
+ PreRender(context, renderContext);
+}
+
void SceneRenderTask::OnPostRender(GPUContext* context, RenderContext& renderContext)
{
PostRender(context, renderContext);
@@ -278,11 +283,10 @@ Viewport SceneRenderTask::GetViewport() const
GPUTextureView* SceneRenderTask::GetOutputView() const
{
- if (Output)
+ if (Output && Output->IsAllocated())
return Output->View();
if (SwapChain)
return SwapChain->GetBackBufferView();
- CRASH;
return nullptr;
}
diff --git a/Source/Engine/Graphics/RenderTask.h b/Source/Engine/Graphics/RenderTask.h
index b00d80a5f..265905e2a 100644
--- a/Source/Engine/Graphics/RenderTask.h
+++ b/Source/Engine/Graphics/RenderTask.h
@@ -313,6 +313,18 @@ public:
/// The rendering context.
virtual void OnCollectDrawCalls(RenderContext& renderContext);
+ ///
+ /// The action called after scene rendering. Can be used to perform custom pre-rendering or to modify the render view.
+ ///
+ API_EVENT() Delegate PreRender;
+
+ ///
+ /// Called before scene rendering. Can be used to perform custom pre-rendering or to modify the render view.
+ ///
+ /// The GPU commands context.
+ /// The rendering context.
+ virtual void OnPreRender(GPUContext* context, RenderContext& renderContext);
+
///
/// The action called after scene rendering. Can be used to render additional visual elements to the output.
///
diff --git a/Source/Engine/Graphics/Shaders/GPUShader.h b/Source/Engine/Graphics/Shaders/GPUShader.h
index 79b165396..76c8df546 100644
--- a/Source/Engine/Graphics/Shaders/GPUShader.h
+++ b/Source/Engine/Graphics/Shaders/GPUShader.h
@@ -97,7 +97,7 @@ public:
///
/// Gets the vertex shader.
///
- /// Thr shader program name.
+ /// The shader program name.
/// The shader permutation index.
/// The shader object.
API_FUNCTION() FORCE_INLINE GPUShaderProgramVS* GetVS(const StringAnsiView& name, int32 permutationIndex = 0) const
@@ -108,7 +108,7 @@ public:
///
/// Gets the hull shader.
///
- /// Thr shader program name.
+ /// The shader program name.
/// The shader permutation index.
/// The shader object.
API_FUNCTION() FORCE_INLINE GPUShaderProgramHS* GetHS(const StringAnsiView& name, int32 permutationIndex = 0) const
@@ -119,7 +119,7 @@ public:
///
/// Gets domain shader.
///
- /// Thr shader program name.
+ /// The shader program name.
/// The shader permutation index.
/// The shader object.
API_FUNCTION() FORCE_INLINE GPUShaderProgramDS* GetDS(const StringAnsiView& name, int32 permutationIndex = 0) const
@@ -130,7 +130,7 @@ public:
///
/// Gets the geometry shader.
///
- /// Thr shader program name.
+ /// The shader program name.
/// The shader permutation index.
/// The shader object.
API_FUNCTION() FORCE_INLINE GPUShaderProgramGS* GetGS(const StringAnsiView& name, int32 permutationIndex = 0) const
@@ -141,7 +141,7 @@ public:
///
/// Gets the pixel shader.
///
- /// Thr shader program name.
+ /// The shader program name.
/// The shader permutation index.
/// The shader object.
API_FUNCTION() FORCE_INLINE GPUShaderProgramPS* GetPS(const StringAnsiView& name, int32 permutationIndex = 0) const
@@ -152,7 +152,7 @@ public:
///
/// Gets the compute shader.
///
- /// Thr shader program name.
+ /// The shader program name.
/// The shader permutation index.
/// The shader object.
API_FUNCTION() FORCE_INLINE GPUShaderProgramCS* GetCS(const StringAnsiView& name, int32 permutationIndex = 0) const
@@ -176,7 +176,7 @@ public:
///
/// Determines whether the specified shader program is in the shader.
///
- /// Thr shader program name.
+ /// The shader program name.
/// The shader permutation index.
/// true if the shader is valid; otherwise, false.
FORCE_INLINE bool HasShader(const StringAnsiView& name, int32 permutationIndex = 0) const
diff --git a/Source/Engine/Graphics/SkinnedMesh.cs b/Source/Engine/Graphics/SkinnedMesh.cs
index e8e0d8353..ea4cf283e 100644
--- a/Source/Engine/Graphics/SkinnedMesh.cs
+++ b/Source/Engine/Graphics/SkinnedMesh.cs
@@ -104,7 +104,7 @@ namespace FlaxEngine
/// Mesh data will be cached and uploaded to the GPU with a delay.
///
/// The mesh vertices positions. Cannot be null.
- /// The mesh index buffer (triangles). Uses 32-bit stride buffer. Cannot be null.
+ /// The mesh index buffer (clockwise triangles). Uses 32-bit stride buffer. Cannot be null.
/// The skinned mesh blend indices buffer. Contains indices of the skeleton bones (up to 4 bones per vertex) to use for vertex position blending. Cannot be null.
/// The skinned mesh blend weights buffer (normalized). Contains weights per blend bone (up to 4 bones per vertex) of the skeleton bones to mix for vertex position blending. Cannot be null.
/// The normal vectors (per vertex).
@@ -140,7 +140,7 @@ namespace FlaxEngine
/// Mesh data will be cached and uploaded to the GPU with a delay.
///
/// The mesh vertices positions. Cannot be null.
- /// The mesh index buffer (triangles). Uses 16-bit stride buffer. Cannot be null.
+ /// The mesh index buffer (clockwise triangles). Uses 16-bit stride buffer. Cannot be null.
/// The skinned mesh blend indices buffer. Contains indices of the skeleton bones (up to 4 bones per vertex) to use for vertex position blending. Cannot be null.
/// The skinned mesh blend weights buffer (normalized). Contains weights per blend bone (up to 4 bones per vertex) of the skeleton bones to mix for vertex position blending. Cannot be null.
/// The normal vectors (per vertex).
diff --git a/Source/Engine/Graphics/Textures/GPUTexture.cpp b/Source/Engine/Graphics/Textures/GPUTexture.cpp
index e51d2e510..29268e721 100644
--- a/Source/Engine/Graphics/Textures/GPUTexture.cpp
+++ b/Source/Engine/Graphics/Textures/GPUTexture.cpp
@@ -458,43 +458,13 @@ protected:
// [ThreadPoolTask]
bool Run() override
{
- // Check resources
auto texture = _texture.Get();
if (texture == nullptr || _staging == nullptr || _data == nullptr)
{
LOG(Warning, "Cannot download texture data. Missing objects.");
return true;
}
-
- const auto arraySize = texture->ArraySize();
- const auto mipLevels = texture->MipLevels();
-
- // Get all mip maps for each array slice
- auto& rawResultData = _data->Items;
- rawResultData.Resize(arraySize, false);
- for (int32 arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
- {
- auto& arraySlice = rawResultData[arrayIndex];
- arraySlice.Mips.Resize(mipLevels);
-
- for (int32 mipMapIndex = 0; mipMapIndex < mipLevels; mipMapIndex++)
- {
- auto& mip = arraySlice.Mips[mipMapIndex];
- const int32 mipWidth = _data->Width >> mipMapIndex;
- const int32 mipHeight = _data->Height >> mipMapIndex;
- uint32 mipRowPitch, mipSlicePitch;
- RenderTools::ComputePitch(_data->Format, mipWidth, mipHeight, mipRowPitch, mipSlicePitch);
-
- // Gather data
- if (_staging->GetData(arrayIndex, mipMapIndex, mip, mipRowPitch))
- {
- LOG(Warning, "Staging resource of \'{0}\' get data failed.", texture->ToString());
- return true;
- }
- }
- }
-
- return false;
+ return _staging->DownloadData(*_data);
}
void OnEnd() override
@@ -508,6 +478,57 @@ protected:
bool GPUTexture::DownloadData(TextureData& result)
{
+ // Skip for empty ones
+ if (MipLevels() == 0)
+ {
+ LOG(Warning, "Cannot download GPU texture data from an empty texture.");
+ return true;
+ }
+ if (Depth() != 1)
+ {
+ MISSING_CODE("support volume texture data downloading.");
+ }
+
+ // Use faster path for staging resources
+ if (IsStaging())
+ {
+ const auto arraySize = ArraySize();
+ const auto mipLevels = MipLevels();
+
+ // Set texture info
+ result.Width = Width();
+ result.Height = Height();
+ result.Depth = Depth();
+ result.Format = Format();
+
+ // Get all mip maps for each array slice
+ auto& rawResultData = result.Items;
+ rawResultData.Resize(arraySize, false);
+ for (int32 arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
+ {
+ auto& arraySlice = rawResultData[arrayIndex];
+ arraySlice.Mips.Resize(mipLevels);
+
+ for (int32 mipMapIndex = 0; mipMapIndex < mipLevels; mipMapIndex++)
+ {
+ auto& mip = arraySlice.Mips[mipMapIndex];
+ const int32 mipWidth = result.Width >> mipMapIndex;
+ const int32 mipHeight = result.Height >> mipMapIndex;
+ uint32 mipRowPitch, mipSlicePitch;
+ RenderTools::ComputePitch(result.Format, mipWidth, mipHeight, mipRowPitch, mipSlicePitch);
+
+ // Gather data
+ if (GetData(arrayIndex, mipMapIndex, mip, mipRowPitch))
+ {
+ LOG(Warning, "Staging resource of \'{0}\' get data failed.", ToString());
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
const auto name = ToString();
// Ensure not running on main thread - we support DownloadData from textures only on a worker threads (Thread Pool Workers or Content Loaders)
@@ -538,7 +559,8 @@ bool GPUTexture::DownloadData(TextureData& result)
Task* GPUTexture::DownloadDataAsync(TextureData& result)
{
- if (!IsAllocated())
+ // Skip for empty ones
+ if (MipLevels() == 0)
{
LOG(Warning, "Cannot download texture data. It has not ben created yet.");
return nullptr;
@@ -548,19 +570,12 @@ Task* GPUTexture::DownloadDataAsync(TextureData& result)
MISSING_CODE("support volume texture data downloading.");
}
- // Set texture info
- result.Width = Width();
- result.Height = Height();
- result.Depth = Depth();
- result.Format = Format();
-
- // Quicker path if texture is already readback
- if (_desc.Usage == GPUResourceUsage::StagingReadback)
+ // Use faster path for staging resources
+ if (IsStaging())
{
// Create task to copy downloaded data to TextureData container
auto getDataTask = ::New(this, this, result);
ASSERT(getDataTask->HasReference(this));
-
return getDataTask;
}
diff --git a/Source/Engine/Graphics/Textures/GPUTexture.h b/Source/Engine/Graphics/Textures/GPUTexture.h
index d0ae27e7f..8b5385f9e 100644
--- a/Source/Engine/Graphics/Textures/GPUTexture.h
+++ b/Source/Engine/Graphics/Textures/GPUTexture.h
@@ -483,7 +483,7 @@ public:
///
/// Creates new staging readback texture with the same dimensions and properties as a source texture (but without a data transferred; warning: caller must delete object).
///
- /// Thr staging readback texture.
+ /// The staging readback texture.
GPUTexture* ToStagingReadback() const;
///
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUTimerQueryDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUTimerQueryDX11.cpp
index 63cd9bcb4..5df4a45a5 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUTimerQueryDX11.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUTimerQueryDX11.cpp
@@ -118,7 +118,7 @@ float GPUTimerQueryDX11::GetResult()
if (!SingleShotLog)
{
SingleShotLog = true;
- LOG(Warning, "Unrealiable GPU timer query detected.");
+ LOG(Warning, "Unreliable GPU timer query detected.");
}
#endif
}
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp
index ce36a7347..4d1bd3e17 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp
@@ -216,7 +216,7 @@ uint64 GPUContextDX12::Execute(bool waitForCompletion)
ASSERT(_currentAllocator != nullptr);
auto queue = _device->GetCommandQueue();
- // Flush reaming and buffered commands
+ // Flush remaining and buffered commands
FlushState();
_currentState = nullptr;
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
index 29d417834..096a0ec11 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
@@ -391,7 +391,7 @@ bool GPUDeviceDX12::Init()
{
// Descriptor tables
D3D12_DESCRIPTOR_RANGE r[2];
- // TODO: separate ranges for pixel/vertex visiblity and one shared for all?
+ // TODO: separate ranges for pixel/vertex visibility and one shared for all?
{
D3D12_DESCRIPTOR_RANGE& range = r[0];
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
diff --git a/Source/Engine/GraphicsDevice/DirectX/IncludeDirectXHeaders.h b/Source/Engine/GraphicsDevice/DirectX/IncludeDirectXHeaders.h
index 8351deb71..ea621c22a 100644
--- a/Source/Engine/GraphicsDevice/DirectX/IncludeDirectXHeaders.h
+++ b/Source/Engine/GraphicsDevice/DirectX/IncludeDirectXHeaders.h
@@ -8,7 +8,7 @@
#include "Engine/Platform/Win32/IncludeWindowsHeaders.h"
#include "Engine/Platform/Windows/ComPtr.h"
-// Helper define to dispose the COM object with reaming references counter checking
+// Helper define to dispose the COM object with remaining references counter checking
#define DX_SAFE_RELEASE_CHECK(x, refs) if(x) { auto res = (x)->Release(); (x) = nullptr; CHECK(res == refs); }
#endif
diff --git a/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.cpp
index c327fd32a..f9a39574c 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/CmdBufferVulkan.cpp
@@ -44,7 +44,7 @@ void CmdBufferVulkan::End()
ASSERT(IsOutsideRenderPass());
#if GPU_ALLOW_PROFILE_EVENTS
- // End reaming events
+ // End remaining events
while (_eventsBegin--)
vkCmdEndDebugUtilsLabelEXT(GetHandle());
#endif
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp
index ea8fa6502..e8f770831 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp
@@ -1155,7 +1155,7 @@ void GPUContextVulkan::FlushState()
void GPUContextVulkan::Flush()
{
- // Flush reaming and buffered commands
+ // Flush remaining and buffered commands
FlushState();
_currentState = nullptr;
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
index 33df0db47..ea9e6a990 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
@@ -1363,23 +1363,7 @@ PixelFormat GPUDeviceVulkan::GetClosestSupportedPixelFormat(PixelFormat format,
if (flags & GPUTextureFlags::UnorderedAccess)
wantedFeatureFlags |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
- // Check actual device for format support
- const auto isSupported = [&](VkFormat vkFormat)
- {
- VkFormatProperties props;
- vkGetPhysicalDeviceFormatProperties(Adapter->Gpu, vkFormat, &props);
- const VkFormatFeatureFlags featureFlags = optimalTiling ? props.optimalTilingFeatures : props.linearTilingFeatures;
- if ((featureFlags & wantedFeatureFlags) != wantedFeatureFlags)
- return false;
-
- //VkImageFormatProperties imageProps;
- //vkGetPhysicalDeviceImageFormatProperties(Adapter->Gpu, vkFormat, , &imageProps);
-
- return true;
- };
-
- VkFormat vkFormat = RenderToolsVulkan::ToVulkanFormat(format);
- if (!isSupported(vkFormat))
+ if (!IsVkFormatSupported(RenderToolsVulkan::ToVulkanFormat(format), wantedFeatureFlags, optimalTiling))
{
// Special case for depth-stencil formats
if (flags & GPUTextureFlags::DepthStencil)
@@ -1389,7 +1373,7 @@ PixelFormat GPUDeviceVulkan::GetClosestSupportedPixelFormat(PixelFormat format,
// Spec guarantees at least one depth-only, and one depth-stencil format to be supported
if (hasStencil)
{
- if (isSupported(VK_FORMAT_D32_SFLOAT_S8_UINT))
+ if (IsVkFormatSupported(VK_FORMAT_D32_SFLOAT_S8_UINT, wantedFeatureFlags, optimalTiling))
format = PixelFormat::D32_Float;
else
format = PixelFormat::D24_UNorm_S8_UInt;
@@ -1493,6 +1477,20 @@ bool GPUDeviceVulkan::SaveValidationCache()
#endif
+bool GPUDeviceVulkan::IsVkFormatSupported(VkFormat vkFormat, VkFormatFeatureFlags wantedFeatureFlags, bool optimalTiling) const
+{
+ VkFormatProperties props;
+ vkGetPhysicalDeviceFormatProperties(Adapter->Gpu, vkFormat, &props);
+ const VkFormatFeatureFlags featureFlags = optimalTiling ? props.optimalTilingFeatures : props.linearTilingFeatures;
+ if ((featureFlags & wantedFeatureFlags) != wantedFeatureFlags)
+ return false;
+
+ //VkImageFormatProperties imageProps;
+ //vkGetPhysicalDeviceImageFormatProperties(Adapter->Gpu, vkFormat, , &imageProps);
+
+ return true;
+}
+
GPUContext* GPUDeviceVulkan::GetMainContext()
{
return reinterpret_cast(MainContext);
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h
index 9bab15dda..ba972932b 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h
@@ -720,6 +720,10 @@ public:
#endif
+private:
+
+ bool IsVkFormatSupported(VkFormat vkFormat, VkFormatFeatureFlags wantedFeatureFlags, bool optimalTiling) const;
+
public:
// [GPUDevice]
diff --git a/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.h
index b18ae9c1b..cf9b7e9cf 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.h
+++ b/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.h
@@ -232,10 +232,10 @@ public:
}
///
- /// Converts Flax comparision function to the Vulkan comparision operation.
+ /// Converts Flax comparison function to the Vulkan comparison operation.
///
- /// The Flax comparision function.
- /// The Vulkan comparision operation.
+ /// The Flax comparison function.
+ /// The Vulkan comparison operation.
static FORCE_INLINE VkCompareOp ToVulkanCompareOp(const ComparisonFunc value)
{
return ComparisonFuncToVkCompareOp[(int32)value];
diff --git a/Source/Engine/Input/Enums.h b/Source/Engine/Input/Enums.h
index 764a17922..e397dd3c2 100644
--- a/Source/Engine/Input/Enums.h
+++ b/Source/Engine/Input/Enums.h
@@ -8,7 +8,7 @@
#define MAX_GAMEPADS 8
///
-/// Hardware mouse cursor behaviour.
+/// Hardware mouse cursor behavior.
///
API_ENUM() enum class CursorLockMode
{
diff --git a/Source/Engine/Input/Input.cpp b/Source/Engine/Input/Input.cpp
index 1dfa0e5fe..825e7f6b2 100644
--- a/Source/Engine/Input/Input.cpp
+++ b/Source/Engine/Input/Input.cpp
@@ -98,6 +98,202 @@ Delegate Input::ActionTriggered;
Array Input::ActionMappings;
Array Input::AxisMappings;
+void Mouse::OnMouseMoved(const Vector2& newPosition)
+{
+ _prevState.MousePosition = newPosition;
+ _state.MousePosition = newPosition;
+}
+
+void Mouse::OnMouseDown(const Vector2& position, const MouseButton button, Window* target)
+{
+ Event& e = _queue.AddOne();
+ e.Type = EventType::MouseDown;
+ e.Target = target;
+ e.MouseData.Button = button;
+ e.MouseData.Position = position;
+}
+
+void Mouse::OnMouseUp(const Vector2& position, const MouseButton button, Window* target)
+{
+ Event& e = _queue.AddOne();
+ e.Type = EventType::MouseUp;
+ e.Target = target;
+ e.MouseData.Button = button;
+ e.MouseData.Position = position;
+}
+
+void Mouse::OnMouseDoubleClick(const Vector2& position, const MouseButton button, Window* target)
+{
+ Event& e = _queue.AddOne();
+ e.Type = EventType::MouseDoubleClick;
+ e.Target = target;
+ e.MouseData.Button = button;
+ e.MouseData.Position = position;
+}
+
+void Mouse::OnMouseMove(const Vector2& position, Window* target)
+{
+ Event& e = _queue.AddOne();
+ e.Type = EventType::MouseMove;
+ e.Target = target;
+ e.MouseData.Position = position;
+}
+
+void Mouse::OnMouseLeave(Window* target)
+{
+ Event& e = _queue.AddOne();
+ e.Type = EventType::MouseLeave;
+ e.Target = target;
+}
+
+void Mouse::OnMouseWheel(const Vector2& position, float delta, Window* target)
+{
+ Event& e = _queue.AddOne();
+ e.Type = EventType::MouseWheel;
+ e.Target = target;
+ e.MouseWheelData.WheelDelta = delta;
+ e.MouseWheelData.Position = position;
+}
+
+void Mouse::ResetState()
+{
+ InputDevice::ResetState();
+
+ _prevState.Clear();
+ _state.Clear();
+}
+
+bool Mouse::Update(EventQueue& queue)
+{
+ // Move the current state to the previous
+ Platform::MemoryCopy(&_prevState, &_state, sizeof(State));
+
+ // Gather new events
+ if (UpdateState())
+ return true;
+
+ // Handle events
+ _state.MouseWheelDelta = 0;
+ for (int32 i = 0; i < _queue.Count(); i++)
+ {
+ const Event& e = _queue[i];
+ switch (e.Type)
+ {
+ case EventType::MouseDown:
+ {
+ _state.MouseButtons[static_cast(e.MouseData.Button)] = true;
+ break;
+ }
+ case EventType::MouseUp:
+ {
+ _state.MouseButtons[static_cast(e.MouseData.Button)] = false;
+ break;
+ }
+ case EventType::MouseDoubleClick:
+ {
+ _state.MouseButtons[static_cast(e.MouseData.Button)] = true;
+ break;
+ }
+ case EventType::MouseWheel:
+ {
+ _state.MouseWheelDelta += e.MouseWheelData.WheelDelta;
+ break;
+ }
+ case EventType::MouseMove:
+ {
+ _state.MousePosition = e.MouseData.Position;
+ break;
+ }
+ case EventType::MouseLeave:
+ {
+ break;
+ }
+ }
+ }
+
+ // Send events further
+ queue.Add(_queue);
+ _queue.Clear();
+ return false;
+}
+
+void Keyboard::OnCharInput(Char c, Window* target)
+{
+ // Skip control characters
+ if (c < 32)
+ return;
+
+ Event& e = _queue.AddOne();
+ e.Type = EventType::Char;
+ e.Target = target;
+ e.CharData.Char = c;
+}
+
+void Keyboard::OnKeyUp(KeyboardKeys key, Window* target)
+{
+ Event& e = _queue.AddOne();
+ e.Type = EventType::KeyUp;
+ e.Target = target;
+ e.KeyData.Key = key;
+}
+
+void Keyboard::OnKeyDown(KeyboardKeys key, Window* target)
+{
+ Event& e = _queue.AddOne();
+ e.Type = EventType::KeyDown;
+ e.Target = target;
+ e.KeyData.Key = key;
+}
+
+void Keyboard::ResetState()
+{
+ InputDevice::ResetState();
+
+ _prevState.Clear();
+ _state.Clear();
+}
+
+bool Keyboard::Update(EventQueue& queue)
+{
+ // Move the current state to the previous
+ Platform::MemoryCopy(&_prevState, &_state, sizeof(State));
+
+ // Gather new events
+ if (UpdateState())
+ return true;
+
+ // Handle events
+ _state.InputTextLength = 0;
+ for (int32 i = 0; i < _queue.Count(); i++)
+ {
+ const Event& e = _queue[i];
+ switch (e.Type)
+ {
+ case EventType::Char:
+ {
+ if (_state.InputTextLength < ARRAY_COUNT(_state.InputText) - 1)
+ _state.InputText[_state.InputTextLength++] = e.CharData.Char;
+ break;
+ }
+ case EventType::KeyDown:
+ {
+ _state.Keys[static_cast(e.KeyData.Key)] = true;
+ break;
+ }
+ case EventType::KeyUp:
+ {
+ _state.Keys[static_cast(e.KeyData.Key)] = false;
+ break;
+ }
+ }
+ }
+
+ // Send events further
+ queue.Add(_queue);
+ _queue.Clear();
+ return false;
+}
+
int32 Input::GetGamepadsCount()
{
return Gamepads.Count();
diff --git a/Source/Engine/Input/Keyboard.h b/Source/Engine/Input/Keyboard.h
index ae958bd86..f182f9731 100644
--- a/Source/Engine/Input/Keyboard.h
+++ b/Source/Engine/Input/Keyboard.h
@@ -13,7 +13,7 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(Keyboard);
public:
///
- /// The mouse state.
+ /// The keyboard state.
///
struct State
{
@@ -94,97 +94,32 @@ public:
return !_state.Keys[static_cast(key)] && _prevState.Keys[static_cast(key)];
}
+public:
+
///
/// Called when keyboard enters input character.
///
/// The Unicode character entered by the user.
/// The target window to receive this event, otherwise input system will pick the window automatically.
- void OnCharInput(const Char c, Window* target = nullptr)
- {
- // Skip control characters
- if (c < 32)
- return;
-
- Event& e = _queue.AddOne();
- e.Type = EventType::Char;
- e.Target = target;
- e.CharData.Char = c;
- }
+ void OnCharInput(Char c, Window* target = nullptr);
///
/// Called when key goes up.
///
/// The keyboard key.
/// The target window to receive this event, otherwise input system will pick the window automatically.
- void OnKeyUp(const KeyboardKeys key, Window* target = nullptr)
- {
- Event& e = _queue.AddOne();
- e.Type = EventType::KeyUp;
- e.Target = target;
- e.KeyData.Key = key;
- }
+ void OnKeyUp(KeyboardKeys key, Window* target = nullptr);
///
/// Called when key goes down.
///
/// The keyboard key.
/// The target window to receive this event, otherwise input system will pick the window automatically.
- void OnKeyDown(const KeyboardKeys key, Window* target = nullptr)
- {
- Event& e = _queue.AddOne();
- e.Type = EventType::KeyDown;
- e.Target = target;
- e.KeyData.Key = key;
- }
+ void OnKeyDown(KeyboardKeys key, Window* target = nullptr);
public:
// [InputDevice]
- void ResetState() override
- {
- InputDevice::ResetState();
-
- _prevState.Clear();
- _state.Clear();
- }
-
- bool Update(EventQueue& queue) final override
- {
- // Move the current state to the previous
- Platform::MemoryCopy(&_prevState, &_state, sizeof(State));
-
- // Gather new events
- if (UpdateState())
- return true;
-
- // Handle events
- for (int32 i = 0; i < _queue.Count(); i++)
- {
- const Event& e = _queue[i];
- switch (e.Type)
- {
- case EventType::Char:
- {
- if (_state.InputTextLength < ARRAY_COUNT(_state.InputText) - 1)
- _state.InputText[_state.InputTextLength++] = e.CharData.Char;
- break;
- }
- case EventType::KeyDown:
- {
- _state.Keys[static_cast(e.KeyData.Key)] = true;
- break;
- }
- case EventType::KeyUp:
- {
- _state.Keys[static_cast(e.KeyData.Key)] = false;
- break;
- }
- }
- }
-
- // Send events further
- queue.Add(_queue);
- _queue.Clear();
- return false;
- }
+ void ResetState() override;;
+ bool Update(EventQueue& queue) final override;
};
diff --git a/Source/Engine/Input/Mouse.h b/Source/Engine/Input/Mouse.h
index 15fa17e6d..d58350956 100644
--- a/Source/Engine/Input/Mouse.h
+++ b/Source/Engine/Input/Mouse.h
@@ -124,14 +124,10 @@ public:
virtual void SetMousePosition(const Vector2& newPosition) = 0;
///
- /// Called when mouse cursor gets moved by the application. Invalidates the previous cached mouse position to prevent mouse jitter when locking the cursor programatically.
+ /// Called when mouse cursor gets moved by the application. Invalidates the previous cached mouse position to prevent mouse jitter when locking the cursor programmatically.
///
/// The new mouse position.
- void OnMouseMoved(const Vector2& newPosition)
- {
- _prevState.MousePosition = newPosition;
- _state.MousePosition = newPosition;
- }
+ void OnMouseMoved(const Vector2& newPosition);
///
/// Called when mouse button goes down.
@@ -139,14 +135,7 @@ public:
/// The mouse position.
/// The button.
/// The target window to receive this event, otherwise input system will pick the window automatically.
- void OnMouseDown(const Vector2& position, const MouseButton button, Window* target = nullptr)
- {
- Event& e = _queue.AddOne();
- e.Type = EventType::MouseDown;
- e.Target = target;
- e.MouseData.Button = button;
- e.MouseData.Position = position;
- }
+ void OnMouseDown(const Vector2& position, const MouseButton button, Window* target = nullptr);
///
/// Called when mouse button goes up.
@@ -154,14 +143,7 @@ public:
/// The mouse position.
/// The button.
/// The target window to receive this event, otherwise input system will pick the window automatically.
- void OnMouseUp(const Vector2& position, const MouseButton button, Window* target = nullptr)
- {
- Event& e = _queue.AddOne();
- e.Type = EventType::MouseUp;
- e.Target = target;
- e.MouseData.Button = button;
- e.MouseData.Position = position;
- }
+ void OnMouseUp(const Vector2& position, const MouseButton button, Window* target = nullptr);
///
/// Called when mouse double clicks.
@@ -169,38 +151,20 @@ public:
/// The mouse position.
/// The button.
/// The target window to receive this event, otherwise input system will pick the window automatically.
- void OnMouseDoubleClick(const Vector2& position, const MouseButton button, Window* target = nullptr)
- {
- Event& e = _queue.AddOne();
- e.Type = EventType::MouseDoubleClick;
- e.Target = target;
- e.MouseData.Button = button;
- e.MouseData.Position = position;
- }
+ void OnMouseDoubleClick(const Vector2& position, const MouseButton button, Window* target = nullptr);
///
/// Called when mouse moves.
///
/// The mouse position.
/// The target window to receive this event, otherwise input system will pick the window automatically.
- void OnMouseMove(const Vector2& position, Window* target = nullptr)
- {
- Event& e = _queue.AddOne();
- e.Type = EventType::MouseMove;
- e.Target = target;
- e.MouseData.Position = position;
- }
+ void OnMouseMove(const Vector2& position, Window* target = nullptr);
///
/// Called when mouse leaves the input source area.
///
/// The target window to receive this event, otherwise input system will pick the window automatically.
- void OnMouseLeave(Window* target = nullptr)
- {
- Event& e = _queue.AddOne();
- e.Type = EventType::MouseLeave;
- e.Target = target;
- }
+ void OnMouseLeave(Window* target = nullptr);
///
/// Called when mouse wheel moves.
@@ -208,76 +172,11 @@ public:
/// The mouse position.
/// The normalized delta (range [-1;1]).
/// The target window to receive this event, otherwise input system will pick the window automatically.
- void OnMouseWheel(const Vector2& position, const float delta, Window* target = nullptr)
- {
- Event& e = _queue.AddOne();
- e.Type = EventType::MouseWheel;
- e.Target = target;
- e.MouseWheelData.WheelDelta = delta;
- e.MouseWheelData.Position = position;
- }
+ void OnMouseWheel(const Vector2& position, float delta, Window* target = nullptr);
public:
// [InputDevice]
- void ResetState() override
- {
- InputDevice::ResetState();
-
- _prevState.Clear();
- _state.Clear();
- }
-
- bool Update(EventQueue& queue) final override
- {
- // Move the current state to the previous
- Platform::MemoryCopy(&_prevState, &_state, sizeof(State));
-
- // Gather new events
- if (UpdateState())
- return true;
-
- // Handle events
- _state.MouseWheelDelta = 0;
- for (int32 i = 0; i < _queue.Count(); i++)
- {
- const Event& e = _queue[i];
- switch (e.Type)
- {
- case EventType::MouseDown:
- {
- _state.MouseButtons[static_cast(e.MouseData.Button)] = true;
- break;
- }
- case EventType::MouseUp:
- {
- _state.MouseButtons[static_cast(e.MouseData.Button)] = false;
- break;
- }
- case EventType::MouseDoubleClick:
- {
- break;
- }
- case EventType::MouseWheel:
- {
- _state.MouseWheelDelta += e.MouseWheelData.WheelDelta;
- break;
- }
- case EventType::MouseMove:
- {
- _state.MousePosition = e.MouseData.Position;
- break;
- }
- case EventType::MouseLeave:
- {
- break;
- }
- }
- }
-
- // Send events further
- queue.Add(_queue);
- _queue.Clear();
- return false;
- }
+ void ResetState() override;
+ bool Update(EventQueue& queue) final override;
};
diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp
index 81a5b3155..f558f25a0 100644
--- a/Source/Engine/Level/Actor.cpp
+++ b/Source/Engine/Level/Actor.cpp
@@ -43,6 +43,8 @@ Actor::Actor(const SpawnParams& params)
, _staticFlags(StaticFlags::FullyStatic)
, _localTransform(Transform::Identity)
, _transform(Transform::Identity)
+ , _sphere(BoundingSphere::Empty)
+ , _box(BoundingBox::Zero)
, HideFlags(HideFlags::None)
{
}
diff --git a/Source/Engine/Level/Actor.h b/Source/Engine/Level/Actor.h
index 334021c28..7621e4a2a 100644
--- a/Source/Engine/Level/Actor.h
+++ b/Source/Engine/Level/Actor.h
@@ -437,13 +437,13 @@ public:
}
///
- /// Sets actor orientation in 3D space
+ /// Sets actor orientation in 3D space.
///
/// The value to set.
API_PROPERTY() void SetOrientation(const Quaternion& value);
///
- /// Gets actor scale in 3D space
+ /// Gets actor scale in 3D space.
///
API_PROPERTY(Attributes="HideInEditor, NoSerialize")
FORCE_INLINE Vector3 GetScale() const
@@ -458,13 +458,13 @@ public:
API_PROPERTY() void SetScale(const Vector3& value);
///
- /// Gets actor rotation matrix
+ /// Gets actor rotation matrix.
///
API_PROPERTY(Attributes="HideInEditor, NoSerialize")
Matrix GetRotation() const;
///
- /// Sets actor rotation matrix
+ /// Sets actor rotation matrix.
///
/// The value to set.
API_PROPERTY() void SetRotation(const Matrix& value);
diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp
index cf3e71f13..3d6450716 100644
--- a/Source/Engine/Level/Actors/AnimatedModel.cpp
+++ b/Source/Engine/Level/Actors/AnimatedModel.cpp
@@ -146,8 +146,32 @@ void AnimatedModel::GetNodeTransformation(const StringView& nodeName, Matrix& no
GetNodeTransformation(SkinnedModel ? SkinnedModel->FindNode(nodeName) : -1, nodeTransformation, worldSpace);
}
+#define CHECK_ANIM_GRAPH_PARAM_ACCESS() \
+ if (!AnimationGraph) \
+ { \
+ LOG(Warning, "Missing animation graph for animated model '{0}'", ToString()); \
+ return; \
+ } \
+ if (AnimationGraph->WaitForLoaded()) \
+ { \
+ LOG(Warning, "Failed to load animation graph for animated model '{0}'", ToString()); \
+ return; \
+ }
+#define CHECK_ANIM_GRAPH_PARAM_ACCESS_RESULT(result) \
+ if (!AnimationGraph) \
+ { \
+ LOG(Warning, "Missing animation graph for animated model '{0}'", ToString()); \
+ return result; \
+ } \
+ if (AnimationGraph->WaitForLoaded()) \
+ { \
+ LOG(Warning, "Failed to load animation graph for animated model '{0}'", ToString()); \
+ return result; \
+ }
+
AnimGraphParameter* AnimatedModel::GetParameter(const StringView& name)
{
+ CHECK_ANIM_GRAPH_PARAM_ACCESS_RESULT(nullptr);
for (auto& param : GraphInstance.Parameters)
{
if (param.Name == name)
@@ -159,6 +183,7 @@ AnimGraphParameter* AnimatedModel::GetParameter(const StringView& name)
Variant AnimatedModel::GetParameterValue(const StringView& name)
{
+ CHECK_ANIM_GRAPH_PARAM_ACCESS_RESULT(Variant::Null);
for (auto& param : GraphInstance.Parameters)
{
if (param.Name == name)
@@ -170,6 +195,7 @@ Variant AnimatedModel::GetParameterValue(const StringView& name)
void AnimatedModel::SetParameterValue(const StringView& name, const Variant& value)
{
+ CHECK_ANIM_GRAPH_PARAM_ACCESS();
for (auto& param : GraphInstance.Parameters)
{
if (param.Name == name)
@@ -183,6 +209,7 @@ void AnimatedModel::SetParameterValue(const StringView& name, const Variant& val
Variant AnimatedModel::GetParameterValue(const Guid& id)
{
+ CHECK_ANIM_GRAPH_PARAM_ACCESS_RESULT(Variant::Null);
for (auto& param : GraphInstance.Parameters)
{
if (param.Identifier == id)
@@ -194,6 +221,7 @@ Variant AnimatedModel::GetParameterValue(const Guid& id)
void AnimatedModel::SetParameterValue(const Guid& id, const Variant& value)
{
+ CHECK_ANIM_GRAPH_PARAM_ACCESS();
for (auto& param : GraphInstance.Parameters)
{
if (param.Identifier == id)
diff --git a/Source/Engine/Level/Actors/Camera.h b/Source/Engine/Level/Actors/Camera.h
index 8076e6a60..edf94ad22 100644
--- a/Source/Engine/Level/Actors/Camera.h
+++ b/Source/Engine/Level/Actors/Camera.h
@@ -211,7 +211,7 @@ public:
/// The result camera view matrix.
/// The result camera projection matrix.
/// The custom output viewport. Use null to skip it.
- API_FUNCTION() void GetMatrices(API_PARAM(Out) Matrix& view, API_PARAM(Out) Matrix& projection, API_PARAM(Ref) const Viewport& viewport) const;
+ API_FUNCTION() virtual void GetMatrices(API_PARAM(Out) Matrix& view, API_PARAM(Out) Matrix& projection, API_PARAM(Ref) const Viewport& viewport) const;
#if USE_EDITOR
// Intersection check for editor picking the camera
diff --git a/Source/Engine/Level/Actors/StaticModel.cpp b/Source/Engine/Level/Actors/StaticModel.cpp
index cba13a601..a884c9707 100644
--- a/Source/Engine/Level/Actors/StaticModel.cpp
+++ b/Source/Engine/Level/Actors/StaticModel.cpp
@@ -98,7 +98,7 @@ void StaticModel::SetVertexColor(int32 lodIndex, int32 meshIndex, int32 vertexIn
{
if (!Model || Model->WaitForLoaded())
{
- LOG(Warning, "Cannot set vertex color if model is missing or faied to load.");
+ LOG(Warning, "Cannot set vertex color if model is missing or failed to load.");
return;
}
diff --git a/Source/Engine/Level/Level.cpp b/Source/Engine/Level/Level.cpp
index 18d9d4a52..62d066803 100644
--- a/Source/Engine/Level/Level.cpp
+++ b/Source/Engine/Level/Level.cpp
@@ -961,7 +961,7 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, bool autoI
}
// Synchronize prefab instances (prefab may have new objects added or some removed so deserialized instances need to synchronize with it)
- // TODO: resave and force sync scenes durign game cooking so this step could be skipped in game
+ // TODO: resave and force sync scenes during game cooking so this step could be skipped in game
Scripting::ObjectsLookupIdMapping.Set(&modifier.Value->IdsMapping);
SceneObjectsFactory::SynchronizePrefabInstances(*sceneObjects.Value, actorToRemovedObjectsData, modifier.Value);
Scripting::ObjectsLookupIdMapping.Set(nullptr);
@@ -973,7 +973,7 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, bool autoI
if (obj && obj->GetParent() == nullptr)
{
sceneObjects->At(i) = nullptr;
- LOG(Warning, "Scene object {0} {1} has missing parent objct after scene load. Removing it.", obj->GetID(), obj->ToString());
+ LOG(Warning, "Scene object {0} {1} has missing parent object after load. Removing it.", obj->GetID(), obj->ToString());
obj->DeleteObject();
}
}
@@ -1326,12 +1326,8 @@ Actor* Level::FindActor(const MClass* type)
CHECK_RETURN(type, nullptr);
Actor* result = nullptr;
ScopeLock lock(ScenesLock);
-
for (int32 i = 0; result == nullptr && i < Scenes.Count(); i++)
- {
result = Scenes[i]->FindActor(type);
- }
-
return result;
}
@@ -1340,25 +1336,57 @@ Script* Level::FindScript(const MClass* type)
CHECK_RETURN(type, nullptr);
Script* result = nullptr;
ScopeLock lock(ScenesLock);
-
for (int32 i = 0; result == nullptr && i < Scenes.Count(); i++)
- {
result = Scenes[i]->FindScript(type);
+ return result;
+}
+
+namespace
+{
+ void GetActors(const MClass* type, Actor* actor, Array& result)
+ {
+ if (actor->GetClass()->IsSubClassOf(type))
+ result.Add(actor);
+ for (auto child : actor->Children)
+ GetActors(type, child, result);
}
+ void GetScripts(const MClass* type, Actor* actor, Array