Merge branch 'master' into android-emulate
This commit is contained in:
29
.github/workflows/cd.yml
vendored
29
.github/workflows/cd.yml
vendored
@@ -1,12 +1,13 @@
|
|||||||
name: Continuous Deployment
|
name: Continuous Deployment
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '15 4 * * *'
|
- cron: '15 6 * * *'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
DOTNET_NOLOGO: true
|
DOTNET_NOLOGO: true
|
||||||
DOTNET_CLI_TELEMETRY_OPTOUT: false
|
DOTNET_CLI_TELEMETRY_OPTOUT: false
|
||||||
|
GIT_LFS_PULL_OPTIONS: '-c lfs.concurrenttransfers=1 -c lfs.transfer.maxretries=2 -c http.version="HTTP/1.1" -c lfs.activitytimeout=60'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ jobs:
|
|||||||
- name: Checkout LFS
|
- name: Checkout LFS
|
||||||
run: |
|
run: |
|
||||||
git lfs version
|
git lfs version
|
||||||
git lfs pull
|
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
||||||
- name: Setup Vulkan
|
- name: Setup Vulkan
|
||||||
uses: ./.github/actions/vulkan
|
uses: ./.github/actions/vulkan
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
@@ -35,12 +36,12 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
.\PackageEditor.bat -arch=x64 -platform=Windows -deployOutput=Output
|
.\PackageEditor.bat -arch=x64 -platform=Windows -deployOutput=Output
|
||||||
- name: Upload
|
- name: Upload
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Windows-Editor
|
name: Windows-Editor
|
||||||
path: Output/Editor.zip
|
path: Output/Editor.zip
|
||||||
- name: Upload
|
- name: Upload
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Windows-EditorDebugSymbols
|
name: Windows-EditorDebugSymbols
|
||||||
path: Output/EditorDebugSymbols.zip
|
path: Output/EditorDebugSymbols.zip
|
||||||
@@ -53,7 +54,7 @@ jobs:
|
|||||||
- name: Checkout LFS
|
- name: Checkout LFS
|
||||||
run: |
|
run: |
|
||||||
git lfs version
|
git lfs version
|
||||||
git lfs pull
|
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
||||||
- name: Setup Vulkan
|
- name: Setup Vulkan
|
||||||
uses: ./.github/actions/vulkan
|
uses: ./.github/actions/vulkan
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
@@ -68,7 +69,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
.\PackagePlatforms.bat -arch=x64 -platform=Windows -deployOutput=Output
|
.\PackagePlatforms.bat -arch=x64 -platform=Windows -deployOutput=Output
|
||||||
- name: Upload
|
- name: Upload
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Windows-Game
|
name: Windows-Game
|
||||||
path: Output/Windows.zip
|
path: Output/Windows.zip
|
||||||
@@ -83,7 +84,7 @@ jobs:
|
|||||||
- name: Checkout LFS
|
- name: Checkout LFS
|
||||||
run: |
|
run: |
|
||||||
git lfs version
|
git lfs version
|
||||||
git lfs pull
|
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||||
@@ -101,7 +102,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
./PackageEditor.sh -arch=x64 -platform=Linux -deployOutput=Output
|
./PackageEditor.sh -arch=x64 -platform=Linux -deployOutput=Output
|
||||||
- name: Upload
|
- name: Upload
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Linux-Editor
|
name: Linux-Editor
|
||||||
path: Output/FlaxEditorLinux.zip
|
path: Output/FlaxEditorLinux.zip
|
||||||
@@ -114,7 +115,7 @@ jobs:
|
|||||||
- name: Checkout LFS
|
- name: Checkout LFS
|
||||||
run: |
|
run: |
|
||||||
git lfs version
|
git lfs version
|
||||||
git lfs pull
|
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||||
@@ -132,7 +133,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
./PackagePlatforms.sh -arch=x64 -platform=Linux -deployOutput=Output
|
./PackagePlatforms.sh -arch=x64 -platform=Linux -deployOutput=Output
|
||||||
- name: Upload
|
- name: Upload
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Linux-Game
|
name: Linux-Game
|
||||||
path: Output/Linux.zip
|
path: Output/Linux.zip
|
||||||
@@ -147,7 +148,7 @@ jobs:
|
|||||||
- name: Checkout LFS
|
- name: Checkout LFS
|
||||||
run: |
|
run: |
|
||||||
git lfs version
|
git lfs version
|
||||||
git lfs pull
|
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
||||||
- name: Setup Vulkan
|
- name: Setup Vulkan
|
||||||
uses: ./.github/actions/vulkan
|
uses: ./.github/actions/vulkan
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
@@ -162,7 +163,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
./PackageEditor.command -arch=ARM64 -platform=Mac -deployOutput=Output
|
./PackageEditor.command -arch=ARM64 -platform=Mac -deployOutput=Output
|
||||||
- name: Upload
|
- name: Upload
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Mac-Editor
|
name: Mac-Editor
|
||||||
path: Output/FlaxEditorMac.zip
|
path: Output/FlaxEditorMac.zip
|
||||||
@@ -175,7 +176,7 @@ jobs:
|
|||||||
- name: Checkout LFS
|
- name: Checkout LFS
|
||||||
run: |
|
run: |
|
||||||
git lfs version
|
git lfs version
|
||||||
git lfs pull
|
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
||||||
- name: Setup Vulkan
|
- name: Setup Vulkan
|
||||||
uses: ./.github/actions/vulkan
|
uses: ./.github/actions/vulkan
|
||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
@@ -190,7 +191,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
./PackagePlatforms.command -arch=ARM64 -platform=Mac -deployOutput=Output
|
./PackagePlatforms.command -arch=ARM64 -platform=Mac -deployOutput=Output
|
||||||
- name: Upload
|
- name: Upload
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Mac-Game
|
name: Mac-Game
|
||||||
path: Output/Mac.zip
|
path: Output/Mac.zip
|
||||||
|
|||||||
BIN
Content/Editor/Camera/M_Camera.flax
(Stored with Git LFS)
BIN
Content/Editor/Camera/M_Camera.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/CubeTexturePreviewMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/CubeTexturePreviewMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/DDGIDebugProbes.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/DDGIDebugProbes.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/SingleColor/Decal.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/SingleColor/Decal.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/SingleColor/Particle.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/SingleColor/Particle.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/SingleColor/Surface.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/SingleColor/Surface.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/SingleColor/SurfaceAdditive.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DebugMaterials/SingleColor/Terrain.flax
(Stored with Git LFS)
BIN
Content/Editor/DebugMaterials/SingleColor/Terrain.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/DefaultFontMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/DefaultFontMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/FoliageBrushMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/FoliageBrushMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/Material.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/MaterialWire.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/MaterialWire.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/SelectionOutlineMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/SelectionOutlineMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/Gizmo/VertexColorsPreviewMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Highlight Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Highlight Material.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Icons/IconsMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/Icons/IconsMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/IesProfilePreviewMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/IesProfilePreviewMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Particles/Particle Material Color.flax
(Stored with Git LFS)
BIN
Content/Editor/Particles/Particle Material Color.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Particles/Smoke Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Particles/Smoke Material.flax
(Stored with Git LFS)
Binary file not shown.
25
Content/Editor/Scripting/GamePluginTemplate.cs
Normal file
25
Content/Editor/Scripting/GamePluginTemplate.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
%copyright%using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using FlaxEngine;
|
||||||
|
|
||||||
|
namespace %namespace%;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// %class% GamePlugin.
|
||||||
|
/// </summary>
|
||||||
|
public class %class% : GamePlugin
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override void Deinitialize()
|
||||||
|
{
|
||||||
|
base.Deinitialize();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Content/Editor/SpriteMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/SpriteMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Terrain/Circle Brush Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Terrain/Circle Brush Material.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Terrain/Highlight Terrain Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Terrain/Highlight Terrain Material.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/TexturePreviewMaterial.flax
(Stored with Git LFS)
BIN
Content/Editor/TexturePreviewMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Editor/Wires Debug Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Wires Debug Material.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/DefaultDeformableMaterial.flax
(Stored with Git LFS)
BIN
Content/Engine/DefaultDeformableMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/DefaultMaterial.flax
(Stored with Git LFS)
BIN
Content/Engine/DefaultMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/DefaultRadialMenu.flax
(Stored with Git LFS)
BIN
Content/Engine/DefaultRadialMenu.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/DefaultTerrainMaterial.flax
(Stored with Git LFS)
BIN
Content/Engine/DefaultTerrainMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/SingleColorMaterial.flax
(Stored with Git LFS)
BIN
Content/Engine/SingleColorMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Engine/SkyboxMaterial.flax
(Stored with Git LFS)
BIN
Content/Engine/SkyboxMaterial.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/Editor/Grid.flax
(Stored with Git LFS)
BIN
Content/Shaders/Editor/Grid.flax
(Stored with Git LFS)
Binary file not shown.
@@ -31,7 +31,7 @@ Follow the instructions below to compile and run the engine from source.
|
|||||||
* Install Visual Studio 2022 or newer
|
* Install Visual Studio 2022 or newer
|
||||||
* Install Windows 8.1 SDK or newer (via Visual Studio Installer)
|
* Install Windows 8.1 SDK or newer (via Visual Studio Installer)
|
||||||
* Install Microsoft Visual C++ 2015 v140 toolset or newer (via Visual Studio Installer)
|
* Install Microsoft Visual C++ 2015 v140 toolset or newer (via Visual Studio Installer)
|
||||||
* Install .NET 8 SDK for **Windows x64** (via Visual Studio Installer or [from web](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
|
* Install .NET 8 or 9 SDK for **Windows x64** (via Visual Studio Installer or [from web](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
|
||||||
* Install Git with LFS
|
* Install Git with LFS
|
||||||
* Clone repo (with LFS)
|
* Clone repo (with LFS)
|
||||||
* Run **GenerateProjectFiles.bat**
|
* Run **GenerateProjectFiles.bat**
|
||||||
@@ -44,8 +44,9 @@ Follow the instructions below to compile and run the engine from source.
|
|||||||
## Linux
|
## Linux
|
||||||
|
|
||||||
* Install Visual Studio Code
|
* Install Visual Studio Code
|
||||||
* Install .NET 8 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
|
* Install .NET 8 or 9 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
|
||||||
* Ubuntu: `sudo apt install dotnet-sdk-8.0`
|
* Ubuntu: `sudo apt install dotnet-sdk-8.0`
|
||||||
|
* Arch: `sudo pacman -S dotnet-sdk-8.0 dotnet-runtime-8.0 dotnet-targeting-pack-8.0 dotnet-host`
|
||||||
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
|
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
|
||||||
* Ubuntu: `sudo apt install vulkan-sdk`
|
* Ubuntu: `sudo apt install vulkan-sdk`
|
||||||
* Arch: `sudo pacman -S spirv-tools vulkan-headers vulkan-tools vulkan-validation-layers`
|
* Arch: `sudo pacman -S spirv-tools vulkan-headers vulkan-tools vulkan-validation-layers`
|
||||||
@@ -67,12 +68,12 @@ Follow the instructions below to compile and run the engine from source.
|
|||||||
## Mac
|
## Mac
|
||||||
|
|
||||||
* Install XCode
|
* Install XCode
|
||||||
* Install .NET 8 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
|
* Install .NET 8 or 9 SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0))
|
||||||
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
|
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
|
||||||
* Clone repo (with LFS)
|
* Clone repo (with LFS)
|
||||||
* Run `GenerateProjectFiles.command`
|
* Run `GenerateProjectFiles.command`
|
||||||
* Open workspace with XCode or Visual Studio Code
|
* Open workspace with XCode or Visual Studio Code
|
||||||
* Build and run (configuration `Editor.Mac.Development`)
|
* Build and run (configuration `Editor.Mac.Development`)
|
||||||
|
|
||||||
#### Troubleshooting
|
#### Troubleshooting
|
||||||
|
|
||||||
|
|||||||
@@ -750,7 +750,8 @@ namespace FlaxEditor.Content
|
|||||||
|
|
||||||
// Draw short name
|
// Draw short name
|
||||||
Render2D.PushClip(ref textRect);
|
Render2D.PushClip(ref textRect);
|
||||||
Render2D.DrawText(style.FontMedium, ShowFileExtension || view.ShowFileExtensions ? FileName : ShortName, textRect, style.Foreground, nameAlignment, TextAlignment.Center, TextWrapping.WrapWords, 1f, 0.95f);
|
var scale = 0.95f * view.ViewScale;
|
||||||
|
Render2D.DrawText(style.FontMedium, ShowFileExtension || view.ShowFileExtensions ? FileName : ShortName, textRect, style.Foreground, nameAlignment, TextAlignment.Center, TextWrapping.WrapWords, 1f, scale);
|
||||||
Render2D.PopClip();
|
Render2D.PopClip();
|
||||||
|
|
||||||
if (IsBeingCut)
|
if (IsBeingCut)
|
||||||
|
|||||||
@@ -106,6 +106,23 @@ namespace FlaxEditor.Content
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Context proxy object for C# GamePlugin files.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="FlaxEditor.Content.CSharpProxy" />
|
||||||
|
[ContentContextMenu("New/C#/C# GamePlugin")]
|
||||||
|
public class CSharpGamePluginProxy : CSharpProxy
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string Name => "C# GamePlugin";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void GetTemplatePath(out string path)
|
||||||
|
{
|
||||||
|
path = StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/GamePluginTemplate.cs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Context proxy object for empty C# files.
|
/// Context proxy object for empty C# files.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using FlaxEditor.Content.Create;
|
using FlaxEditor.Content.Create;
|
||||||
using FlaxEditor.CustomEditors;
|
using FlaxEditor.CustomEditors;
|
||||||
using FlaxEditor.CustomEditors.Editors;
|
using FlaxEditor.CustomEditors.Editors;
|
||||||
|
using FlaxEditor.Scripting;
|
||||||
using FlaxEditor.Windows;
|
using FlaxEditor.Windows;
|
||||||
using FlaxEditor.Windows.Assets;
|
using FlaxEditor.Windows.Assets;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
@@ -84,18 +86,67 @@ namespace FlaxEditor.Content
|
|||||||
|
|
||||||
if (_element != null)
|
if (_element != null)
|
||||||
{
|
{
|
||||||
// Define the rule for the types that can be used to create a json data asset
|
_element.CustomControl.CheckValid += OnCheckValidJsonAssetType;
|
||||||
_element.CustomControl.CheckValid += type =>
|
|
||||||
type.Type != null &&
|
|
||||||
type.IsClass &&
|
|
||||||
type.Type.IsVisible &&
|
|
||||||
!type.IsAbstract &&
|
|
||||||
!type.IsGenericType &&
|
|
||||||
type.Type.GetConstructor(Type.EmptyTypes) != null &&
|
|
||||||
!typeof(FlaxEngine.GUI.Control).IsAssignableFrom(type.Type) &&
|
|
||||||
!typeof(FlaxEngine.Object).IsAssignableFrom(type.Type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Type[] BlacklistedClasses =
|
||||||
|
[
|
||||||
|
typeof(System.Attribute),
|
||||||
|
typeof(FlaxEngine.Object),
|
||||||
|
typeof(FlaxEngine.GUI.Control),
|
||||||
|
];
|
||||||
|
|
||||||
|
private static Type[] BlacklistedStructs =
|
||||||
|
[
|
||||||
|
typeof(Float2),
|
||||||
|
typeof(Float3),
|
||||||
|
typeof(Float4),
|
||||||
|
typeof(Double2),
|
||||||
|
typeof(Double3),
|
||||||
|
typeof(Double4),
|
||||||
|
typeof(Vector2),
|
||||||
|
typeof(Vector3),
|
||||||
|
typeof(Vector4),
|
||||||
|
typeof(Half2),
|
||||||
|
typeof(Half3),
|
||||||
|
typeof(Half4),
|
||||||
|
typeof(Int2),
|
||||||
|
typeof(Int3),
|
||||||
|
typeof(Int4),
|
||||||
|
typeof(Transform),
|
||||||
|
typeof(Quaternion),
|
||||||
|
typeof(BoundingBox),
|
||||||
|
typeof(BoundingSphere),
|
||||||
|
typeof(BoundingFrustum),
|
||||||
|
typeof(Ray),
|
||||||
|
typeof(Plane),
|
||||||
|
typeof(Matrix),
|
||||||
|
typeof(Color),
|
||||||
|
typeof(Color32),
|
||||||
|
typeof(FloatR11G11B10),
|
||||||
|
typeof(FloatR10G10B10A2),
|
||||||
|
typeof(FlaxEngine.Half),
|
||||||
|
];
|
||||||
|
|
||||||
|
private static bool OnCheckValidJsonAssetType(ScriptType type)
|
||||||
|
{
|
||||||
|
// Define the rule for the types that can be used to create a json data asset
|
||||||
|
var mType = type.Type;
|
||||||
|
if (mType == null ||
|
||||||
|
type.IsAbstract ||
|
||||||
|
type.IsStatic ||
|
||||||
|
type.IsGenericType ||
|
||||||
|
!mType.IsVisible)
|
||||||
|
return false;
|
||||||
|
if (type.IsClass)
|
||||||
|
return mType.GetConstructor(Type.EmptyTypes) != null && BlacklistedClasses.FirstOrDefault(x => x.IsAssignableFrom(mType)) == null;
|
||||||
|
if (type.IsStructure)
|
||||||
|
return !type.IsPrimitive &&
|
||||||
|
!type.IsVoid &&
|
||||||
|
!BlacklistedStructs.Contains(mType);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +226,7 @@ namespace FlaxEditor.Content
|
|||||||
{
|
{
|
||||||
_thumbnail = SpriteHandle.Invalid;
|
_thumbnail = SpriteHandle.Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructor with overriden thumbnail.
|
/// Constructor with overriden thumbnail.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -196,7 +247,7 @@ namespace FlaxEditor.Content
|
|||||||
{
|
{
|
||||||
Editor.SaveJsonAsset(outputPath, new T());
|
Editor.SaveJsonAsset(outputPath, new T());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
|
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -496,7 +496,7 @@ namespace FlaxEditor.Content.Thumbnails
|
|||||||
// Prepare requests
|
// Prepare requests
|
||||||
bool isAnyReady = false;
|
bool isAnyReady = false;
|
||||||
int checks = Mathf.Min(10, _requests.Count);
|
int checks = Mathf.Min(10, _requests.Count);
|
||||||
for (int i = 0; i < checks; i++)
|
for (int i = 0; i < checks && i < _requests.Count; i++)
|
||||||
{
|
{
|
||||||
var request = _requests[i];
|
var request = _requests[i];
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -671,11 +671,14 @@ bool GameCookerImpl::Build()
|
|||||||
MCore::Thread::Attach();
|
MCore::Thread::Attach();
|
||||||
|
|
||||||
// Build Started
|
// Build Started
|
||||||
CallEvent(GameCooker::EventType::BuildStarted);
|
if (!EnumHasAnyFlags(data.Options, BuildOptions::NoCook))
|
||||||
data.Tools->OnBuildStarted(data);
|
{
|
||||||
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
CallEvent(GameCooker::EventType::BuildStarted);
|
||||||
Steps[stepIndex]->OnBuildStarted(data);
|
data.Tools->OnBuildStarted(data);
|
||||||
data.InitProgress(Steps.Count());
|
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
||||||
|
Steps[stepIndex]->OnBuildStarted(data);
|
||||||
|
data.InitProgress(Steps.Count());
|
||||||
|
}
|
||||||
|
|
||||||
// Execute all steps in a sequence
|
// Execute all steps in a sequence
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
@@ -741,10 +744,13 @@ bool GameCookerImpl::Build()
|
|||||||
}
|
}
|
||||||
IsRunning = false;
|
IsRunning = false;
|
||||||
CancelFlag = 0;
|
CancelFlag = 0;
|
||||||
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
if (!EnumHasAnyFlags(data.Options, BuildOptions::NoCook))
|
||||||
Steps[stepIndex]->OnBuildEnded(data, failed);
|
{
|
||||||
data.Tools->OnBuildEnded(data, failed);
|
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
||||||
CallEvent(failed ? GameCooker::EventType::BuildFailed : GameCooker::EventType::BuildDone);
|
Steps[stepIndex]->OnBuildEnded(data, failed);
|
||||||
|
data.Tools->OnBuildEnded(data, failed);
|
||||||
|
CallEvent(failed ? GameCooker::EventType::BuildFailed : GameCooker::EventType::BuildDone);
|
||||||
|
}
|
||||||
Delete(Data);
|
Delete(Data);
|
||||||
Data = nullptr;
|
Data = nullptr;
|
||||||
|
|
||||||
|
|||||||
@@ -364,6 +364,33 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
const bool distributionPackage = buildSettings->ForDistribution || data.Configuration == BuildConfiguration::Release;
|
const bool distributionPackage = buildSettings->ForDistribution || data.Configuration == BuildConfiguration::Release;
|
||||||
|
|
||||||
|
if (platformSettings->BuildAAB)
|
||||||
|
{
|
||||||
|
// .aab
|
||||||
|
{
|
||||||
|
CreateProcessSettings procSettings;
|
||||||
|
procSettings.FileName = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT(":app:bundle") : TEXT(":app:bundleDebug"));
|
||||||
|
procSettings.WorkingDirectory = data.OriginalOutputPath;
|
||||||
|
const int32 result = Platform::CreateProcess(procSettings);
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
data.Error(String::Format(TEXT("Failed to build Gradle project into .aab package (result code: {0}). See log for more info."), result));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Copy result package
|
||||||
|
const String aab = data.OriginalOutputPath / (distributionPackage ? TEXT("app/build/outputs/bundle/release/app-release.aab") : TEXT("app/build/outputs/bundle/debug/app-debug.aab"));
|
||||||
|
const String outputAab = data.OriginalOutputPath / EditorUtilities::GetOutputName() + TEXT(".aab");
|
||||||
|
if (FileSystem::CopyFile(outputAab, aab))
|
||||||
|
{
|
||||||
|
LOG(Error, "Failed to copy .aab package from {0} to {1}", aab, outputAab);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
LOG(Info, "Output Android AAB application package: {0} (size: {1} MB)", outputAab, FileSystem::GetFileSize(outputAab) / 1024 / 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
// .apk
|
||||||
{
|
{
|
||||||
CreateProcessSettings procSettings;
|
CreateProcessSettings procSettings;
|
||||||
procSettings.FileName = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT("assemble") : TEXT("assembleDebug"));
|
procSettings.FileName = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT("assemble") : TEXT("assembleDebug"));
|
||||||
@@ -371,20 +398,20 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
|||||||
const int32 result = Platform::CreateProcess(procSettings);
|
const int32 result = Platform::CreateProcess(procSettings);
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
{
|
{
|
||||||
data.Error(String::Format(TEXT("Failed to build Gradle project into package (result code: {0}). See log for more info."), result));
|
data.Error(String::Format(TEXT("Failed to build Gradle project into .apk package (result code: {0}). See log for more info."), result));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy result package
|
// Copy result package
|
||||||
const String apk = data.OriginalOutputPath / (distributionPackage ? TEXT("app/build/outputs/apk/release/app-release-unsigned.apk") : TEXT("app/build/outputs/apk/debug/app-debug.apk"));
|
const String apk = data.OriginalOutputPath / (distributionPackage ? TEXT("app/build/outputs/apk/release/app-release-unsigned.apk") : TEXT("app/build/outputs/apk/debug/app-debug.apk"));
|
||||||
const String outputApk = data.OriginalOutputPath / EditorUtilities::GetOutputName() + TEXT(".apk");
|
const String outputApk = data.OriginalOutputPath / EditorUtilities::GetOutputName() + TEXT(".apk");
|
||||||
if (FileSystem::CopyFile(outputApk, apk))
|
if (FileSystem::CopyFile(outputApk, apk))
|
||||||
{
|
{
|
||||||
LOG(Error, "Failed to copy package from {0} to {1}", apk, outputApk);
|
LOG(Error, "Failed to copy .apk package from {0} to {1}", apk, outputApk);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
LOG(Info, "Output Android application package: {0} (size: {1} MB)", outputApk, FileSystem::GetFileSize(outputApk) / 1024 / 1024);
|
LOG(Info, "Output Android APK application package: {0} (size: {1} MB)", outputApk, FileSystem::GetFileSize(outputApk) / 1024 / 1024);
|
||||||
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -214,6 +214,33 @@ bool DeployDataStep::Perform(CookingData& data)
|
|||||||
FileSystem::NormalizePath(srcDotnet);
|
FileSystem::NormalizePath(srcDotnet);
|
||||||
LOG(Info, "Using .NET Runtime {} at {}", TEXT("Host"), srcDotnet);
|
LOG(Info, "Using .NET Runtime {} at {}", TEXT("Host"), srcDotnet);
|
||||||
|
|
||||||
|
// Get major Version
|
||||||
|
Array<String> pathParts;
|
||||||
|
srcDotnet.Split('/', pathParts);
|
||||||
|
String version;
|
||||||
|
for (int i = 0; i < pathParts.Count(); i++)
|
||||||
|
{
|
||||||
|
if (pathParts[i] == TEXT("runtimes"))
|
||||||
|
{
|
||||||
|
Array<String> versionParts;
|
||||||
|
pathParts[i - 1].Split('.', versionParts);
|
||||||
|
if (!versionParts.IsEmpty())
|
||||||
|
{
|
||||||
|
const String majorVersion = versionParts[0].TrimTrailing();
|
||||||
|
int32 versionNum;
|
||||||
|
StringUtils::Parse(*majorVersion, majorVersion.Length(), &versionNum);
|
||||||
|
if (Math::IsInRange(versionNum, GAME_BUILD_DOTNET_RUNTIME_MIN_VER, GAME_BUILD_DOTNET_RUNTIME_MAX_VER)) // Check for major part
|
||||||
|
version = majorVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version.IsEmpty())
|
||||||
|
{
|
||||||
|
data.Error(TEXT("Failed to find supported .NET version for the current host platform."));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Deploy runtime files
|
// Deploy runtime files
|
||||||
const Char* corlibPrivateName = TEXT("System.Private.CoreLib.dll");
|
const Char* corlibPrivateName = TEXT("System.Private.CoreLib.dll");
|
||||||
const bool srcDotnetFromEngine = srcDotnet.Contains(TEXT("Source/Platforms"));
|
const bool srcDotnetFromEngine = srcDotnet.Contains(TEXT("Source/Platforms"));
|
||||||
@@ -226,14 +253,14 @@ bool DeployDataStep::Perform(CookingData& data)
|
|||||||
{
|
{
|
||||||
// AOT runtime files inside Engine Platform folder
|
// AOT runtime files inside Engine Platform folder
|
||||||
packFolder /= TEXT("Dotnet");
|
packFolder /= TEXT("Dotnet");
|
||||||
dstDotnetLibs /= TEXT("lib/net8.0");
|
dstDotnetLibs /= String::Format(TEXT("lib/net{}.0"), version);
|
||||||
srcDotnetLibs = packFolder / TEXT("lib/net8.0");
|
srcDotnetLibs = packFolder / String::Format(TEXT("lib/net{}.0"), version);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Runtime files inside Dotnet SDK folder but placed for AOT
|
// Runtime files inside Dotnet SDK folder but placed for AOT
|
||||||
dstDotnetLibs /= TEXT("lib/net8.0");
|
dstDotnetLibs /= String::Format(TEXT("lib/net{}.0"), version);
|
||||||
srcDotnetLibs /= TEXT("../lib/net8.0");
|
srcDotnetLibs /= String::Format(TEXT("../lib/net{}.0"), version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -241,14 +268,14 @@ bool DeployDataStep::Perform(CookingData& data)
|
|||||||
if (srcDotnetFromEngine)
|
if (srcDotnetFromEngine)
|
||||||
{
|
{
|
||||||
// Runtime files inside Engine Platform folder
|
// Runtime files inside Engine Platform folder
|
||||||
dstDotnetLibs /= TEXT("lib/net8.0");
|
dstDotnetLibs /= String::Format(TEXT("lib/net{}.0"), version);
|
||||||
srcDotnetLibs /= TEXT("lib/net8.0");
|
srcDotnetLibs /= String::Format(TEXT("lib/net{}.0"), version);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Runtime files inside Dotnet SDK folder
|
// Runtime files inside Dotnet SDK folder
|
||||||
dstDotnetLibs /= TEXT("shared/Microsoft.NETCore.App");
|
dstDotnetLibs /= TEXT("shared/Microsoft.NETCore.App");
|
||||||
srcDotnetLibs /= TEXT("../lib/net8.0");
|
srcDotnetLibs /= String::Format(TEXT("../lib/net{}.0"), version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG(Info, "Copying .NET files from {} to {}", packFolder, dstDotnet);
|
LOG(Info, "Copying .NET files from {} to {}", packFolder, dstDotnet);
|
||||||
@@ -273,6 +300,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
|||||||
DEPLOY_NATIVE_FILE("libmonosgen-2.0.so");
|
DEPLOY_NATIVE_FILE("libmonosgen-2.0.so");
|
||||||
DEPLOY_NATIVE_FILE("libSystem.IO.Compression.Native.so");
|
DEPLOY_NATIVE_FILE("libSystem.IO.Compression.Native.so");
|
||||||
DEPLOY_NATIVE_FILE("libSystem.Native.so");
|
DEPLOY_NATIVE_FILE("libSystem.Native.so");
|
||||||
|
DEPLOY_NATIVE_FILE("libSystem.Globalization.Native.so");
|
||||||
DEPLOY_NATIVE_FILE("libSystem.Security.Cryptography.Native.Android.so");
|
DEPLOY_NATIVE_FILE("libSystem.Security.Cryptography.Native.Android.so");
|
||||||
break;
|
break;
|
||||||
case BuildPlatform::iOSARM64:
|
case BuildPlatform::iOSARM64:
|
||||||
|
|||||||
@@ -883,7 +883,7 @@ namespace FlaxEditor.CustomEditors
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void ClearToken()
|
protected virtual void ClearToken()
|
||||||
{
|
{
|
||||||
ParentEditor.ClearToken();
|
ParentEditor?.ClearToken();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using FlaxEditor.CustomEditors.Elements;
|
|||||||
using FlaxEditor.GUI;
|
using FlaxEditor.GUI;
|
||||||
using FlaxEditor.GUI.ContextMenu;
|
using FlaxEditor.GUI.ContextMenu;
|
||||||
using FlaxEditor.GUI.Tree;
|
using FlaxEditor.GUI.Tree;
|
||||||
|
using FlaxEditor.Modules;
|
||||||
using FlaxEditor.Scripting;
|
using FlaxEditor.Scripting;
|
||||||
using FlaxEditor.Windows;
|
using FlaxEditor.Windows;
|
||||||
using FlaxEditor.Windows.Assets;
|
using FlaxEditor.Windows.Assets;
|
||||||
@@ -67,12 +68,16 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
// Use default prefab instance as a reference for the editor
|
// Use default prefab instance as a reference for the editor
|
||||||
Values.SetReferenceValue(prefabInstance);
|
Values.SetReferenceValue(prefabInstance);
|
||||||
|
|
||||||
if (Presenter == Editor.Instance.Windows.PropertiesWin.Presenter)
|
// Display prefab UI (when displaying object inside Prefab Window then display only nested prefabs)
|
||||||
|
var prefabId = prefab.ID;
|
||||||
|
Editor.GetPrefabNestedObject(ref prefabId, ref prefabObjectId, out var nestedPrefabId, out var nestedPrefabObjectId);
|
||||||
|
var nestedPrefab = FlaxEngine.Content.Load<Prefab>(nestedPrefabId);
|
||||||
|
var panel = layout.CustomContainer<UniformGridPanel>();
|
||||||
|
panel.CustomControl.Height = 20.0f;
|
||||||
|
panel.CustomControl.SlotsVertically = 1;
|
||||||
|
if (Presenter == Editor.Instance.Windows.PropertiesWin.Presenter || nestedPrefab)
|
||||||
{
|
{
|
||||||
// Add some UI
|
var targetPrefab = nestedPrefab ?? prefab;
|
||||||
var panel = layout.CustomContainer<UniformGridPanel>();
|
|
||||||
panel.CustomControl.Height = 20.0f;
|
|
||||||
panel.CustomControl.SlotsVertically = 1;
|
|
||||||
panel.CustomControl.SlotsHorizontally = 3;
|
panel.CustomControl.SlotsHorizontally = 3;
|
||||||
|
|
||||||
// Selecting actor prefab asset
|
// Selecting actor prefab asset
|
||||||
@@ -80,22 +85,21 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
selectPrefab.Button.Clicked += () =>
|
selectPrefab.Button.Clicked += () =>
|
||||||
{
|
{
|
||||||
Editor.Instance.Windows.ContentWin.ClearItemsSearch();
|
Editor.Instance.Windows.ContentWin.ClearItemsSearch();
|
||||||
Editor.Instance.Windows.ContentWin.Select(prefab);
|
Editor.Instance.Windows.ContentWin.Select(targetPrefab);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Edit selected prefab asset
|
// Edit selected prefab asset
|
||||||
var editPrefab = panel.Button("Edit Prefab");
|
var editPrefab = panel.Button("Edit Prefab");
|
||||||
editPrefab.Button.Clicked += () =>
|
editPrefab.Button.Clicked += () => Editor.Instance.Windows.ContentWin.Open(Editor.Instance.ContentDatabase.FindAsset(targetPrefab.ID));
|
||||||
{
|
|
||||||
Editor.Instance.Windows.ContentWin.ClearItemsSearch();
|
|
||||||
Editor.Instance.Windows.ContentWin.Select(prefab);
|
|
||||||
Editor.Instance.Windows.ContentWin.Open(Editor.Instance.Windows.ContentWin.View.Selection[0]);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Viewing changes applied to this actor
|
|
||||||
var viewChanges = panel.Button("View Changes");
|
|
||||||
viewChanges.Button.Clicked += () => ViewChanges(viewChanges.Button, new Float2(0.0f, 20.0f));
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
panel.CustomControl.SlotsHorizontally = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Viewing changes applied to this actor
|
||||||
|
var viewChanges = panel.Button("View Changes");
|
||||||
|
viewChanges.Button.Clicked += () => ViewChanges(viewChanges.Button, new Float2(0.0f, 20.0f));
|
||||||
|
|
||||||
// Link event to update editor on prefab apply
|
// Link event to update editor on prefab apply
|
||||||
_linkedPrefabId = prefab.ID;
|
_linkedPrefabId = prefab.ID;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using FlaxEditor.CustomEditors.Elements;
|
using FlaxEditor.CustomEditors.Elements;
|
||||||
using FlaxEditor.Surface;
|
using FlaxEditor.Surface;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
@@ -35,6 +36,8 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
(instance, parameter, tag) => ((AnimatedModel)instance).GetParameterValue(parameter.Identifier),
|
(instance, parameter, tag) => ((AnimatedModel)instance).GetParameterValue(parameter.Identifier),
|
||||||
(instance, value, parameter, tag) => ((AnimatedModel)instance).SetParameterValue(parameter.Identifier, value),
|
(instance, value, parameter, tag) => ((AnimatedModel)instance).SetParameterValue(parameter.Identifier, value),
|
||||||
Values);
|
Values);
|
||||||
|
if (!parameters.Any())
|
||||||
|
group.Label("No parameters", TextAlignment.Center);
|
||||||
_parametersAdded = true;
|
_parametersAdded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,13 +15,23 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
private int _firstTimeShow;
|
private int _firstTimeShow;
|
||||||
private BezierCurveEditor<T> _curve;
|
private BezierCurveEditor<T> _curve;
|
||||||
private Splitter _splitter;
|
private Splitter _splitter;
|
||||||
|
private string _heightCachedPath;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Initialize(LayoutElementsContainer layout)
|
public override void Initialize(LayoutElementsContainer layout)
|
||||||
{
|
{
|
||||||
var item = layout.CustomContainer<BezierCurveEditor<T>>();
|
var item = layout.CustomContainer<BezierCurveEditor<T>>();
|
||||||
_curve = item.CustomControl;
|
_curve = item.CustomControl;
|
||||||
_curve.Height = 120.0f;
|
var height = 120.0f;
|
||||||
|
var presenter = Presenter;
|
||||||
|
if (presenter != null && (presenter.Features & FeatureFlags.CacheExpandedGroups) != 0)
|
||||||
|
{
|
||||||
|
// Try to restore curve height
|
||||||
|
_heightCachedPath = layout.GetLayoutCachePath("Height");
|
||||||
|
if (Editor.Instance.ProjectCache.TryGetCustomData(_heightCachedPath, out float cachedHeight) && cachedHeight > 10.0f)
|
||||||
|
height = cachedHeight;
|
||||||
|
}
|
||||||
|
_curve.Height = height;
|
||||||
_curve.Edited += OnCurveEdited;
|
_curve.Edited += OnCurveEdited;
|
||||||
_firstTimeShow = 4; // For some weird reason it needs several frames of warmup (probably due to sliders smoothing)
|
_firstTimeShow = 4; // For some weird reason it needs several frames of warmup (probably due to sliders smoothing)
|
||||||
_splitter = new Splitter
|
_splitter = new Splitter
|
||||||
@@ -45,7 +55,11 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
|
|
||||||
private void OnSplitterMoved(Float2 location)
|
private void OnSplitterMoved(Float2 location)
|
||||||
{
|
{
|
||||||
_curve.Height = Mathf.Clamp(_splitter.PointToParent(location).Y, 50.0f, 1000.0f);
|
_curve.Height = Mathf.Clamp(_splitter.PointToParent(location).Y, 50.0f, 1000.0f);
|
||||||
|
|
||||||
|
// Cache curve height
|
||||||
|
if (_heightCachedPath != null)
|
||||||
|
Editor.Instance.ProjectCache.SetCustomData(_heightCachedPath, _curve.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -133,13 +147,23 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
private int _firstTimeShow;
|
private int _firstTimeShow;
|
||||||
private LinearCurveEditor<T> _curve;
|
private LinearCurveEditor<T> _curve;
|
||||||
private Splitter _splitter;
|
private Splitter _splitter;
|
||||||
|
private string _heightCachedPath;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Initialize(LayoutElementsContainer layout)
|
public override void Initialize(LayoutElementsContainer layout)
|
||||||
{
|
{
|
||||||
var item = layout.CustomContainer<LinearCurveEditor<T>>();
|
var item = layout.CustomContainer<LinearCurveEditor<T>>();
|
||||||
_curve = item.CustomControl;
|
_curve = item.CustomControl;
|
||||||
_curve.Height = 120.0f;
|
var height = 120.0f;
|
||||||
|
var presenter = Presenter;
|
||||||
|
if (presenter != null && (presenter.Features & FeatureFlags.CacheExpandedGroups) != 0)
|
||||||
|
{
|
||||||
|
// Try to restore curve height
|
||||||
|
_heightCachedPath = layout.GetLayoutCachePath("Height");
|
||||||
|
if (Editor.Instance.ProjectCache.TryGetCustomData(_heightCachedPath, out float cachedHeight) && cachedHeight > 10.0f)
|
||||||
|
height = cachedHeight;
|
||||||
|
}
|
||||||
|
_curve.Height = height;
|
||||||
_curve.Edited += OnCurveEdited;
|
_curve.Edited += OnCurveEdited;
|
||||||
_firstTimeShow = 4; // For some weird reason it needs several frames of warmup (probably due to sliders smoothing)
|
_firstTimeShow = 4; // For some weird reason it needs several frames of warmup (probably due to sliders smoothing)
|
||||||
_splitter = new Splitter
|
_splitter = new Splitter
|
||||||
@@ -164,6 +188,10 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
private void OnSplitterMoved(Float2 location)
|
private void OnSplitterMoved(Float2 location)
|
||||||
{
|
{
|
||||||
_curve.Height = Mathf.Clamp(_splitter.PointToParent(location).Y, 50.0f, 1000.0f);
|
_curve.Height = Mathf.Clamp(_splitter.PointToParent(location).Y, 50.0f, 1000.0f);
|
||||||
|
|
||||||
|
// Cache curve height
|
||||||
|
if (_heightCachedPath != null)
|
||||||
|
Editor.Instance.ProjectCache.SetCustomData(_heightCachedPath, _curve.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ public class ModelPrefabEditor : GenericEditor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates the import path UI
|
||||||
|
Utilities.Utils.CreateImportPathUI(layout, modelPrefab.ImportPath, false);
|
||||||
|
|
||||||
var button = layout.Button("Reimport", "Reimports the source asset as prefab.");
|
var button = layout.Button("Reimport", "Reimports the source asset as prefab.");
|
||||||
_reimportButton = button.Button;
|
_reimportButton = button.Button;
|
||||||
_reimportButton.Clicked += OnReimport;
|
_reimportButton.Clicked += OnReimport;
|
||||||
|
|||||||
@@ -117,6 +117,9 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
var data = SurfaceUtils.InitGraphParameters(parametersGroup);
|
var data = SurfaceUtils.InitGraphParameters(parametersGroup);
|
||||||
SurfaceUtils.DisplayGraphParameters(group, data, ParameterGet, ParameterSet, Values, ParameterDefaultValue);
|
SurfaceUtils.DisplayGraphParameters(group, data, ParameterGet, ParameterSet, Values, ParameterDefaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!parameters.Any())
|
||||||
|
groups.Label("No parameters", TextAlignment.Center);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FlaxEditor.Content;
|
using FlaxEditor.Content;
|
||||||
using FlaxEditor.GUI;
|
using FlaxEditor.GUI;
|
||||||
|
using FlaxEditor.GUI.Drag;
|
||||||
using FlaxEditor.Scripting;
|
using FlaxEditor.Scripting;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
@@ -122,7 +123,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
{
|
{
|
||||||
base.Refresh();
|
base.Refresh();
|
||||||
|
|
||||||
if (!HasDifferentValues)
|
var differentValues = HasDifferentValues;
|
||||||
|
Picker.DifferentValues = differentValues;
|
||||||
|
if (!differentValues)
|
||||||
{
|
{
|
||||||
_isRefreshing = true;
|
_isRefreshing = true;
|
||||||
var value = Values[0];
|
var value = Values[0];
|
||||||
@@ -156,6 +159,17 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
private Rectangle DropdownRect => new Rectangle(Width - DropdownIconSize - DropdownIconMargin, DropdownIconMargin, DropdownIconSize, DropdownIconSize);
|
private Rectangle DropdownRect => new Rectangle(Width - DropdownIconSize - DropdownIconMargin, DropdownIconMargin, DropdownIconSize, DropdownIconSize);
|
||||||
|
|
||||||
public Action ShowPicker;
|
public Action ShowPicker;
|
||||||
|
public Action<ContentItem> OnAssetDropped;
|
||||||
|
|
||||||
|
private DragItems _dragItems;
|
||||||
|
private DragHandlers _dragHandlers;
|
||||||
|
private bool _hasValidDragOver;
|
||||||
|
private Func<ContentItem, bool> _validate;
|
||||||
|
|
||||||
|
public void SetValidationMethod(Func<ContentItem, bool> validate)
|
||||||
|
{
|
||||||
|
_validate = validate;
|
||||||
|
}
|
||||||
|
|
||||||
public override void Draw()
|
public override void Draw()
|
||||||
{
|
{
|
||||||
@@ -164,6 +178,14 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
var style = FlaxEngine.GUI.Style.Current;
|
var style = FlaxEngine.GUI.Style.Current;
|
||||||
var dropdownRect = DropdownRect;
|
var dropdownRect = DropdownRect;
|
||||||
Render2D.DrawSprite(style.ArrowDown, dropdownRect, Enabled ? (DropdownRect.Contains(PointFromWindow(RootWindow.MousePosition)) ? style.BorderSelected : style.Foreground) : style.ForegroundDisabled);
|
Render2D.DrawSprite(style.ArrowDown, dropdownRect, Enabled ? (DropdownRect.Contains(PointFromWindow(RootWindow.MousePosition)) ? style.BorderSelected : style.Foreground) : style.ForegroundDisabled);
|
||||||
|
|
||||||
|
// Check if drag is over
|
||||||
|
if (IsDragOver && _hasValidDragOver)
|
||||||
|
{
|
||||||
|
var bounds = new Rectangle(Float2.Zero, Size);
|
||||||
|
Render2D.FillRectangle(bounds, style.Selection);
|
||||||
|
Render2D.DrawRectangle(bounds, style.SelectionBorder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||||
@@ -207,6 +229,68 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DragDropEffect DragEffect => _hasValidDragOver ? DragDropEffect.Move : DragDropEffect.None;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override DragDropEffect OnDragEnter(ref Float2 location, DragData data)
|
||||||
|
{
|
||||||
|
base.OnDragEnter(ref location, data);
|
||||||
|
|
||||||
|
// Ensure to have valid drag helpers (uses lazy init)
|
||||||
|
if (_dragItems == null)
|
||||||
|
_dragItems = new DragItems(ValidateDragAsset);
|
||||||
|
if (_dragHandlers == null)
|
||||||
|
{
|
||||||
|
_dragHandlers = new DragHandlers
|
||||||
|
{
|
||||||
|
_dragItems,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_hasValidDragOver = _dragHandlers.OnDragEnter(data) != DragDropEffect.None;
|
||||||
|
|
||||||
|
|
||||||
|
return DragEffect;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ValidateDragAsset(ContentItem contentItem)
|
||||||
|
{
|
||||||
|
// Load or get asset
|
||||||
|
return _validate?.Invoke(contentItem) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override DragDropEffect OnDragMove(ref Float2 location, DragData data)
|
||||||
|
{
|
||||||
|
base.OnDragMove(ref location, data);
|
||||||
|
|
||||||
|
return DragEffect;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnDragLeave()
|
||||||
|
{
|
||||||
|
_hasValidDragOver = false;
|
||||||
|
_dragHandlers.OnDragLeave();
|
||||||
|
|
||||||
|
base.OnDragLeave();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override DragDropEffect OnDragDrop(ref Float2 location, DragData data)
|
||||||
|
{
|
||||||
|
var result = DragEffect;
|
||||||
|
|
||||||
|
base.OnDragDrop(ref location, data);
|
||||||
|
|
||||||
|
if (_dragItems.HasValidDrag)
|
||||||
|
{
|
||||||
|
OnAssetDropped(_dragItems.Objects[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextBoxWithPicker _textBox;
|
private TextBoxWithPicker _textBox;
|
||||||
@@ -221,13 +305,21 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
{
|
{
|
||||||
if (HasDifferentTypes)
|
if (HasDifferentTypes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
_validator = new AssetPickerValidator(ScriptType.Null);
|
||||||
_textBox = layout.Custom<TextBoxWithPicker>().CustomControl;
|
_textBox = layout.Custom<TextBoxWithPicker>().CustomControl;
|
||||||
_textBox.ShowPicker = OnShowPicker;
|
_textBox.ShowPicker = OnShowPicker;
|
||||||
|
_textBox.OnAssetDropped = OnItemDropped;
|
||||||
_textBox.EditEnd += OnEditEnd;
|
_textBox.EditEnd += OnEditEnd;
|
||||||
_validator = new AssetPickerValidator(ScriptType.Null);
|
_textBox.SetValidationMethod(_validator.IsValid);
|
||||||
AssetRefEditor.ApplyAssetReferenceAttribute(Values, out _, _validator);
|
AssetRefEditor.ApplyAssetReferenceAttribute(Values, out _, _validator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnItemDropped(ContentItem item)
|
||||||
|
{
|
||||||
|
SetPickerPath(item);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnShowPicker()
|
private void OnShowPicker()
|
||||||
{
|
{
|
||||||
if (_validator.AssetType != ScriptType.Null)
|
if (_validator.AssetType != ScriptType.Null)
|
||||||
@@ -285,12 +377,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
{
|
{
|
||||||
base.Refresh();
|
base.Refresh();
|
||||||
|
|
||||||
if (!HasDifferentValues)
|
_isRefreshing = true;
|
||||||
{
|
_textBox.Text = HasDifferentValues ? "Multiple Values" : GetPath();
|
||||||
_isRefreshing = true;
|
_isRefreshing = false;
|
||||||
_textBox.Text = GetPath();
|
|
||||||
_isRefreshing = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ using FlaxEditor.GUI.Drag;
|
|||||||
using FlaxEditor.SceneGraph;
|
using FlaxEditor.SceneGraph;
|
||||||
using FlaxEditor.SceneGraph.GUI;
|
using FlaxEditor.SceneGraph.GUI;
|
||||||
using FlaxEditor.Scripting;
|
using FlaxEditor.Scripting;
|
||||||
|
using FlaxEditor.Windows;
|
||||||
|
using FlaxEditor.Windows.Assets;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
using FlaxEngine.Utilities;
|
using FlaxEngine.Utilities;
|
||||||
@@ -40,6 +42,11 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
private DragScripts _dragScripts;
|
private DragScripts _dragScripts;
|
||||||
private DragHandlers _dragHandlers;
|
private DragHandlers _dragHandlers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The presenter using this control.
|
||||||
|
/// </summary>
|
||||||
|
public IPresenterOwner PresenterContext;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the allowed objects type (given type and all sub classes). Must be <see cref="Object"/> type of any subclass.
|
/// Gets or sets the allowed objects type (given type and all sub classes). Must be <see cref="Object"/> type of any subclass.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -129,6 +136,11 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<Object, ScriptType, bool> CheckValid;
|
public Func<Object, ScriptType, bool> CheckValid;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Utility flag used to indicate that there are different values assigned to this reference editor and user should be informed about it.
|
||||||
|
/// </summary>
|
||||||
|
public bool DifferentValues;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="FlaxObjectRefPickerControl"/> class.
|
/// Initializes a new instance of the <see cref="FlaxObjectRefPickerControl"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -154,7 +166,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
Value = actor;
|
Value = actor;
|
||||||
RootWindow.Focus();
|
RootWindow.Focus();
|
||||||
Focus();
|
Focus();
|
||||||
});
|
}, PresenterContext);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -163,7 +175,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
Value = script;
|
Value = script;
|
||||||
RootWindow.Focus();
|
RootWindow.Focus();
|
||||||
Focus();
|
Focus();
|
||||||
});
|
}, PresenterContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,7 +209,14 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
Render2D.DrawRectangle(frameRect, isEnabled && (IsMouseOver || IsNavFocused) ? style.BorderHighlighted : style.BorderNormal);
|
Render2D.DrawRectangle(frameRect, isEnabled && (IsMouseOver || IsNavFocused) ? style.BorderHighlighted : style.BorderNormal);
|
||||||
|
|
||||||
// Check if has item selected
|
// Check if has item selected
|
||||||
if (isSelected)
|
if (DifferentValues)
|
||||||
|
{
|
||||||
|
// Draw info
|
||||||
|
Render2D.PushClip(nameRect);
|
||||||
|
Render2D.DrawText(style.FontMedium, Type != null ? $"Multiple Values ({Utilities.Utils.GetPropertyNameUI(Type.ToString())})" : "-", nameRect, isEnabled ? style.ForegroundGrey : style.ForegroundGrey.AlphaMultiplied(0.75f), TextAlignment.Near, TextAlignment.Center);
|
||||||
|
Render2D.PopClip();
|
||||||
|
}
|
||||||
|
else if (isSelected)
|
||||||
{
|
{
|
||||||
// Draw name
|
// Draw name
|
||||||
Render2D.PushClip(nameRect);
|
Render2D.PushClip(nameRect);
|
||||||
@@ -415,13 +434,13 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
|
|
||||||
// Ensure to have valid drag helpers (uses lazy init)
|
// Ensure to have valid drag helpers (uses lazy init)
|
||||||
if (_dragActors == null)
|
if (_dragActors == null)
|
||||||
_dragActors = new DragActors(x => IsValid(x.Actor));
|
_dragActors = new DragActors(ValidateDragActor);
|
||||||
if (_dragActorsWithScript == null)
|
if (_dragActorsWithScript == null)
|
||||||
_dragActorsWithScript = new DragActors(ValidateDragActorWithScript);
|
_dragActorsWithScript = new DragActors(ValidateDragActorWithScript);
|
||||||
if (_dragAssets == null)
|
if (_dragAssets == null)
|
||||||
_dragAssets = new DragAssets(ValidateDragAsset);
|
_dragAssets = new DragAssets(ValidateDragAsset);
|
||||||
if (_dragScripts == null)
|
if (_dragScripts == null)
|
||||||
_dragScripts = new DragScripts(IsValid);
|
_dragScripts = new DragScripts(ValidateDragScript);
|
||||||
if (_dragHandlers == null)
|
if (_dragHandlers == null)
|
||||||
{
|
{
|
||||||
_dragHandlers = new DragHandlers
|
_dragHandlers = new DragHandlers
|
||||||
@@ -446,6 +465,43 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
return DragEffect;
|
return DragEffect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool ValidateDragActor(ActorNode a)
|
||||||
|
{
|
||||||
|
if (!IsValid(a.Actor))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (PresenterContext is PrefabWindow prefabWindow)
|
||||||
|
{
|
||||||
|
if (prefabWindow.Tree == a.TreeNode.ParentTree)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (PresenterContext is PropertiesWindow || PresenterContext == null)
|
||||||
|
{
|
||||||
|
if (a.ParentScene != null)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ValidateDragScript(Script script)
|
||||||
|
{
|
||||||
|
if (!IsValid(script))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (PresenterContext is PrefabWindow prefabWindow)
|
||||||
|
{
|
||||||
|
var actorNode = prefabWindow.Graph.Root.Find(script.Actor);
|
||||||
|
if (actorNode != null)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (PresenterContext is PropertiesWindow || PresenterContext == null)
|
||||||
|
{
|
||||||
|
if (script.Actor.HasScene)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private bool ValidateDragAsset(AssetItem assetItem)
|
private bool ValidateDragAsset(AssetItem assetItem)
|
||||||
{
|
{
|
||||||
// Check if can accept assets
|
// Check if can accept assets
|
||||||
@@ -464,7 +520,18 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
|
|
||||||
private bool ValidateDragActorWithScript(ActorNode node)
|
private bool ValidateDragActorWithScript(ActorNode node)
|
||||||
{
|
{
|
||||||
return node.Actor.Scripts.Any(IsValid);
|
bool isCorrectContext = false;
|
||||||
|
if (PresenterContext is PrefabWindow prefabWindow)
|
||||||
|
{
|
||||||
|
if (prefabWindow.Tree == node.TreeNode.ParentTree)
|
||||||
|
isCorrectContext = true;
|
||||||
|
}
|
||||||
|
else if (PresenterContext is PropertiesWindow || PresenterContext == null)
|
||||||
|
{
|
||||||
|
if (node.ParentScene != null)
|
||||||
|
isCorrectContext = true;
|
||||||
|
}
|
||||||
|
return node.Actor.Scripts.Any(IsValid) && isCorrectContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -536,6 +603,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
if (!HasDifferentTypes)
|
if (!HasDifferentTypes)
|
||||||
{
|
{
|
||||||
_element = layout.Custom<FlaxObjectRefPickerControl>();
|
_element = layout.Custom<FlaxObjectRefPickerControl>();
|
||||||
|
_element.CustomControl.PresenterContext = Presenter.Owner;
|
||||||
_element.CustomControl.Type = Values.Type.Type != typeof(object) || Values[0] == null ? Values.Type : TypeUtils.GetObjectType(Values[0]);
|
_element.CustomControl.Type = Values.Type.Type != typeof(object) || Values[0] == null ? Values.Type : TypeUtils.GetObjectType(Values[0]);
|
||||||
_element.CustomControl.ValueChanged += () => SetValue(_element.CustomControl.Value);
|
_element.CustomControl.ValueChanged += () => SetValue(_element.CustomControl.Value);
|
||||||
}
|
}
|
||||||
@@ -546,7 +614,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
{
|
{
|
||||||
base.Refresh();
|
base.Refresh();
|
||||||
|
|
||||||
if (!HasDifferentValues)
|
var differentValues = HasDifferentValues;
|
||||||
|
_element.CustomControl.DifferentValues = differentValues;
|
||||||
|
if (!differentValues)
|
||||||
{
|
{
|
||||||
_element.CustomControl.Value = Values[0] as Object;
|
_element.CustomControl.Value = Values[0] as Object;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -228,7 +228,6 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
// Handle Sliding
|
// Handle Sliding
|
||||||
if (AllowSlidingForDifferentValues && (isSliding || _slidingEnded))
|
if (AllowSlidingForDifferentValues && (isSliding || _slidingEnded))
|
||||||
{
|
{
|
||||||
// TODO: handle linked values
|
|
||||||
Float3 average = Float3.Zero;
|
Float3 average = Float3.Zero;
|
||||||
for (int i = 0; i < Values.Count; i++)
|
for (int i = 0; i < Values.Count; i++)
|
||||||
{
|
{
|
||||||
@@ -251,12 +250,24 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
for (int i = 0; i < Values.Count; i++)
|
for (int i = 0; i < Values.Count; i++)
|
||||||
{
|
{
|
||||||
var v = Values[i];
|
var v = Values[i];
|
||||||
if (v is Vector3 asVector3)
|
if (LinkValues)
|
||||||
v = asVector3 + new Vector3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
|
{
|
||||||
else if (v is Float3 asFloat3)
|
if (v is Vector3 asVector3)
|
||||||
v = asFloat3 + new Float3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
|
v = asVector3 + new Vector3(newValue.X, newValue.Y, newValue.Z);
|
||||||
else if (v is Double3 asDouble3)
|
else if (v is Float3 asFloat3)
|
||||||
v = asDouble3 + new Double3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
|
v = asFloat3 + new Float3(newValue.X, newValue.Y, newValue.Z);
|
||||||
|
else if (v is Double3 asDouble3)
|
||||||
|
v = asDouble3 + new Double3(newValue.X, newValue.Y, newValue.Z);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (v is Vector3 asVector3)
|
||||||
|
v = asVector3 + new Vector3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
|
||||||
|
else if (v is Float3 asFloat3)
|
||||||
|
v = asFloat3 + new Float3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
|
||||||
|
else if (v is Double3 asDouble3)
|
||||||
|
v = asDouble3 + new Double3(_valueChanged == ValueChanged.X ? newValue.X : 0, _valueChanged == ValueChanged.Y ? newValue.Y : 0, _valueChanged == ValueChanged.Z ? newValue.Z : 0);
|
||||||
|
}
|
||||||
|
|
||||||
newObjects[i] = v;
|
newObjects[i] = v;
|
||||||
}
|
}
|
||||||
@@ -267,16 +278,27 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: handle linked values
|
|
||||||
for (int i = 0; i < Values.Count; i++)
|
for (int i = 0; i < Values.Count; i++)
|
||||||
{
|
{
|
||||||
object v = Values[i];
|
object v = Values[i];
|
||||||
if (v is Vector3 asVector3)
|
if (LinkValues)
|
||||||
v = new Vector3(_valueChanged == ValueChanged.X ? xValue : asVector3.X, _valueChanged == ValueChanged.Y ? yValue : asVector3.Y, _valueChanged == ValueChanged.Z ? zValue : asVector3.Z);
|
{
|
||||||
else if (v is Float3 asFloat3)
|
if (v is Vector3 asVector3)
|
||||||
v = new Float3(_valueChanged == ValueChanged.X ? xValue : asFloat3.X, _valueChanged == ValueChanged.Y ? yValue : asFloat3.Y, _valueChanged == ValueChanged.Z ? zValue : asFloat3.Z);
|
v = asVector3 + new Vector3(xValue, yValue, zValue);
|
||||||
else if (v is Double3 asDouble3)
|
else if (v is Float3 asFloat3)
|
||||||
v = new Double3(_valueChanged == ValueChanged.X ? xValue : asDouble3.X, _valueChanged == ValueChanged.Y ? yValue : asDouble3.Y, _valueChanged == ValueChanged.Z ? zValue : asDouble3.Z);
|
v = asFloat3 + new Float3(xValue, yValue, zValue);
|
||||||
|
else if (v is Double3 asDouble3)
|
||||||
|
v = asDouble3 + new Double3(xValue, yValue, zValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (v is Vector3 asVector3)
|
||||||
|
v = new Vector3(_valueChanged == ValueChanged.X ? xValue : asVector3.X, _valueChanged == ValueChanged.Y ? yValue : asVector3.Y, _valueChanged == ValueChanged.Z ? zValue : asVector3.Z);
|
||||||
|
else if (v is Float3 asFloat3)
|
||||||
|
v = new Float3(_valueChanged == ValueChanged.X ? xValue : asFloat3.X, _valueChanged == ValueChanged.Y ? yValue : asFloat3.Y, _valueChanged == ValueChanged.Z ? zValue : asFloat3.Z);
|
||||||
|
else if (v is Double3 asDouble3)
|
||||||
|
v = new Double3(_valueChanged == ValueChanged.X ? xValue : asDouble3.X, _valueChanged == ValueChanged.Y ? yValue : asDouble3.Y, _valueChanged == ValueChanged.Z ? zValue : asDouble3.Z);
|
||||||
|
}
|
||||||
|
|
||||||
newObjects[i] = v;
|
newObjects[i] = v;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,20 @@ namespace FlaxEditor.CustomEditors
|
|||||||
menu.Show(groupPanel, location);
|
menu.Show(groupPanel, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal string GetLayoutCachePath(string name)
|
||||||
|
{
|
||||||
|
// Build group identifier (made of path from group titles)
|
||||||
|
var expandPath = name;
|
||||||
|
var container = this;
|
||||||
|
while (container != null && !(container is CustomEditorPresenter))
|
||||||
|
{
|
||||||
|
if (container.ContainerControl is DropPanel dropPanel)
|
||||||
|
expandPath = dropPanel.HeaderText + "/" + expandPath;
|
||||||
|
container = container._parent;
|
||||||
|
}
|
||||||
|
return expandPath;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds new group element.
|
/// Adds new group element.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -112,14 +126,7 @@ namespace FlaxEditor.CustomEditors
|
|||||||
if (presenter != null && (presenter.Features & FeatureFlags.CacheExpandedGroups) != 0)
|
if (presenter != null && (presenter.Features & FeatureFlags.CacheExpandedGroups) != 0)
|
||||||
{
|
{
|
||||||
// Build group identifier (made of path from group titles)
|
// Build group identifier (made of path from group titles)
|
||||||
var expandPath = title;
|
var expandPath = GetLayoutCachePath(title);
|
||||||
var container = this;
|
|
||||||
while (container != null && !(container is CustomEditorPresenter))
|
|
||||||
{
|
|
||||||
if (container.ContainerControl is DropPanel dropPanel)
|
|
||||||
expandPath = dropPanel.HeaderText + "/" + expandPath;
|
|
||||||
container = container._parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Caching/restoring expanded groups (non-root groups cache expanded state so invert boolean expression)
|
// Caching/restoring expanded groups (non-root groups cache expanded state so invert boolean expression)
|
||||||
if (Editor.Instance.ProjectCache.IsGroupToggled(expandPath) ^ isSubGroup)
|
if (Editor.Instance.ProjectCache.IsGroupToggled(expandPath) ^ isSubGroup)
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ namespace FlaxEditor.CustomEditors
|
|||||||
if (objA == null && objB is string objBStr && objBStr.Length == 0)
|
if (objA == null && objB is string objBStr && objBStr.Length == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return Newtonsoft.Json.Utilities.MiscellaneousUtils.ValueEquals(objA, objB);
|
return FlaxEngine.Json.JsonSerializer.ValueEquals(objA, objB);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -550,7 +550,7 @@ int32 Editor::LoadProduct()
|
|||||||
}
|
}
|
||||||
if (!FileSystem::FileExists(files[0]))
|
if (!FileSystem::FileExists(files[0]))
|
||||||
{
|
{
|
||||||
Platform::Fatal(TEXT("Cannot opoen selected project file because it doesn't exist."));
|
Platform::Fatal(TEXT("Cannot open selected project file because it doesn't exist."));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
projectPath = StringUtils::GetDirectoryName(files[0]);
|
projectPath = StringUtils::GetDirectoryName(files[0]);
|
||||||
|
|||||||
@@ -1686,9 +1686,6 @@ namespace FlaxEditor
|
|||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static partial bool Internal_CanSetToRoot(IntPtr prefab, IntPtr newRoot);
|
internal static partial bool Internal_CanSetToRoot(IntPtr prefab, IntPtr newRoot);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetPrefabNestedObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
|
||||||
internal static partial void Internal_GetPrefabNestedObject(IntPtr prefabId, IntPtr prefabObjectId, IntPtr outPrefabId, IntPtr outPrefabObjectId);
|
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||||
internal static partial float Internal_GetAnimationTime(IntPtr animatedModel);
|
internal static partial float Internal_GetAnimationTime(IntPtr animatedModel);
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,11 @@ namespace FlaxEditor.GUI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanEdit = true;
|
public bool CanEdit = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Utility flag used to indicate that there are different values assigned to this reference editor and user should be informed about it.
|
||||||
|
/// </summary>
|
||||||
|
public bool DifferentValues;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="AssetPicker"/> class.
|
/// Initializes a new instance of the <see cref="AssetPicker"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -121,7 +126,13 @@ namespace FlaxEditor.GUI
|
|||||||
if (CanEdit)
|
if (CanEdit)
|
||||||
Render2D.DrawSprite(style.ArrowDown, button1Rect, button1Rect.Contains(_mousePos) ? style.Foreground : style.ForegroundGrey);
|
Render2D.DrawSprite(style.ArrowDown, button1Rect, button1Rect.Contains(_mousePos) ? style.Foreground : style.ForegroundGrey);
|
||||||
|
|
||||||
if (Validator.SelectedItem != null)
|
if (DifferentValues)
|
||||||
|
{
|
||||||
|
// No element selected
|
||||||
|
Render2D.FillRectangle(iconRect, style.BackgroundNormal);
|
||||||
|
Render2D.DrawText(style.FontMedium, "Multiple\nValues", iconRect, style.Foreground, TextAlignment.Center, TextAlignment.Center, TextWrapping.NoWrap, 1.0f, Height / DefaultIconSize);
|
||||||
|
}
|
||||||
|
else if (Validator.SelectedItem != null)
|
||||||
{
|
{
|
||||||
// Draw item preview
|
// Draw item preview
|
||||||
Validator.SelectedItem.DrawThumbnail(ref iconRect);
|
Validator.SelectedItem.DrawThumbnail(ref iconRect);
|
||||||
|
|||||||
@@ -30,8 +30,10 @@ namespace FlaxEditor.GUI
|
|||||||
internal bool _isMovingTangent;
|
internal bool _isMovingTangent;
|
||||||
internal bool _movedView;
|
internal bool _movedView;
|
||||||
internal bool _movedKeyframes;
|
internal bool _movedKeyframes;
|
||||||
|
internal bool _toggledSelection;
|
||||||
private TangentPoint _movingTangent;
|
private TangentPoint _movingTangent;
|
||||||
private Float2 _movingSelectionStart;
|
private Float2 _movingSelectionStart;
|
||||||
|
private Float2 _movingSelectionStartPosLock;
|
||||||
private Float2[] _movingSelectionOffsets;
|
private Float2[] _movingSelectionOffsets;
|
||||||
private Float2 _cmShowPos;
|
private Float2 _cmShowPos;
|
||||||
|
|
||||||
@@ -56,12 +58,11 @@ namespace FlaxEditor.GUI
|
|||||||
internal void UpdateSelection(ref Rectangle selectionRect)
|
internal void UpdateSelection(ref Rectangle selectionRect)
|
||||||
{
|
{
|
||||||
// Find controls to select
|
// Find controls to select
|
||||||
for (int i = 0; i < Children.Count; i++)
|
var children = _children;
|
||||||
|
for (int i = 0; i < children.Count; i++)
|
||||||
{
|
{
|
||||||
if (Children[i] is KeyframePoint p)
|
if (children[i] is KeyframePoint p)
|
||||||
{
|
|
||||||
p.IsSelected = p.Bounds.Intersects(ref selectionRect);
|
p.IsSelected = p.Bounds.Intersects(ref selectionRect);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_editor.UpdateTangents();
|
_editor.UpdateTangents();
|
||||||
}
|
}
|
||||||
@@ -72,6 +73,7 @@ namespace FlaxEditor.GUI
|
|||||||
_isMovingSelection = true;
|
_isMovingSelection = true;
|
||||||
_movedKeyframes = false;
|
_movedKeyframes = false;
|
||||||
var viewRect = _editor._mainPanel.GetClientArea();
|
var viewRect = _editor._mainPanel.GetClientArea();
|
||||||
|
_movingSelectionStartPosLock = location;
|
||||||
_movingSelectionStart = PointToKeyframes(location, ref viewRect);
|
_movingSelectionStart = PointToKeyframes(location, ref viewRect);
|
||||||
if (_movingSelectionOffsets == null || _movingSelectionOffsets.Length != _editor._points.Count)
|
if (_movingSelectionOffsets == null || _movingSelectionOffsets.Length != _editor._points.Count)
|
||||||
_movingSelectionOffsets = new Float2[_editor._points.Count];
|
_movingSelectionOffsets = new Float2[_editor._points.Count];
|
||||||
@@ -82,10 +84,17 @@ namespace FlaxEditor.GUI
|
|||||||
|
|
||||||
internal void OnMove(Float2 location)
|
internal void OnMove(Float2 location)
|
||||||
{
|
{
|
||||||
|
// Skip updating keyframes until move actual starts to be meaningful
|
||||||
|
if (Float2.Distance(ref _movingSelectionStartPosLock, ref location) < 1.5f)
|
||||||
|
return;
|
||||||
|
_movingSelectionStartPosLock = Float2.Minimum;
|
||||||
|
|
||||||
var viewRect = _editor._mainPanel.GetClientArea();
|
var viewRect = _editor._mainPanel.GetClientArea();
|
||||||
var locationKeyframes = PointToKeyframes(location, ref viewRect);
|
var locationKeyframes = PointToKeyframes(location, ref viewRect);
|
||||||
var accessor = _editor.Accessor;
|
var accessor = _editor.Accessor;
|
||||||
var components = accessor.GetCurveComponents();
|
var components = accessor.GetCurveComponents();
|
||||||
|
var snapEnabled = Root.GetKey(KeyboardKeys.Control);
|
||||||
|
var snapGrid = snapEnabled ? _editor.GetGridSnap() : Float2.One;
|
||||||
for (var i = 0; i < _editor._points.Count; i++)
|
for (var i = 0; i < _editor._points.Count; i++)
|
||||||
{
|
{
|
||||||
var p = _editor._points[i];
|
var p = _editor._points[i];
|
||||||
@@ -122,7 +131,20 @@ namespace FlaxEditor.GUI
|
|||||||
if (isFirstSelected)
|
if (isFirstSelected)
|
||||||
{
|
{
|
||||||
time = locationKeyframes.X + offset.X;
|
time = locationKeyframes.X + offset.X;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snapEnabled)
|
||||||
|
{
|
||||||
|
// Snap to the grid
|
||||||
|
var key = new Float2(time, value);
|
||||||
|
key = Float2.SnapToGrid(key, snapGrid);
|
||||||
|
time = key.X;
|
||||||
|
value = key.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp and snap time to the valid range
|
||||||
|
if (isFirstSelected)
|
||||||
|
{
|
||||||
if (_editor.FPS.HasValue)
|
if (_editor.FPS.HasValue)
|
||||||
{
|
{
|
||||||
float fps = _editor.FPS.Value;
|
float fps = _editor.FPS.Value;
|
||||||
@@ -131,8 +153,6 @@ namespace FlaxEditor.GUI
|
|||||||
time = Mathf.Clamp(time, minTime, maxTime);
|
time = Mathf.Clamp(time, minTime, maxTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: snapping keyframes to grid when moving
|
|
||||||
|
|
||||||
_editor.SetKeyframeInternal(p.Index, time, value, p.Component);
|
_editor.SetKeyframeInternal(p.Index, time, value, p.Component);
|
||||||
}
|
}
|
||||||
_editor.UpdateKeyframes();
|
_editor.UpdateKeyframes();
|
||||||
@@ -234,7 +254,11 @@ namespace FlaxEditor.GUI
|
|||||||
var k = _editor.GetKeyframe(_movingTangent.Index);
|
var k = _editor.GetKeyframe(_movingTangent.Index);
|
||||||
var kv = _editor.GetKeyframeValue(k);
|
var kv = _editor.GetKeyframeValue(k);
|
||||||
var value = _editor.Accessor.GetCurveValue(ref kv, _movingTangent.Component);
|
var value = _editor.Accessor.GetCurveValue(ref kv, _movingTangent.Component);
|
||||||
_movingTangent.TangentValue = PointToKeyframes(location, ref viewRect).Y - value;
|
var tangent = PointToKeyframes(location, ref viewRect).Y - value;
|
||||||
|
if (Root.GetKey(KeyboardKeys.Control))
|
||||||
|
tangent = Float2.SnapToGrid(new Float2(0, tangent), _editor.GetGridSnap()).Y; // Snap tangent over Y axis
|
||||||
|
tangent = tangent * _editor.ViewScale.X * 2;
|
||||||
|
_movingTangent.TangentValue = tangent;
|
||||||
_editor.UpdateTangents();
|
_editor.UpdateTangents();
|
||||||
Cursor = CursorType.SizeNS;
|
Cursor = CursorType.SizeNS;
|
||||||
_movedKeyframes = true;
|
_movedKeyframes = true;
|
||||||
@@ -283,6 +307,7 @@ namespace FlaxEditor.GUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cache data
|
// Cache data
|
||||||
|
_toggledSelection = false;
|
||||||
_isMovingSelection = false;
|
_isMovingSelection = false;
|
||||||
_isMovingTangent = false;
|
_isMovingTangent = false;
|
||||||
_mousePos = location;
|
_mousePos = location;
|
||||||
@@ -305,13 +330,7 @@ namespace FlaxEditor.GUI
|
|||||||
{
|
{
|
||||||
if (_leftMouseDown)
|
if (_leftMouseDown)
|
||||||
{
|
{
|
||||||
if (Root.GetKey(KeyboardKeys.Control))
|
if (Root.GetKey(KeyboardKeys.Shift))
|
||||||
{
|
|
||||||
// Toggle selection
|
|
||||||
keyframe.IsSelected = !keyframe.IsSelected;
|
|
||||||
_editor.UpdateTangents();
|
|
||||||
}
|
|
||||||
else if (Root.GetKey(KeyboardKeys.Shift))
|
|
||||||
{
|
{
|
||||||
// Select range
|
// Select range
|
||||||
keyframe.IsSelected = true;
|
keyframe.IsSelected = true;
|
||||||
@@ -335,10 +354,14 @@ namespace FlaxEditor.GUI
|
|||||||
else if (!keyframe.IsSelected)
|
else if (!keyframe.IsSelected)
|
||||||
{
|
{
|
||||||
// Select node
|
// Select node
|
||||||
if (_editor.KeyframesEditorContext != null)
|
if (!Root.GetKey(KeyboardKeys.Control))
|
||||||
_editor.KeyframesEditorContext.OnKeyframesDeselect(_editor);
|
{
|
||||||
else
|
if (_editor.KeyframesEditorContext != null)
|
||||||
_editor.ClearSelection();
|
_editor.KeyframesEditorContext.OnKeyframesDeselect(_editor);
|
||||||
|
else
|
||||||
|
_editor.ClearSelection();
|
||||||
|
}
|
||||||
|
_toggledSelection = true;
|
||||||
keyframe.IsSelected = true;
|
keyframe.IsSelected = true;
|
||||||
_editor.UpdateTangents();
|
_editor.UpdateTangents();
|
||||||
}
|
}
|
||||||
@@ -429,6 +452,12 @@ namespace FlaxEditor.GUI
|
|||||||
else
|
else
|
||||||
OnMoveEnd(location);
|
OnMoveEnd(location);
|
||||||
}
|
}
|
||||||
|
// Toggle selection
|
||||||
|
else if (!_toggledSelection && Root.GetKey(KeyboardKeys.Control) && GetChildAt(location) is KeyframePoint keyframe)
|
||||||
|
{
|
||||||
|
keyframe.IsSelected = !keyframe.IsSelected;
|
||||||
|
_editor.UpdateTangents();
|
||||||
|
}
|
||||||
|
|
||||||
_isMovingSelection = false;
|
_isMovingSelection = false;
|
||||||
_isMovingTangent = false;
|
_isMovingTangent = false;
|
||||||
@@ -514,11 +543,11 @@ namespace FlaxEditor.GUI
|
|||||||
{
|
{
|
||||||
if (base.OnMouseDoubleClick(location, button))
|
if (base.OnMouseDoubleClick(location, button))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Add keyframe on double click
|
// Add keyframe on double click
|
||||||
var child = GetChildAt(location);
|
var child = GetChildAt(location);
|
||||||
if (child is not KeyframePoint &&
|
if (child is not KeyframePoint &&
|
||||||
child is not TangentPoint &&
|
child is not TangentPoint &&
|
||||||
_editor.KeyframesCount < _editor.MaxKeyframes)
|
_editor.KeyframesCount < _editor.MaxKeyframes)
|
||||||
{
|
{
|
||||||
var viewRect = _editor._mainPanel.GetClientArea();
|
var viewRect = _editor._mainPanel.GetClientArea();
|
||||||
@@ -545,7 +574,7 @@ namespace FlaxEditor.GUI
|
|||||||
var viewRect = _editor._mainPanel.GetClientArea();
|
var viewRect = _editor._mainPanel.GetClientArea();
|
||||||
var locationInKeyframes = PointToKeyframes(location, ref viewRect);
|
var locationInKeyframes = PointToKeyframes(location, ref viewRect);
|
||||||
var locationInEditorBefore = _editor.PointFromKeyframes(locationInKeyframes, ref viewRect);
|
var locationInEditorBefore = _editor.PointFromKeyframes(locationInKeyframes, ref viewRect);
|
||||||
|
|
||||||
// Scale relative to the curve size
|
// Scale relative to the curve size
|
||||||
var scale = new Float2(delta * 0.1f);
|
var scale = new Float2(delta * 0.1f);
|
||||||
_editor._mainPanel.GetDesireClientArea(out var mainPanelArea);
|
_editor._mainPanel.GetDesireClientArea(out var mainPanelArea);
|
||||||
|
|||||||
@@ -163,10 +163,11 @@ namespace FlaxEditor.GUI
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Draw()
|
public override void Draw()
|
||||||
{
|
{
|
||||||
|
var style = Style.Current;
|
||||||
var rect = new Rectangle(Float2.Zero, Size);
|
var rect = new Rectangle(Float2.Zero, Size);
|
||||||
var color = Editor.ShowCollapsed ? Color.Gray : Editor.Colors[Component];
|
var color = Editor.ShowCollapsed ? style.ForegroundDisabled : Editor.Colors[Component];
|
||||||
if (IsSelected)
|
if (IsSelected)
|
||||||
color = Editor.ContainsFocus ? Color.YellowGreen : Color.Lerp(Color.Gray, Color.YellowGreen, 0.4f);
|
color = Editor.ContainsFocus ? style.SelectionBorder : Color.Lerp(style.ForegroundDisabled, style.SelectionBorder, 0.4f);
|
||||||
if (IsMouseOver)
|
if (IsMouseOver)
|
||||||
color *= 1.1f;
|
color *= 1.1f;
|
||||||
Render2D.FillRectangle(rect, color);
|
Render2D.FillRectangle(rect, color);
|
||||||
@@ -244,14 +245,19 @@ namespace FlaxEditor.GUI
|
|||||||
set => Editor.SetKeyframeTangentInternal(Index, IsIn, Component, value);
|
set => Editor.SetKeyframeTangentInternal(Index, IsIn, Component, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal float TangentOffset => 50.0f / Editor.ViewScale.X;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Draw()
|
public override void Draw()
|
||||||
{
|
{
|
||||||
|
var style = Style.Current;
|
||||||
|
var thickness = 6.0f / Mathf.Max(Editor.ViewScale.X, 1.0f);
|
||||||
|
var size = Size;
|
||||||
var pointPos = PointFromParent(Point.Center);
|
var pointPos = PointFromParent(Point.Center);
|
||||||
Render2D.DrawLine(Size * 0.5f, pointPos, Color.Gray);
|
Render2D.DrawLine(size * 0.5f, pointPos, style.ForegroundDisabled, thickness);
|
||||||
|
|
||||||
var rect = new Rectangle(Float2.Zero, Size);
|
var rect = new Rectangle(Float2.Zero, size);
|
||||||
var color = Color.MediumVioletRed;
|
var color = style.BorderSelected;
|
||||||
if (IsMouseOver)
|
if (IsMouseOver)
|
||||||
color *= 1.1f;
|
color *= 1.1f;
|
||||||
Render2D.FillRectangle(rect, color);
|
Render2D.FillRectangle(rect, color);
|
||||||
@@ -289,7 +295,7 @@ namespace FlaxEditor.GUI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The curve time/value axes tick steps.
|
/// The curve time/value axes tick steps.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected float[] TickSteps = Utilities.Utils.CurveTickSteps;
|
protected double[] TickSteps = Utilities.Utils.CurveTickSteps;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The curve contents area.
|
/// The curve contents area.
|
||||||
@@ -442,7 +448,7 @@ namespace FlaxEditor.GUI
|
|||||||
_mainPanel = new Panel(ScrollBars.Both)
|
_mainPanel = new Panel(ScrollBars.Both)
|
||||||
{
|
{
|
||||||
ScrollMargin = new Margin(150.0f),
|
ScrollMargin = new Margin(150.0f),
|
||||||
AlwaysShowScrollbars = true,
|
AlwaysShowScrollbars = false,
|
||||||
AnchorPreset = AnchorPresets.StretchAll,
|
AnchorPreset = AnchorPresets.StretchAll,
|
||||||
Offsets = Margin.Zero,
|
Offsets = Margin.Zero,
|
||||||
Parent = this
|
Parent = this
|
||||||
@@ -668,26 +674,82 @@ namespace FlaxEditor.GUI
|
|||||||
OnEditingEnd();
|
OnEditingEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ShowCurve(bool selectedOnly)
|
||||||
|
{
|
||||||
|
if (_points.Count == 0)
|
||||||
|
return;
|
||||||
|
int pass = 1;
|
||||||
|
REDO:
|
||||||
|
|
||||||
|
// Get curve bounds in Keyframes (time and value)
|
||||||
|
Float2 posMin = Float2.Maximum, posMax = Float2.Minimum;
|
||||||
|
// TODO: include bezier curve bounds calculation to handle curve outside the bounds made out of points
|
||||||
|
foreach (var point in _points)
|
||||||
|
{
|
||||||
|
if (selectedOnly && !point.IsSelected)
|
||||||
|
continue;
|
||||||
|
var pos = point.Point;
|
||||||
|
Float2.Min(ref posMin, ref pos, out posMin);
|
||||||
|
Float2.Max(ref posMax, ref pos, out posMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply margin around the area
|
||||||
|
var posMargin = (posMax - posMin) * 0.05f;
|
||||||
|
posMin -= posMargin;
|
||||||
|
posMax += posMargin;
|
||||||
|
|
||||||
|
// Convert from Keyframes to Contents
|
||||||
|
_mainPanel.GetDesireClientArea(out var viewRect);
|
||||||
|
PointFromKeyframesToContents(ref posMin, ref viewRect);
|
||||||
|
PointFromKeyframesToContents(ref posMax, ref viewRect);
|
||||||
|
var tmp = posMin;
|
||||||
|
Float2.Min(ref posMin, ref posMax, out posMin);
|
||||||
|
Float2.Max(ref posMax, ref tmp, out posMax);
|
||||||
|
var contentsSize = posMax - posMin;
|
||||||
|
|
||||||
|
// Convert from Contents to Main Panel
|
||||||
|
posMin = _contents.PointToParent(posMin);
|
||||||
|
posMax = _contents.PointToParent(posMax);
|
||||||
|
tmp = posMin;
|
||||||
|
Float2.Min(ref posMin, ref posMax, out posMin);
|
||||||
|
Float2.Max(ref posMax, ref tmp, out posMax);
|
||||||
|
|
||||||
|
// Update zoom (leave unchanged when focusing a single point)
|
||||||
|
var zoomMask = EnableZoom;
|
||||||
|
if (Mathf.IsZero(posMargin.X))
|
||||||
|
zoomMask &= ~UseMode.Horizontal;
|
||||||
|
if (Mathf.IsZero(posMargin.Y))
|
||||||
|
zoomMask &= ~UseMode.Vertical;
|
||||||
|
ViewScale = ApplyUseModeMask(zoomMask, viewRect.Size / contentsSize, ViewScale);
|
||||||
|
|
||||||
|
// Update scroll (attempt to center the area when it's smaller than the view)
|
||||||
|
Float2 viewOffset = -posMin;
|
||||||
|
Float2 viewSize = _mainPanel.Size;
|
||||||
|
Float2 viewSizeLeft = viewSize - Float2.Clamp(posMax - posMin, Float2.Zero, viewSize);
|
||||||
|
viewOffset += viewSizeLeft * 0.5f;
|
||||||
|
viewOffset = ApplyUseModeMask(EnablePanning, viewOffset, _mainPanel.ViewOffset);
|
||||||
|
_mainPanel.ViewOffset = viewOffset;
|
||||||
|
|
||||||
|
// Do it multiple times so the view offset can be properly calculate once the view scale gets changes
|
||||||
|
if (pass++ <= 2)
|
||||||
|
goto REDO;
|
||||||
|
|
||||||
|
UpdateKeyframes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Focuses the view on the selected keyframes.
|
||||||
|
/// </summary>
|
||||||
|
public void FocusSelection()
|
||||||
|
{
|
||||||
|
// Fallback to showing whole curve if nothing is selected
|
||||||
|
ShowCurve(SelectionCount != 0);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void ShowWholeCurve()
|
public override void ShowWholeCurve()
|
||||||
{
|
{
|
||||||
_mainPanel.GetDesireClientArea(out var mainPanelArea);
|
ShowCurve(false);
|
||||||
ViewScale = ApplyUseModeMask(EnableZoom, mainPanelArea.Size / _contents.Size, ViewScale);
|
|
||||||
Float2 minPos = Float2.Maximum;
|
|
||||||
foreach (var point in _points)
|
|
||||||
{
|
|
||||||
var pos = point.PointToParent(point.Location);
|
|
||||||
Float2.Min(ref minPos, ref pos, out minPos);
|
|
||||||
}
|
|
||||||
var minPosPoint = _contents.PointToParent(ref minPos);
|
|
||||||
var scroll = new Float2(_mainPanel.HScrollBar?.TargetValue ?? 0, _mainPanel.VScrollBar?.TargetValue ?? 0);
|
|
||||||
scroll = ApplyUseModeMask(EnablePanning, minPosPoint, scroll);
|
|
||||||
if (_mainPanel.HScrollBar != null)
|
|
||||||
_mainPanel.HScrollBar.TargetValue = scroll.X;
|
|
||||||
if (_mainPanel.VScrollBar != null)
|
|
||||||
_mainPanel.VScrollBar.TargetValue = scroll.Y;
|
|
||||||
|
|
||||||
UpdateKeyframes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -766,10 +828,7 @@ namespace FlaxEditor.GUI
|
|||||||
point = _contents.PointFromParent(point);
|
point = _contents.PointFromParent(point);
|
||||||
|
|
||||||
// Contents -> Keyframes
|
// Contents -> Keyframes
|
||||||
return new Float2(
|
return PointFromContentsToKeyframes(ref point, ref curveContentAreaBounds);
|
||||||
(point.X + _contents.Location.X) / UnitsPerSecond,
|
|
||||||
(point.Y + _contents.Location.Y - curveContentAreaBounds.Height) / -UnitsPerSecond
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -781,10 +840,7 @@ namespace FlaxEditor.GUI
|
|||||||
protected Float2 PointFromKeyframes(Float2 point, ref Rectangle curveContentAreaBounds)
|
protected Float2 PointFromKeyframes(Float2 point, ref Rectangle curveContentAreaBounds)
|
||||||
{
|
{
|
||||||
// Keyframes -> Contents
|
// Keyframes -> Contents
|
||||||
point = new Float2(
|
PointFromKeyframesToContents(ref point, ref curveContentAreaBounds);
|
||||||
point.X * UnitsPerSecond - _contents.Location.X,
|
|
||||||
point.Y * -UnitsPerSecond + curveContentAreaBounds.Height - _contents.Location.Y
|
|
||||||
);
|
|
||||||
|
|
||||||
// Contents -> Main Panel
|
// Contents -> Main Panel
|
||||||
point = _contents.PointToParent(point);
|
point = _contents.PointToParent(point);
|
||||||
@@ -793,11 +849,27 @@ namespace FlaxEditor.GUI
|
|||||||
return _mainPanel.PointToParent(point);
|
return _mainPanel.PointToParent(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal Float2 PointFromContentsToKeyframes(ref Float2 point, ref Rectangle curveContentAreaBounds)
|
||||||
|
{
|
||||||
|
return new Float2(
|
||||||
|
(point.X + _contents.Location.X) / UnitsPerSecond,
|
||||||
|
(point.Y + _contents.Location.Y - curveContentAreaBounds.Height) / -UnitsPerSecond
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void PointFromKeyframesToContents(ref Float2 point, ref Rectangle curveContentAreaBounds)
|
||||||
|
{
|
||||||
|
point = new Float2(
|
||||||
|
point.X * UnitsPerSecond - _contents.Location.X,
|
||||||
|
point.Y * -UnitsPerSecond + curveContentAreaBounds.Height - _contents.Location.Y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private void DrawAxis(Float2 axis, Rectangle viewRect, float min, float max, float pixelRange)
|
private void DrawAxis(Float2 axis, Rectangle viewRect, float min, float max, float pixelRange)
|
||||||
{
|
{
|
||||||
Utilities.Utils.DrawCurveTicks((float tick, float strength) =>
|
Utilities.Utils.DrawCurveTicks((decimal tick, double step, float strength) =>
|
||||||
{
|
{
|
||||||
var p = PointFromKeyframes(axis * tick, ref viewRect);
|
var p = PointFromKeyframes(axis * (float)tick, ref viewRect);
|
||||||
|
|
||||||
// Draw line
|
// Draw line
|
||||||
var lineRect = new Rectangle
|
var lineRect = new Rectangle
|
||||||
@@ -820,6 +892,24 @@ namespace FlaxEditor.GUI
|
|||||||
}, TickSteps, ref _tickStrengths, min, max, pixelRange);
|
}, TickSteps, ref _tickStrengths, min, max, pixelRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetupGrid(out Float2 min, out Float2 max, out Float2 pixelRange)
|
||||||
|
{
|
||||||
|
var viewRect = _mainPanel.GetClientArea();
|
||||||
|
var upperLeft = PointToKeyframes(viewRect.Location, ref viewRect);
|
||||||
|
var bottomRight = PointToKeyframes(viewRect.Size, ref viewRect);
|
||||||
|
|
||||||
|
min = Float2.Min(upperLeft, bottomRight);
|
||||||
|
max = Float2.Max(upperLeft, bottomRight);
|
||||||
|
pixelRange = (max - min) * ViewScale * UnitsPerSecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Float2 GetGridSnap()
|
||||||
|
{
|
||||||
|
SetupGrid(out var min, out var max, out var pixelRange);
|
||||||
|
return new Float2(Utilities.Utils.GetCurveGridSnap(TickSteps, ref _tickStrengths, min.X, max.X, pixelRange.X),
|
||||||
|
Utilities.Utils.GetCurveGridSnap(TickSteps, ref _tickStrengths, min.Y, max.Y, pixelRange.Y));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Draws the curve.
|
/// Draws the curve.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -849,12 +939,7 @@ namespace FlaxEditor.GUI
|
|||||||
// Draw time and values axes
|
// Draw time and values axes
|
||||||
if (ShowAxes != UseMode.Off)
|
if (ShowAxes != UseMode.Off)
|
||||||
{
|
{
|
||||||
var upperLeft = PointToKeyframes(viewRect.Location, ref viewRect);
|
SetupGrid(out var min, out var max, out var pixelRange);
|
||||||
var bottomRight = PointToKeyframes(viewRect.Size, ref viewRect);
|
|
||||||
|
|
||||||
var min = Float2.Min(upperLeft, bottomRight);
|
|
||||||
var max = Float2.Max(upperLeft, bottomRight);
|
|
||||||
var pixelRange = (max - min) * ViewScale * UnitsPerSecond;
|
|
||||||
|
|
||||||
Render2D.PushClip(ref viewRect);
|
Render2D.PushClip(ref viewRect);
|
||||||
|
|
||||||
@@ -939,7 +1024,7 @@ namespace FlaxEditor.GUI
|
|||||||
}
|
}
|
||||||
else if (options.FocusSelection.Process(this))
|
else if (options.FocusSelection.Process(this))
|
||||||
{
|
{
|
||||||
ShowWholeCurve();
|
FocusSelection();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2200,7 +2285,7 @@ namespace FlaxEditor.GUI
|
|||||||
|
|
||||||
var tangent = t.TangentValue;
|
var tangent = t.TangentValue;
|
||||||
var direction = t.IsIn ? -1.0f : 1.0f;
|
var direction = t.IsIn ? -1.0f : 1.0f;
|
||||||
var offset = 30.0f;
|
var offset = t.TangentOffset;
|
||||||
var location = GetKeyframePoint(ref k, selectedComponent);
|
var location = GetKeyframePoint(ref k, selectedComponent);
|
||||||
t.Size = KeyframesSize / ViewScale;
|
t.Size = KeyframesSize / ViewScale;
|
||||||
t.Location = new Float2
|
t.Location = new Float2
|
||||||
@@ -2227,6 +2312,18 @@ namespace FlaxEditor.GUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void SetScaleInternal(ref Float2 scale)
|
||||||
|
{
|
||||||
|
base.SetScaleInternal(ref scale);
|
||||||
|
|
||||||
|
if (!_showCollapsed)
|
||||||
|
{
|
||||||
|
// Refresh keyframes when zooming (their size depends on the scale)
|
||||||
|
UpdateKeyframes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnShowContextMenu(ContextMenu.ContextMenu cm, int selectionCount)
|
protected override void OnShowContextMenu(ContextMenu.ContextMenu cm, int selectionCount)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using FlaxEditor.Windows;
|
||||||
|
using FlaxEditor.Windows.Assets;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
|
|
||||||
@@ -55,18 +57,26 @@ namespace FlaxEditor.GUI
|
|||||||
private IsValidDelegate _isValid;
|
private IsValidDelegate _isValid;
|
||||||
private Action<Actor> _selected;
|
private Action<Actor> _selected;
|
||||||
|
|
||||||
private ActorSearchPopup(IsValidDelegate isValid, Action<Actor> selected)
|
private ActorSearchPopup(IsValidDelegate isValid, Action<Actor> selected, CustomEditors.IPresenterOwner context)
|
||||||
{
|
{
|
||||||
_isValid = isValid;
|
_isValid = isValid;
|
||||||
_selected = selected;
|
_selected = selected;
|
||||||
|
|
||||||
ItemClicked += OnItemClicked;
|
ItemClicked += OnItemClicked;
|
||||||
|
|
||||||
// TODO: use async thread to search scenes
|
if (context is PropertiesWindow propertiesWindow || context == null)
|
||||||
for (int i = 0; i < Level.ScenesCount; i++)
|
|
||||||
{
|
{
|
||||||
Find(Level.GetScene(i));
|
// TODO: use async thread to search scenes
|
||||||
|
for (int i = 0; i < Level.ScenesCount; i++)
|
||||||
|
{
|
||||||
|
Find(Level.GetScene(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else if (context is PrefabWindow prefabWindow)
|
||||||
|
{
|
||||||
|
Find(prefabWindow.Graph.MainActor);
|
||||||
|
}
|
||||||
|
|
||||||
SortItems();
|
SortItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,10 +108,11 @@ namespace FlaxEditor.GUI
|
|||||||
/// <param name="showTargetLocation">The show target location.</param>
|
/// <param name="showTargetLocation">The show target location.</param>
|
||||||
/// <param name="isValid">Event called to check if a given actor item is valid to be used.</param>
|
/// <param name="isValid">Event called to check if a given actor item is valid to be used.</param>
|
||||||
/// <param name="selected">Event called on actor item pick.</param>
|
/// <param name="selected">Event called on actor item pick.</param>
|
||||||
|
/// <param name="context">The presenter owner context (i.e. PrefabWindow, PropertiesWindow).</param>
|
||||||
/// <returns>The dialog.</returns>
|
/// <returns>The dialog.</returns>
|
||||||
public static ActorSearchPopup Show(Control showTarget, Float2 showTargetLocation, IsValidDelegate isValid, Action<Actor> selected)
|
public static ActorSearchPopup Show(Control showTarget, Float2 showTargetLocation, IsValidDelegate isValid, Action<Actor> selected, CustomEditors.IPresenterOwner context)
|
||||||
{
|
{
|
||||||
var popup = new ActorSearchPopup(isValid, selected);
|
var popup = new ActorSearchPopup(isValid, selected, context);
|
||||||
popup.Show(showTarget, showTargetLocation);
|
popup.Show(showTarget, showTargetLocation);
|
||||||
return popup;
|
return popup;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using FlaxEditor.Windows;
|
||||||
|
using FlaxEditor.Windows.Assets;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
using FlaxEngine.Utilities;
|
using FlaxEngine.Utilities;
|
||||||
@@ -66,18 +68,26 @@ namespace FlaxEditor.GUI
|
|||||||
private IsValidDelegate _isValid;
|
private IsValidDelegate _isValid;
|
||||||
private Action<Script> _selected;
|
private Action<Script> _selected;
|
||||||
|
|
||||||
private ScriptSearchPopup(IsValidDelegate isValid, Action<Script> selected)
|
private ScriptSearchPopup(IsValidDelegate isValid, Action<Script> selected, CustomEditors.IPresenterOwner context)
|
||||||
{
|
{
|
||||||
_isValid = isValid;
|
_isValid = isValid;
|
||||||
_selected = selected;
|
_selected = selected;
|
||||||
|
|
||||||
ItemClicked += OnItemClicked;
|
ItemClicked += OnItemClicked;
|
||||||
|
|
||||||
// TODO: use async thread to search scenes
|
if (context is PropertiesWindow propertiesWindow || context == null)
|
||||||
for (int i = 0; i < Level.ScenesCount; i++)
|
|
||||||
{
|
{
|
||||||
Find(Level.GetScene(i));
|
// TODO: use async thread to search scenes
|
||||||
|
for (int i = 0; i < Level.ScenesCount; i++)
|
||||||
|
{
|
||||||
|
Find(Level.GetScene(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else if (context is PrefabWindow prefabWindow)
|
||||||
|
{
|
||||||
|
Find(prefabWindow.Graph.MainActor);
|
||||||
|
}
|
||||||
|
|
||||||
SortItems();
|
SortItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,10 +123,11 @@ namespace FlaxEditor.GUI
|
|||||||
/// <param name="showTargetLocation">The show target location.</param>
|
/// <param name="showTargetLocation">The show target location.</param>
|
||||||
/// <param name="isValid">Event called to check if a given script item is valid to be used.</param>
|
/// <param name="isValid">Event called to check if a given script item is valid to be used.</param>
|
||||||
/// <param name="selected">Event called on script item pick.</param>
|
/// <param name="selected">Event called on script item pick.</param>
|
||||||
|
/// <param name="context">The presenter owner context (i.e. PrefabWindow, PropertiesWindow).</param>
|
||||||
/// <returns>The dialog.</returns>
|
/// <returns>The dialog.</returns>
|
||||||
public static ScriptSearchPopup Show(Control showTarget, Float2 showTargetLocation, IsValidDelegate isValid, Action<Script> selected)
|
public static ScriptSearchPopup Show(Control showTarget, Float2 showTargetLocation, IsValidDelegate isValid, Action<Script> selected, CustomEditors.IPresenterOwner context)
|
||||||
{
|
{
|
||||||
var popup = new ScriptSearchPopup(isValid, selected);
|
var popup = new ScriptSearchPopup(isValid, selected, context);
|
||||||
popup.Show(showTarget, showTargetLocation);
|
popup.Show(showTarget, showTargetLocation);
|
||||||
return popup;
|
return popup;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using FlaxEditor.History;
|
||||||
using FlaxEditor.Scripting;
|
using FlaxEditor.Scripting;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
|
using CategoryAttribute = FlaxEngine.CategoryAttribute;
|
||||||
|
|
||||||
namespace FlaxEditor.GUI
|
namespace FlaxEditor.GUI
|
||||||
{
|
{
|
||||||
@@ -101,11 +104,26 @@ namespace FlaxEditor.GUI
|
|||||||
if (_isValid(type))
|
if (_isValid(type))
|
||||||
{
|
{
|
||||||
var attributes = type.GetAttributes(true);
|
var attributes = type.GetAttributes(true);
|
||||||
if (attributes.FirstOrDefault(x => x is HideInEditorAttribute || x is System.Runtime.CompilerServices.CompilerGeneratedAttribute) == null)
|
if (IsHideAttributes(attributes))
|
||||||
{
|
{
|
||||||
var mType = type.Type;
|
var mType = type.Type;
|
||||||
if (mType != null && mType.IsValueType && mType.ReflectedType != null && string.Equals(mType.ReflectedType.Name, "<PrivateImplementationDetails>", StringComparison.Ordinal))
|
if (mType != null)
|
||||||
continue;
|
{
|
||||||
|
// Skip if type is compiler-generated
|
||||||
|
if (mType.IsValueType && mType.ReflectedType != null && string.Equals(mType.ReflectedType.Name, "<PrivateImplementationDetails>", StringComparison.Ordinal))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Skip if outer type is hidden
|
||||||
|
if (mType.DeclaringType != null && IsHideAttributes(mType.DeclaringType.GetCustomAttributes(true)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Blacklist some types
|
||||||
|
if (typeof(TypeConverter).IsAssignableFrom(mType) ||
|
||||||
|
typeof(IHistoryAction).IsAssignableFrom(mType) ||
|
||||||
|
(mType.Namespace != null && mType.Namespace.StartsWith("Newtonsoft.Json")))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
AddItem(new TypeItemView(type, attributes));
|
AddItem(new TypeItemView(type, attributes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,6 +131,17 @@ namespace FlaxEditor.GUI
|
|||||||
SortItems();
|
SortItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsHideAttributes(object[] attributes)
|
||||||
|
{
|
||||||
|
return attributes.FirstOrDefault(IsHideAttribute) == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsHideAttribute(object attr)
|
||||||
|
{
|
||||||
|
return attr is HideInEditorAttribute ||
|
||||||
|
attr is System.Runtime.CompilerServices.CompilerGeneratedAttribute;
|
||||||
|
}
|
||||||
|
|
||||||
private void OnItemClicked(Item item)
|
private void OnItemClicked(Item item)
|
||||||
{
|
{
|
||||||
_selected(((TypeItemView)item).Type);
|
_selected(((TypeItemView)item).Type);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace FlaxEditor.GUI.Timeline.GUI
|
|||||||
class Background : ContainerControl
|
class Background : ContainerControl
|
||||||
{
|
{
|
||||||
private readonly Timeline _timeline;
|
private readonly Timeline _timeline;
|
||||||
private float[] _tickSteps;
|
private double[] _tickSteps;
|
||||||
private float[] _tickStrengths;
|
private float[] _tickStrengths;
|
||||||
private bool _isSelecting;
|
private bool _isSelecting;
|
||||||
private Float2 _selectingStartPos = Float2.Minimum;
|
private Float2 _selectingStartPos = Float2.Minimum;
|
||||||
@@ -176,9 +176,9 @@ namespace FlaxEditor.GUI.Timeline.GUI
|
|||||||
// Draw vertical lines for time axis
|
// Draw vertical lines for time axis
|
||||||
var pixelsInRange = _timeline.Zoom;
|
var pixelsInRange = _timeline.Zoom;
|
||||||
var pixelRange = pixelsInRange * (max - min);
|
var pixelRange = pixelsInRange * (max - min);
|
||||||
var tickRange = Utilities.Utils.DrawCurveTicks((float tick, float strength) =>
|
var tickRange = Utilities.Utils.DrawCurveTicks((decimal tick, double step, float strength) =>
|
||||||
{
|
{
|
||||||
var time = tick / _timeline.FramesPerSecond;
|
var time = (float)tick / _timeline.FramesPerSecond;
|
||||||
var x = time * zoom + Timeline.StartOffset;
|
var x = time * zoom + Timeline.StartOffset;
|
||||||
var lineColor = style.ForegroundDisabled.RGBMultiplied(0.7f).AlphaMultiplied(strength);
|
var lineColor = style.ForegroundDisabled.RGBMultiplied(0.7f).AlphaMultiplied(strength);
|
||||||
Render2D.FillRectangle(new Rectangle(x - 0.5f, 0, 1.0f, height), lineColor);
|
Render2D.FillRectangle(new Rectangle(x - 0.5f, 0, 1.0f, height), lineColor);
|
||||||
@@ -233,20 +233,20 @@ namespace FlaxEditor.GUI.Timeline.GUI
|
|||||||
int l = Mathf.Clamp(smallestTick + level, 0, _tickSteps.Length - 2);
|
int l = Mathf.Clamp(smallestTick + level, 0, _tickSteps.Length - 2);
|
||||||
var lStep = _tickSteps[l];
|
var lStep = _tickSteps[l];
|
||||||
var lNextStep = _tickSteps[l + 1];
|
var lNextStep = _tickSteps[l + 1];
|
||||||
int startTick = Mathf.FloorToInt(min / lStep);
|
var startTick = Mathd.FloorToInt(min / lStep);
|
||||||
int endTick = Mathf.CeilToInt(max / lStep);
|
var endTick = Mathd.CeilToInt(max / lStep);
|
||||||
Color lineColor = style.Foreground.RGBMultiplied(0.8f).AlphaMultiplied(strength);
|
Color lineColor = style.Foreground.RGBMultiplied(0.8f).AlphaMultiplied(strength);
|
||||||
Color labelColor = style.ForegroundDisabled.AlphaMultiplied(strength);
|
Color labelColor = style.ForegroundDisabled.AlphaMultiplied(strength);
|
||||||
for (int i = startTick; i <= endTick; i++)
|
for (var i = startTick; i <= endTick; i++)
|
||||||
{
|
{
|
||||||
if (l < biggestTick && (i % Mathf.RoundToInt(lNextStep / lStep) == 0))
|
if (l < biggestTick && (i % Mathd.RoundToInt(lNextStep / lStep) == 0))
|
||||||
continue;
|
continue;
|
||||||
var tick = i * lStep;
|
var tick = (decimal)lStep * i;
|
||||||
var time = tick / _timeline.FramesPerSecond;
|
var time = (double)tick / _timeline.FramesPerSecond;
|
||||||
var x = time * zoom + Timeline.StartOffset;
|
var x = (float)time * zoom + Timeline.StartOffset;
|
||||||
|
|
||||||
// Header line
|
// Header line
|
||||||
var lineRect = new Rectangle(x - 0.5f, -verticalLinesHeaderExtend * 0.6f + timeAxisHeaderOffset, 1.0f, verticalLinesHeaderExtend * 0.6f);
|
var lineRect = new Rectangle((float)x - 0.5f, -verticalLinesHeaderExtend * 0.6f + timeAxisHeaderOffset, 1.0f, verticalLinesHeaderExtend * 0.6f);
|
||||||
Render2D.FillRectangle(lineRect, lineColor);
|
Render2D.FillRectangle(lineRect, lineColor);
|
||||||
|
|
||||||
// Time label
|
// Time label
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ using System.Text;
|
|||||||
using FlaxEditor.CustomEditors;
|
using FlaxEditor.CustomEditors;
|
||||||
using FlaxEditor.GUI.ContextMenu;
|
using FlaxEditor.GUI.ContextMenu;
|
||||||
using FlaxEditor.Options;
|
using FlaxEditor.Options;
|
||||||
using FlaxEditor.Scripting;
|
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
using FlaxEngine.Json;
|
using FlaxEngine.Json;
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
|||||||
|
|
||||||
private void OnClickedSelect()
|
private void OnClickedSelect()
|
||||||
{
|
{
|
||||||
ActorSearchPopup.Show(this, PointFromScreen(FlaxEngine.Input.MouseScreenPosition), IsActorValid, SetActor);
|
ActorSearchPopup.Show(this, PointFromScreen(FlaxEngine.Input.MouseScreenPosition), IsActorValid, SetActor, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnClickedSelectActor(Image image, MouseButton button)
|
private void OnClickedSelectActor(Image image, MouseButton button)
|
||||||
|
|||||||
@@ -19,12 +19,11 @@ namespace FlaxEditor.Gizmo
|
|||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
private struct Data
|
private struct Data
|
||||||
{
|
{
|
||||||
public Matrix WorldMatrix;
|
|
||||||
public Matrix ViewProjectionMatrix;
|
public Matrix ViewProjectionMatrix;
|
||||||
public Float4 GridColor;
|
public Float4 GridColor;
|
||||||
public Float3 ViewPos;
|
public Float3 ViewPos;
|
||||||
public float Far;
|
public float Far;
|
||||||
public Float3 Padding;
|
public Float3 ViewOrigin;
|
||||||
public float GridSize;
|
public float GridSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +61,6 @@ namespace FlaxEditor.Gizmo
|
|||||||
Profiler.BeginEventGPU("Editor Grid");
|
Profiler.BeginEventGPU("Editor Grid");
|
||||||
|
|
||||||
var options = Editor.Instance.Options.Options;
|
var options = Editor.Instance.Options.Options;
|
||||||
Float3 camPos = renderContext.View.WorldPosition;
|
|
||||||
float gridSize = renderContext.View.Far + 20000;
|
float gridSize = renderContext.View.Far + 20000;
|
||||||
|
|
||||||
// Lazy-init resources
|
// Lazy-init resources
|
||||||
@@ -97,10 +95,10 @@ namespace FlaxEditor.Gizmo
|
|||||||
float y = 1.5f; // Add small bias to reduce Z-fighting with geometry at scene origin
|
float y = 1.5f; // Add small bias to reduce Z-fighting with geometry at scene origin
|
||||||
var vertices = new Float3[]
|
var vertices = new Float3[]
|
||||||
{
|
{
|
||||||
new Float3(-gridSize + camPos.X, y, -gridSize + camPos.Z),
|
new Float3(-gridSize, y, -gridSize),
|
||||||
new Float3(gridSize + camPos.X, y, gridSize + camPos.Z),
|
new Float3(gridSize, y, gridSize),
|
||||||
new Float3(-gridSize + camPos.X, y, gridSize + camPos.Z),
|
new Float3(-gridSize, y, gridSize),
|
||||||
new Float3(gridSize + camPos.X, y, -gridSize + camPos.Z),
|
new Float3(gridSize, y, -gridSize),
|
||||||
};
|
};
|
||||||
fixed (Float3* ptr = vertices)
|
fixed (Float3* ptr = vertices)
|
||||||
{
|
{
|
||||||
@@ -113,12 +111,12 @@ namespace FlaxEditor.Gizmo
|
|||||||
{
|
{
|
||||||
var data = new Data();
|
var data = new Data();
|
||||||
Matrix.Multiply(ref renderContext.View.View, ref renderContext.View.Projection, out var viewProjection);
|
Matrix.Multiply(ref renderContext.View.View, ref renderContext.View.Projection, out var viewProjection);
|
||||||
data.WorldMatrix = Matrix.Identity;
|
|
||||||
Matrix.Transpose(ref viewProjection, out data.ViewProjectionMatrix);
|
Matrix.Transpose(ref viewProjection, out data.ViewProjectionMatrix);
|
||||||
data.ViewPos = renderContext.View.WorldPosition;
|
data.ViewPos = renderContext.View.WorldPosition;
|
||||||
data.GridColor = options.Viewport.ViewportGridColor;
|
data.GridColor = options.Viewport.ViewportGridColor;
|
||||||
data.Far = renderContext.View.Far;
|
data.Far = renderContext.View.Far;
|
||||||
data.GridSize = options.Viewport.ViewportGridViewDistance;
|
data.GridSize = options.Viewport.ViewportGridViewDistance;
|
||||||
|
data.ViewOrigin = renderContext.View.Origin;
|
||||||
context.UpdateCB(cb, new IntPtr(&data));
|
context.UpdateCB(cb, new IntPtr(&data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -169,12 +169,12 @@ namespace FlaxEditor.Gizmo
|
|||||||
closestIntersection = intersection;
|
closestIntersection = intersection;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*// Center
|
// Center
|
||||||
if (CenterBoxRaw.Intersects(ref localRay, out intersection) && intersection < closestIntersection)
|
if (CenterBoxRaw.Intersects(ref localRay, out intersection) && intersection > closestIntersection)
|
||||||
{
|
{
|
||||||
_activeAxis = Axis.Center;
|
_activeAxis = Axis.Center;
|
||||||
closestIntersection = intersection;
|
closestIntersection = intersection;
|
||||||
}*/
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace FlaxEditor.Gizmo
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Offset to move axis away from center
|
/// Offset to move axis away from center
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const float AxisOffset = 0.8f;
|
private const float AxisOffset = 1.2f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How thick the axis should be
|
/// How thick the axis should be
|
||||||
|
|||||||
@@ -501,7 +501,7 @@ namespace FlaxEditor.Gizmo
|
|||||||
_scaleDelta = Vector3.Zero;
|
_scaleDelta = Vector3.Zero;
|
||||||
|
|
||||||
if (ActiveAxis == Axis.Center)
|
if (ActiveAxis == Axis.Center)
|
||||||
scaleDelta = new Vector3(scaleDelta.AvgValue);
|
scaleDelta = new Vector3(scaleDelta.ValuesSum);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply transformation (but to the parents, not whole selection pool)
|
// Apply transformation (but to the parents, not whole selection pool)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FlaxEditor.Gizmo;
|
using FlaxEditor.Gizmo;
|
||||||
@@ -149,7 +150,8 @@ namespace FlaxEditor
|
|||||||
private float _mouseMoveSum;
|
private float _mouseMoveSum;
|
||||||
private UndoMultiBlock _undoBlock;
|
private UndoMultiBlock _undoBlock;
|
||||||
private View _view;
|
private View _view;
|
||||||
private float[] _gridTickSteps = Utilities.Utils.CurveTickSteps, _gridTickStrengths;
|
private double[] _gridTickSteps = Utilities.Utils.CurveTickSteps;
|
||||||
|
private float[] _gridTickStrengths;
|
||||||
private List<Widget> _widgets;
|
private List<Widget> _widgets;
|
||||||
private Widget _activeWidget;
|
private Widget _activeWidget;
|
||||||
|
|
||||||
@@ -563,9 +565,9 @@ namespace FlaxEditor
|
|||||||
var linesColor = style.ForegroundDisabled.RGBMultiplied(0.5f);
|
var linesColor = style.ForegroundDisabled.RGBMultiplied(0.5f);
|
||||||
var labelsColor = style.ForegroundDisabled;
|
var labelsColor = style.ForegroundDisabled;
|
||||||
var labelsSize = 10.0f;
|
var labelsSize = 10.0f;
|
||||||
Utilities.Utils.DrawCurveTicks((float tick, float strength) =>
|
Utilities.Utils.DrawCurveTicks((decimal tick, double step, float strength) =>
|
||||||
{
|
{
|
||||||
var p = _view.PointToParent(axis * tick);
|
var p = _view.PointToParent(axis * (float)tick);
|
||||||
|
|
||||||
// Draw line
|
// Draw line
|
||||||
var lineRect = new Rectangle
|
var lineRect = new Rectangle
|
||||||
@@ -640,14 +642,103 @@ namespace FlaxEditor
|
|||||||
DrawControlWidget(uiControl, ref eu, ref mousePos, ref widgetHandleSize, viewScale, new Float2(0, -1), CursorType.SizeNS);
|
DrawControlWidget(uiControl, ref eu, ref mousePos, ref widgetHandleSize, viewScale, new Float2(0, -1), CursorType.SizeNS);
|
||||||
DrawControlWidget(uiControl, ref eb, ref mousePos, ref widgetHandleSize, viewScale, new Float2(0, 1), CursorType.SizeNS);
|
DrawControlWidget(uiControl, ref eb, ref mousePos, ref widgetHandleSize, viewScale, new Float2(0, 1), CursorType.SizeNS);
|
||||||
|
|
||||||
// TODO: draw anchors
|
// Draw pivot
|
||||||
|
var pivotSize = 8.0f;
|
||||||
|
if (viewScale < 0.7f)
|
||||||
|
pivotSize *= viewScale;
|
||||||
|
var pivotX = Mathf.Remap(control.Pivot.X, 0, 1, bounds.Location.X, bounds.Location.X + bounds.Width);
|
||||||
|
var pivotY = Mathf.Remap(control.Pivot.Y, 0, 1, bounds.Location.Y, bounds.Location.Y + bounds.Height);
|
||||||
|
var pivotLoc = control.PointToParent(this, new Float2(pivotX, pivotY));
|
||||||
|
var pivotRect = new Rectangle(pivotLoc - pivotSize * 0.5f, new Float2(pivotSize));
|
||||||
|
var pivotColor = options.UIPivotColor;
|
||||||
|
Render2D.FillRectangle(pivotRect, pivotColor);
|
||||||
|
|
||||||
|
// Draw anchors
|
||||||
|
var controlParent = control.Parent;
|
||||||
|
if (controlParent != null)
|
||||||
|
{
|
||||||
|
var parentBounds = controlParent.EditorBounds;
|
||||||
|
var anchorMin = control.AnchorMin;
|
||||||
|
var anchorMax = control.AnchorMax;
|
||||||
|
var newMinX = Mathf.Remap(anchorMin.X, 0, 1, parentBounds.UpperLeft.X, parentBounds.UpperRight.X);
|
||||||
|
var newMinY = Mathf.Remap(anchorMin.Y, 0, 1, parentBounds.UpperLeft.Y, parentBounds.LowerLeft.Y);
|
||||||
|
var newMaxX = Mathf.Remap(anchorMax.X, 0, 1, parentBounds.UpperLeft.X, parentBounds.UpperRight.X);
|
||||||
|
var newMaxY = Mathf.Remap(anchorMax.Y, 0, 1, parentBounds.UpperLeft.Y, parentBounds.LowerLeft.Y);
|
||||||
|
|
||||||
|
var anchorUpperLeft = controlParent.PointToParent(this, new Float2(newMinX, newMinY));
|
||||||
|
var anchorUpperRight = controlParent.PointToParent(this, new Float2(newMaxX, newMinY));
|
||||||
|
var anchorLowerLeft = controlParent.PointToParent(this, new Float2(newMinX, newMaxY));
|
||||||
|
var anchorLowerRight = controlParent.PointToParent(this, new Float2(newMaxX, newMaxY));
|
||||||
|
|
||||||
|
var anchorRectSize = 8.0f;
|
||||||
|
if (viewScale < 0.7f)
|
||||||
|
anchorRectSize *= viewScale;
|
||||||
|
|
||||||
|
// Make anchor rects and rotate if parent is rotated.
|
||||||
|
var parentRotation = controlParent.Rotation * Mathf.DegreesToRadians;
|
||||||
|
|
||||||
|
var rect1Axis = new Float2(-1, -1);
|
||||||
|
var rect1 = new Rectangle(anchorUpperLeft +
|
||||||
|
new Float2(anchorRectSize * rect1Axis.X * Mathf.Cos(parentRotation) - anchorRectSize * rect1Axis.Y * Mathf.Sin(parentRotation),
|
||||||
|
anchorRectSize * rect1Axis.Y * Mathf.Cos(parentRotation) + anchorRectSize * rect1Axis.X * Mathf.Sin(parentRotation)) - anchorRectSize * 0.5f, new Float2(anchorRectSize));
|
||||||
|
var rect2Axis = new Float2(1, -1);
|
||||||
|
var rect2 = new Rectangle(anchorUpperRight +
|
||||||
|
new Float2(anchorRectSize * rect2Axis.X * Mathf.Cos(parentRotation) - anchorRectSize * rect2Axis.Y * Mathf.Sin(parentRotation),
|
||||||
|
anchorRectSize * rect2Axis.Y * Mathf.Cos(parentRotation) + anchorRectSize * rect2Axis.X * Mathf.Sin(parentRotation)) - anchorRectSize * 0.5f, new Float2(anchorRectSize));
|
||||||
|
var rect3Axis = new Float2(-1, 1);
|
||||||
|
var rect3 = new Rectangle(anchorLowerLeft +
|
||||||
|
new Float2(anchorRectSize * rect3Axis.X * Mathf.Cos(parentRotation) - anchorRectSize * rect3Axis.Y * Mathf.Sin(parentRotation),
|
||||||
|
anchorRectSize * rect3Axis.Y * Mathf.Cos(parentRotation) + anchorRectSize * rect3Axis.X * Mathf.Sin(parentRotation)) - anchorRectSize * 0.5f, new Float2(anchorRectSize));
|
||||||
|
var rect4Axis = new Float2(1, 1);
|
||||||
|
var rect4 = new Rectangle(anchorLowerRight +
|
||||||
|
new Float2(anchorRectSize * rect4Axis.X * Mathf.Cos(parentRotation) - anchorRectSize * rect4Axis.Y * Mathf.Sin(parentRotation),
|
||||||
|
anchorRectSize * rect4Axis.Y * Mathf.Cos(parentRotation) + anchorRectSize * rect4Axis.X * Mathf.Sin(parentRotation)) - anchorRectSize * 0.5f, new Float2(anchorRectSize));
|
||||||
|
|
||||||
|
var rectColor = options.UIAnchorColor;
|
||||||
|
Render2D.DrawLine(anchorUpperLeft, anchorUpperRight, rectColor);
|
||||||
|
Render2D.DrawLine(anchorUpperRight, anchorLowerRight, rectColor);
|
||||||
|
Render2D.DrawLine(anchorLowerRight, anchorLowerLeft, rectColor);
|
||||||
|
Render2D.DrawLine(anchorLowerLeft, anchorUpperLeft, rectColor);
|
||||||
|
Render2D.FillRectangle(rect1, rectColor);
|
||||||
|
Render2D.FillRectangle(rect2, rectColor);
|
||||||
|
Render2D.FillRectangle(rect3, rectColor);
|
||||||
|
Render2D.FillRectangle(rect4, rectColor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawControlWidget(UIControl uiControl, ref Float2 pos, ref Float2 mousePos, ref Float2 size, float scale, Float2 resizeAxis, CursorType cursor)
|
private void DrawControlWidget(UIControl uiControl, ref Float2 pos, ref Float2 mousePos, ref Float2 size, float scale, Float2 resizeAxis, CursorType cursor)
|
||||||
{
|
{
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
var rect = new Rectangle((pos + resizeAxis * 10 * scale) - size * 0.5f, size);
|
var control = uiControl.Control;
|
||||||
|
var rotation = control.Rotation;
|
||||||
|
var rotationInRadians = rotation * Mathf.DegreesToRadians;
|
||||||
|
var rect = new Rectangle((pos +
|
||||||
|
new Float2(resizeAxis.X * Mathf.Cos(rotationInRadians) - resizeAxis.Y * Mathf.Sin(rotationInRadians),
|
||||||
|
resizeAxis.Y * Mathf.Cos(rotationInRadians) + resizeAxis.X * Mathf.Sin(rotationInRadians)) * 10 * scale) - size * 0.5f,
|
||||||
|
size);
|
||||||
|
|
||||||
|
// Find more correct cursor at different angles
|
||||||
|
var unwindRotation = Mathf.UnwindDegrees(rotation);
|
||||||
|
if (unwindRotation is (>= 45 and < 135) or (> -135 and <= -45) )
|
||||||
|
{
|
||||||
|
switch (cursor)
|
||||||
|
{
|
||||||
|
case CursorType.SizeNESW:
|
||||||
|
cursor = CursorType.SizeNWSE;
|
||||||
|
break;
|
||||||
|
case CursorType.SizeNS:
|
||||||
|
cursor = CursorType.SizeWE;
|
||||||
|
break;
|
||||||
|
case CursorType.SizeNWSE:
|
||||||
|
cursor = CursorType.SizeNESW;
|
||||||
|
break;
|
||||||
|
case CursorType.SizeWE:
|
||||||
|
cursor = CursorType.SizeNS;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (rect.Contains(ref mousePos))
|
if (rect.Contains(ref mousePos))
|
||||||
{
|
{
|
||||||
Render2D.FillRectangle(rect, style.Foreground);
|
Render2D.FillRectangle(rect, style.Foreground);
|
||||||
@@ -684,16 +775,15 @@ namespace FlaxEditor
|
|||||||
|
|
||||||
private bool RayCastControl(ref Float2 location, out Control hit)
|
private bool RayCastControl(ref Float2 location, out Control hit)
|
||||||
{
|
{
|
||||||
#if false
|
// First, raycast only controls with content (eg. skips transparent panels)
|
||||||
// Raycast only controls with content (eg. skips transparent panels)
|
RayCastChildren(ref location, out hit);
|
||||||
return RayCastChildren(ref location, out hit);
|
|
||||||
#else
|
// If raycast failed, then find any control under mouse (hierarchical)
|
||||||
// Find any control under mouse (hierarchical)
|
hit = hit ?? GetChildAtRecursive(location);
|
||||||
hit = GetChildAtRecursive(location);
|
|
||||||
if (hit is View || hit is CanvasContainer)
|
if (hit is View || hit is CanvasContainer)
|
||||||
hit = null;
|
hit = null;
|
||||||
|
|
||||||
return hit != null;
|
return hit != null;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private UIControlNode FindUIControlNode(Control control)
|
private UIControlNode FindUIControlNode(Control control)
|
||||||
|
|||||||
@@ -501,7 +501,8 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CanSetToRoot(Prefab* prefab, Actor* ta
|
|||||||
return false;
|
return false;
|
||||||
const ISerializable::DeserializeStream& newRootData = **newRootDataPtr;
|
const ISerializable::DeserializeStream& newRootData = **newRootDataPtr;
|
||||||
Guid prefabId, prefabObjectID;
|
Guid prefabId, prefabObjectID;
|
||||||
if (JsonTools::GetGuidIfValid(prefabId, newRootData, "PrefabID") && JsonTools::GetGuidIfValid(prefabObjectID, newRootData, "PrefabObjectID"))
|
if (JsonTools::GetGuidIfValid(prefabId, newRootData, "PrefabID") &&
|
||||||
|
JsonTools::GetGuidIfValid(prefabObjectID, newRootData, "PrefabObjectID"))
|
||||||
{
|
{
|
||||||
const auto nestedPrefab = Content::Load<Prefab>(prefabId);
|
const auto nestedPrefab = Content::Load<Prefab>(prefabId);
|
||||||
if (nestedPrefab && nestedPrefab->GetRootObjectId() != prefabObjectID)
|
if (nestedPrefab && nestedPrefab->GetRootObjectId() != prefabObjectID)
|
||||||
@@ -511,21 +512,6 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CanSetToRoot(Prefab* prefab, Actor* ta
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_INTERNAL_CALL(void) EditorInternal_GetPrefabNestedObject(Guid* prefabId, Guid* prefabObjectId, Guid* outPrefabId, Guid* outPrefabObjectId)
|
|
||||||
{
|
|
||||||
*outPrefabId = Guid::Empty;
|
|
||||||
*outPrefabObjectId = Guid::Empty;
|
|
||||||
const auto prefab = Content::Load<Prefab>(*prefabId);
|
|
||||||
if (!prefab)
|
|
||||||
return;
|
|
||||||
const ISerializable::DeserializeStream** prefabObjectDataPtr = prefab->ObjectsDataCache.TryGet(*prefabObjectId);
|
|
||||||
if (!prefabObjectDataPtr)
|
|
||||||
return;
|
|
||||||
const ISerializable::DeserializeStream& prefabObjectData = **prefabObjectDataPtr;
|
|
||||||
JsonTools::GetGuidIfValid(*outPrefabId, prefabObjectData, "PrefabID");
|
|
||||||
JsonTools::GetGuidIfValid(*outPrefabObjectId, prefabObjectData, "PrefabObjectID");
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINE_INTERNAL_CALL(float) EditorInternal_GetAnimationTime(AnimatedModel* animatedModel)
|
DEFINE_INTERNAL_CALL(float) EditorInternal_GetAnimationTime(AnimatedModel* animatedModel)
|
||||||
{
|
{
|
||||||
return animatedModel && animatedModel->GraphInstance.State.Count() == 1 ? animatedModel->GraphInstance.State[0].Animation.TimePosition : 0.0f;
|
return animatedModel && animatedModel->GraphInstance.State.Count() == 1 ? animatedModel->GraphInstance.State[0].Animation.TimePosition : 0.0f;
|
||||||
|
|||||||
@@ -12,11 +12,14 @@
|
|||||||
#include "Engine/Scripting/ManagedCLR/MException.h"
|
#include "Engine/Scripting/ManagedCLR/MException.h"
|
||||||
#include "Engine/Scripting/Internal/MainThreadManagedInvokeAction.h"
|
#include "Engine/Scripting/Internal/MainThreadManagedInvokeAction.h"
|
||||||
#include "Engine/Content/Assets/VisualScript.h"
|
#include "Engine/Content/Assets/VisualScript.h"
|
||||||
|
#include "Engine/Content/Content.h"
|
||||||
#include "Engine/CSG/CSGBuilder.h"
|
#include "Engine/CSG/CSGBuilder.h"
|
||||||
#include "Engine/Engine/CommandLine.h"
|
#include "Engine/Engine/CommandLine.h"
|
||||||
#include "Engine/Renderer/ProbesRenderer.h"
|
#include "Engine/Renderer/ProbesRenderer.h"
|
||||||
#include "Engine/Animations/Graph/AnimGraph.h"
|
#include "Engine/Animations/Graph/AnimGraph.h"
|
||||||
#include "Engine/Core/ObjectsRemovalService.h"
|
#include "Engine/Core/ObjectsRemovalService.h"
|
||||||
|
#include "Engine/Level/Prefabs/Prefab.h"
|
||||||
|
#include "Engine/Serialization/JsonTools.h"
|
||||||
|
|
||||||
ManagedEditor::InternalOptions ManagedEditor::ManagedEditorOptions;
|
ManagedEditor::InternalOptions ManagedEditor::ManagedEditorOptions;
|
||||||
|
|
||||||
@@ -592,6 +595,7 @@ bool ManagedEditor::EvaluateVisualScriptLocal(VisualScript* script, VisualScript
|
|||||||
|
|
||||||
void ManagedEditor::WipeOutLeftoverSceneObjects()
|
void ManagedEditor::WipeOutLeftoverSceneObjects()
|
||||||
{
|
{
|
||||||
|
PROFILE_CPU();
|
||||||
Array<ScriptingObject*> objects = Scripting::GetObjects();
|
Array<ScriptingObject*> objects = Scripting::GetObjects();
|
||||||
bool removedAny = false;
|
bool removedAny = false;
|
||||||
for (ScriptingObject* object : objects)
|
for (ScriptingObject* object : objects)
|
||||||
@@ -613,6 +617,21 @@ void ManagedEditor::WipeOutLeftoverSceneObjects()
|
|||||||
ObjectsRemovalService::Flush();
|
ObjectsRemovalService::Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ManagedEditor::GetPrefabNestedObject(const Guid& prefabId, const Guid& prefabObjectId, Guid& outPrefabId, Guid& outPrefabObjectId)
|
||||||
|
{
|
||||||
|
outPrefabId = Guid::Empty;
|
||||||
|
outPrefabObjectId = Guid::Empty;
|
||||||
|
const auto prefab = Content::Load<Prefab>(prefabId);
|
||||||
|
if (!prefab)
|
||||||
|
return;
|
||||||
|
const ISerializable::DeserializeStream** prefabObjectDataPtr = prefab->ObjectsDataCache.TryGet(prefabObjectId);
|
||||||
|
if (!prefabObjectDataPtr)
|
||||||
|
return;
|
||||||
|
const ISerializable::DeserializeStream& prefabObjectData = **prefabObjectDataPtr;
|
||||||
|
JsonTools::GetGuidIfValid(outPrefabId, prefabObjectData, "PrefabID");
|
||||||
|
JsonTools::GetGuidIfValid(outPrefabObjectId, prefabObjectData, "PrefabObjectID");
|
||||||
|
}
|
||||||
|
|
||||||
void ManagedEditor::OnEditorAssemblyLoaded(MAssembly* assembly)
|
void ManagedEditor::OnEditorAssemblyLoaded(MAssembly* assembly)
|
||||||
{
|
{
|
||||||
ASSERT(!HasManagedInstance());
|
ASSERT(!HasManagedInstance());
|
||||||
|
|||||||
@@ -259,6 +259,7 @@ public:
|
|||||||
API_FUNCTION(Internal) static Array<VisualScriptLocal> GetVisualScriptLocals();
|
API_FUNCTION(Internal) static Array<VisualScriptLocal> GetVisualScriptLocals();
|
||||||
API_FUNCTION(Internal) static bool EvaluateVisualScriptLocal(VisualScript* script, API_PARAM(Ref) VisualScriptLocal& local);
|
API_FUNCTION(Internal) static bool EvaluateVisualScriptLocal(VisualScript* script, API_PARAM(Ref) VisualScriptLocal& local);
|
||||||
API_FUNCTION(Internal) static void WipeOutLeftoverSceneObjects();
|
API_FUNCTION(Internal) static void WipeOutLeftoverSceneObjects();
|
||||||
|
API_FUNCTION(Internal) static void GetPrefabNestedObject(API_PARAM(Ref) const Guid& prefabId, API_PARAM(Ref) const Guid& prefabObjectId, API_PARAM(Out) Guid& outPrefabId, API_PARAM(Out) Guid& outPrefabObjectId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnEditorAssemblyLoaded(MAssembly* assembly);
|
void OnEditorAssemblyLoaded(MAssembly* assembly);
|
||||||
|
|||||||
@@ -1140,6 +1140,7 @@ namespace FlaxEditor.Modules
|
|||||||
Proxy.Add(new CSharpEmptyStructProxy());
|
Proxy.Add(new CSharpEmptyStructProxy());
|
||||||
Proxy.Add(new CSharpEmptyInterfaceProxy());
|
Proxy.Add(new CSharpEmptyInterfaceProxy());
|
||||||
Proxy.Add(new CSharpActorProxy());
|
Proxy.Add(new CSharpActorProxy());
|
||||||
|
Proxy.Add(new CSharpGamePluginProxy());
|
||||||
Proxy.Add(new CppAssetProxy());
|
Proxy.Add(new CppAssetProxy());
|
||||||
Proxy.Add(new CppStaticClassProxy());
|
Proxy.Add(new CppStaticClassProxy());
|
||||||
Proxy.Add(new CppScriptProxy());
|
Proxy.Add(new CppScriptProxy());
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System.Text;
|
||||||
using FlaxEditor.CustomEditors;
|
using FlaxEditor.CustomEditors;
|
||||||
using FlaxEditor.CustomEditors.Editors;
|
using FlaxEditor.CustomEditors.Editors;
|
||||||
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
using FlaxEngine.Json;
|
using FlaxEngine.Json;
|
||||||
|
|
||||||
@@ -31,11 +33,33 @@ namespace FlaxEditor.Options
|
|||||||
|
|
||||||
private void OnResetButtonClicked()
|
private void OnResetButtonClicked()
|
||||||
{
|
{
|
||||||
var obj = new T();
|
var editorClassName = typeof(T).Name;
|
||||||
var str = JsonSerializer.Serialize(obj);
|
|
||||||
JsonSerializer.Deserialize(Values[0], str);
|
var editorName = new StringBuilder();
|
||||||
SetValue(Values[0]);
|
editorName.Append(editorClassName[0]);
|
||||||
Refresh();
|
for (var i = 1; i < editorClassName.Length; i++)
|
||||||
|
{
|
||||||
|
// Whenever there is an uppercase letter, add a space to make it more pretty for the end user
|
||||||
|
if (char.IsUpper(editorClassName[i]))
|
||||||
|
{
|
||||||
|
editorName.Append(' ');
|
||||||
|
}
|
||||||
|
editorName.Append(editorClassName[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = MessageBox.Show($"Are you sure you want to reset \"{editorName}\" to default values?",
|
||||||
|
"Reset values?",
|
||||||
|
MessageBoxButtons.YesNo
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result == DialogResult.Yes || result == DialogResult.OK)
|
||||||
|
{
|
||||||
|
var obj = new T();
|
||||||
|
var str = JsonSerializer.Serialize(obj);
|
||||||
|
JsonSerializer.Deserialize(Values[0], str);
|
||||||
|
SetValue(Values[0]);
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,20 @@ namespace FlaxEditor.Options
|
|||||||
[EditorDisplay("UI Gizmo", "UI Control Outline Size"), EditorOrder(103), Tooltip("The size of the selection outline for UI controls.")]
|
[EditorDisplay("UI Gizmo", "UI Control Outline Size"), EditorOrder(103), Tooltip("The size of the selection outline for UI controls.")]
|
||||||
public float UISelectionOutlineSize { get; set; } = 2.0f;
|
public float UISelectionOutlineSize { get; set; } = 2.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the pivot color for the UI Gizmo.
|
||||||
|
/// </summary>
|
||||||
|
[DefaultValue(typeof(Color), "0.0,0.5725,0.8,0.5")]
|
||||||
|
[EditorDisplay("UI Gizmo", "Pivot Color"), EditorOrder(103), Tooltip("The color of the pivot for the UI Gizmo.")]
|
||||||
|
public Color UIPivotColor { get; set; } = new Color(0.0f, 0.5725f, 0.8f, 0.5f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the anchor color for the UI Gizmo.
|
||||||
|
/// </summary>
|
||||||
|
[DefaultValue(typeof(Color), "0.8392,0.8471,0.8706,0.5")]
|
||||||
|
[EditorDisplay("UI Gizmo", "Anchor Color"), EditorOrder(103), Tooltip("The color of the anchors for the UI Gizmo.")]
|
||||||
|
public Color UIAnchorColor { get; set; } = new Color(0.8392f, 0.8471f, 0.8706f, 0.5f);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the transform gizmo size.
|
/// Gets or sets the transform gizmo size.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -215,10 +215,10 @@ namespace FlaxEditor.SceneGraph
|
|||||||
public override bool CanDuplicate => (_actor.HideFlags & HideFlags.HideInHierarchy) == 0;
|
public override bool CanDuplicate => (_actor.HideFlags & HideFlags.HideInHierarchy) == 0;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool IsActive => _actor.IsActive;
|
public override bool IsActive => _actor?.IsActive ?? false;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool IsActiveInHierarchy => _actor.IsActiveInHierarchy;
|
public override bool IsActiveInHierarchy => _actor?.IsActiveInHierarchy ?? false;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override int OrderInParent
|
public override int OrderInParent
|
||||||
|
|||||||
@@ -596,11 +596,17 @@ namespace FlaxEditor.SceneGraph.GUI
|
|||||||
{
|
{
|
||||||
bool worldPositionsStays = Root.GetKey(KeyboardKeys.Control) == false;
|
bool worldPositionsStays = Root.GetKey(KeyboardKeys.Control) == false;
|
||||||
var objects = new SceneObject[_dragActors.Objects.Count];
|
var objects = new SceneObject[_dragActors.Objects.Count];
|
||||||
|
var treeNodes = new TreeNode[_dragActors.Objects.Count];
|
||||||
for (int i = 0; i < objects.Length; i++)
|
for (int i = 0; i < objects.Length; i++)
|
||||||
|
{
|
||||||
objects[i] = _dragActors.Objects[i].Actor;
|
objects[i] = _dragActors.Objects[i].Actor;
|
||||||
|
treeNodes[i] = _dragActors.Objects[i].TreeNode;
|
||||||
|
}
|
||||||
var action = new ParentActorsAction(objects, newParent, newOrder, worldPositionsStays);
|
var action = new ParentActorsAction(objects, newParent, newOrder, worldPositionsStays);
|
||||||
ActorNode.Root.Undo?.AddAction(action);
|
ActorNode.Root.Undo?.AddAction(action);
|
||||||
action.Do();
|
action.Do();
|
||||||
|
ParentTree.Focus();
|
||||||
|
ParentTree.Select(treeNodes.ToList());
|
||||||
result = DragDropEffect.Move;
|
result = DragDropEffect.Move;
|
||||||
}
|
}
|
||||||
// Drag scripts
|
// Drag scripts
|
||||||
|
|||||||
@@ -1182,9 +1182,9 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void DrawEditorBackground(ref Rectangle rect)
|
public override void DrawEditorGrid(ref Rectangle rect)
|
||||||
{
|
{
|
||||||
base.DrawEditorBackground(ref rect);
|
base.DrawEditorGrid(ref rect);
|
||||||
|
|
||||||
// Draw triangulated multi blend space
|
// Draw triangulated multi blend space
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
@@ -1195,23 +1195,19 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
else
|
else
|
||||||
Render2D.FillTriangles(_triangles, style.TextBoxBackgroundSelected.AlphaMultiplied(0.6f));
|
Render2D.FillTriangles(_triangles, style.TextBoxBackgroundSelected.AlphaMultiplied(0.6f));
|
||||||
Render2D.DrawTriangles(_triangles, style.Foreground);
|
Render2D.DrawTriangles(_triangles, style.Foreground);
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void DrawEditorGrid(ref Rectangle rect)
|
|
||||||
{
|
|
||||||
base.DrawEditorGrid(ref rect);
|
|
||||||
|
|
||||||
// Highlight selected blend point
|
// Highlight selected blend point
|
||||||
var style = Style.Current;
|
|
||||||
var selectedIndex = _selectedAnimation.SelectedIndex;
|
var selectedIndex = _selectedAnimation.SelectedIndex;
|
||||||
if (selectedIndex != -1 && (ContainsFocus || IsMouseOver))
|
if (selectedIndex != -1 && selectedIndex < _editor.BlendPoints.Count && (ContainsFocus || IsMouseOver))
|
||||||
{
|
{
|
||||||
var point = _editor.BlendPoints[selectedIndex];
|
var point = _editor.BlendPoints[selectedIndex];
|
||||||
var highlightColor = point.IsMouseDown ? style.SelectionBorder : style.BackgroundSelected;
|
if (point != null)
|
||||||
Render2D.PushTint(ref highlightColor);
|
{
|
||||||
Render2D.DrawTriangles(_selectedTriangles, _selectedColors);
|
var highlightColor = point.IsMouseDown ? style.SelectionBorder : style.BackgroundSelected;
|
||||||
Render2D.PopTint();
|
Render2D.PushTint(ref highlightColor);
|
||||||
|
Render2D.DrawTriangles(_selectedTriangles, _selectedColors);
|
||||||
|
Render2D.PopTint();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -924,6 +924,25 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
(int)ModuleType.Initialize,
|
(int)ModuleType.Initialize,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
new NodeArchetype
|
||||||
|
{
|
||||||
|
TypeID = 216,
|
||||||
|
Create = CreateParticleModuleNode,
|
||||||
|
Title = "Rotate Position Shape",
|
||||||
|
Description = "Rotate the shape.",
|
||||||
|
Flags = DefaultModuleFlags,
|
||||||
|
Size = new Float2(200, 1 * Surface.Constants.LayoutOffsetY),
|
||||||
|
DefaultValues = new object[]
|
||||||
|
{
|
||||||
|
true,
|
||||||
|
(int)ModuleType.Initialize,
|
||||||
|
Quaternion.Identity,
|
||||||
|
},
|
||||||
|
Elements = new []
|
||||||
|
{
|
||||||
|
NodeElementArchetype.Factory.Input(-0.5f, "Rotation", true, typeof(Quaternion), 0, 2),
|
||||||
|
}
|
||||||
|
},
|
||||||
GetParticleAttribute(ModuleType.Initialize, 250, "Set Position", "Sets the particle position", typeof(Float3), Float3.Zero),
|
GetParticleAttribute(ModuleType.Initialize, 250, "Set Position", "Sets the particle position", typeof(Float3), Float3.Zero),
|
||||||
GetParticleAttribute(ModuleType.Initialize, 251, "Set Lifetime", "Sets the particle lifetime (in seconds)", typeof(float), 10.0f),
|
GetParticleAttribute(ModuleType.Initialize, 251, "Set Lifetime", "Sets the particle lifetime (in seconds)", typeof(float), 10.0f),
|
||||||
GetParticleAttribute(ModuleType.Initialize, 252, "Set Age", "Sets the particle age (in seconds)", typeof(float), 0.0f),
|
GetParticleAttribute(ModuleType.Initialize, 252, "Set Age", "Sets the particle age (in seconds)", typeof(float), 0.0f),
|
||||||
|
|||||||
@@ -87,11 +87,17 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
private class GradientStop : Control
|
private class GradientStop : Control
|
||||||
{
|
{
|
||||||
private bool _isMoving;
|
private bool _isMoving;
|
||||||
|
private float _movedToTime = float.MaxValue;
|
||||||
private Float2 _startMovePos;
|
private Float2 _startMovePos;
|
||||||
|
|
||||||
public ColorGradientNode Node;
|
public ColorGradientNode Node;
|
||||||
public Color Color;
|
public Color Color;
|
||||||
|
|
||||||
|
public void UpdateLocation(float time)
|
||||||
|
{
|
||||||
|
Location = Node._gradient.BottomLeft + new Float2(time * Node._gradient.Width - Width * 0.5f, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Draw()
|
public override void Draw()
|
||||||
{
|
{
|
||||||
@@ -118,6 +124,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
if (button == MouseButton.Left)
|
if (button == MouseButton.Left)
|
||||||
{
|
{
|
||||||
Node.Select(this);
|
Node.Select(this);
|
||||||
|
_movedToTime = float.MaxValue;
|
||||||
_isMoving = true;
|
_isMoving = true;
|
||||||
_startMovePos = location;
|
_startMovePos = location;
|
||||||
StartMouseCapture();
|
StartMouseCapture();
|
||||||
@@ -133,6 +140,12 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
if (button == MouseButton.Left && _isMoving)
|
if (button == MouseButton.Left && _isMoving)
|
||||||
{
|
{
|
||||||
_isMoving = false;
|
_isMoving = false;
|
||||||
|
if (_movedToTime < float.MaxValue)
|
||||||
|
{
|
||||||
|
int index = Node._stops.IndexOf(this);
|
||||||
|
Node.SetStopTime(index, _movedToTime);
|
||||||
|
_movedToTime = float.MaxValue;
|
||||||
|
}
|
||||||
EndMouseCapture();
|
EndMouseCapture();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,9 +172,10 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
if (_isMoving && Float2.DistanceSquared(ref location, ref _startMovePos) > 25.0f)
|
if (_isMoving && Float2.DistanceSquared(ref location, ref _startMovePos) > 25.0f)
|
||||||
{
|
{
|
||||||
_startMovePos = Float2.Minimum;
|
_startMovePos = Float2.Minimum;
|
||||||
var index = Node._stops.IndexOf(this);
|
int index = Node._stops.IndexOf(this);
|
||||||
var time = (PointToParent(location).X - Node._gradient.BottomLeft.X) / Node._gradient.Width;
|
_movedToTime = (PointToParent(location).X - Node._gradient.BottomLeft.X) / Node._gradient.Width;
|
||||||
Node.SetStopTime(index, time);
|
_movedToTime = Node.ClampStopTime(index, _movedToTime);
|
||||||
|
UpdateLocation(_movedToTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnMouseMove(location);
|
base.OnMouseMove(location);
|
||||||
@@ -171,6 +185,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
public override void OnEndMouseCapture()
|
public override void OnEndMouseCapture()
|
||||||
{
|
{
|
||||||
_isMoving = false;
|
_isMoving = false;
|
||||||
|
_movedToTime = float.MaxValue;
|
||||||
|
|
||||||
base.OnEndMouseCapture();
|
base.OnEndMouseCapture();
|
||||||
}
|
}
|
||||||
@@ -223,6 +238,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
Parent = this
|
Parent = this
|
||||||
};
|
};
|
||||||
_timeValue.ValueChanged += OnTimeValueChanged;
|
_timeValue.ValueChanged += OnTimeValueChanged;
|
||||||
|
_timeValue.SlidingEnd += OnTimeValueChanged;
|
||||||
|
|
||||||
_colorValue = new ColorValueBox(Color.Black, _timeValue.Right + 4.0f, controlsLevel)
|
_colorValue = new ColorValueBox(Color.Black, _timeValue.Right + 4.0f, controlsLevel)
|
||||||
{
|
{
|
||||||
@@ -301,8 +317,16 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
|
|
||||||
private void OnTimeValueChanged()
|
private void OnTimeValueChanged()
|
||||||
{
|
{
|
||||||
|
var time = _timeValue.Value;
|
||||||
var index = _stops.IndexOf(_selected);
|
var index = _stops.IndexOf(_selected);
|
||||||
SetStopTime(index, _timeValue.Value);
|
if (_timeValue.IsSliding)
|
||||||
|
{
|
||||||
|
// Preview-only while sliding
|
||||||
|
time = ClampStopTime(index, time);
|
||||||
|
_selected.UpdateLocation(time);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SetStopTime(index, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnColorValueChanged()
|
private void OnColorValueChanged()
|
||||||
@@ -346,7 +370,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
UpdateStops();
|
UpdateStops();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetStopTime(int index, float time)
|
private float ClampStopTime(int index, float time)
|
||||||
{
|
{
|
||||||
time = Mathf.Saturate(time);
|
time = Mathf.Saturate(time);
|
||||||
if (index != 0)
|
if (index != 0)
|
||||||
@@ -357,6 +381,12 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
{
|
{
|
||||||
time = Mathf.Min(time, (float)Values[1 + index * 2 + 2]);
|
time = Mathf.Min(time, (float)Values[1 + index * 2 + 2]);
|
||||||
}
|
}
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetStopTime(int index, float time)
|
||||||
|
{
|
||||||
|
time = ClampStopTime(index, time);
|
||||||
SetValue(1 + index * 2, time);
|
SetValue(1 + index * 2, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +425,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
{
|
{
|
||||||
var stop = _stops[i];
|
var stop = _stops[i];
|
||||||
var time = (float)Values[i * 2 + 1];
|
var time = (float)Values[i * 2 + 1];
|
||||||
stop.Location = _gradient.BottomLeft + new Float2(time * _gradient.Width - stop.Width * 0.5f, 0.0f);
|
stop.UpdateLocation(time);
|
||||||
stop.Color = (Color)Values[i * 2 + 2];
|
stop.Color = (Color)Values[i * 2 + 2];
|
||||||
stop.TooltipText = stop.Color + " at " + time;
|
stop.TooltipText = stop.Color + " at " + time;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace FlaxEditor.Actions
|
|||||||
public Guid PrefabID;
|
public Guid PrefabID;
|
||||||
public Guid PrefabObjectID;
|
public Guid PrefabObjectID;
|
||||||
|
|
||||||
public unsafe Item(SceneObject obj, List<Item> nestedPrefabLinks)
|
public Item(SceneObject obj, List<Item> nestedPrefabLinks)
|
||||||
{
|
{
|
||||||
ID = obj.ID;
|
ID = obj.ID;
|
||||||
PrefabID = obj.PrefabID;
|
PrefabID = obj.PrefabID;
|
||||||
@@ -33,8 +33,7 @@ namespace FlaxEditor.Actions
|
|||||||
// Check if this object comes from another nested prefab (to break link only from the top-level prefab)
|
// Check if this object comes from another nested prefab (to break link only from the top-level prefab)
|
||||||
Item nested;
|
Item nested;
|
||||||
nested.ID = ID;
|
nested.ID = ID;
|
||||||
fixed (Item* i = &this)
|
Editor.GetPrefabNestedObject(ref PrefabID, ref PrefabObjectID, out nested.PrefabID, out nested.PrefabObjectID);
|
||||||
Editor.Internal_GetPrefabNestedObject(new IntPtr(&i->PrefabID), new IntPtr(&i->PrefabObjectID), new IntPtr(&nested.PrefabID), new IntPtr(&nested.PrefabObjectID));
|
|
||||||
if (nested.PrefabID != Guid.Empty && nested.PrefabObjectID != Guid.Empty)
|
if (nested.PrefabID != Guid.Empty && nested.PrefabObjectID != Guid.Empty)
|
||||||
nestedPrefabLinks.Add(nested);
|
nestedPrefabLinks.Add(nested);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ namespace FlaxEditor
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TData">The type of the data. Must have <see cref="SerializableAttribute"/>.</typeparam>
|
/// <typeparam name="TData">The type of the data. Must have <see cref="SerializableAttribute"/>.</typeparam>
|
||||||
/// <seealso cref="FlaxEditor.IUndoAction" />
|
/// <seealso cref="FlaxEditor.IUndoAction" />
|
||||||
[Serializable]
|
[Serializable, HideInEditor]
|
||||||
public abstract class UndoActionBase<TData> : IUndoAction where TData : struct
|
public abstract class UndoActionBase<TData> : IUndoAction where TData : struct
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace FlaxEditor.Utilities;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Units display utilities for Editor.
|
/// Units display utilities for Editor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Units
|
public static class Units
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Factor of units per meter.
|
/// Factor of units per meter.
|
||||||
|
|||||||
@@ -236,19 +236,19 @@ namespace FlaxEditor.Utilities
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The time/value axes tick steps for editors with timeline.
|
/// The time/value axes tick steps for editors with timeline.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static readonly float[] CurveTickSteps =
|
internal static readonly double[] CurveTickSteps =
|
||||||
{
|
{
|
||||||
0.0000001f, 0.0000005f, 0.000001f, 0.000005f, 0.00001f,
|
0.0000001, 0.0000005, 0.000001, 0.000005, 0.00001,
|
||||||
0.00005f, 0.0001f, 0.0005f, 0.001f, 0.005f,
|
0.00005, 0.0001, 0.0005, 0.001, 0.005,
|
||||||
0.01f, 0.05f, 0.1f, 0.5f, 1,
|
0.01, 0.05, 0.1, 0.5, 1,
|
||||||
5, 10, 50, 100, 500,
|
5, 10, 50, 100, 500,
|
||||||
1000, 5000, 10000, 50000, 100000,
|
1000, 5000, 10000, 50000, 100000,
|
||||||
500000, 1000000, 5000000, 10000000, 100000000
|
500000, 1000000, 5000000, 10000000, 100000000
|
||||||
};
|
};
|
||||||
|
|
||||||
internal delegate void DrawCurveTick(float tick, float strength);
|
internal delegate void DrawCurveTick(decimal tick, double step, float strength);
|
||||||
|
|
||||||
internal static Int2 DrawCurveTicks(DrawCurveTick drawTick, float[] tickSteps, ref float[] tickStrengths, float min, float max, float pixelRange, float minDistanceBetweenTicks = 20, float maxDistanceBetweenTicks = 60)
|
internal static Int2 DrawCurveTicks(DrawCurveTick drawTick, double[] tickSteps, ref float[] tickStrengths, float min, float max, float pixelRange, float minDistanceBetweenTicks = 20, float maxDistanceBetweenTicks = 60)
|
||||||
{
|
{
|
||||||
if (pixelRange <= Mathf.Epsilon || maxDistanceBetweenTicks <= minDistanceBetweenTicks)
|
if (pixelRange <= Mathf.Epsilon || maxDistanceBetweenTicks <= minDistanceBetweenTicks)
|
||||||
return Int2.Zero;
|
return Int2.Zero;
|
||||||
@@ -262,10 +262,10 @@ namespace FlaxEditor.Utilities
|
|||||||
for (int i = tickSteps.Length - 1; i >= 0; i--)
|
for (int i = tickSteps.Length - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
// Calculate how far apart these modulo tick steps are spaced
|
// Calculate how far apart these modulo tick steps are spaced
|
||||||
float tickSpacing = tickSteps[i] * pixelsInRange;
|
var tickSpacing = tickSteps[i] * pixelsInRange;
|
||||||
|
|
||||||
// Calculate the strength of the tick markers based on the spacing
|
// Calculate the strength of the tick markers based on the spacing
|
||||||
tickStrengths[i] = Mathf.Saturate((tickSpacing - minDistanceBetweenTicks) / (maxDistanceBetweenTicks - minDistanceBetweenTicks));
|
tickStrengths[i] = (float)Mathd.Saturate((tickSpacing - minDistanceBetweenTicks) / (maxDistanceBetweenTicks - minDistanceBetweenTicks));
|
||||||
|
|
||||||
// Beyond threshold the ticks don't get any bigger or fatter
|
// Beyond threshold the ticks don't get any bigger or fatter
|
||||||
if (tickStrengths[i] >= 1)
|
if (tickStrengths[i] >= 1)
|
||||||
@@ -283,7 +283,7 @@ namespace FlaxEditor.Utilities
|
|||||||
// Draw all tick levels
|
// Draw all tick levels
|
||||||
for (int level = 0; level < tickLevels; level++)
|
for (int level = 0; level < tickLevels; level++)
|
||||||
{
|
{
|
||||||
float strength = tickStrengths[smallestTick + level];
|
var strength = tickStrengths[smallestTick + level];
|
||||||
if (strength <= Mathf.Epsilon)
|
if (strength <= Mathf.Epsilon)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -291,20 +291,36 @@ namespace FlaxEditor.Utilities
|
|||||||
int l = Mathf.Clamp(smallestTick + level, 0, tickSteps.Length - 2);
|
int l = Mathf.Clamp(smallestTick + level, 0, tickSteps.Length - 2);
|
||||||
var lStep = tickSteps[l];
|
var lStep = tickSteps[l];
|
||||||
var lNextStep = tickSteps[l + 1];
|
var lNextStep = tickSteps[l + 1];
|
||||||
int startTick = Mathf.FloorToInt(min / lStep);
|
var startTick = Mathd.FloorToInt(min / lStep);
|
||||||
int endTick = Mathf.CeilToInt(max / lStep);
|
var endTick = Mathd.CeilToInt(max / lStep);
|
||||||
for (int i = startTick; i <= endTick; i++)
|
for (var i = startTick; i <= endTick; i++)
|
||||||
{
|
{
|
||||||
if (l < biggestTick && (i % Mathf.RoundToInt(lNextStep / lStep) == 0))
|
if (l < biggestTick && (i % Mathd.RoundToInt(lNextStep / lStep) == 0))
|
||||||
continue;
|
continue;
|
||||||
var tick = i * lStep;
|
var tick = (decimal)lStep * i;
|
||||||
drawTick(tick, strength);
|
drawTick(tick, lStep, strength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Int2(smallestTick, biggestTick);
|
return new Int2(smallestTick, biggestTick);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static float GetCurveGridSnap(double[] tickSteps, ref float[] tickStrengths, float min, float max, float pixelRange, float minDistanceBetweenTicks = 20, float maxDistanceBetweenTicks = 60)
|
||||||
|
{
|
||||||
|
double gridStep = 0; // No grid
|
||||||
|
float gridWeight = 0.0f;
|
||||||
|
DrawCurveTicks((decimal tick, double step, float strength) =>
|
||||||
|
{
|
||||||
|
// Find the smallest grid step that has meaningful strength (it's the most visible to the user)
|
||||||
|
if (strength > gridWeight && (step < gridStep || gridStep <= 0.0) && strength > 0.5f)
|
||||||
|
{
|
||||||
|
gridStep = Math.Abs(step);
|
||||||
|
gridWeight = strength;
|
||||||
|
}
|
||||||
|
}, tickSteps, ref tickStrengths, min, max, pixelRange, minDistanceBetweenTicks, maxDistanceBetweenTicks);
|
||||||
|
return (float)gridStep;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the specified path string contains any invalid character.
|
/// Determines whether the specified path string contains any invalid character.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -383,6 +399,40 @@ namespace FlaxEditor.Utilities
|
|||||||
File.Delete(file);
|
File.Delete(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an Import path ui that show the asset import path and adds a button to show the folder in the file system.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parentLayout">The parent layout container.</param>
|
||||||
|
/// <param name="assetItem">The asset item to get the import path of.</param>
|
||||||
|
public static void CreateImportPathUI(CustomEditors.LayoutElementsContainer parentLayout, Content.BinaryAssetItem assetItem)
|
||||||
|
{
|
||||||
|
assetItem.GetImportPath(out var path);
|
||||||
|
CreateImportPathUI(parentLayout, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an Import path ui that show the import path and adds a button to show the folder in the file system.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parentLayout">The parent layout container.</param>
|
||||||
|
/// <param name="path">The import path.</param>
|
||||||
|
/// <param name="useInitialSpacing">Whether to use an initial layout space of 5 for separation.</param>
|
||||||
|
public static void CreateImportPathUI(CustomEditors.LayoutElementsContainer parentLayout, string path, bool useInitialSpacing = true)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(path))
|
||||||
|
{
|
||||||
|
if (useInitialSpacing)
|
||||||
|
parentLayout.Space(5);
|
||||||
|
parentLayout.Label("Import Path:").Label.TooltipText = "Source asset path (can be relative or absolute to the project)";
|
||||||
|
var textBox = parentLayout.TextBox().TextBox;
|
||||||
|
textBox.TooltipText = "Path is not editable here.";
|
||||||
|
textBox.IsReadOnly = true;
|
||||||
|
textBox.Text = path;
|
||||||
|
parentLayout.Space(2);
|
||||||
|
var button = parentLayout.Button(Constants.ShowInExplorer).Button;
|
||||||
|
button.Clicked += () => FileSystem.ShowFileExplorer(Path.GetDirectoryName(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copies the directory. Supports subdirectories copy with files override option.
|
/// Copies the directory. Supports subdirectories copy with files override option.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -135,6 +135,8 @@ namespace FlaxEditor.Viewport.Cameras
|
|||||||
float a = Mathf.Saturate(progress);
|
float a = Mathf.Saturate(progress);
|
||||||
a = a * a * a;
|
a = a * a * a;
|
||||||
var targetTransform = Transform.Lerp(_startMove, _endMove, a);
|
var targetTransform = Transform.Lerp(_startMove, _endMove, a);
|
||||||
|
if (progress >= 1.0f)
|
||||||
|
targetTransform = _endMove; // Be precise
|
||||||
targetTransform.Scale = Vector3.Zero;
|
targetTransform.Scale = Vector3.Zero;
|
||||||
Viewport.ViewPosition = targetTransform.Translation;
|
Viewport.ViewPosition = targetTransform.Translation;
|
||||||
Viewport.ViewOrientation = targetTransform.Orientation;
|
Viewport.ViewOrientation = targetTransform.Orientation;
|
||||||
|
|||||||
@@ -229,13 +229,11 @@ namespace FlaxEditor.Viewport
|
|||||||
{
|
{
|
||||||
if (Mathf.Abs(_movementSpeed - _maxMovementSpeed) < Mathf.Epsilon || Mathf.Abs(_movementSpeed - _minMovementSpeed) < Mathf.Epsilon)
|
if (Mathf.Abs(_movementSpeed - _maxMovementSpeed) < Mathf.Epsilon || Mathf.Abs(_movementSpeed - _minMovementSpeed) < Mathf.Epsilon)
|
||||||
return "{0:0.##}";
|
return "{0:0.##}";
|
||||||
|
|
||||||
if (_movementSpeed < 10.0f)
|
if (_movementSpeed < 10.0f)
|
||||||
return "{0:0.00}";
|
return "{0:0.00}";
|
||||||
else if (_movementSpeed < 100.0f)
|
if (_movementSpeed < 100.0f)
|
||||||
return "{0:0.0}";
|
return "{0:0.0}";
|
||||||
else
|
return "{0:#}";
|
||||||
return "{0:#}";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,11 +284,6 @@ namespace FlaxEditor.Viewport
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Float2 MousePositionDelta => _mouseDelta;
|
public Float2 MousePositionDelta => _mouseDelta;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Camera's pitch angle clamp range (in degrees).
|
|
||||||
/// </summary>
|
|
||||||
public Float2 CamPitchAngles = new Float2(-88, 88);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the view transform.
|
/// Gets the view transform.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -326,7 +319,7 @@ namespace FlaxEditor.Viewport
|
|||||||
get => Float3.Forward * ViewOrientation;
|
get => Float3.Forward * ViewOrientation;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
var right = Float3.Cross(value, Float3.Up);
|
var right = Mathf.Abs(Float3.Dot(value, Float3.Up)) < 1.0f - Mathf.Epsilon ? Float3.Cross(value, Float3.Up) : Float3.Forward;
|
||||||
var up = Float3.Cross(right, value);
|
var up = Float3.Cross(right, value);
|
||||||
ViewOrientation = Quaternion.LookRotation(value, up);
|
ViewOrientation = Quaternion.LookRotation(value, up);
|
||||||
}
|
}
|
||||||
@@ -376,7 +369,11 @@ namespace FlaxEditor.Viewport
|
|||||||
public float Pitch
|
public float Pitch
|
||||||
{
|
{
|
||||||
get => _pitch;
|
get => _pitch;
|
||||||
set => _pitch = Mathf.Clamp(value, CamPitchAngles.X, CamPitchAngles.Y);
|
set
|
||||||
|
{
|
||||||
|
var pitchLimit = _isOrtho ? new Float2(-90, 90) : new Float2(-88, 88);
|
||||||
|
_pitch = Mathf.Clamp(value, pitchLimit.X, pitchLimit.Y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1155,8 +1152,7 @@ namespace FlaxEditor.Viewport
|
|||||||
/// <param name="orientation">The orientation.</param>
|
/// <param name="orientation">The orientation.</param>
|
||||||
protected void OrientViewport(Quaternion orientation)
|
protected void OrientViewport(Quaternion orientation)
|
||||||
{
|
{
|
||||||
var quat = orientation;
|
OrientViewport(ref orientation);
|
||||||
OrientViewport(ref quat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1367,7 +1363,7 @@ namespace FlaxEditor.Viewport
|
|||||||
{
|
{
|
||||||
var direction = ViewDirection;
|
var direction = ViewDirection;
|
||||||
var target = position + direction;
|
var target = position + direction;
|
||||||
var right = Float3.Normalize(Float3.Cross(Float3.Up, direction));
|
var right = Mathf.Abs(Float3.Dot(direction, Float3.Up)) < 1.0f - Mathf.Epsilon ? Float3.Normalize(Float3.Cross(Float3.Up, direction)) : Float3.Forward;
|
||||||
var up = Float3.Normalize(Float3.Cross(direction, right));
|
var up = Float3.Normalize(Float3.Cross(direction, right));
|
||||||
Matrix.LookAt(ref position, ref target, ref up, out result);
|
Matrix.LookAt(ref position, ref target, ref up, out result);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FlaxEditor.Content;
|
using FlaxEditor.Content;
|
||||||
using FlaxEditor.Gizmo;
|
using FlaxEditor.Gizmo;
|
||||||
|
using FlaxEditor.GUI.ContextMenu;
|
||||||
using FlaxEditor.SceneGraph;
|
using FlaxEditor.SceneGraph;
|
||||||
using FlaxEditor.Scripting;
|
using FlaxEditor.Scripting;
|
||||||
using FlaxEditor.Viewport.Cameras;
|
using FlaxEditor.Viewport.Cameras;
|
||||||
using FlaxEditor.Viewport.Previews;
|
using FlaxEditor.Viewport.Previews;
|
||||||
|
using FlaxEditor.Viewport.Widgets;
|
||||||
using FlaxEditor.Windows.Assets;
|
using FlaxEditor.Windows.Assets;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
@@ -44,7 +46,7 @@ namespace FlaxEditor.Viewport
|
|||||||
private sealed class PrefabUIEditorRoot : UIEditorRoot
|
private sealed class PrefabUIEditorRoot : UIEditorRoot
|
||||||
{
|
{
|
||||||
private readonly PrefabWindowViewport _viewport;
|
private readonly PrefabWindowViewport _viewport;
|
||||||
private bool UI => _viewport._hasUILinkedCached;
|
private bool UI => _viewport.ShowUI;
|
||||||
|
|
||||||
public PrefabUIEditorRoot(PrefabWindowViewport viewport)
|
public PrefabUIEditorRoot(PrefabWindowViewport viewport)
|
||||||
: base(true)
|
: base(true)
|
||||||
@@ -67,8 +69,78 @@ namespace FlaxEditor.Viewport
|
|||||||
private PrefabSpritesRenderer _spritesRenderer;
|
private PrefabSpritesRenderer _spritesRenderer;
|
||||||
private IntPtr _tempDebugDrawContext;
|
private IntPtr _tempDebugDrawContext;
|
||||||
|
|
||||||
private bool _hasUILinkedCached;
|
|
||||||
private PrefabUIEditorRoot _uiRoot;
|
private PrefabUIEditorRoot _uiRoot;
|
||||||
|
private bool _showUI = false;
|
||||||
|
|
||||||
|
private ContextMenuButton _uiModeButton;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event fired when the UI Mode is toggled.
|
||||||
|
/// </summary>
|
||||||
|
public event Action<bool> UIModeToggled;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// set the initial UI mod
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">the initial ShowUI value</param>
|
||||||
|
public void SetInitialUIMode(bool value)
|
||||||
|
{
|
||||||
|
ShowUI = value;
|
||||||
|
_uiModeButton.Checked = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to show the UI mode or not.
|
||||||
|
/// </summary>
|
||||||
|
public bool ShowUI
|
||||||
|
{
|
||||||
|
get => _showUI;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_showUI = value;
|
||||||
|
if (_showUI)
|
||||||
|
{
|
||||||
|
// UI widget
|
||||||
|
Gizmos.Active = null;
|
||||||
|
ViewportCamera = new UIEditorCamera { UIEditor = _uiRoot };
|
||||||
|
|
||||||
|
// Hide 3D visuals
|
||||||
|
ShowEditorPrimitives = false;
|
||||||
|
ShowDefaultSceneActors = false;
|
||||||
|
ShowDebugDraw = false;
|
||||||
|
|
||||||
|
// Show whole UI on startup
|
||||||
|
var canvas = (CanvasRootControl)_uiParentLink.Children.FirstOrDefault(x => x is CanvasRootControl);
|
||||||
|
if (canvas != null)
|
||||||
|
ViewportCamera.ShowActor(canvas.Canvas);
|
||||||
|
else if (Instance is UIControl)
|
||||||
|
ViewportCamera.ShowActor(Instance);
|
||||||
|
_uiRoot.Visible = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Generic prefab
|
||||||
|
Gizmos.Active = TransformGizmo;
|
||||||
|
ViewportCamera = new FPSCamera();
|
||||||
|
_uiRoot.Visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update default components usage
|
||||||
|
bool defaultFeatures = !_showUI;
|
||||||
|
_disableInputUpdate = _showUI;
|
||||||
|
_spritesRenderer.Enabled = defaultFeatures;
|
||||||
|
SelectionOutline.Enabled = defaultFeatures;
|
||||||
|
_showDefaultSceneButton.Visible = defaultFeatures;
|
||||||
|
_cameraWidget.Visible = defaultFeatures;
|
||||||
|
_cameraButton.Visible = defaultFeatures;
|
||||||
|
_orthographicModeButton.Visible = defaultFeatures;
|
||||||
|
Task.Enabled = defaultFeatures;
|
||||||
|
UseAutomaticTaskManagement = defaultFeatures;
|
||||||
|
ShowDefaultSceneActors = defaultFeatures;
|
||||||
|
TintColor = defaultFeatures ? Color.White : Color.Transparent;
|
||||||
|
UIModeToggled?.Invoke(_showUI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Drag and drop handlers
|
/// Drag and drop handlers
|
||||||
@@ -138,6 +210,11 @@ namespace FlaxEditor.Viewport
|
|||||||
_uiRoot.IndexInParent = 0; // Move viewport down below other widgets in the viewport
|
_uiRoot.IndexInParent = 0; // Move viewport down below other widgets in the viewport
|
||||||
_uiParentLink = _uiRoot.UIRoot;
|
_uiParentLink = _uiRoot.UIRoot;
|
||||||
|
|
||||||
|
// UI mode buton
|
||||||
|
_uiModeButton = ViewWidgetShowMenu.AddButton("UI Mode", (button) => ShowUI = button.Checked);
|
||||||
|
_uiModeButton.AutoCheck = true;
|
||||||
|
_uiModeButton.VisibleChanged += control => (control as ContextMenuButton).Checked = ShowUI;
|
||||||
|
|
||||||
EditorGizmoViewport.AddGizmoViewportWidgets(this, TransformGizmo);
|
EditorGizmoViewport.AddGizmoViewportWidgets(this, TransformGizmo);
|
||||||
|
|
||||||
// Setup input actions
|
// Setup input actions
|
||||||
@@ -146,58 +223,8 @@ namespace FlaxEditor.Viewport
|
|||||||
SetUpdate(ref _update, OnUpdate);
|
SetUpdate(ref _update, OnUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the viewport's gizmos, especially to toggle between 3D and UI editing modes.
|
|
||||||
/// </summary>
|
|
||||||
internal void UpdateGizmoMode()
|
|
||||||
{
|
|
||||||
// Skip if gizmo mode was unmodified
|
|
||||||
if (_hasUILinked == _hasUILinkedCached)
|
|
||||||
return;
|
|
||||||
_hasUILinkedCached = _hasUILinked;
|
|
||||||
|
|
||||||
if (_hasUILinked)
|
|
||||||
{
|
|
||||||
// UI widget
|
|
||||||
Gizmos.Active = null;
|
|
||||||
ViewportCamera = new UIEditorCamera { UIEditor = _uiRoot };
|
|
||||||
|
|
||||||
// Hide 3D visuals
|
|
||||||
ShowEditorPrimitives = false;
|
|
||||||
ShowDefaultSceneActors = false;
|
|
||||||
ShowDebugDraw = false;
|
|
||||||
|
|
||||||
// Show whole UI on startup
|
|
||||||
var canvas = (CanvasRootControl)_uiParentLink.Children.FirstOrDefault(x => x is CanvasRootControl);
|
|
||||||
if (canvas != null)
|
|
||||||
ViewportCamera.ShowActor(canvas.Canvas);
|
|
||||||
else if (Instance is UIControl)
|
|
||||||
ViewportCamera.ShowActor(Instance);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Generic prefab
|
|
||||||
Gizmos.Active = TransformGizmo;
|
|
||||||
ViewportCamera = new FPSCamera();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update default components usage
|
|
||||||
bool defaultFeatures = !_hasUILinked;
|
|
||||||
_disableInputUpdate = _hasUILinked;
|
|
||||||
_spritesRenderer.Enabled = defaultFeatures;
|
|
||||||
SelectionOutline.Enabled = defaultFeatures;
|
|
||||||
_showDefaultSceneButton.Visible = defaultFeatures;
|
|
||||||
_cameraWidget.Visible = defaultFeatures;
|
|
||||||
_cameraButton.Visible = defaultFeatures;
|
|
||||||
_orthographicModeButton.Visible = defaultFeatures;
|
|
||||||
Task.Enabled = defaultFeatures;
|
|
||||||
UseAutomaticTaskManagement = defaultFeatures;
|
|
||||||
TintColor = defaultFeatures ? Color.White : Color.Transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnUpdate(float deltaTime)
|
private void OnUpdate(float deltaTime)
|
||||||
{
|
{
|
||||||
UpdateGizmoMode();
|
|
||||||
for (int i = 0; i < Gizmos.Count; i++)
|
for (int i = 0; i < Gizmos.Count; i++)
|
||||||
{
|
{
|
||||||
Gizmos[i].Update(deltaTime);
|
Gizmos[i].Update(deltaTime);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using FlaxEditor.Content;
|
using FlaxEditor.Content;
|
||||||
@@ -210,8 +211,11 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
var importSettingsValues = new ValueContainer(new ScriptMemberInfo(importSettingsField)) { proxy.ImportSettings };
|
var importSettingsValues = new ValueContainer(new ScriptMemberInfo(importSettingsField)) { proxy.ImportSettings };
|
||||||
group.Object(importSettingsValues);
|
group.Object(importSettingsValues);
|
||||||
|
|
||||||
|
// Creates the import path UI
|
||||||
|
Utilities.Utils.CreateImportPathUI(layout, proxy.Window.Item as BinaryAssetItem);
|
||||||
|
|
||||||
layout.Space(5);
|
layout.Space(5);
|
||||||
var reimportButton = group.Button("Reimport");
|
var reimportButton = layout.Button("Reimport");
|
||||||
reimportButton.Button.Clicked += () => ((PropertiesProxy)Values[0]).Reimport();
|
reimportButton.Button.Clicked += () => ((PropertiesProxy)Values[0]).Reimport();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using FlaxEditor.Content;
|
using FlaxEditor.Content;
|
||||||
using FlaxEditor.Content.Import;
|
using FlaxEditor.Content.Import;
|
||||||
@@ -100,7 +101,10 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
|
|
||||||
base.Initialize(layout);
|
base.Initialize(layout);
|
||||||
|
|
||||||
layout.Space(10);
|
// Creates the import path UI
|
||||||
|
Utilities.Utils.CreateImportPathUI(layout, window.Item as BinaryAssetItem);
|
||||||
|
|
||||||
|
layout.Space(5);
|
||||||
var reimportButton = layout.Button("Reimport");
|
var reimportButton = layout.Button("Reimport");
|
||||||
reimportButton.Button.Clicked += () => ((PropertiesProxy)Values[0]).Reimport();
|
reimportButton.Button.Clicked += () => ((PropertiesProxy)Values[0]).Reimport();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using FlaxEditor.Content;
|
using FlaxEditor.Content;
|
||||||
using FlaxEditor.Content.Import;
|
using FlaxEditor.Content.Import;
|
||||||
@@ -53,7 +54,10 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
|
|
||||||
base.Initialize(layout);
|
base.Initialize(layout);
|
||||||
|
|
||||||
layout.Space(10);
|
// Creates the import path UI
|
||||||
|
Utilities.Utils.CreateImportPathUI(layout, window.Item as BinaryAssetItem);
|
||||||
|
|
||||||
|
layout.Space(5);
|
||||||
var reimportButton = layout.Button("Reimport");
|
var reimportButton = layout.Button("Reimport");
|
||||||
reimportButton.Button.Clicked += () => ((PropertiesProxy)Values[0]).Reimport();
|
reimportButton.Button.Clicked += () => ((PropertiesProxy)Values[0]).Reimport();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -758,8 +759,11 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
var importSettingsValues = new ValueContainer(new ScriptMemberInfo(importSettingsField)) { proxy.ImportSettings };
|
var importSettingsValues = new ValueContainer(new ScriptMemberInfo(importSettingsField)) { proxy.ImportSettings };
|
||||||
group.Object(importSettingsValues);
|
group.Object(importSettingsValues);
|
||||||
|
|
||||||
|
// Creates the import path UI
|
||||||
|
Utilities.Utils.CreateImportPathUI(layout, proxy.Window.Item as BinaryAssetItem);
|
||||||
|
|
||||||
layout.Space(5);
|
layout.Space(5);
|
||||||
var reimportButton = group.Button("Reimport");
|
var reimportButton = layout.Button("Reimport");
|
||||||
reimportButton.Button.Clicked += () => ((ImportPropertiesProxy)Values[0]).Reimport();
|
reimportButton.Button.Clicked += () => ((ImportPropertiesProxy)Values[0]).Reimport();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -355,13 +355,22 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
private void OnPrefabOpened()
|
private void OnPrefabOpened()
|
||||||
{
|
{
|
||||||
_viewport.Prefab = _asset;
|
_viewport.Prefab = _asset;
|
||||||
_viewport.UpdateGizmoMode();
|
if (Editor.ProjectCache.TryGetCustomData($"UIMode:{_asset.ID}", out bool value))
|
||||||
|
_viewport.SetInitialUIMode(value);
|
||||||
|
else
|
||||||
|
_viewport.SetInitialUIMode(_viewport._hasUILinked);
|
||||||
|
_viewport.UIModeToggled += OnUIModeToggled;
|
||||||
Graph.MainActor = _viewport.Instance;
|
Graph.MainActor = _viewport.Instance;
|
||||||
Selection.Clear();
|
Selection.Clear();
|
||||||
Select(Graph.Main);
|
Select(Graph.Main);
|
||||||
Graph.Root.TreeNode.Expand(true);
|
Graph.Root.TreeNode.Expand(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnUIModeToggled(bool value)
|
||||||
|
{
|
||||||
|
Editor.ProjectCache.SetCustomData($"UIMode:{_asset.ID}", value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Save()
|
public override void Save()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1023,8 +1023,11 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
var importSettingsValues = new ValueContainer(new ScriptMemberInfo(importSettingsField)) { proxy.ImportSettings };
|
var importSettingsValues = new ValueContainer(new ScriptMemberInfo(importSettingsField)) { proxy.ImportSettings };
|
||||||
group.Object(importSettingsValues);
|
group.Object(importSettingsValues);
|
||||||
|
|
||||||
|
// Creates the import path UI
|
||||||
|
Utilities.Utils.CreateImportPathUI(layout, proxy.Window.Item as BinaryAssetItem);
|
||||||
|
|
||||||
layout.Space(5);
|
layout.Space(5);
|
||||||
var reimportButton = group.Button("Reimport");
|
var reimportButton = layout.Button("Reimport");
|
||||||
reimportButton.Button.Clicked += () => ((ImportPropertiesProxy)Values[0]).Reimport();
|
reimportButton.Button.Clicked += () => ((ImportPropertiesProxy)Values[0]).Reimport();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using FlaxEditor.Content;
|
using FlaxEditor.Content;
|
||||||
@@ -110,9 +111,19 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
{
|
{
|
||||||
public override void Initialize(LayoutElementsContainer layout)
|
public override void Initialize(LayoutElementsContainer layout)
|
||||||
{
|
{
|
||||||
|
var proxy = (PropertiesProxy)Values[0];
|
||||||
|
if (proxy._window == null)
|
||||||
|
{
|
||||||
|
layout.Label("Loading...", TextAlignment.Center);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
base.Initialize(layout);
|
base.Initialize(layout);
|
||||||
|
|
||||||
|
// Creates the import path UI
|
||||||
|
Utilities.Utils.CreateImportPathUI(layout, proxy._window.Item as BinaryAssetItem);
|
||||||
|
|
||||||
layout.Space(10);
|
layout.Space(5);
|
||||||
var reimportButton = layout.Button("Reimport");
|
var reimportButton = layout.Button("Reimport");
|
||||||
reimportButton.Button.Clicked += () => ((PropertiesProxy)Values[0]).Reimport();
|
reimportButton.Button.Clicked += () => ((PropertiesProxy)Values[0]).Reimport();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using FlaxEditor.Content;
|
using FlaxEditor.Content;
|
||||||
using FlaxEditor.Content.Import;
|
using FlaxEditor.Content.Import;
|
||||||
@@ -134,11 +135,21 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
{
|
{
|
||||||
public override void Initialize(LayoutElementsContainer layout)
|
public override void Initialize(LayoutElementsContainer layout)
|
||||||
{
|
{
|
||||||
|
var proxy = (ImportPropertiesProxy)Values[0];
|
||||||
|
if (proxy._window == null)
|
||||||
|
{
|
||||||
|
layout.Label("Loading...", TextAlignment.Center);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Import settings
|
// Import settings
|
||||||
base.Initialize(layout);
|
base.Initialize(layout);
|
||||||
|
|
||||||
|
// Creates the import path UI
|
||||||
|
Utilities.Utils.CreateImportPathUI(layout, proxy._window.Item as BinaryAssetItem);
|
||||||
|
|
||||||
// Reimport
|
// Reimport
|
||||||
layout.Space(10);
|
layout.Space(5);
|
||||||
var reimportButton = layout.Button("Reimport");
|
var reimportButton = layout.Button("Reimport");
|
||||||
reimportButton.Button.Clicked += () => ((ImportPropertiesProxy)Values[0]).Reimport();
|
reimportButton.Button.Clicked += () => ((ImportPropertiesProxy)Values[0]).Reimport();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ namespace FlaxEditor.Windows
|
|||||||
private readonly GameRoot _guiRoot;
|
private readonly GameRoot _guiRoot;
|
||||||
private bool _showGUI = true;
|
private bool _showGUI = true;
|
||||||
private bool _showDebugDraw = false;
|
private bool _showDebugDraw = false;
|
||||||
|
private bool _audioMuted = false;
|
||||||
|
private float _audioVolume = 1;
|
||||||
private bool _isMaximized = false, _isUnlockingMouse = false;
|
private bool _isMaximized = false, _isUnlockingMouse = false;
|
||||||
private bool _isFloating = false, _isBorderless = false;
|
private bool _isFloating = false, _isBorderless = false;
|
||||||
private bool _cursorVisible = true;
|
private bool _cursorVisible = true;
|
||||||
@@ -91,6 +93,35 @@ namespace FlaxEditor.Windows
|
|||||||
set => _showDebugDraw = value;
|
set => _showDebugDraw = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or set a value indicating whether Audio is muted.
|
||||||
|
/// </summary>
|
||||||
|
public bool AudioMuted
|
||||||
|
{
|
||||||
|
get => _audioMuted;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Audio.MasterVolume = value ? 0 : AudioVolume;
|
||||||
|
_audioMuted = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value that set the audio volume.
|
||||||
|
/// </summary>
|
||||||
|
public float AudioVolume
|
||||||
|
{
|
||||||
|
get => _audioVolume;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!AudioMuted)
|
||||||
|
Audio.MasterVolume = value;
|
||||||
|
|
||||||
|
_audioVolume = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether the game window is maximized (only in play mode).
|
/// Gets or sets a value indicating whether the game window is maximized (only in play mode).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -646,6 +677,24 @@ namespace FlaxEditor.Windows
|
|||||||
checkbox.StateChanged += x => ShowDebugDraw = x.Checked;
|
checkbox.StateChanged += x => ShowDebugDraw = x.Checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
menu.AddSeparator();
|
||||||
|
|
||||||
|
// Mute Audio
|
||||||
|
{
|
||||||
|
var button = menu.AddButton("Mute Audio");
|
||||||
|
button.CloseMenuOnClick = false;
|
||||||
|
var checkbox = new CheckBox(140, 2, AudioMuted) { Parent = button };
|
||||||
|
checkbox.StateChanged += x => AudioMuted = x.Checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Audio Volume
|
||||||
|
{
|
||||||
|
var button = menu.AddButton("Audio Volume");
|
||||||
|
button.CloseMenuOnClick = false;
|
||||||
|
var slider = new FloatValueBox(AudioVolume, 140, 2, 50, 0, 1) { Parent = button };
|
||||||
|
slider.ValueChanged += () => AudioVolume = slider.Value;
|
||||||
|
}
|
||||||
|
|
||||||
menu.MinimumWidth = 200;
|
menu.MinimumWidth = 200;
|
||||||
menu.AddSeparator();
|
menu.AddSeparator();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
|
|
||||||
private string FormatCellBytes(object x)
|
private string FormatCellBytes(object x)
|
||||||
{
|
{
|
||||||
return Utilities.Utils.FormatBytesCount((ulong)x);
|
return Utilities.Utils.FormatBytesCount(Convert.ToUInt64(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class AnimationsSystem : public TaskGraphSystem
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
float DeltaTime, UnscaledDeltaTime, Time, UnscaledTime;
|
float DeltaTime, UnscaledDeltaTime, Time, UnscaledTime;
|
||||||
|
bool Active;
|
||||||
|
|
||||||
void Job(int32 index);
|
void Job(int32 index);
|
||||||
void Execute(TaskGraph* graph) override;
|
void Execute(TaskGraph* graph) override;
|
||||||
@@ -51,6 +52,7 @@ namespace
|
|||||||
|
|
||||||
AnimationsService AnimationManagerInstance;
|
AnimationsService AnimationManagerInstance;
|
||||||
TaskGraphSystem* Animations::System = nullptr;
|
TaskGraphSystem* Animations::System = nullptr;
|
||||||
|
ConcurrentSystemLocker Animations::SystemLocker;
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
Delegate<Animations::DebugFlowInfo> Animations::DebugFlow;
|
Delegate<Animations::DebugFlowInfo> Animations::DebugFlow;
|
||||||
#endif
|
#endif
|
||||||
@@ -116,6 +118,10 @@ void AnimationsSystem::Execute(TaskGraph* graph)
|
|||||||
{
|
{
|
||||||
if (AnimationManagerInstance.UpdateList.Count() == 0)
|
if (AnimationManagerInstance.UpdateList.Count() == 0)
|
||||||
return;
|
return;
|
||||||
|
Active = true;
|
||||||
|
|
||||||
|
// Ensure no animation assets can be reloaded/modified during async update
|
||||||
|
Animations::SystemLocker.Begin(false);
|
||||||
|
|
||||||
// Setup data for async update
|
// Setup data for async update
|
||||||
const auto& tickData = Time::Update;
|
const auto& tickData = Time::Update;
|
||||||
@@ -138,6 +144,8 @@ void AnimationsSystem::Execute(TaskGraph* graph)
|
|||||||
|
|
||||||
void AnimationsSystem::PostExecute(TaskGraph* graph)
|
void AnimationsSystem::PostExecute(TaskGraph* graph)
|
||||||
{
|
{
|
||||||
|
if (!Active)
|
||||||
|
return;
|
||||||
PROFILE_CPU_NAMED("Animations.PostExecute");
|
PROFILE_CPU_NAMED("Animations.PostExecute");
|
||||||
|
|
||||||
// Update gameplay
|
// Update gameplay
|
||||||
@@ -153,6 +161,8 @@ void AnimationsSystem::PostExecute(TaskGraph* graph)
|
|||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
AnimationManagerInstance.UpdateList.Clear();
|
AnimationManagerInstance.UpdateList.Clear();
|
||||||
|
Animations::SystemLocker.End(false);
|
||||||
|
Active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animations::AddToUpdate(AnimatedModel* obj)
|
void Animations::AddToUpdate(AnimatedModel* obj)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "Engine/Scripting/ScriptingType.h"
|
#include "Engine/Scripting/ScriptingType.h"
|
||||||
#include "Engine/Core/Delegate.h"
|
#include "Engine/Core/Delegate.h"
|
||||||
|
#include "Engine/Threading/ConcurrentSystemLocker.h"
|
||||||
|
|
||||||
class TaskGraphSystem;
|
class TaskGraphSystem;
|
||||||
class AnimatedModel;
|
class AnimatedModel;
|
||||||
@@ -21,6 +22,9 @@ API_CLASS(Static) class FLAXENGINE_API Animations
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD(ReadOnly) static TaskGraphSystem* System;
|
API_FIELD(ReadOnly) static TaskGraphSystem* System;
|
||||||
|
|
||||||
|
// Data access locker for animations data.
|
||||||
|
static ConcurrentSystemLocker SystemLocker;
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
// Data wrapper for the debug flow information.
|
// Data wrapper for the debug flow information.
|
||||||
API_STRUCT(NoDefault) struct DebugFlowInfo
|
API_STRUCT(NoDefault) struct DebugFlowInfo
|
||||||
|
|||||||
@@ -161,7 +161,10 @@ public:
|
|||||||
case 2:
|
case 2:
|
||||||
default: // TODO: implement multi-channel support (eg. 5.1, 7.1)
|
default: // TODO: implement multi-channel support (eg. 5.1, 7.1)
|
||||||
outputMatrix[0] = channels[FrontLeft];
|
outputMatrix[0] = channels[FrontLeft];
|
||||||
outputMatrix[sourceChannels + 1] = channels[FrontRight];
|
if (sourceChannels == 1)
|
||||||
|
outputMatrix[1] = channels[FrontRight];
|
||||||
|
else
|
||||||
|
outputMatrix[sourceChannels + 1] = channels[FrontRight];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,11 +40,17 @@
|
|||||||
|
|
||||||
namespace ALC
|
namespace ALC
|
||||||
{
|
{
|
||||||
|
struct SourceData
|
||||||
|
{
|
||||||
|
AudioDataInfo Format;
|
||||||
|
bool Spatial;
|
||||||
|
};
|
||||||
|
|
||||||
ALCdevice* Device = nullptr;
|
ALCdevice* Device = nullptr;
|
||||||
ALCcontext* Context = nullptr;
|
ALCcontext* Context = nullptr;
|
||||||
AudioBackend::FeatureFlags Features = AudioBackend::FeatureFlags::None;
|
AudioBackend::FeatureFlags Features = AudioBackend::FeatureFlags::None;
|
||||||
CriticalSection Locker;
|
CriticalSection Locker;
|
||||||
Dictionary<uint32, AudioDataInfo> SourceIDtoFormat;
|
Dictionary<uint32, SourceData> SourcesData;
|
||||||
|
|
||||||
bool IsExtensionSupported(const char* extension)
|
bool IsExtensionSupported(const char* extension)
|
||||||
{
|
{
|
||||||
@@ -88,32 +94,32 @@ namespace ALC
|
|||||||
alSourcef(sourceID, AL_PITCH, pitch);
|
alSourcef(sourceID, AL_PITCH, pitch);
|
||||||
alSourcef(sourceID, AL_SEC_OFFSET, 0.0f);
|
alSourcef(sourceID, AL_SEC_OFFSET, 0.0f);
|
||||||
alSourcei(sourceID, AL_LOOPING, loop);
|
alSourcei(sourceID, AL_LOOPING, loop);
|
||||||
alSourcei(sourceID, AL_SOURCE_RELATIVE, !spatial);
|
alSourcei(sourceID, AL_SOURCE_RELATIVE, !spatial); // Non-spatial sounds use AL_POSITION for panning
|
||||||
alSourcei(sourceID, AL_BUFFER, 0);
|
alSourcei(sourceID, AL_BUFFER, 0);
|
||||||
|
#ifdef AL_SOFT_source_spatialize
|
||||||
|
alSourcei(sourceID, AL_SOURCE_SPATIALIZE_SOFT, AL_TRUE); // Always spatialize, fixes multi-channel played as spatial
|
||||||
|
#endif
|
||||||
if (spatial)
|
if (spatial)
|
||||||
{
|
{
|
||||||
#ifdef AL_SOFT_source_spatialize
|
|
||||||
alSourcei(sourceID, AL_SOURCE_SPATIALIZE_SOFT, AL_TRUE);
|
|
||||||
#endif
|
|
||||||
alSourcef(sourceID, AL_ROLLOFF_FACTOR, attenuation);
|
alSourcef(sourceID, AL_ROLLOFF_FACTOR, attenuation);
|
||||||
alSourcef(sourceID, AL_DOPPLER_FACTOR, doppler);
|
alSourcef(sourceID, AL_DOPPLER_FACTOR, doppler);
|
||||||
alSourcef(sourceID, AL_REFERENCE_DISTANCE, FLAX_DST_TO_OAL(minDistance));
|
alSourcef(sourceID, AL_REFERENCE_DISTANCE, FLAX_DST_TO_OAL(minDistance));
|
||||||
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position));
|
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position));
|
||||||
alSource3f(sourceID, AL_VELOCITY, FLAX_VEL_TO_OAL(Vector3::Zero));
|
alSource3f(sourceID, AL_VELOCITY, FLAX_VEL_TO_OAL(Vector3::Zero));
|
||||||
|
#ifdef AL_EXT_STEREO_ANGLES
|
||||||
|
const float panAngle = pan * PI_HALF;
|
||||||
|
const ALfloat panAngles[2] = { (ALfloat)(PI / 6.0 - panAngle), (ALfloat)(-PI / 6.0 - panAngle) }; // Angles are specified counter-clockwise in radians
|
||||||
|
alSourcefv(sourceID, AL_STEREO_ANGLES, panAngles);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
alSourcef(sourceID, AL_ROLLOFF_FACTOR, 0.0f);
|
alSourcef(sourceID, AL_ROLLOFF_FACTOR, 0.0f);
|
||||||
alSourcef(sourceID, AL_DOPPLER_FACTOR, 1.0f);
|
alSourcef(sourceID, AL_DOPPLER_FACTOR, 1.0f);
|
||||||
alSourcef(sourceID, AL_REFERENCE_DISTANCE, 0.0f);
|
alSourcef(sourceID, AL_REFERENCE_DISTANCE, 0.0f);
|
||||||
alSource3f(sourceID, AL_POSITION, 0.0f, 0.0f, 0.0f);
|
alSource3f(sourceID, AL_POSITION, pan, 0, -sqrtf(1.0f - pan * pan));
|
||||||
alSource3f(sourceID, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
|
alSource3f(sourceID, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
|
||||||
}
|
}
|
||||||
#ifdef AL_EXT_STEREO_ANGLES
|
|
||||||
const float panAngle = pan * PI_HALF;
|
|
||||||
const ALfloat panAngles[2] = { (ALfloat)(PI / 6.0 - panAngle), (ALfloat)(-PI / 6.0 - panAngle) }; // Angles are specified counter-clockwise in radians
|
|
||||||
alSourcefv(sourceID, AL_STEREO_ANGLES, panAngles);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,7 +309,9 @@ uint32 AudioBackendOAL::Source_Add(const AudioDataInfo& format, const Vector3& p
|
|||||||
|
|
||||||
// Cache audio data format assigned on source (used in Source_GetCurrentBufferTime)
|
// Cache audio data format assigned on source (used in Source_GetCurrentBufferTime)
|
||||||
ALC::Locker.Lock();
|
ALC::Locker.Lock();
|
||||||
ALC::SourceIDtoFormat[sourceID] = format;
|
auto& data = ALC::SourcesData[sourceID];
|
||||||
|
data.Format = format;
|
||||||
|
data.Spatial = spatial;
|
||||||
ALC::Locker.Unlock();
|
ALC::Locker.Unlock();
|
||||||
|
|
||||||
return sourceID;
|
return sourceID;
|
||||||
@@ -317,18 +325,30 @@ void AudioBackendOAL::Source_Remove(uint32 sourceID)
|
|||||||
ALC_CHECK_ERROR(alDeleteSources);
|
ALC_CHECK_ERROR(alDeleteSources);
|
||||||
|
|
||||||
ALC::Locker.Lock();
|
ALC::Locker.Lock();
|
||||||
ALC::SourceIDtoFormat.Remove(sourceID);
|
ALC::SourcesData.Remove(sourceID);
|
||||||
ALC::Locker.Unlock();
|
ALC::Locker.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioBackendOAL::Source_VelocityChanged(uint32 sourceID, const Vector3& velocity)
|
void AudioBackendOAL::Source_VelocityChanged(uint32 sourceID, const Vector3& velocity)
|
||||||
{
|
{
|
||||||
alSource3f(sourceID, AL_VELOCITY, FLAX_VEL_TO_OAL(velocity));
|
ALC::Locker.Lock();
|
||||||
|
const bool spatial = ALC::SourcesData[sourceID].Spatial;
|
||||||
|
ALC::Locker.Unlock();
|
||||||
|
if (spatial)
|
||||||
|
{
|
||||||
|
alSource3f(sourceID, AL_VELOCITY, FLAX_VEL_TO_OAL(velocity));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioBackendOAL::Source_TransformChanged(uint32 sourceID, const Vector3& position, const Quaternion& orientation)
|
void AudioBackendOAL::Source_TransformChanged(uint32 sourceID, const Vector3& position, const Quaternion& orientation)
|
||||||
{
|
{
|
||||||
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position));
|
ALC::Locker.Lock();
|
||||||
|
const bool spatial = ALC::SourcesData[sourceID].Spatial;
|
||||||
|
ALC::Locker.Unlock();
|
||||||
|
if (spatial)
|
||||||
|
{
|
||||||
|
alSource3f(sourceID, AL_POSITION, FLAX_POS_TO_OAL(position));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioBackendOAL::Source_VolumeChanged(uint32 sourceID, float volume)
|
void AudioBackendOAL::Source_VolumeChanged(uint32 sourceID, float volume)
|
||||||
@@ -343,11 +363,21 @@ void AudioBackendOAL::Source_PitchChanged(uint32 sourceID, float pitch)
|
|||||||
|
|
||||||
void AudioBackendOAL::Source_PanChanged(uint32 sourceID, float pan)
|
void AudioBackendOAL::Source_PanChanged(uint32 sourceID, float pan)
|
||||||
{
|
{
|
||||||
|
ALC::Locker.Lock();
|
||||||
|
const bool spatial = ALC::SourcesData[sourceID].Spatial;
|
||||||
|
ALC::Locker.Unlock();
|
||||||
|
if (spatial)
|
||||||
|
{
|
||||||
#ifdef AL_EXT_STEREO_ANGLES
|
#ifdef AL_EXT_STEREO_ANGLES
|
||||||
const float panAngle = pan * PI_HALF;
|
const float panAngle = pan * PI_HALF;
|
||||||
const ALfloat panAngles[2] = { (ALfloat)(PI / 6.0 - panAngle), (ALfloat)(-PI / 6.0 - panAngle) }; // Angles are specified counter-clockwise in radians
|
const ALfloat panAngles[2] = { (ALfloat)(PI / 6.0 - panAngle), (ALfloat)(-PI / 6.0 - panAngle) }; // Angles are specified counter-clockwise in radians
|
||||||
alSourcefv(sourceID, AL_STEREO_ANGLES, panAngles);
|
alSourcefv(sourceID, AL_STEREO_ANGLES, panAngles);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
alSource3f(sourceID, AL_POSITION, pan, 0, -sqrtf(1.0f - pan * pan));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioBackendOAL::Source_IsLoopingChanged(uint32 sourceID, bool loop)
|
void AudioBackendOAL::Source_IsLoopingChanged(uint32 sourceID, bool loop)
|
||||||
@@ -357,12 +387,8 @@ void AudioBackendOAL::Source_IsLoopingChanged(uint32 sourceID, bool loop)
|
|||||||
|
|
||||||
void AudioBackendOAL::Source_SpatialSetupChanged(uint32 sourceID, bool spatial, float attenuation, float minDistance, float doppler)
|
void AudioBackendOAL::Source_SpatialSetupChanged(uint32 sourceID, bool spatial, float attenuation, float minDistance, float doppler)
|
||||||
{
|
{
|
||||||
alSourcei(sourceID, AL_SOURCE_RELATIVE, !spatial);
|
|
||||||
if (spatial)
|
if (spatial)
|
||||||
{
|
{
|
||||||
#ifdef AL_SOFT_source_spatialize
|
|
||||||
alSourcei(sourceID, AL_SOURCE_SPATIALIZE_SOFT, AL_TRUE);
|
|
||||||
#endif
|
|
||||||
alSourcef(sourceID, AL_ROLLOFF_FACTOR, attenuation);
|
alSourcef(sourceID, AL_ROLLOFF_FACTOR, attenuation);
|
||||||
alSourcef(sourceID, AL_DOPPLER_FACTOR, doppler);
|
alSourcef(sourceID, AL_DOPPLER_FACTOR, doppler);
|
||||||
alSourcef(sourceID, AL_REFERENCE_DISTANCE, FLAX_DST_TO_OAL(minDistance));
|
alSourcef(sourceID, AL_REFERENCE_DISTANCE, FLAX_DST_TO_OAL(minDistance));
|
||||||
@@ -411,7 +437,7 @@ float AudioBackendOAL::Source_GetCurrentBufferTime(uint32 sourceID)
|
|||||||
alGetSourcef(sourceID, AL_SEC_OFFSET, &time);
|
alGetSourcef(sourceID, AL_SEC_OFFSET, &time);
|
||||||
#else
|
#else
|
||||||
ALC::Locker.Lock();
|
ALC::Locker.Lock();
|
||||||
AudioDataInfo clipInfo = ALC::SourceIDtoFormat[sourceID];
|
AudioDataInfo clipInfo = ALC::SourcesData[sourceID].Format;
|
||||||
ALC::Locker.Unlock();
|
ALC::Locker.Unlock();
|
||||||
ALint samplesPlayed;
|
ALint samplesPlayed;
|
||||||
alGetSourcei(sourceID, AL_SAMPLE_OFFSET, &samplesPlayed);
|
alGetSourcei(sourceID, AL_SAMPLE_OFFSET, &samplesPlayed);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user