Merge branch 'master' of https://github.com/FlaxEngine/FlaxEngine into convertactor
This commit is contained in:
19
.github/workflows/build_linux.todo
vendored
Normal file
19
.github/workflows/build_linux.todo
vendored
Normal file
@@ -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
|
||||
34
.github/workflows/build_windows.yml
vendored
Normal file
34
.github/workflows/build_windows.yml
vendored
Normal file
@@ -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
|
||||
34
CONTRIBUTING.md
Normal file
34
CONTRIBUTING.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# How to contribute to the FlaxEngine
|
||||
|
||||
For any questions, suggestions or help join our discord!
|
||||
|
||||
<a href="https://flaxengine.com/discord"><img src="https://discordapp.com/api/guilds/437989205315158016/widget.png"/></a>
|
||||
|
||||
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!
|
||||
Binary file not shown.
Binary file not shown.
BIN
Content/Shaders/BitonicSort.flax
LFS
BIN
Content/Shaders/BitonicSort.flax
LFS
Binary file not shown.
6
Development/Scripts/Linux/CallBuildTool.sh
Normal file → Executable file
6
Development/Scripts/Linux/CallBuildTool.sh
Normal file → Executable file
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -16,6 +16,7 @@ exit /B 0
|
||||
|
||||
:BuildToolFailed
|
||||
echo Flax.Build tool failed.
|
||||
pause
|
||||
goto Exit
|
||||
|
||||
:Exit
|
||||
|
||||
0
GenerateProjectFiles.sh
Normal file → Executable file
0
GenerateProjectFiles.sh
Normal file → Executable file
0
PackagePlatforms.sh
Normal file → Executable file
0
PackagePlatforms.sh
Normal file → Executable file
11
README.md
11
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
|
||||
|
||||
@@ -262,9 +262,9 @@ namespace FlaxEditor.Content.Import
|
||||
public int BaseLOD { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 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).
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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
|
||||
/// <inheritdoc />
|
||||
public override void OnThumbnailDrawEnd(ThumbnailRequest request, ContainerControl guiRoot)
|
||||
{
|
||||
_preview.RemoveChildren();
|
||||
_preview.Prefab = null;
|
||||
_preview.Parent = null;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the value indicating whenever platform requires AOT.
|
||||
/// </summary>
|
||||
/// <returns>True if platform uses AOT and needs C# assemblies to be be precompiled, otherwise false.</returns>
|
||||
/// <returns>True if platform uses AOT and needs C# assemblies to be precompiled, otherwise false.</returns>
|
||||
virtual bool UseAOT() const
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
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)
|
||||
|
||||
@@ -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
|
||||
/// </summary>
|
||||
protected virtual void OnValueChanged()
|
||||
{
|
||||
SetValue(element.EnumComboBox.EnumTypeValue);
|
||||
SetValue(element.ComboBox.EnumTypeValue);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -63,7 +63,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
else
|
||||
{
|
||||
element.EnumComboBox.EnumTypeValue = Values[0];
|
||||
element.ComboBox.EnumTypeValue = Values[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace FlaxEditor.CustomEditors.Elements
|
||||
/// <summary>
|
||||
/// The combo box used to show enum values.
|
||||
/// </summary>
|
||||
public EnumComboBox EnumComboBox;
|
||||
public EnumComboBox ComboBox;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EnumElement"/> class.
|
||||
@@ -26,10 +26,10 @@ namespace FlaxEditor.CustomEditors.Elements
|
||||
/// <param name="formatMode">The formatting mode.</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Control Control => EnumComboBox;
|
||||
public override Control Control => ComboBox;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
static bool IsOldProjectOpened;
|
||||
|
||||
|
||||
@@ -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
|
||||
/// <inheritdoc />
|
||||
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
|
||||
/// <inheritdoc />
|
||||
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;
|
||||
|
||||
@@ -221,7 +221,7 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filters teh given value using the the <see cref="UseMode"/>.
|
||||
/// Filters the given value using the <see cref="UseMode"/>.
|
||||
/// </summary>
|
||||
/// <param name="mode">The mode.</param>
|
||||
/// <param name="value">The value to process.</param>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -307,6 +307,14 @@ namespace FlaxEditor.GUI.Docking
|
||||
_dockedTo?.SelectTab(this, autoFocus);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Brings the window to the front of the Z order.
|
||||
/// </summary>
|
||||
public void BringToFront()
|
||||
{
|
||||
_dockedTo?.RootWindow?.BringToFront();
|
||||
}
|
||||
|
||||
internal void OnUnlinkInternal()
|
||||
{
|
||||
OnUnlink();
|
||||
@@ -412,6 +420,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
base.Focus();
|
||||
|
||||
SelectTab();
|
||||
BringToFront();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -49,6 +49,11 @@ namespace FlaxEditor.GUI.Input
|
||||
/// </summary>
|
||||
protected T _startSlideValue;
|
||||
|
||||
/// <summary>
|
||||
/// The text cached on editing start. Used to compare with the end result to detect changes.
|
||||
/// </summary>
|
||||
protected string _startEditText;
|
||||
|
||||
private Vector2 _startSlideLocation;
|
||||
|
||||
/// <summary>
|
||||
@@ -257,11 +262,23 @@ namespace FlaxEditor.GUI.Input
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnEditBegin()
|
||||
{
|
||||
base.OnEditBegin();
|
||||
|
||||
_startEditText = _text;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnEditEnd()
|
||||
{
|
||||
// Update value
|
||||
TryGetValue();
|
||||
if (_startEditText != _text)
|
||||
{
|
||||
// Update value
|
||||
TryGetValue();
|
||||
}
|
||||
_startEditText = null;
|
||||
|
||||
base.OnEditEnd();
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace FlaxEditor.GUI
|
||||
/// <summary>
|
||||
/// Draws the column.
|
||||
/// </summary>
|
||||
/// <param name="rect">The the header area rectangle.</param>
|
||||
/// <param name="rect">The header area rectangle.</param>
|
||||
/// <param name="columnIndex">The zero-based index of the column.</param>
|
||||
protected virtual void DrawColumn(ref Rectangle rect, int columnIndex)
|
||||
{
|
||||
|
||||
@@ -401,7 +401,7 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="point">The point.</param>
|
||||
/// <param name="keyframesContentAreaBounds">The keyframes contents area bounds.</param>
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace FlaxEditor.GUI.Timeline
|
||||
/// The Timeline track that contains a header and custom timeline events/media.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
|
||||
[HideInEditor]
|
||||
public class Track : ContainerControl
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the member value value at the specified time.
|
||||
/// Evaluates the member value at the specified time.
|
||||
/// </summary>
|
||||
/// <param name="time">The time to evaluate the member at.</param>
|
||||
/// <returns>The member value at provided time.</returns>
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace FlaxEditor.GUI.Tree
|
||||
/// <summary>
|
||||
/// The default node offset on Y axis.
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
@@ -7,7 +7,7 @@ using FlaxEngine;
|
||||
namespace FlaxEditor.Gizmo
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents collection of Gizmo tools where one is active and in use.
|
||||
/// Represents collection of gizmo tools where one is active and in use.
|
||||
/// </summary>
|
||||
/// <seealso cref="GizmoBase" />
|
||||
[HideInEditor]
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace FlaxEditor.Gizmo
|
||||
)
|
||||
{
|
||||
// Error
|
||||
Platform.Fatal("Failed to load Transform Gizmo resources.");
|
||||
Platform.Fatal("Failed to load transform gizmo resources.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace FlaxEditor.Gizmo
|
||||
public Axis ActiveAxis => _activeAxis;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sts the current gizmo mode.
|
||||
/// Gets or sets the current gizmo mode.
|
||||
/// </summary>
|
||||
public Mode ActiveMode
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace FlaxEditor.Modules
|
||||
/// <summary>
|
||||
/// Removes a quick action by name.
|
||||
/// </summary>
|
||||
/// <param name="name">Thr action's name.</param>
|
||||
/// <param name="name">The action's name.</param>
|
||||
/// <returns>True when it succeed, false if there is no Quick Action with this name.</returns>
|
||||
public bool RemoveQuickAction(string name)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes this input binding to check if state matches.
|
||||
/// </summary>
|
||||
/// <param name="control">The input providing control.</param>
|
||||
/// <param name="key">The input key.</param>
|
||||
/// <returns>True if input has been processed, otherwise false.</returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace FlaxEditor.Options
|
||||
private readonly Dictionary<string, CreateCustomSettingsDelegate> _customSettings = new Dictionary<string, CreateCustomSettingsDelegate>();
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, CreateCustomSettingsDelegate> CustomSettings => _customSettings;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the panning direction is inverted for the viewport camera.
|
||||
/// </summary>
|
||||
[DefaultValue(false)]
|
||||
[EditorDisplay("Defaults"), EditorOrder(150), Tooltip( "Invert the panning direction for the viewport camera." )]
|
||||
public bool DefaultInvertPanning { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace FlaxEditor.Progress
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when progress action gets updated (changed nfo text or progress value).
|
||||
/// Called when progress action gets updated (changed info text or progress value).
|
||||
/// </summary>
|
||||
/// <param name="progress">The progress (normalized to range [0;1]).</param>
|
||||
/// <param name="infoText">The information text.</param>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
{
|
||||
if (dwRejectType == SERVERCALL_RETRYLATER)
|
||||
{
|
||||
// Retry immediatey
|
||||
// Retry immediately
|
||||
return 99;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
public Dictionary<Type, NodeElementArchetype[]> Prototypes = DefaultPrototypes;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public static readonly Dictionary<Type, NodeElementArchetype[]> DefaultPrototypes = new Dictionary<Type, NodeElementArchetype[]>
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -239,6 +239,32 @@ namespace FlaxEditor.Surface
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates new Unsigned Integer value element description.
|
||||
/// </summary>
|
||||
/// <param name="x">The x location (in node area space).</param>
|
||||
/// <param name="y">The y location (in node area space).</param>
|
||||
/// <param name="valueIndex">The index of the node variable linked as the input. Useful to make a physical connection between input box and default value for it.</param>
|
||||
/// <param name="component">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.</param>
|
||||
/// <param name="valueMin">The minimum value range.</param>
|
||||
/// <param name="valueMax">The maximum value range.</param>
|
||||
/// <returns>The archetype.</returns>
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates new Float value element description.
|
||||
/// </summary>
|
||||
|
||||
@@ -94,5 +94,10 @@ namespace FlaxEditor.Surface
|
||||
/// The actor picker.
|
||||
/// </summary>
|
||||
Actor = 19,
|
||||
|
||||
/// <summary>
|
||||
/// The unsigned integer value.
|
||||
/// </summary>
|
||||
UnsignedIntegerValue = 20,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)", () =>
|
||||
|
||||
@@ -107,7 +107,7 @@ namespace FlaxEditor.Surface
|
||||
/// Validates the parameter drag operation.
|
||||
/// </summary>
|
||||
/// <param name="parameterName">Name of the parameter.</param>
|
||||
/// <returns>Tre if can drag that parameter, otherwise false.</returns>
|
||||
/// <returns>True if can drag that parameter, otherwise false.</returns>
|
||||
protected virtual bool ValidateDragParameter(string parameterName)
|
||||
{
|
||||
return GetParameter(parameterName) != null;
|
||||
|
||||
287
Source/Editor/Surface/VisjectSurface.Formatting.cs
Normal file
287
Source/Editor/Surface/VisjectSurface.Formatting.cs
Normal file
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Starting from 0 at the main nodes
|
||||
/// </summary>
|
||||
public int Layer;
|
||||
|
||||
/// <summary>
|
||||
/// Position in the layer
|
||||
/// </summary>
|
||||
public int Offset;
|
||||
|
||||
/// <summary>
|
||||
/// How far the subtree needs to be moved additionally
|
||||
/// </summary>
|
||||
public int SubtreeOffset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a graph where the nodes can be disjointed.
|
||||
/// Uses the Sugiyama method
|
||||
/// </summary>
|
||||
/// <param name="nodes">List of nodes</param>
|
||||
protected void FormatGraph(List<SurfaceNode> nodes)
|
||||
{
|
||||
if (nodes.Count <= 1 || !CanEdit) return;
|
||||
|
||||
var nodesToVisit = new HashSet<SurfaceNode>(nodes);
|
||||
|
||||
// While we haven't formatted every node
|
||||
while (nodesToVisit.Count > 0)
|
||||
{
|
||||
// Run a search in both directions
|
||||
var connectedNodes = new List<SurfaceNode>();
|
||||
var queue = new Queue<SurfaceNode>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a graph where all nodes are connected
|
||||
/// </summary>
|
||||
/// <param name="nodes">List of connected nodes</param>
|
||||
protected void FormatConnectedGraph(List<SurfaceNode> 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<MoveNodesAction>();
|
||||
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"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assigns a layer to every node
|
||||
/// </summary>
|
||||
/// <param name="nodeData">The exta node data</param>
|
||||
/// <param name="endNodes">The end nodes</param>
|
||||
/// <returns>The number of the maximum layer</returns>
|
||||
private int SetLayers(Dictionary<SurfaceNode, NodeFormattingData> nodeData, List<SurfaceNode> endNodes)
|
||||
{
|
||||
// Longest path layering
|
||||
int maxLayer = 0;
|
||||
var stack = new Stack<SurfaceNode>(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;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets the node offsets
|
||||
/// </summary>
|
||||
/// <param name="nodeData">The exta node data</param>
|
||||
/// <param name="endNodes">The end nodes</param>
|
||||
/// <param name="maxLayer">The number of the maximum layer</param>
|
||||
/// <returns>The number of the maximum offset</returns>
|
||||
private int SetOffsets(Dictionary<SurfaceNode, NodeFormattingData> nodeData, List<SurfaceNode> 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<SurfaceNode>();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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<SurfaceNode> Nodes { get; } = new List<SurfaceNode>();
|
||||
@@ -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
|
||||
/// </summary>
|
||||
public event Window.MouseWheelDelegate CustomMouseWheel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the node under the mouse location.
|
||||
/// </summary>
|
||||
/// <returns>The node or null if no intersection.</returns>
|
||||
public SurfaceNode GetNodeUnderMouse()
|
||||
{
|
||||
var pos = _rootControl.PointFromParent(ref _mousePos);
|
||||
if (_rootControl.GetChildAt(pos) is SurfaceNode node)
|
||||
return node;
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the control under the mouse location.
|
||||
/// </summary>
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace FlaxEditor.Tools.Foliage
|
||||
private readonly Tabs _modes;
|
||||
private readonly ContainerControl _noFoliagePanel;
|
||||
private int _selectedFoliageTypeIndex = -1;
|
||||
private Button _createNewFoliage;
|
||||
|
||||
/// <summary>
|
||||
/// 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();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
if (_createNewFoliage.Enabled)
|
||||
Level.SceneUnloaded -= OnSceneUnloaded;
|
||||
else
|
||||
Level.SceneLoaded -= OnSceneLoaded;
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace FlaxEditor.Tools.Terrain
|
||||
{
|
||||
private readonly Tabs _modes;
|
||||
private readonly ContainerControl _noTerrainPanel;
|
||||
private readonly Button _createTerrainButton;
|
||||
|
||||
/// <summary>
|
||||
/// 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.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
if (_createTerrainButton.Enabled)
|
||||
Level.SceneUnloaded -= OnSceneUnloaded;
|
||||
else
|
||||
Level.SceneLoaded -= OnSceneLoaded;
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace FlaxEditor.Tools.Terrain.Paint
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace FlaxEditor.Tools.Terrain.Sculpt
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<String> files;
|
||||
|
||||
@@ -42,6 +42,13 @@ public:
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified path character is invalid.
|
||||
/// </summary>
|
||||
/// <param name="c">The path character.</param>
|
||||
/// <returns><c>true</c> if the given character cannot be used as a path because it is illegal character; otherwise, <c>false</c>.</returns>
|
||||
static bool IsInvalidPathChar(Char c);
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the given text with other one in the files.
|
||||
/// </summary>
|
||||
|
||||
@@ -251,7 +251,7 @@ namespace FlaxEditor.Utilities
|
||||
|
||||
var list = new List<MemberComparison>();
|
||||
#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--)
|
||||
{
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace FlaxEditor.Utilities
|
||||
/// </summary>
|
||||
/// <param name="oper1">The first operator.</param>
|
||||
/// <param name="oper2">The second operator.</param>
|
||||
/// <returns>The comparision result.</returns>
|
||||
/// <returns>The comparison result.</returns>
|
||||
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 '-'
|
||||
|
||||
@@ -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<object, object>));
|
||||
case VariantType.ManagedObject: return new ScriptType(typeof(object));
|
||||
case VariantType.Blob: return new ScriptType(typeof(byte[]));
|
||||
default: throw new ArgumentOutOfRangeException($"Unknown Variant Type {variantType} without typename.");
|
||||
}
|
||||
}
|
||||
@@ -760,7 +763,7 @@ namespace FlaxEditor.Utilities
|
||||
data[i] = (byte)(c ^ 77);
|
||||
}
|
||||
var typeName = System.Text.Encoding.ASCII.GetString(data);
|
||||
return TypeUtils.GetType(typeName).Type;
|
||||
return TypeUtils.GetManagedType(typeName);
|
||||
}
|
||||
if (typeNameLength > 0)
|
||||
{
|
||||
@@ -772,7 +775,7 @@ namespace FlaxEditor.Utilities
|
||||
data[i] = (char)(c ^ 77);
|
||||
}
|
||||
var typeName = new string(data);
|
||||
return TypeUtils.GetType(typeName).Type;
|
||||
return TypeUtils.GetManagedType(typeName);
|
||||
}
|
||||
switch (variantType)
|
||||
{
|
||||
@@ -805,6 +808,7 @@ namespace FlaxEditor.Utilities
|
||||
case VariantType.Array: return typeof(object[]);
|
||||
case VariantType.Dictionary: return typeof(Dictionary<object, object>);
|
||||
case VariantType.ManagedObject: return typeof(object);
|
||||
case VariantType.Blob: return typeof(byte[]);
|
||||
default: throw new ArgumentOutOfRangeException($"Unknown Variant Type {variantType} without typename.");
|
||||
}
|
||||
}
|
||||
@@ -824,7 +828,7 @@ namespace FlaxEditor.Utilities
|
||||
data[i] = (byte)(c ^ 77);
|
||||
}
|
||||
var typeName = System.Text.Encoding.ASCII.GetString(data);
|
||||
type = TypeUtils.GetType(typeName).Type;
|
||||
type = TypeUtils.GetManagedType(typeName);
|
||||
}
|
||||
else if (typeNameLength > 0)
|
||||
{
|
||||
@@ -836,7 +840,7 @@ namespace FlaxEditor.Utilities
|
||||
data[i] = (char)(c ^ 77);
|
||||
}
|
||||
var typeName = new string(data);
|
||||
type = TypeUtils.GetType(typeName).Type;
|
||||
type = TypeUtils.GetManagedType(typeName);
|
||||
}
|
||||
switch (variantType)
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace FlaxEditor.Viewport.Cameras
|
||||
public bool IsAnimatingMove => _moveStartTime > Mathf.Epsilon;
|
||||
|
||||
/// <summary>
|
||||
/// The target point location. It's used to orbit around it whe user clicks Alt+LMB.
|
||||
/// The target point location. It's used to orbit around it when user clicks Alt+LMB.
|
||||
/// </summary>
|
||||
public Vector3 TargetPoint = new Vector3(-200);
|
||||
|
||||
@@ -188,8 +188,16 @@ namespace FlaxEditor.Viewport.Cameras
|
||||
if (input.IsPanning)
|
||||
{
|
||||
var panningSpeed = 0.8f;
|
||||
position -= right * (mouseDelta.X * panningSpeed);
|
||||
position -= up * (mouseDelta.Y * panningSpeed);
|
||||
if (Viewport.InvertPanning)
|
||||
{
|
||||
position += up * (mouseDelta.Y * panningSpeed);
|
||||
position += right * (mouseDelta.X * panningSpeed);
|
||||
}
|
||||
else
|
||||
{
|
||||
position -= right * (mouseDelta.X * panningSpeed);
|
||||
position -= up * (mouseDelta.Y * panningSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
// Move
|
||||
|
||||
@@ -32,9 +32,9 @@ namespace FlaxEditor.Viewport.Cameras
|
||||
/// </summary>
|
||||
/// <param name="objectBounds">The target object bounds.</param>
|
||||
/// <param name="marginDistanceScale">The margin distance scale of the orbit radius.</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -42,18 +42,18 @@ namespace FlaxEditor.Viewport.Cameras
|
||||
/// </summary>
|
||||
/// <param name="objectBounds">The target object bounds.</param>
|
||||
/// <param name="marginDistanceScale">The margin distance scale of the orbit radius.</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets view orientation and position to match the arc ball camera style view for the given orbit radius.
|
||||
/// </summary>
|
||||
/// <param name="orbitRadius">The orbit radius.</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -62,7 +62,7 @@ namespace FlaxEditor.Viewport.Cameras
|
||||
/// <param name="orientation">The view rotation.</param>
|
||||
/// <param name="orbitCenter">The orbit center location.</param>
|
||||
/// <param name="orbitRadius">The orbit radius.</param>
|
||||
public void SerArcBallView(Quaternion orientation, Vector3 orbitCenter, float orbitRadius)
|
||||
public void SetArcBallView(Quaternion orientation, Vector3 orbitCenter, float orbitRadius)
|
||||
{
|
||||
// Rotate
|
||||
Viewport.ViewOrientation = orientation;
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Speed of the mouse.
|
||||
@@ -403,6 +402,15 @@ namespace FlaxEditor.Viewport
|
||||
set => _isOrtho = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the panning direction is inverted.
|
||||
/// </summary>
|
||||
public bool InvertPanning
|
||||
{
|
||||
get => _invertPanning;
|
||||
set => _invertPanning = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The input actions collection to processed during user input.
|
||||
/// </summary>
|
||||
@@ -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
|
||||
/// </summary>
|
||||
protected virtual void OnLeftMouseButtonDown()
|
||||
{
|
||||
_startPosLeft = _viewMousePos;
|
||||
_startPos = _viewMousePos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -827,7 +863,7 @@ namespace FlaxEditor.Viewport
|
||||
/// </summary>
|
||||
protected virtual void OnRightMouseButtonDown()
|
||||
{
|
||||
_startPosRight = _viewMousePos;
|
||||
_startPos = _viewMousePos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -842,7 +878,7 @@ namespace FlaxEditor.Viewport
|
||||
/// </summary>
|
||||
protected virtual void OnMiddleMouseButtonDown()
|
||||
{
|
||||
_startPosMiddle = _viewMousePos;
|
||||
_startPos = _viewMousePos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -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,
|
||||
|
||||
@@ -485,6 +485,23 @@ namespace FlaxEditor.Viewport
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnLeftMouseButtonUp()
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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<Model>("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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// 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));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -87,7 +124,6 @@ namespace FlaxEditor.Viewport.Previews
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
// Cleanup
|
||||
Prefab = null;
|
||||
|
||||
base.OnDestroy();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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[]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user