Merge remote-tracking branch 'origin/master' into 1.10
# Conflicts: # Source/Engine/Graphics/Materials/MaterialShader.h
This commit is contained in:
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|||||||
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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -883,7 +883,7 @@ namespace FlaxEditor.CustomEditors
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void ClearToken()
|
protected virtual void ClearToken()
|
||||||
{
|
{
|
||||||
ParentEditor.ClearToken();
|
ParentEditor?.ClearToken();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,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
|
||||||
@@ -81,17 +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 += () => Editor.Instance.Windows.ContentWin.Open(Editor.Instance.ContentDatabase.FindAsset(prefab.ID));
|
editPrefab.Button.Clicked += () => Editor.Instance.Windows.ContentWin.Open(Editor.Instance.ContentDatabase.FindAsset(targetPrefab.ID));
|
||||||
|
|
||||||
// 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;
|
||||||
|
|||||||
@@ -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 />
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -437,13 +456,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
|
||||||
@@ -468,6 +487,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
|
||||||
@@ -486,7 +542,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 />
|
||||||
@@ -558,6 +625,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);
|
||||||
}
|
}
|
||||||
@@ -568,7 +636,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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -98,10 +96,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)
|
||||||
{
|
{
|
||||||
@@ -114,12 +112,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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -150,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;
|
||||||
|
|
||||||
@@ -564,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
|
||||||
@@ -641,7 +642,68 @@ 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -651,8 +713,7 @@ namespace FlaxEditor
|
|||||||
var control = uiControl.Control;
|
var control = uiControl.Control;
|
||||||
var rotation = control.Rotation;
|
var rotation = control.Rotation;
|
||||||
var rotationInRadians = rotation * Mathf.DegreesToRadians;
|
var rotationInRadians = rotation * Mathf.DegreesToRadians;
|
||||||
var rect = new Rectangle(
|
var rect = new Rectangle((pos +
|
||||||
(pos +
|
|
||||||
new Float2(resizeAxis.X * Mathf.Cos(rotationInRadians) - resizeAxis.Y * Mathf.Sin(rotationInRadians),
|
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,
|
resizeAxis.Y * Mathf.Cos(rotationInRadians) + resizeAxis.X * Mathf.Sin(rotationInRadians)) * 10 * scale) - size * 0.5f,
|
||||||
size);
|
size);
|
||||||
@@ -714,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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -1193,9 +1193,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;
|
||||||
@@ -1206,15 +1206,8 @@ 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 && selectedIndex < _editor.BlendPoints.Count && (ContainsFocus || IsMouseOver))
|
if (selectedIndex != -1 && selectedIndex < _editor.BlendPoints.Count && (ContainsFocus || IsMouseOver))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -648,6 +679,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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
#include "Engine/Utilities/StringConverter.h"
|
#include "Engine/Utilities/StringConverter.h"
|
||||||
#include "Engine/Threading/MainThreadTask.h"
|
#include "Engine/Threading/MainThreadTask.h"
|
||||||
|
#include "Engine/Level/SceneObject.h"
|
||||||
#include "FlaxEngine.Gen.h"
|
#include "FlaxEngine.Gen.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@@ -41,6 +42,22 @@ namespace
|
|||||||
Log::Logger::Write(type, stack);
|
Log::Logger::Write(type, stack);
|
||||||
Log::Logger::Write(type, TEXT(""));
|
Log::Logger::Write(type, TEXT(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SerializeValue(const Variant& a, const Variant& b)
|
||||||
|
{
|
||||||
|
bool result = a != b;
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
// Special case for scene objects to handle prefab object references
|
||||||
|
auto* aSceneObject = ScriptingObject::Cast<SceneObject>((ScriptingObject*)a);
|
||||||
|
auto* bSceneObject = ScriptingObject::Cast<SceneObject>((ScriptingObject*)b);
|
||||||
|
if (aSceneObject && bSceneObject)
|
||||||
|
{
|
||||||
|
result = Serialization::ShouldSerialize(aSceneObject, bSceneObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if VISUAL_SCRIPT_DEBUGGING
|
#if VISUAL_SCRIPT_DEBUGGING
|
||||||
@@ -1978,7 +1995,7 @@ void VisualScriptingBinaryModule::SerializeObject(JsonWriter& stream, ScriptingO
|
|||||||
auto& param = asset->Graph.Parameters[paramIndex];
|
auto& param = asset->Graph.Parameters[paramIndex];
|
||||||
auto& value = params[paramIndex];
|
auto& value = params[paramIndex];
|
||||||
auto& otherValue = otherParams->Value.Params[paramIndex];
|
auto& otherValue = otherParams->Value.Params[paramIndex];
|
||||||
if (value != otherValue)
|
if (SerializeValue(value, otherValue))
|
||||||
{
|
{
|
||||||
param.Identifier.ToString(idName, Guid::FormatType::N);
|
param.Identifier.ToString(idName, Guid::FormatType::N);
|
||||||
stream.Key(idName, 32);
|
stream.Key(idName, 32);
|
||||||
@@ -1993,7 +2010,7 @@ void VisualScriptingBinaryModule::SerializeObject(JsonWriter& stream, ScriptingO
|
|||||||
auto& param = asset->Graph.Parameters[paramIndex];
|
auto& param = asset->Graph.Parameters[paramIndex];
|
||||||
auto& value = params[paramIndex];
|
auto& value = params[paramIndex];
|
||||||
auto& otherValue = param.Value;
|
auto& otherValue = param.Value;
|
||||||
if (value != otherValue)
|
if (SerializeValue(value, otherValue))
|
||||||
{
|
{
|
||||||
param.Identifier.ToString(idName, Guid::FormatType::N);
|
param.Identifier.ToString(idName, Guid::FormatType::N);
|
||||||
stream.Key(idName, 32);
|
stream.Key(idName, 32);
|
||||||
|
|||||||
@@ -1263,8 +1263,10 @@ namespace FlaxEngine
|
|||||||
/// <returns>The position snapped to the grid.</returns>
|
/// <returns>The position snapped to the grid.</returns>
|
||||||
public static Double2 SnapToGrid(Double2 pos, Double2 gridSize)
|
public static Double2 SnapToGrid(Double2 pos, Double2 gridSize)
|
||||||
{
|
{
|
||||||
pos.X = Mathd.Ceil((pos.X - (gridSize.X * 0.5)) / gridSize.Y) * gridSize.X;
|
if (Mathd.Abs(gridSize.X) > Mathd.Epsilon)
|
||||||
pos.Y = Mathd.Ceil((pos.Y - (gridSize.Y * 0.5)) / gridSize.X) * gridSize.Y;
|
pos.X = Mathd.Ceil((pos.X - (gridSize.X * 0.5)) / gridSize.Y) * gridSize.X;
|
||||||
|
if (Mathd.Abs(gridSize.Y) > Mathd.Epsilon)
|
||||||
|
pos.Y = Mathd.Ceil((pos.Y - (gridSize.Y * 0.5)) / gridSize.X) * gridSize.Y;
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1544,9 +1544,12 @@ namespace FlaxEngine
|
|||||||
/// <returns>The position snapped to the grid.</returns>
|
/// <returns>The position snapped to the grid.</returns>
|
||||||
public static Double3 SnapToGrid(Double3 pos, Double3 gridSize)
|
public static Double3 SnapToGrid(Double3 pos, Double3 gridSize)
|
||||||
{
|
{
|
||||||
pos.X = Mathd.Ceil((pos.X - (gridSize.X * 0.5)) / gridSize.X) * gridSize.X;
|
if (Mathd.Abs(gridSize.X) > Mathd.Epsilon)
|
||||||
pos.Y = Mathd.Ceil((pos.Y - (gridSize.Y * 0.5)) / gridSize.Y) * gridSize.Y;
|
pos.X = Mathd.Ceil((pos.X - (gridSize.X * 0.5)) / gridSize.X) * gridSize.X;
|
||||||
pos.Z = Mathd.Ceil((pos.Z - (gridSize.Z * 0.5)) / gridSize.Z) * gridSize.Z;
|
if (Mathd.Abs(gridSize.Y) > Mathd.Epsilon)
|
||||||
|
pos.Y = Mathd.Ceil((pos.Y - (gridSize.Y * 0.5)) / gridSize.Y) * gridSize.Y;
|
||||||
|
if (Mathd.Abs(gridSize.Z) > Mathd.Epsilon)
|
||||||
|
pos.Z = Mathd.Ceil((pos.Z - (gridSize.Z * 0.5)) / gridSize.Z) * gridSize.Z;
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Vector4.h"
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a 4x4 mathematical matrix using double-precision floating-point values.
|
||||||
|
/// </summary>
|
||||||
|
struct FLAXENGINE_API Double4x4
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
/// <summary>Value at row 1 column 1 of the matrix.</summary>
|
||||||
|
double M11;
|
||||||
|
|
||||||
|
/// <summary>Value at row 1 column 2 of the matrix.</summary>
|
||||||
|
double M12;
|
||||||
|
|
||||||
|
/// <summary>Value at row 1 column 3 of the matrix.</summary>
|
||||||
|
double M13;
|
||||||
|
|
||||||
|
/// <summary>Value at row 1 column 4 of the matrix.</summary>
|
||||||
|
double M14;
|
||||||
|
|
||||||
|
/// <summary>Value at row 2 column 1 of the matrix.</summary>
|
||||||
|
double M21;
|
||||||
|
|
||||||
|
/// <summary>Value at row 2 column 2 of the matrix.</summary>
|
||||||
|
double M22;
|
||||||
|
|
||||||
|
/// <summary>Value at row 2 column 3 of the matrix.</summary>
|
||||||
|
double M23;
|
||||||
|
|
||||||
|
/// <summary>Value at row 2 column 4 of the matrix.</summary>
|
||||||
|
double M24;
|
||||||
|
|
||||||
|
/// <summary>Value at row 3 column 1 of the matrix.</summary>
|
||||||
|
double M31;
|
||||||
|
|
||||||
|
/// <summary>Value at row 3 column 2 of the matrix.</summary>
|
||||||
|
double M32;
|
||||||
|
|
||||||
|
/// <summary>Value at row 3 column 3 of the matrix.</summary>
|
||||||
|
double M33;
|
||||||
|
|
||||||
|
/// <summary>Value at row 3 column 4 of the matrix.</summary>
|
||||||
|
double M34;
|
||||||
|
|
||||||
|
/// <summary>Value at row 4 column 1 of the matrix.</summary>
|
||||||
|
double M41;
|
||||||
|
|
||||||
|
/// <summary>Value at row 4 column 2 of the matrix.</summary>
|
||||||
|
double M42;
|
||||||
|
|
||||||
|
/// <summary>Value at row 4 column 3 of the matrix.</summary>
|
||||||
|
double M43;
|
||||||
|
|
||||||
|
/// <summary>Value at row 4 column 4 of the matrix.</summary>
|
||||||
|
double M44;
|
||||||
|
};
|
||||||
|
|
||||||
|
double Values[4][4];
|
||||||
|
double Raw[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// Empty constructor.
|
||||||
|
/// </summary>
|
||||||
|
Double4x4() = default;
|
||||||
|
|
||||||
|
Double4x4(const Matrix& matrix);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Inverts the matrix.
|
||||||
|
void Invert()
|
||||||
|
{
|
||||||
|
Invert(*this, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates the inverse of the specified matrix.
|
||||||
|
static Double4x4 Invert(const Double4x4& value)
|
||||||
|
{
|
||||||
|
Double4x4 result;
|
||||||
|
Invert(value, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculates the inverse of the specified matrix.
|
||||||
|
static void Invert(const Double4x4& value, Double4x4& result);
|
||||||
|
|
||||||
|
// Calculates the product of two matrices.
|
||||||
|
static void Multiply(const Double4x4& left, const Double4x4& right, Double4x4& result);
|
||||||
|
|
||||||
|
// Creates a matrix that contains both the X, Y and Z rotation, as well as scaling and translation.
|
||||||
|
static void Transformation(const Float3& scaling, const Quaternion& rotation, const Vector3& translation, Double4x4& result);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Double4x4 operator*(const Double4x4& other) const
|
||||||
|
{
|
||||||
|
Double4x4 result;
|
||||||
|
Multiply(*this, other, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct TIsPODType<Double4x4>
|
||||||
|
{
|
||||||
|
enum { Value = true };
|
||||||
|
};
|
||||||
@@ -1291,8 +1291,10 @@ namespace FlaxEngine
|
|||||||
/// <returns>The position snapped to the grid.</returns>
|
/// <returns>The position snapped to the grid.</returns>
|
||||||
public static Float2 SnapToGrid(Float2 pos, Float2 gridSize)
|
public static Float2 SnapToGrid(Float2 pos, Float2 gridSize)
|
||||||
{
|
{
|
||||||
pos.X = Mathf.Ceil((pos.X - (gridSize.X * 0.5f)) / gridSize.X) * gridSize.X;
|
if (Mathf.Abs(gridSize.X) > Mathf.Epsilon)
|
||||||
pos.Y = Mathf.Ceil((pos.Y - (gridSize.Y * 0.5f)) / gridSize.Y) * gridSize.Y;
|
pos.X = Mathf.Ceil((pos.X - (gridSize.X * 0.5f)) / gridSize.X) * gridSize.X;
|
||||||
|
if (Mathf.Abs(gridSize.Y) > Mathf.Epsilon)
|
||||||
|
pos.Y = Mathf.Ceil((pos.Y - (gridSize.Y * 0.5f)) / gridSize.Y) * gridSize.Y;
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1528,9 +1528,12 @@ namespace FlaxEngine
|
|||||||
/// <returns>The position snapped to the grid.</returns>
|
/// <returns>The position snapped to the grid.</returns>
|
||||||
public static Float3 SnapToGrid(Float3 pos, Float3 gridSize)
|
public static Float3 SnapToGrid(Float3 pos, Float3 gridSize)
|
||||||
{
|
{
|
||||||
pos.X = Mathf.Ceil((pos.X - (gridSize.X * 0.5f)) / gridSize.X) * gridSize.X;
|
if (Mathf.Abs(gridSize.X) > Mathf.Epsilon)
|
||||||
pos.Y = Mathf.Ceil((pos.Y - (gridSize.Y * 0.5f)) / gridSize.Y) * gridSize.Y;
|
pos.X = Mathf.Ceil((pos.X - (gridSize.X * 0.5f)) / gridSize.X) * gridSize.X;
|
||||||
pos.Z = Mathf.Ceil((pos.Z - (gridSize.Z * 0.5f)) / gridSize.Z) * gridSize.Z;
|
if (Mathf.Abs(gridSize.Y) > Mathf.Epsilon)
|
||||||
|
pos.Y = Mathf.Ceil((pos.Y - (gridSize.Y * 0.5f)) / gridSize.Y) * gridSize.Y;
|
||||||
|
if (Mathf.Abs(gridSize.Z) > Mathf.Epsilon)
|
||||||
|
pos.Z = Mathf.Ceil((pos.Z - (gridSize.Z * 0.5f)) / gridSize.Z) * gridSize.Z;
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
#include "Matrix.h"
|
#include "Matrix.h"
|
||||||
|
#include "Double4x4.h"
|
||||||
#include "Matrix3x3.h"
|
#include "Matrix3x3.h"
|
||||||
#include "Matrix3x4.h"
|
#include "Matrix3x4.h"
|
||||||
#include "Vector2.h"
|
#include "Vector2.h"
|
||||||
@@ -28,6 +29,12 @@ Matrix::Matrix(const Matrix3x3& matrix)
|
|||||||
M44 = 1.0f;
|
M44 = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Matrix::Matrix(const Double4x4& matrix)
|
||||||
|
{
|
||||||
|
for (int32 i = 0; i < 16; i++)
|
||||||
|
Raw[i] = (float)matrix.Raw[i];
|
||||||
|
}
|
||||||
|
|
||||||
String Matrix::ToString() const
|
String Matrix::ToString() const
|
||||||
{
|
{
|
||||||
return String::Format(TEXT("{}"), *this);
|
return String::Format(TEXT("{}"), *this);
|
||||||
@@ -924,3 +931,144 @@ void Matrix3x4::SetMatrixTranspose(const Matrix& m)
|
|||||||
dst[10] = src[10];
|
dst[10] = src[10];
|
||||||
dst[11] = src[14];
|
dst[11] = src[14];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Double4x4::Double4x4(const Matrix& matrix)
|
||||||
|
{
|
||||||
|
for (int32 i = 0; i < 16; i++)
|
||||||
|
Raw[i] = matrix.Raw[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Double4x4::Invert(const Double4x4& value, Double4x4& result)
|
||||||
|
{
|
||||||
|
const double b0 = value.M31 * value.M42 - value.M32 * value.M41;
|
||||||
|
const double b1 = value.M31 * value.M43 - value.M33 * value.M41;
|
||||||
|
const double b2 = value.M34 * value.M41 - value.M31 * value.M44;
|
||||||
|
const double b3 = value.M32 * value.M43 - value.M33 * value.M42;
|
||||||
|
const double b4 = value.M34 * value.M42 - value.M32 * value.M44;
|
||||||
|
const double b5 = value.M33 * value.M44 - value.M34 * value.M43;
|
||||||
|
|
||||||
|
const double d11 = value.M22 * b5 + value.M23 * b4 + value.M24 * b3;
|
||||||
|
const double d12 = value.M21 * b5 + value.M23 * b2 + value.M24 * b1;
|
||||||
|
const double d13 = value.M21 * -b4 + value.M22 * b2 + value.M24 * b0;
|
||||||
|
const double d14 = value.M21 * b3 + value.M22 * -b1 + value.M23 * b0;
|
||||||
|
|
||||||
|
double det = value.M11 * d11 - value.M12 * d12 + value.M13 * d13 - value.M14 * d14;
|
||||||
|
if (Math::Abs(det) <= 1e-12)
|
||||||
|
{
|
||||||
|
Platform::MemoryClear(&result, sizeof(Double4x4));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
det = 1.0 / det;
|
||||||
|
|
||||||
|
const double a0 = value.M11 * value.M22 - value.M12 * value.M21;
|
||||||
|
const double a1 = value.M11 * value.M23 - value.M13 * value.M21;
|
||||||
|
const double a2 = value.M14 * value.M21 - value.M11 * value.M24;
|
||||||
|
const double a3 = value.M12 * value.M23 - value.M13 * value.M22;
|
||||||
|
const double a4 = value.M14 * value.M22 - value.M12 * value.M24;
|
||||||
|
const double a5 = value.M13 * value.M24 - value.M14 * value.M23;
|
||||||
|
|
||||||
|
const double d21 = value.M12 * b5 + value.M13 * b4 + value.M14 * b3;
|
||||||
|
const double d22 = value.M11 * b5 + value.M13 * b2 + value.M14 * b1;
|
||||||
|
const double d23 = value.M11 * -b4 + value.M12 * b2 + value.M14 * b0;
|
||||||
|
const double d24 = value.M11 * b3 + value.M12 * -b1 + value.M13 * b0;
|
||||||
|
|
||||||
|
const double d31 = value.M42 * a5 + value.M43 * a4 + value.M44 * a3;
|
||||||
|
const double d32 = value.M41 * a5 + value.M43 * a2 + value.M44 * a1;
|
||||||
|
const double d33 = value.M41 * -a4 + value.M42 * a2 + value.M44 * a0;
|
||||||
|
const double d34 = value.M41 * a3 + value.M42 * -a1 + value.M43 * a0;
|
||||||
|
|
||||||
|
const double d41 = value.M32 * a5 + value.M33 * a4 + value.M34 * a3;
|
||||||
|
const double d42 = value.M31 * a5 + value.M33 * a2 + value.M34 * a1;
|
||||||
|
const double d43 = value.M31 * -a4 + value.M32 * a2 + value.M34 * a0;
|
||||||
|
const double d44 = value.M31 * a3 + value.M32 * -a1 + value.M33 * a0;
|
||||||
|
|
||||||
|
result.M11 = +d11 * det;
|
||||||
|
result.M12 = -d21 * det;
|
||||||
|
result.M13 = +d31 * det;
|
||||||
|
result.M14 = -d41 * det;
|
||||||
|
result.M21 = -d12 * det;
|
||||||
|
result.M22 = +d22 * det;
|
||||||
|
result.M23 = -d32 * det;
|
||||||
|
result.M24 = +d42 * det;
|
||||||
|
result.M31 = +d13 * det;
|
||||||
|
result.M32 = -d23 * det;
|
||||||
|
result.M33 = +d33 * det;
|
||||||
|
result.M34 = -d43 * det;
|
||||||
|
result.M41 = -d14 * det;
|
||||||
|
result.M42 = +d24 * det;
|
||||||
|
result.M43 = -d34 * det;
|
||||||
|
result.M44 = +d44 * det;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Double4x4::Multiply(const Double4x4& left, const Double4x4& right, Double4x4& result)
|
||||||
|
{
|
||||||
|
result.M11 = left.M11 * right.M11 + left.M12 * right.M21 + left.M13 * right.M31 + left.M14 * right.M41;
|
||||||
|
result.M12 = left.M11 * right.M12 + left.M12 * right.M22 + left.M13 * right.M32 + left.M14 * right.M42;
|
||||||
|
result.M13 = left.M11 * right.M13 + left.M12 * right.M23 + left.M13 * right.M33 + left.M14 * right.M43;
|
||||||
|
result.M14 = left.M11 * right.M14 + left.M12 * right.M24 + left.M13 * right.M34 + left.M14 * right.M44;
|
||||||
|
result.M21 = left.M21 * right.M11 + left.M22 * right.M21 + left.M23 * right.M31 + left.M24 * right.M41;
|
||||||
|
result.M22 = left.M21 * right.M12 + left.M22 * right.M22 + left.M23 * right.M32 + left.M24 * right.M42;
|
||||||
|
result.M23 = left.M21 * right.M13 + left.M22 * right.M23 + left.M23 * right.M33 + left.M24 * right.M43;
|
||||||
|
result.M24 = left.M21 * right.M14 + left.M22 * right.M24 + left.M23 * right.M34 + left.M24 * right.M44;
|
||||||
|
result.M31 = left.M31 * right.M11 + left.M32 * right.M21 + left.M33 * right.M31 + left.M34 * right.M41;
|
||||||
|
result.M32 = left.M31 * right.M12 + left.M32 * right.M22 + left.M33 * right.M32 + left.M34 * right.M42;
|
||||||
|
result.M33 = left.M31 * right.M13 + left.M32 * right.M23 + left.M33 * right.M33 + left.M34 * right.M43;
|
||||||
|
result.M34 = left.M31 * right.M14 + left.M32 * right.M24 + left.M33 * right.M34 + left.M34 * right.M44;
|
||||||
|
result.M41 = left.M41 * right.M11 + left.M42 * right.M21 + left.M43 * right.M31 + left.M44 * right.M41;
|
||||||
|
result.M42 = left.M41 * right.M12 + left.M42 * right.M22 + left.M43 * right.M32 + left.M44 * right.M42;
|
||||||
|
result.M43 = left.M41 * right.M13 + left.M42 * right.M23 + left.M43 * right.M33 + left.M44 * right.M43;
|
||||||
|
result.M44 = left.M41 * right.M14 + left.M42 * right.M24 + left.M43 * right.M34 + left.M44 * right.M44;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Double4x4::Transformation(const Float3& scaling, const Quaternion& rotation, const Vector3& translation, Double4x4& result)
|
||||||
|
{
|
||||||
|
// Equivalent to:
|
||||||
|
//result =
|
||||||
|
// Matrix.Scaling(scaling)
|
||||||
|
// *Matrix.RotationX(rotation.X)
|
||||||
|
// *Matrix.RotationY(rotation.Y)
|
||||||
|
// *Matrix.RotationZ(rotation.Z)
|
||||||
|
// *Matrix.Position(translation);
|
||||||
|
|
||||||
|
// Rotation
|
||||||
|
const float xx = rotation.X * rotation.X;
|
||||||
|
const float yy = rotation.Y * rotation.Y;
|
||||||
|
const float zz = rotation.Z * rotation.Z;
|
||||||
|
const float xy = rotation.X * rotation.Y;
|
||||||
|
const float zw = rotation.Z * rotation.W;
|
||||||
|
const float zx = rotation.Z * rotation.X;
|
||||||
|
const float yw = rotation.Y * rotation.W;
|
||||||
|
const float yz = rotation.Y * rotation.Z;
|
||||||
|
const float xw = rotation.X * rotation.W;
|
||||||
|
result.M11 = 1.0f - 2.0f * (yy + zz);
|
||||||
|
result.M12 = 2.0f * (xy + zw);
|
||||||
|
result.M13 = 2.0f * (zx - yw);
|
||||||
|
result.M21 = 2.0f * (xy - zw);
|
||||||
|
result.M22 = 1.0f - 2.0f * (zz + xx);
|
||||||
|
result.M23 = 2.0f * (yz + xw);
|
||||||
|
result.M31 = 2.0f * (zx + yw);
|
||||||
|
result.M32 = 2.0f * (yz - xw);
|
||||||
|
result.M33 = 1.0f - 2.0f * (yy + xx);
|
||||||
|
|
||||||
|
// Position
|
||||||
|
result.M41 = translation.X;
|
||||||
|
result.M42 = translation.Y;
|
||||||
|
result.M43 = translation.Z;
|
||||||
|
|
||||||
|
// Scale
|
||||||
|
result.M11 *= scaling.X;
|
||||||
|
result.M12 *= scaling.X;
|
||||||
|
result.M13 *= scaling.X;
|
||||||
|
result.M21 *= scaling.Y;
|
||||||
|
result.M22 *= scaling.Y;
|
||||||
|
result.M23 *= scaling.Y;
|
||||||
|
result.M31 *= scaling.Z;
|
||||||
|
result.M32 *= scaling.Z;
|
||||||
|
result.M33 *= scaling.Z;
|
||||||
|
|
||||||
|
result.M14 = 0.0;
|
||||||
|
result.M24 = 0.0;
|
||||||
|
result.M34 = 0.0;
|
||||||
|
result.M44 = 1.0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -146,6 +146,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
explicit Matrix(const Matrix3x3& matrix);
|
explicit Matrix(const Matrix3x3& matrix);
|
||||||
|
explicit Matrix(const Double4x4& matrix);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
String ToString() const;
|
String ToString() const;
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ namespace FlaxEngine
|
|||||||
{
|
{
|
||||||
Position = position;
|
Position = position;
|
||||||
Direction = direction;
|
Direction = direction;
|
||||||
Assert.IsTrue(Direction.IsNormalized, "The Ray Direction was not normalized");
|
Assert.IsTrue(Direction.IsNormalized, $"The Ray Direction was not normalized (direction: {direction}, length: {direction.Length})");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
#include "Transform.h"
|
#include "Transform.h"
|
||||||
|
#include "Double4x4.h"
|
||||||
#include "Matrix.h"
|
#include "Matrix.h"
|
||||||
#include "Matrix3x3.h"
|
#include "Matrix3x3.h"
|
||||||
#include "../Types/String.h"
|
#include "../Types/String.h"
|
||||||
@@ -57,6 +58,11 @@ void Transform::GetWorld(Matrix& result) const
|
|||||||
Matrix::Transformation(Scale, Orientation, Translation, result);
|
Matrix::Transformation(Scale, Orientation, Translation, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Transform::GetWorld(Double4x4& result) const
|
||||||
|
{
|
||||||
|
Double4x4::Transformation(Scale, Orientation, Translation, result);
|
||||||
|
}
|
||||||
|
|
||||||
Transform Transform::Add(const Vector3& translation) const
|
Transform Transform::Add(const Vector3& translation) const
|
||||||
{
|
{
|
||||||
Transform result;
|
Transform result;
|
||||||
|
|||||||
@@ -136,6 +136,12 @@ public:
|
|||||||
/// <param name="result">World matrix</param>
|
/// <param name="result">World matrix</param>
|
||||||
void GetWorld(Matrix& result) const;
|
void GetWorld(Matrix& result) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets world matrix that describes transformation as a 4 by 4 matrix.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result">World matrix</param>
|
||||||
|
void GetWorld(Double4x4& result) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds translation to this transform.
|
/// Adds translation to this transform.
|
||||||
|
|||||||
@@ -1689,6 +1689,16 @@ namespace FlaxEngine
|
|||||||
return new Double2(value.X, value.Y);
|
return new Double2(value.X, value.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs an explicit conversion from <see cref="Vector2" /> to <see cref="Int2" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <returns>The result of the conversion.</returns>
|
||||||
|
public static explicit operator Int2(Vector2 value)
|
||||||
|
{
|
||||||
|
return new Int2((int)value.X, (int)value.Y);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs an explicit conversion from <see cref="Vector2" /> to <see cref="Vector3" />.
|
/// Performs an explicit conversion from <see cref="Vector2" /> to <see cref="Vector3" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -2026,7 +2026,7 @@ namespace FlaxEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs an explicit conversion from <see cref="Vector3" /> to <see cref="Float3" />.
|
/// Performs an implicit conversion from <see cref="Vector3" /> to <see cref="Float3" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The value.</param>
|
/// <param name="value">The value.</param>
|
||||||
/// <returns>The result of the conversion.</returns>
|
/// <returns>The result of the conversion.</returns>
|
||||||
@@ -2036,7 +2036,7 @@ namespace FlaxEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs an explicit conversion from <see cref="Vector3" /> to <see cref="Double3" />.
|
/// Performs an implicit conversion from <see cref="Vector3" /> to <see cref="Double3" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The value.</param>
|
/// <param name="value">The value.</param>
|
||||||
/// <returns>The result of the conversion.</returns>
|
/// <returns>The result of the conversion.</returns>
|
||||||
@@ -2045,6 +2045,16 @@ namespace FlaxEngine
|
|||||||
return new Double3(value.X, value.Y, value.Z);
|
return new Double3(value.X, value.Y, value.Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs an explicit conversion from <see cref="Vector3" /> to <see cref="Int3" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <returns>The result of the conversion.</returns>
|
||||||
|
public static explicit operator Int3(Vector3 value)
|
||||||
|
{
|
||||||
|
return new Int3((int)value.X, (int)value.Y, (int)value.Z);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs an explicit conversion from <see cref="Vector3" /> to <see cref="Vector2" />.
|
/// Performs an explicit conversion from <see cref="Vector3" /> to <see cref="Vector2" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1378,7 +1378,7 @@ namespace FlaxEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs an explicit conversion from <see cref="Vector4" /> to <see cref="Float4" />.
|
/// Performs an implicit conversion from <see cref="Vector4" /> to <see cref="Float4" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The value.</param>
|
/// <param name="value">The value.</param>
|
||||||
/// <returns>The result of the conversion.</returns>
|
/// <returns>The result of the conversion.</returns>
|
||||||
@@ -1388,7 +1388,7 @@ namespace FlaxEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs an explicit conversion from <see cref="Vector4" /> to <see cref="Double4" />.
|
/// Performs an implicit conversion from <see cref="Vector4" /> to <see cref="Double4" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The value.</param>
|
/// <param name="value">The value.</param>
|
||||||
/// <returns>The result of the conversion.</returns>
|
/// <returns>The result of the conversion.</returns>
|
||||||
@@ -1397,6 +1397,16 @@ namespace FlaxEngine
|
|||||||
return new Double4(value.X, value.Y, value.Z, value.W);
|
return new Double4(value.X, value.Y, value.Z, value.W);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs an explicit conversion from <see cref="Vector4" /> to <see cref="Int4" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
|
/// <returns>The result of the conversion.</returns>
|
||||||
|
public static explicit operator Int4(Vector4 value)
|
||||||
|
{
|
||||||
|
return new Int4((int)value.X, (int)value.Y, (int)value.Z, (int)value.W);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs an explicit conversion from <see cref="Vector4" /> to <see cref="Vector2" />.
|
/// Performs an explicit conversion from <see cref="Vector4" /> to <see cref="Vector2" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ API_TYPEDEF(Alias) typedef Vector4Base<Real> Vector4;
|
|||||||
struct BoundingBox;
|
struct BoundingBox;
|
||||||
struct Matrix;
|
struct Matrix;
|
||||||
struct Matrix3x3;
|
struct Matrix3x3;
|
||||||
|
struct Double4x4;
|
||||||
struct Ray;
|
struct Ray;
|
||||||
struct Plane;
|
struct Plane;
|
||||||
struct Rectangle;
|
struct Rectangle;
|
||||||
@@ -138,6 +139,11 @@ struct OrientedBoundingBox;
|
|||||||
struct Transform;
|
struct Transform;
|
||||||
struct Color;
|
struct Color;
|
||||||
struct Color32;
|
struct Color32;
|
||||||
|
#if USE_LARGE_WORLDS
|
||||||
|
typedef Double4x4 Real4x4;
|
||||||
|
#else
|
||||||
|
typedef Matrix Real4x4;
|
||||||
|
#endif
|
||||||
|
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
|
|||||||
@@ -3920,6 +3920,114 @@ Variant Variant::Cast(const Variant& v, const VariantType& to)
|
|||||||
default: ;
|
default: ;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case VariantType::Double2:
|
||||||
|
switch (to.Type)
|
||||||
|
{
|
||||||
|
case VariantType::Bool:
|
||||||
|
return Variant(Math::Abs(((Double2*)v.AsData)->X) > ZeroTolerance);
|
||||||
|
case VariantType::Int16:
|
||||||
|
return Variant((int16)((Double2*)v.AsData)->X);
|
||||||
|
case VariantType::Int:
|
||||||
|
return Variant((int32)((Double2*)v.AsData)->X);
|
||||||
|
case VariantType::Uint16:
|
||||||
|
return Variant((uint16)((Double2*)v.AsData)->X);
|
||||||
|
case VariantType::Uint:
|
||||||
|
return Variant((uint32)((Double2*)v.AsData)->X);
|
||||||
|
case VariantType::Int64:
|
||||||
|
return Variant((int64)((Double2*)v.AsData)->X);
|
||||||
|
case VariantType::Uint64:
|
||||||
|
return Variant((uint64)((Double2*)v.AsData)->X);
|
||||||
|
case VariantType::Float:
|
||||||
|
return Variant((float)((Double2*)v.AsData)->X);
|
||||||
|
case VariantType::Double:
|
||||||
|
return Variant((double)((Double2*)v.AsData)->X);
|
||||||
|
case VariantType::Float2:
|
||||||
|
return Variant(Float2(*(Double2*)v.AsData));
|
||||||
|
case VariantType::Float3:
|
||||||
|
return Variant(Float3(*(Double2*)v.AsData, 0.0f));
|
||||||
|
case VariantType::Float4:
|
||||||
|
return Variant(Float4(*(Double2*)v.AsData, 0.0f, 0.0f));
|
||||||
|
case VariantType::Color:
|
||||||
|
return Variant(Color(((Double2*)v.AsData)->X, ((Double2*)v.AsData)->Y, 0.0f, 0.0f));
|
||||||
|
case VariantType::Double3:
|
||||||
|
return Variant(Double3(*(Double2*)v.AsData, 0.0));
|
||||||
|
case VariantType::Double4:
|
||||||
|
return Variant(Double4(*(Double2*)v.AsData, 0.0, 0.0));
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VariantType::Double3:
|
||||||
|
switch (to.Type)
|
||||||
|
{
|
||||||
|
case VariantType::Bool:
|
||||||
|
return Variant(Math::Abs(((Double3*)v.AsData)->X) > ZeroTolerance);
|
||||||
|
case VariantType::Int16:
|
||||||
|
return Variant((int16)((Double3*)v.AsData)->X);
|
||||||
|
case VariantType::Int:
|
||||||
|
return Variant((int32)((Double3*)v.AsData)->X);
|
||||||
|
case VariantType::Uint16:
|
||||||
|
return Variant((uint16)((Double3*)v.AsData)->X);
|
||||||
|
case VariantType::Uint:
|
||||||
|
return Variant((uint32)((Double3*)v.AsData)->X);
|
||||||
|
case VariantType::Int64:
|
||||||
|
return Variant((int64)((Double3*)v.AsData)->X);
|
||||||
|
case VariantType::Uint64:
|
||||||
|
return Variant((uint64)((Double3*)v.AsData)->X);
|
||||||
|
case VariantType::Float:
|
||||||
|
return Variant((float)((Double3*)v.AsData)->X);
|
||||||
|
case VariantType::Double:
|
||||||
|
return Variant((double)((Double3*)v.AsData)->X);
|
||||||
|
case VariantType::Float2:
|
||||||
|
return Variant(Float2(*(Double3*)v.AsData));
|
||||||
|
case VariantType::Float3:
|
||||||
|
return Variant(Float3(*(Double3*)v.AsData));
|
||||||
|
case VariantType::Float4:
|
||||||
|
return Variant(Float4(*(Double3*)v.AsData, 0.0f));
|
||||||
|
case VariantType::Color:
|
||||||
|
return Variant(Color(((Double3*)v.AsData)->X, ((Double3*)v.AsData)->Y, ((Double3*)v.AsData)->Z, 0.0f));
|
||||||
|
case VariantType::Double2:
|
||||||
|
return Variant(Double2(*(Double3*)v.AsData));
|
||||||
|
case VariantType::Double4:
|
||||||
|
return Variant(Double4(*(Double3*)v.AsData, 0.0));
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VariantType::Double4:
|
||||||
|
switch (to.Type)
|
||||||
|
{
|
||||||
|
case VariantType::Bool:
|
||||||
|
return Variant(Math::Abs(((Double4*)v.AsData)->X) > ZeroTolerance);
|
||||||
|
case VariantType::Int16:
|
||||||
|
return Variant((int16)((Double4*)v.AsData)->X);
|
||||||
|
case VariantType::Int:
|
||||||
|
return Variant((int32)((Double4*)v.AsData)->X);
|
||||||
|
case VariantType::Uint16:
|
||||||
|
return Variant((uint16)((Double4*)v.AsData)->X);
|
||||||
|
case VariantType::Uint:
|
||||||
|
return Variant((uint32)((Double4*)v.AsData)->X);
|
||||||
|
case VariantType::Int64:
|
||||||
|
return Variant((int64)((Double4*)v.AsData)->X);
|
||||||
|
case VariantType::Uint64:
|
||||||
|
return Variant((uint64)((Double4*)v.AsData)->X);
|
||||||
|
case VariantType::Float:
|
||||||
|
return Variant((float)((Double4*)v.AsData)->X);
|
||||||
|
case VariantType::Double:
|
||||||
|
return Variant((double)((Double4*)v.AsData)->X);
|
||||||
|
case VariantType::Float2:
|
||||||
|
return Variant(Float2(*(Double4*)v.AsData));
|
||||||
|
case VariantType::Float3:
|
||||||
|
return Variant(Float3(*(Double4*)v.AsData));
|
||||||
|
case VariantType::Float4:
|
||||||
|
return Variant(Float4(*(Double4*)v.AsData));
|
||||||
|
case VariantType::Color:
|
||||||
|
return Variant(*(Double4*)v.AsData);
|
||||||
|
case VariantType::Double2:
|
||||||
|
return Variant(Double2(*(Double4*)v.AsData));
|
||||||
|
case VariantType::Double3:
|
||||||
|
return Variant(Double3(*(Double4*)v.AsData));
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case VariantType::Color:
|
case VariantType::Color:
|
||||||
switch (to.Type)
|
switch (to.Type)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ DEFINE_DEFAULT_FORMATTING_VIA_TO_STRING(VariantType);
|
|||||||
API_STRUCT(InBuild) struct FLAXENGINE_API Variant
|
API_STRUCT(InBuild) struct FLAXENGINE_API Variant
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Thee value type.
|
/// The value type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
VariantType Type;
|
VariantType Type;
|
||||||
|
|
||||||
|
|||||||
@@ -750,6 +750,11 @@ void DebugDraw::SetContext(void* context)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Vector3 DebugDraw::GetViewPos()
|
||||||
|
{
|
||||||
|
return Context->LastViewPos;
|
||||||
|
}
|
||||||
|
|
||||||
void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTextureView* depthBuffer, bool enableDepthTest)
|
void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTextureView* depthBuffer, bool enableDepthTest)
|
||||||
{
|
{
|
||||||
PROFILE_GPU_CPU("Debug Draw");
|
PROFILE_GPU_CPU("Debug Draw");
|
||||||
@@ -2073,16 +2078,23 @@ void DebugDraw::DrawWireArc(const Vector3& position, const Quaternion& orientati
|
|||||||
prevPos = Float3(Math::Cos(TWO_PI - angleStep) * radius, Math::Sin(TWO_PI - angleStep) * radius, 0);
|
prevPos = Float3(Math::Cos(TWO_PI - angleStep) * radius, Math::Sin(TWO_PI - angleStep) * radius, 0);
|
||||||
Float3::Transform(prevPos, world, prevPos);
|
Float3::Transform(prevPos, world, prevPos);
|
||||||
}
|
}
|
||||||
|
const Color32 color32(color);
|
||||||
|
auto& debugDrawData = depthTest ? Context->DebugDrawDepthTest : Context->DebugDrawDefault;
|
||||||
|
#define ADD_LINE(a, b) if (duration > 0) debugDrawData.DefaultLines.Add({ a, b, color32, duration }); else { debugDrawData.OneFrameLines.Add({ a, color32 }); debugDrawData.OneFrameLines.Add({ b, color32 }); }
|
||||||
for (int32 i = 0; i <= resolution; i++)
|
for (int32 i = 0; i <= resolution; i++)
|
||||||
{
|
{
|
||||||
Float3 pos(Math::Cos(currentAngle) * radius, Math::Sin(currentAngle) * radius, 0);
|
Float3 pos(Math::Cos(currentAngle) * radius, Math::Sin(currentAngle) * radius, 0);
|
||||||
Float3::Transform(pos, world, pos);
|
Float3::Transform(pos, world, pos);
|
||||||
DrawLine(prevPos, pos, color, duration, depthTest);
|
ADD_LINE(prevPos, pos);
|
||||||
currentAngle += angleStep;
|
currentAngle += angleStep;
|
||||||
prevPos = pos;
|
prevPos = pos;
|
||||||
}
|
}
|
||||||
if (angle < TWO_PI)
|
if (angle < TWO_PI)
|
||||||
DrawLine(prevPos, world.GetTranslation(), color, duration, depthTest);
|
{
|
||||||
|
Float3 pos(world.GetTranslation());
|
||||||
|
ADD_LINE(prevPos, pos);
|
||||||
|
}
|
||||||
|
#undef ADD_LINE
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugDraw::DrawWireArrow(const Vector3& position, const Quaternion& orientation, float scale, float capScale, const Color& color, float duration, bool depthTest)
|
void DebugDraw::DrawWireArrow(const Vector3& position, const Quaternion& orientation, float scale, float capScale, const Color& color, float duration, bool depthTest)
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
|||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Allocates the context for Debug Drawing. Can be use to redirect debug shapes collecting to a separate container (instead of global state).
|
/// Allocates the context for Debug Drawing. Can be used to redirect debug shapes collecting to a separate container (instead of global state).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The context object. Release it wil FreeContext. Returns null if failed.</returns>
|
/// <returns>The context object. Release it wil FreeContext. Returns null if failed.</returns>
|
||||||
API_FUNCTION() static void* AllocateContext();
|
API_FUNCTION() static void* AllocateContext();
|
||||||
@@ -67,6 +67,9 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
|||||||
API_FUNCTION() static void SetContext(void* context);
|
API_FUNCTION() static void SetContext(void* context);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Gets the last view position when rendering the current context. Can be sued for custom culling or LODing when drawing more complex shapes.
|
||||||
|
static Vector3 GetViewPos();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Draws the collected debug shapes to the output.
|
/// Draws the collected debug shapes to the output.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -720,7 +723,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
|||||||
API_FUNCTION() static void Clear(void* context = nullptr);
|
API_FUNCTION() static void Clear(void* context = nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEBUG_DRAW_AXIS_FROM_DIRECTION(origin, direction, size, duration, depthTest) DebugDraw::DrawAxisFromDirection(origin, direction, size, duration, depthTest);
|
#define DEBUG_DRAW_AXIS_FROM_DIRECTION(origin, direction, size, duration, depthTest) DebugDraw::DrawAxisFromDirection(origin, direction, size, duration, depthTest);
|
||||||
#define DEBUG_DRAW_DIRECTION(origin, direction, color, duration, depthTest) DebugDraw::DrawDirection(origin, direction, color, duration, depthTest);
|
#define DEBUG_DRAW_DIRECTION(origin, direction, color, duration, depthTest) DebugDraw::DrawDirection(origin, direction, color, duration, depthTest);
|
||||||
#define DEBUG_DRAW_RAY(origin, direction, color, length, duration, depthTest) DebugDraw::DrawRay(origin, direction, color, length, duration, depthTest);
|
#define DEBUG_DRAW_RAY(origin, direction, color, length, duration, depthTest) DebugDraw::DrawRay(origin, direction, color, length, duration, depthTest);
|
||||||
#define DEBUG_DRAW_RAY(ray, color, length, duration, depthTest) DebugDraw::DrawRay(ray, color, length, duration, depthTest);
|
#define DEBUG_DRAW_RAY(ray, color, length, duration, depthTest) DebugDraw::DrawRay(ray, color, length, duration, depthTest);
|
||||||
|
|||||||
@@ -308,6 +308,17 @@ API_ENUM() enum class GPUResourceUsage
|
|||||||
/// - Any resources read or accessed randomly on host, e.g. CPU-side copy of vertex buffer used as source of transfer, but also used for collision detection.
|
/// - Any resources read or accessed randomly on host, e.g. CPU-side copy of vertex buffer used as source of transfer, but also used for collision detection.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
StagingReadback = 3,
|
StagingReadback = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A resource that supports both read and write from the CPU.
|
||||||
|
/// This is likely to be the common choice for read-write buffers to transfer data between GPU compute buffers and CPU memory.
|
||||||
|
/// It usually means CPU (system) memory.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Usage:
|
||||||
|
/// - Staging memory to upload to GPU for compute and gather results back after processing.
|
||||||
|
/// </remarks>
|
||||||
|
Staging = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -113,6 +113,15 @@ GPUBufferDescription GPUBufferDescription::ToStagingReadback() const
|
|||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GPUBufferDescription GPUBufferDescription::ToStaging() const
|
||||||
|
{
|
||||||
|
auto desc = *this;
|
||||||
|
desc.Usage = GPUResourceUsage::Staging;
|
||||||
|
desc.Flags = GPUBufferFlags::None;
|
||||||
|
desc.InitData = nullptr;
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
bool GPUBufferDescription::Equals(const GPUBufferDescription& other) const
|
bool GPUBufferDescription::Equals(const GPUBufferDescription& other) const
|
||||||
{
|
{
|
||||||
return Size == other.Size
|
return Size == other.Size
|
||||||
@@ -167,6 +176,16 @@ GPUBuffer::GPUBuffer()
|
|||||||
_desc.Size = 0;
|
_desc.Size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GPUBuffer::IsStaging() const
|
||||||
|
{
|
||||||
|
return _desc.Usage == GPUResourceUsage::StagingReadback || _desc.Usage == GPUResourceUsage::StagingUpload || _desc.Usage == GPUResourceUsage::Staging;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GPUBuffer::IsDynamic() const
|
||||||
|
{
|
||||||
|
return _desc.Usage == GPUResourceUsage::Dynamic;
|
||||||
|
}
|
||||||
|
|
||||||
bool GPUBuffer::Init(const GPUBufferDescription& desc)
|
bool GPUBuffer::Init(const GPUBufferDescription& desc)
|
||||||
{
|
{
|
||||||
// Validate description
|
// Validate description
|
||||||
@@ -280,7 +299,7 @@ bool GPUBuffer::DownloadData(BytesContainer& result)
|
|||||||
LOG(Warning, "Cannot download GPU buffer data from an empty buffer.");
|
LOG(Warning, "Cannot download GPU buffer data from an empty buffer.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (_desc.Usage == GPUResourceUsage::StagingReadback || _desc.Usage == GPUResourceUsage::Dynamic)
|
if (_desc.Usage == GPUResourceUsage::StagingReadback || _desc.Usage == GPUResourceUsage::Dynamic || _desc.Usage == GPUResourceUsage::Staging)
|
||||||
{
|
{
|
||||||
// Use faster path for staging resources
|
// Use faster path for staging resources
|
||||||
return GetData(result);
|
return GetData(result);
|
||||||
|
|||||||
@@ -94,20 +94,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if buffer is a staging buffer (supports CPU readback).
|
/// Checks if buffer is a staging buffer (supports CPU access).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_PROPERTY() FORCE_INLINE bool IsStaging() const
|
API_PROPERTY() bool IsStaging() const;
|
||||||
{
|
|
||||||
return _desc.Usage == GPUResourceUsage::StagingReadback || _desc.Usage == GPUResourceUsage::StagingUpload;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if buffer is a staging buffer (supports CPU readback).
|
/// Checks if buffer is a dynamic buffer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_PROPERTY() FORCE_INLINE bool IsDynamic() const
|
API_PROPERTY() bool IsDynamic() const;
|
||||||
{
|
|
||||||
return _desc.Usage == GPUResourceUsage::Dynamic;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether this buffer is a shader resource.
|
/// Gets a value indicating whether this buffer is a shader resource.
|
||||||
@@ -181,7 +175,7 @@ public:
|
|||||||
Task* DownloadDataAsync(BytesContainer& result);
|
Task* DownloadDataAsync(BytesContainer& result);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the buffer data via map/memcpy/unmap sequence. Always supported for dynamic and staging readback buffers (other types support depends on graphics backend implementation).
|
/// Gets the buffer data via map/memcpy/unmap sequence. Always supported for dynamic and staging buffers (other types support depends on graphics backend implementation).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="output">The output data container.</param>
|
/// <param name="output">The output data container.</param>
|
||||||
/// <returns>True if failed, otherwise false.</returns>
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
|
|||||||
@@ -320,7 +320,7 @@ namespace FlaxEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the staging upload description for this instance.
|
/// Gets the staging upload (CPU write) description for this instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A staging buffer description</returns>
|
/// <returns>A staging buffer description</returns>
|
||||||
public GPUBufferDescription ToStagingUpload()
|
public GPUBufferDescription ToStagingUpload()
|
||||||
@@ -333,7 +333,7 @@ namespace FlaxEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the staging readback description for this instance.
|
/// Gets the staging readback (CPU read) description for this instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A staging buffer description</returns>
|
/// <returns>A staging buffer description</returns>
|
||||||
public GPUBufferDescription ToStagingReadback()
|
public GPUBufferDescription ToStagingReadback()
|
||||||
@@ -345,6 +345,19 @@ namespace FlaxEngine
|
|||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the staging (CPU read/write) description for this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A staging buffer description</returns>
|
||||||
|
public GPUBufferDescription ToStaging()
|
||||||
|
{
|
||||||
|
var desc = this;
|
||||||
|
desc.Usage = GPUResourceUsage.Staging;
|
||||||
|
desc.Flags = GPUBufferFlags.None;
|
||||||
|
desc.InitData = IntPtr.Zero;
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool Equals(GPUBufferDescription other)
|
public bool Equals(GPUBufferDescription other)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -382,6 +382,7 @@ public:
|
|||||||
void Clear();
|
void Clear();
|
||||||
GPUBufferDescription ToStagingUpload() const;
|
GPUBufferDescription ToStagingUpload() const;
|
||||||
GPUBufferDescription ToStagingReadback() const;
|
GPUBufferDescription ToStagingReadback() const;
|
||||||
|
GPUBufferDescription ToStaging() const;
|
||||||
bool Equals(const GPUBufferDescription& other) const;
|
bool Equals(const GPUBufferDescription& other) const;
|
||||||
String ToString() const;
|
String ToString() const;
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,53 @@ GPUContext::GPUContext(GPUDevice* device)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !BUILD_RELEASE
|
||||||
|
|
||||||
|
#include "Engine/Core/Log.h"
|
||||||
|
|
||||||
|
void GPUContext::LogInvalidResourceUsage(int32 slot, const GPUResourceView* view, InvalidBindPoint bindPoint)
|
||||||
|
{
|
||||||
|
GPUResource* resource = view ? view->GetParent() : nullptr;
|
||||||
|
const Char* resourceType = TEXT("resource");
|
||||||
|
const Char* flagType = TEXT("flags");
|
||||||
|
if (resource)
|
||||||
|
{
|
||||||
|
switch (resource->GetResourceType())
|
||||||
|
{
|
||||||
|
case GPUResourceType::RenderTarget:
|
||||||
|
case GPUResourceType::Texture:
|
||||||
|
case GPUResourceType::CubeTexture:
|
||||||
|
case GPUResourceType::VolumeTexture:
|
||||||
|
resourceType = TEXT("texture");
|
||||||
|
flagType = TEXT("GPUTextureFlags");
|
||||||
|
break;
|
||||||
|
case GPUResourceType::Buffer:
|
||||||
|
resourceType = TEXT("buffer");
|
||||||
|
flagType = TEXT("GPUBufferFlags");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const Char* usage = TEXT("-");
|
||||||
|
switch (bindPoint)
|
||||||
|
{
|
||||||
|
case InvalidBindPoint::SRV:
|
||||||
|
usage = TEXT("shader resource");
|
||||||
|
break;
|
||||||
|
case InvalidBindPoint::UAV:
|
||||||
|
usage = TEXT("unordered access");
|
||||||
|
break;
|
||||||
|
case InvalidBindPoint::DSV:
|
||||||
|
usage = TEXT("depth stencil");
|
||||||
|
break;
|
||||||
|
case InvalidBindPoint::RTV:
|
||||||
|
usage = TEXT("render target");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
LOG(Error, "Incorrect {} bind at slot {} as {} (ensure to setup correct {} when creating that resource)", resourceType, slot, usage, flagType);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
void GPUContext::FrameBegin()
|
void GPUContext::FrameBegin()
|
||||||
{
|
{
|
||||||
_lastRenderTime = Platform::GetTimeSeconds();
|
_lastRenderTime = Platform::GetTimeSeconds();
|
||||||
|
|||||||
@@ -122,6 +122,12 @@ protected:
|
|||||||
double _lastRenderTime = -1;
|
double _lastRenderTime = -1;
|
||||||
GPUContext(GPUDevice* device);
|
GPUContext(GPUDevice* device);
|
||||||
|
|
||||||
|
#if !BUILD_RELEASE
|
||||||
|
enum class InvalidBindPoint { SRV, UAV, DSV, RTV };
|
||||||
|
|
||||||
|
static void LogInvalidResourceUsage(int32 slot, const GPUResourceView* view, InvalidBindPoint bindPoint);
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the graphics device.
|
/// Gets the graphics device.
|
||||||
@@ -144,7 +150,6 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
#if GPU_ALLOW_PROFILE_EVENTS
|
#if GPU_ALLOW_PROFILE_EVENTS
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Begins the profile event.
|
/// Begins the profile event.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -159,7 +164,6 @@ public:
|
|||||||
virtual void EventEnd()
|
virtual void EventEnd()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -190,6 +190,7 @@ API_CLASS(Abstract, NoSpawn, Attributes="HideInEditor") class FLAXENGINE_API GPU
|
|||||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(GPUResourceView);
|
DECLARE_SCRIPTING_TYPE_NO_SPAWN(GPUResourceView);
|
||||||
protected:
|
protected:
|
||||||
static double DummyLastRenderTime;
|
static double DummyLastRenderTime;
|
||||||
|
GPUResource* _parent = nullptr;
|
||||||
|
|
||||||
explicit GPUResourceView(const SpawnParams& params)
|
explicit GPUResourceView(const SpawnParams& params)
|
||||||
: ScriptingObject(params)
|
: ScriptingObject(params)
|
||||||
@@ -201,6 +202,14 @@ public:
|
|||||||
// Points to the cache used by the resource for the resource visibility/usage detection. Written during rendering when resource view is used.
|
// Points to the cache used by the resource for the resource visibility/usage detection. Written during rendering when resource view is used.
|
||||||
double* LastRenderTime;
|
double* LastRenderTime;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets parent GPU resource owning that view.
|
||||||
|
/// </summary>
|
||||||
|
API_PROPERTY() FORCE_INLINE GPUResource* GetParent() const
|
||||||
|
{
|
||||||
|
return _parent;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the native pointer to the underlying view. It's a platform-specific handle.
|
/// Gets the native pointer to the underlying view. It's a platform-specific handle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "MaterialShader.h"
|
#include "MaterialShader.h"
|
||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
#include "Engine/Serialization/MemoryReadStream.h"
|
#include "Engine/Serialization/MemoryReadStream.h"
|
||||||
|
#include "Engine/Level/LargeWorlds.h"
|
||||||
#include "Engine/Renderer/RenderList.h"
|
#include "Engine/Renderer/RenderList.h"
|
||||||
#include "Engine/Graphics/RenderTask.h"
|
#include "Engine/Graphics/RenderTask.h"
|
||||||
#include "Engine/Graphics/GPUDevice.h"
|
#include "Engine/Graphics/GPUDevice.h"
|
||||||
@@ -33,6 +34,8 @@ GPU_CB_STRUCT(MaterialShaderDataPerView {
|
|||||||
Float4 ViewInfo;
|
Float4 ViewInfo;
|
||||||
Float4 ScreenSize;
|
Float4 ScreenSize;
|
||||||
Float4 TemporalAAJitter;
|
Float4 TemporalAAJitter;
|
||||||
|
Float3 LargeWorldsChunkIndex;
|
||||||
|
float LargeWorldsChunkSize;
|
||||||
});
|
});
|
||||||
|
|
||||||
IMaterial::BindParameters::BindParameters(::GPUContext* context, const ::RenderContext& renderContext)
|
IMaterial::BindParameters::BindParameters(::GPUContext* context, const ::RenderContext& renderContext)
|
||||||
@@ -78,6 +81,8 @@ void IMaterial::BindParameters::BindViewData()
|
|||||||
cb.ViewInfo = view.ViewInfo;
|
cb.ViewInfo = view.ViewInfo;
|
||||||
cb.ScreenSize = view.ScreenSize;
|
cb.ScreenSize = view.ScreenSize;
|
||||||
cb.TemporalAAJitter = view.TemporalAAJitter;
|
cb.TemporalAAJitter = view.TemporalAAJitter;
|
||||||
|
cb.LargeWorldsChunkIndex = LargeWorlds::Enable ? (Float3)Int3(view.Origin / LargeWorlds::ChunkSize) : Float3::Zero;
|
||||||
|
cb.LargeWorldsChunkSize = LargeWorlds::ChunkSize;
|
||||||
|
|
||||||
// Update constants
|
// Update constants
|
||||||
GPUContext->UpdateCB(PerViewConstants, &cb);
|
GPUContext->UpdateCB(PerViewConstants, &cb);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Current materials shader version.
|
/// Current materials shader version.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
#define MATERIAL_GRAPH_VERSION 171
|
#define MATERIAL_GRAPH_VERSION 172
|
||||||
|
|
||||||
class Material;
|
class Material;
|
||||||
class GPUShader;
|
class GPUShader;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "RenderView.h"
|
#include "RenderView.h"
|
||||||
#include "Engine/Level/LargeWorlds.h"
|
#include "Engine/Level/LargeWorlds.h"
|
||||||
#include "Engine/Level/Actors/Camera.h"
|
#include "Engine/Level/Actors/Camera.h"
|
||||||
|
#include "Engine/Core/Math/Double4x4.h"
|
||||||
#include "Engine/Renderer/RenderList.h"
|
#include "Engine/Renderer/RenderList.h"
|
||||||
#include "Engine/Renderer/RendererPass.h"
|
#include "Engine/Renderer/RendererPass.h"
|
||||||
#include "RenderBuffers.h"
|
#include "RenderBuffers.h"
|
||||||
@@ -215,6 +216,13 @@ void RenderView::GetWorldMatrix(const Transform& transform, Matrix& world) const
|
|||||||
Matrix::Transformation(transform.Scale, transform.Orientation, translation, world);
|
Matrix::Transformation(transform.Scale, transform.Orientation, translation, world);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RenderView::GetWorldMatrix(Double4x4& world) const
|
||||||
|
{
|
||||||
|
world.M41 -= Origin.X;
|
||||||
|
world.M42 -= Origin.Y;
|
||||||
|
world.M43 -= Origin.Z;
|
||||||
|
}
|
||||||
|
|
||||||
TaaJitterRemoveContext::TaaJitterRemoveContext(const RenderView& view)
|
TaaJitterRemoveContext::TaaJitterRemoveContext(const RenderView& view)
|
||||||
{
|
{
|
||||||
if (view.IsTaaResolved)
|
if (view.IsTaaResolved)
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
#include "Engine/Core/Math/BoundingFrustum.h"
|
#include "Engine/Core/Math/BoundingFrustum.h"
|
||||||
#include "Engine/Core/Math/Matrix.h"
|
#include "Engine/Core/Math/Matrix.h"
|
||||||
#include "Engine/Core/Math/Vector3.h"
|
#include "Engine/Core/Math/Vector3.h"
|
||||||
|
#if USE_LARGE_WORLDS
|
||||||
|
#include "Engine/Core/Math/Double4x4.h"
|
||||||
|
#endif
|
||||||
#include "Engine/Core/Types/LayersMask.h"
|
#include "Engine/Core/Types/LayersMask.h"
|
||||||
#include "Engine/Level/Types.h"
|
#include "Engine/Level/Types.h"
|
||||||
#include "Enums.h"
|
#include "Enums.h"
|
||||||
@@ -355,6 +358,9 @@ public:
|
|||||||
world.M42 -= (float)Origin.Y;
|
world.M42 -= (float)Origin.Y;
|
||||||
world.M43 -= (float)Origin.Z;
|
world.M43 -= (float)Origin.Z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Applies the render origin to the transformation instance matrix.
|
||||||
|
void GetWorldMatrix(Double4x4& world) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Removes TAA jitter from the RenderView when drawing geometry after TAA has been resolved to prevent unwanted jittering.
|
// Removes TAA jitter from the RenderView when drawing geometry after TAA has been resolved to prevent unwanted jittering.
|
||||||
|
|||||||
@@ -142,6 +142,14 @@ GPUTextureDescription GPUTextureDescription::ToStagingReadback() const
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GPUTextureDescription GPUTextureDescription::ToStaging() const
|
||||||
|
{
|
||||||
|
auto copy = *this;
|
||||||
|
copy.Flags = GPUTextureFlags::None;
|
||||||
|
copy.Usage = GPUResourceUsage::Staging;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
bool GPUTextureDescription::Equals(const GPUTextureDescription& other) const
|
bool GPUTextureDescription::Equals(const GPUTextureDescription& other) const
|
||||||
{
|
{
|
||||||
return Dimensions == other.Dimensions
|
return Dimensions == other.Dimensions
|
||||||
@@ -208,6 +216,11 @@ GPUTexture::GPUTexture()
|
|||||||
_desc.Clear();
|
_desc.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GPUTexture::IsStaging() const
|
||||||
|
{
|
||||||
|
return _desc.Usage == GPUResourceUsage::StagingUpload || _desc.Usage == GPUResourceUsage::StagingReadback || _desc.Usage == GPUResourceUsage::Staging;
|
||||||
|
}
|
||||||
|
|
||||||
Float2 GPUTexture::Size() const
|
Float2 GPUTexture::Size() const
|
||||||
{
|
{
|
||||||
return Float2(static_cast<float>(_desc.Width), static_cast<float>(_desc.Height));
|
return Float2(static_cast<float>(_desc.Width), static_cast<float>(_desc.Height));
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API GPUTextureView : public GPUResou
|
|||||||
{
|
{
|
||||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(GPUTextureView);
|
DECLARE_SCRIPTING_TYPE_NO_SPAWN(GPUTextureView);
|
||||||
protected:
|
protected:
|
||||||
GPUResource* _parent = nullptr;
|
|
||||||
PixelFormat _format = PixelFormat::Unknown;
|
PixelFormat _format = PixelFormat::Unknown;
|
||||||
MSAALevel _msaa = MSAALevel::None;
|
MSAALevel _msaa = MSAALevel::None;
|
||||||
|
|
||||||
@@ -40,14 +39,6 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
|
||||||
/// Gets parent GPU resource owning that view.
|
|
||||||
/// </summary>
|
|
||||||
API_PROPERTY() FORCE_INLINE GPUResource* GetParent() const
|
|
||||||
{
|
|
||||||
return _parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the view format.
|
/// Gets the view format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -294,10 +285,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if texture is a staging buffer (supports direct CPU access).
|
/// Checks if texture is a staging buffer (supports direct CPU access).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE bool IsStaging() const
|
bool IsStaging() const;
|
||||||
{
|
|
||||||
return _desc.Usage == GPUResourceUsage::StagingUpload || _desc.Usage == GPUResourceUsage::StagingReadback;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a boolean indicating whether this <see cref="GPUTexture"/> is a using a block compress format (BC1, BC2, BC3, BC4, BC5, BC6H, BC7, etc.).
|
/// Gets a boolean indicating whether this <see cref="GPUTexture"/> is a using a block compress format (BC1, BC2, BC3, BC4, BC5, BC6H, BC7, etc.).
|
||||||
|
|||||||
@@ -300,7 +300,7 @@ namespace FlaxEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the staging description for this instance.
|
/// Gets the staging upload (CPU write) description for this instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A staging texture description</returns>
|
/// <returns>A staging texture description</returns>
|
||||||
public GPUTextureDescription ToStagingUpload()
|
public GPUTextureDescription ToStagingUpload()
|
||||||
@@ -312,7 +312,7 @@ namespace FlaxEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the staging description for this instance.
|
/// Gets the staging readback (CPU read) description for this instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A staging texture description</returns>
|
/// <returns>A staging texture description</returns>
|
||||||
public GPUTextureDescription ToStagingReadback()
|
public GPUTextureDescription ToStagingReadback()
|
||||||
@@ -323,6 +323,18 @@ namespace FlaxEngine
|
|||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the staging (CPU read/write) description for this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A staging texture description</returns>
|
||||||
|
public GPUTextureDescription ToStaging()
|
||||||
|
{
|
||||||
|
var desc = this;
|
||||||
|
desc.Flags = GPUTextureFlags.None;
|
||||||
|
desc.Usage = GPUResourceUsage.Staging;
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -397,6 +397,7 @@ public:
|
|||||||
void Clear();
|
void Clear();
|
||||||
GPUTextureDescription ToStagingUpload() const;
|
GPUTextureDescription ToStagingUpload() const;
|
||||||
GPUTextureDescription ToStagingReadback() const;
|
GPUTextureDescription ToStagingReadback() const;
|
||||||
|
GPUTextureDescription ToStaging() const;
|
||||||
bool Equals(const GPUTextureDescription& other) const;
|
bool Equals(const GPUTextureDescription& other) const;
|
||||||
String ToString() const;
|
String ToString() const;
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
GPUBufferDX11::GPUBufferDX11(GPUDeviceDX11* device, const StringView& name)
|
GPUBufferDX11::GPUBufferDX11(GPUDeviceDX11* device, const StringView& name)
|
||||||
: GPUResourceDX11(device, name)
|
: GPUResourceDX11(device, name)
|
||||||
{
|
{
|
||||||
|
_view.SetParnet(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
GPUBufferView* GPUBufferDX11::View() const
|
GPUBufferView* GPUBufferDX11::View() const
|
||||||
|
|||||||
@@ -40,6 +40,11 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
void SetParnet(GPUBuffer* parent)
|
||||||
|
{
|
||||||
|
_parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Release the view.
|
/// Release the view.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -358,7 +358,11 @@ void GPUContextDX11::BindCB(int32 slot, GPUConstantBuffer* cb)
|
|||||||
|
|
||||||
void GPUContextDX11::BindSR(int32 slot, GPUResourceView* view)
|
void GPUContextDX11::BindSR(int32 slot, GPUResourceView* view)
|
||||||
{
|
{
|
||||||
|
#if !BUILD_RELEASE
|
||||||
ASSERT(slot >= 0 && slot < GPU_MAX_SR_BINDED);
|
ASSERT(slot >= 0 && slot < GPU_MAX_SR_BINDED);
|
||||||
|
if (view && ((IShaderResourceDX11*)view->GetNativePtr())->SRV() == nullptr)
|
||||||
|
LogInvalidResourceUsage(slot, view, InvalidBindPoint::SRV);
|
||||||
|
#endif
|
||||||
auto handle = view ? ((IShaderResourceDX11*)view->GetNativePtr())->SRV() : nullptr;
|
auto handle = view ? ((IShaderResourceDX11*)view->GetNativePtr())->SRV() : nullptr;
|
||||||
if (_srHandles[slot] != handle)
|
if (_srHandles[slot] != handle)
|
||||||
{
|
{
|
||||||
@@ -372,7 +376,11 @@ void GPUContextDX11::BindSR(int32 slot, GPUResourceView* view)
|
|||||||
|
|
||||||
void GPUContextDX11::BindUA(int32 slot, GPUResourceView* view)
|
void GPUContextDX11::BindUA(int32 slot, GPUResourceView* view)
|
||||||
{
|
{
|
||||||
|
#if !BUILD_RELEASE
|
||||||
ASSERT(slot >= 0 && slot < GPU_MAX_UA_BINDED);
|
ASSERT(slot >= 0 && slot < GPU_MAX_UA_BINDED);
|
||||||
|
if (view && ((IShaderResourceDX11*)view->GetNativePtr())->UAV() == nullptr)
|
||||||
|
LogInvalidResourceUsage(slot, view, InvalidBindPoint::UAV);
|
||||||
|
#endif
|
||||||
auto handle = view ? ((IShaderResourceDX11*)view->GetNativePtr())->UAV() : nullptr;
|
auto handle = view ? ((IShaderResourceDX11*)view->GetNativePtr())->UAV() : nullptr;
|
||||||
if (_uaHandles[slot] != handle)
|
if (_uaHandles[slot] != handle)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,13 +12,11 @@
|
|||||||
class IShaderResourceDX11
|
class IShaderResourceDX11
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
IShaderResourceDX11()
|
IShaderResourceDX11()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets handle to the shader resource view object.
|
/// Gets handle to the shader resource view object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -28,7 +26,6 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets CPU to the unordered access view object.
|
/// Gets CPU to the unordered access view object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>UAV</returns>
|
|
||||||
virtual ID3D11UnorderedAccessView* UAV() const = 0;
|
virtual ID3D11UnorderedAccessView* UAV() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,18 +6,6 @@
|
|||||||
#include "GPUDeviceDX12.h"
|
#include "GPUDeviceDX12.h"
|
||||||
#include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h"
|
#include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h"
|
||||||
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE DescriptorHeapWithSlotsDX12::Slot::CPU() const
|
|
||||||
{
|
|
||||||
ASSERT_LOW_LAYER(Heap);
|
|
||||||
return Heap->CPU(Index);
|
|
||||||
}
|
|
||||||
|
|
||||||
D3D12_GPU_DESCRIPTOR_HANDLE DescriptorHeapWithSlotsDX12::Slot::GPU() const
|
|
||||||
{
|
|
||||||
ASSERT_LOW_LAYER(Heap);
|
|
||||||
return Heap->GPU(Index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DescriptorHeapWithSlotsDX12::Slot::CreateSRV(GPUDeviceDX12* device, ID3D12Resource* resource, D3D12_SHADER_RESOURCE_VIEW_DESC* desc)
|
void DescriptorHeapWithSlotsDX12::Slot::CreateSRV(GPUDeviceDX12* device, ID3D12Resource* resource, D3D12_SHADER_RESOURCE_VIEW_DESC* desc)
|
||||||
{
|
{
|
||||||
if (Heap == nullptr)
|
if (Heap == nullptr)
|
||||||
|
|||||||
@@ -35,8 +35,15 @@ public:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE CPU() const;
|
FORCE_INLINE D3D12_CPU_DESCRIPTOR_HANDLE CPU() const
|
||||||
D3D12_GPU_DESCRIPTOR_HANDLE GPU() const;
|
{
|
||||||
|
return Heap ? Heap->CPU(Index) : D3D12_CPU_DESCRIPTOR_HANDLE {};
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE D3D12_GPU_DESCRIPTOR_HANDLE GPU() const
|
||||||
|
{
|
||||||
|
return Heap ? Heap->GPU(Index) : D3D12_GPU_DESCRIPTOR_HANDLE {};
|
||||||
|
}
|
||||||
|
|
||||||
void CreateSRV(GPUDeviceDX12* device, ID3D12Resource* resource, D3D12_SHADER_RESOURCE_VIEW_DESC* desc = nullptr);
|
void CreateSRV(GPUDeviceDX12* device, ID3D12Resource* resource, D3D12_SHADER_RESOURCE_VIEW_DESC* desc = nullptr);
|
||||||
void CreateRTV(GPUDeviceDX12* device, ID3D12Resource* resource, D3D12_RENDER_TARGET_VIEW_DESC* desc = nullptr);
|
void CreateRTV(GPUDeviceDX12* device, ID3D12Resource* resource, D3D12_RENDER_TARGET_VIEW_DESC* desc = nullptr);
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ bool GPUBufferDX12::OnInit()
|
|||||||
switch (_desc.Usage)
|
switch (_desc.Usage)
|
||||||
{
|
{
|
||||||
case GPUResourceUsage::StagingUpload:
|
case GPUResourceUsage::StagingUpload:
|
||||||
|
case GPUResourceUsage::Staging:
|
||||||
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||||
break;
|
break;
|
||||||
case GPUResourceUsage::StagingReadback:
|
case GPUResourceUsage::StagingReadback:
|
||||||
@@ -152,7 +153,7 @@ bool GPUBufferDX12::OnInit()
|
|||||||
// But if we are doing it during update or from the other thread we have to register resource data upload job.
|
// But if we are doing it during update or from the other thread we have to register resource data upload job.
|
||||||
// In both cases options.InitData data have to exist for a few next frames.
|
// In both cases options.InitData data have to exist for a few next frames.
|
||||||
|
|
||||||
if (_desc.Usage == GPUResourceUsage::StagingUpload)
|
if (_desc.Usage == GPUResourceUsage::StagingUpload || _desc.Usage == GPUResourceUsage::Staging)
|
||||||
{
|
{
|
||||||
// Modify staging resource data now
|
// Modify staging resource data now
|
||||||
SetData(_desc.InitData, _desc.Size);
|
SetData(_desc.InitData, _desc.Size);
|
||||||
@@ -188,7 +189,7 @@ bool GPUBufferDX12::OnInit()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create views
|
// Create views
|
||||||
_view.Init(_device, this);
|
_view.Init(_device, this, this);
|
||||||
if (useSRV)
|
if (useSRV)
|
||||||
{
|
{
|
||||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
|
||||||
|
|||||||
@@ -46,10 +46,12 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="device">The graphics device.</param>
|
/// <param name="device">The graphics device.</param>
|
||||||
/// <param name="owner">The resource owner.</param>
|
/// <param name="owner">The resource owner.</param>
|
||||||
void Init(GPUDeviceDX12* device, ResourceOwnerDX12* owner)
|
/// <param name="parent">The parent resource.</param>
|
||||||
|
void Init(GPUDeviceDX12* device, ResourceOwnerDX12* owner, GPUResource* parent)
|
||||||
{
|
{
|
||||||
_device = device;
|
_device = device;
|
||||||
_owner = owner;
|
_owner = owner;
|
||||||
|
_parent = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -934,9 +934,13 @@ void GPUContextDX12::BindCB(int32 slot, GPUConstantBuffer* cb)
|
|||||||
|
|
||||||
void GPUContextDX12::BindSR(int32 slot, GPUResourceView* view)
|
void GPUContextDX12::BindSR(int32 slot, GPUResourceView* view)
|
||||||
{
|
{
|
||||||
|
#if !BUILD_RELEASE
|
||||||
ASSERT(slot >= 0 && slot < GPU_MAX_SR_BINDED);
|
ASSERT(slot >= 0 && slot < GPU_MAX_SR_BINDED);
|
||||||
|
if (view && ((IShaderResourceDX12*)view->GetNativePtr())->SRV().ptr == 0)
|
||||||
|
LogInvalidResourceUsage(slot, view, InvalidBindPoint::SRV);
|
||||||
|
#endif
|
||||||
auto handle = view ? (IShaderResourceDX12*)view->GetNativePtr() : nullptr;
|
auto handle = view ? (IShaderResourceDX12*)view->GetNativePtr() : nullptr;
|
||||||
if (_srHandles[slot] != handle || !handle)
|
if (_srHandles[slot] != handle)
|
||||||
{
|
{
|
||||||
_srMaskDirtyGraphics |= 1 << slot;
|
_srMaskDirtyGraphics |= 1 << slot;
|
||||||
_srMaskDirtyCompute |= 1 << slot;
|
_srMaskDirtyCompute |= 1 << slot;
|
||||||
@@ -948,7 +952,11 @@ void GPUContextDX12::BindSR(int32 slot, GPUResourceView* view)
|
|||||||
|
|
||||||
void GPUContextDX12::BindUA(int32 slot, GPUResourceView* view)
|
void GPUContextDX12::BindUA(int32 slot, GPUResourceView* view)
|
||||||
{
|
{
|
||||||
|
#if !BUILD_RELEASE
|
||||||
ASSERT(slot >= 0 && slot < GPU_MAX_UA_BINDED);
|
ASSERT(slot >= 0 && slot < GPU_MAX_UA_BINDED);
|
||||||
|
if (view && ((IShaderResourceDX12*)view->GetNativePtr())->UAV().ptr == 0)
|
||||||
|
LogInvalidResourceUsage(slot, view, InvalidBindPoint::UAV);
|
||||||
|
#endif
|
||||||
_uaHandles[slot] = view ? (IShaderResourceDX12*)view->GetNativePtr() : nullptr;
|
_uaHandles[slot] = view ? (IShaderResourceDX12*)view->GetNativePtr() : nullptr;
|
||||||
if (view)
|
if (view)
|
||||||
*view->LastRenderTime = _lastRenderTime;
|
*view->LastRenderTime = _lastRenderTime;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ namespace RenderToolsDX
|
|||||||
{
|
{
|
||||||
case GPUResourceUsage::Dynamic:
|
case GPUResourceUsage::Dynamic:
|
||||||
return D3D11_USAGE_DYNAMIC;
|
return D3D11_USAGE_DYNAMIC;
|
||||||
|
case GPUResourceUsage::Staging:
|
||||||
case GPUResourceUsage::StagingUpload:
|
case GPUResourceUsage::StagingUpload:
|
||||||
case GPUResourceUsage::StagingReadback:
|
case GPUResourceUsage::StagingReadback:
|
||||||
return D3D11_USAGE_STAGING;
|
return D3D11_USAGE_STAGING;
|
||||||
@@ -37,6 +38,8 @@ namespace RenderToolsDX
|
|||||||
{
|
{
|
||||||
case GPUResourceUsage::Dynamic:
|
case GPUResourceUsage::Dynamic:
|
||||||
return D3D11_CPU_ACCESS_WRITE;
|
return D3D11_CPU_ACCESS_WRITE;
|
||||||
|
case GPUResourceUsage::Staging:
|
||||||
|
return D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
|
||||||
case GPUResourceUsage::StagingReadback:
|
case GPUResourceUsage::StagingReadback:
|
||||||
return D3D11_CPU_ACCESS_READ;
|
return D3D11_CPU_ACCESS_READ;
|
||||||
case GPUResourceUsage::StagingUpload:
|
case GPUResourceUsage::StagingUpload:
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ void GPUBufferViewVulkan::Init(GPUDeviceVulkan* device, GPUBufferVulkan* owner,
|
|||||||
{
|
{
|
||||||
ASSERT(View == VK_NULL_HANDLE);
|
ASSERT(View == VK_NULL_HANDLE);
|
||||||
|
|
||||||
|
_parent = owner;
|
||||||
Device = device;
|
Device = device;
|
||||||
Owner = owner;
|
Owner = owner;
|
||||||
Buffer = buffer;
|
Buffer = buffer;
|
||||||
@@ -128,6 +129,9 @@ bool GPUBufferVulkan::OnInit()
|
|||||||
case GPUResourceUsage::StagingReadback:
|
case GPUResourceUsage::StagingReadback:
|
||||||
allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
|
allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
|
||||||
break;
|
break;
|
||||||
|
case GPUResourceUsage::Staging:
|
||||||
|
allocInfo.usage = VMA_MEMORY_USAGE_CPU_COPY;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
|
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,10 @@ public:
|
|||||||
void DescriptorAsUniformTexelBuffer(GPUContextVulkan* context, VkBufferView& bufferView) override;
|
void DescriptorAsUniformTexelBuffer(GPUContextVulkan* context, VkBufferView& bufferView) override;
|
||||||
void DescriptorAsStorageBuffer(GPUContextVulkan* context, VkBuffer& buffer, VkDeviceSize& offset, VkDeviceSize& range) override;
|
void DescriptorAsStorageBuffer(GPUContextVulkan* context, VkBuffer& buffer, VkDeviceSize& offset, VkDeviceSize& range) override;
|
||||||
void DescriptorAsStorageTexelBuffer(GPUContextVulkan* context, VkBufferView& bufferView) override;
|
void DescriptorAsStorageTexelBuffer(GPUContextVulkan* context, VkBufferView& bufferView) override;
|
||||||
|
#if !BUILD_RELEASE
|
||||||
|
bool HasSRV() const override { return ((GPUBuffer*)_parent)->IsShaderResource(); }
|
||||||
|
bool HasUAV() const override { return ((GPUBuffer*)_parent)->IsUnorderedAccess(); }
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1005,7 +1005,11 @@ void GPUContextVulkan::BindCB(int32 slot, GPUConstantBuffer* cb)
|
|||||||
|
|
||||||
void GPUContextVulkan::BindSR(int32 slot, GPUResourceView* view)
|
void GPUContextVulkan::BindSR(int32 slot, GPUResourceView* view)
|
||||||
{
|
{
|
||||||
|
#if !BUILD_RELEASE
|
||||||
ASSERT(slot >= 0 && slot < GPU_MAX_SR_BINDED);
|
ASSERT(slot >= 0 && slot < GPU_MAX_SR_BINDED);
|
||||||
|
if (view && ((DescriptorOwnerResourceVulkan*)view->GetNativePtr())->HasSRV() == false)
|
||||||
|
LogInvalidResourceUsage(slot, view, InvalidBindPoint::SRV);
|
||||||
|
#endif
|
||||||
const auto handle = view ? (DescriptorOwnerResourceVulkan*)view->GetNativePtr() : nullptr;
|
const auto handle = view ? (DescriptorOwnerResourceVulkan*)view->GetNativePtr() : nullptr;
|
||||||
if (_srHandles[slot] != handle)
|
if (_srHandles[slot] != handle)
|
||||||
{
|
{
|
||||||
@@ -1017,7 +1021,11 @@ void GPUContextVulkan::BindSR(int32 slot, GPUResourceView* view)
|
|||||||
|
|
||||||
void GPUContextVulkan::BindUA(int32 slot, GPUResourceView* view)
|
void GPUContextVulkan::BindUA(int32 slot, GPUResourceView* view)
|
||||||
{
|
{
|
||||||
|
#if !BUILD_RELEASE
|
||||||
ASSERT(slot >= 0 && slot < GPU_MAX_UA_BINDED);
|
ASSERT(slot >= 0 && slot < GPU_MAX_UA_BINDED);
|
||||||
|
if (view && ((DescriptorOwnerResourceVulkan*)view->GetNativePtr())->HasUAV() == false)
|
||||||
|
LogInvalidResourceUsage(slot, view, InvalidBindPoint::UAV);
|
||||||
|
#endif
|
||||||
const auto handle = view ? (DescriptorOwnerResourceVulkan*)view->GetNativePtr() : nullptr;
|
const auto handle = view ? (DescriptorOwnerResourceVulkan*)view->GetNativePtr() : nullptr;
|
||||||
if (_uaHandles[slot] != handle)
|
if (_uaHandles[slot] != handle)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -724,6 +724,12 @@ public:
|
|||||||
{
|
{
|
||||||
CRASH;
|
CRASH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !BUILD_RELEASE
|
||||||
|
// Utilities for incorrect resource usage.
|
||||||
|
virtual bool HasSRV() const { return false; }
|
||||||
|
virtual bool HasUAV() const { return false; }
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
extern GPUDevice* CreateGPUDeviceVulkan();
|
extern GPUDevice* CreateGPUDeviceVulkan();
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ public:
|
|||||||
// [DescriptorOwnerResourceVulkan]
|
// [DescriptorOwnerResourceVulkan]
|
||||||
void DescriptorAsImage(GPUContextVulkan* context, VkImageView& imageView, VkImageLayout& layout) override;
|
void DescriptorAsImage(GPUContextVulkan* context, VkImageView& imageView, VkImageLayout& layout) override;
|
||||||
void DescriptorAsStorageImage(GPUContextVulkan* context, VkImageView& imageView, VkImageLayout& layout) override;
|
void DescriptorAsStorageImage(GPUContextVulkan* context, VkImageView& imageView, VkImageLayout& layout) override;
|
||||||
|
#if !BUILD_RELEASE
|
||||||
|
bool HasSRV() const override { return ((GPUTexture*)_parent)->IsShaderResource(); }
|
||||||
|
bool HasUAV() const override { return ((GPUTexture*)_parent)->IsUnorderedAccess(); }
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
+102
-14
@@ -3,6 +3,7 @@
|
|||||||
#include "Actor.h"
|
#include "Actor.h"
|
||||||
#include "ActorsCache.h"
|
#include "ActorsCache.h"
|
||||||
#include "Level.h"
|
#include "Level.h"
|
||||||
|
#include "SceneQuery.h"
|
||||||
#include "SceneObjectsFactory.h"
|
#include "SceneObjectsFactory.h"
|
||||||
#include "Scene/Scene.h"
|
#include "Scene/Scene.h"
|
||||||
#include "Prefabs/Prefab.h"
|
#include "Prefabs/Prefab.h"
|
||||||
@@ -15,6 +16,7 @@
|
|||||||
#include "Engine/Content/Deprecated.h"
|
#include "Engine/Content/Deprecated.h"
|
||||||
#include "Engine/Core/Cache.h"
|
#include "Engine/Core/Cache.h"
|
||||||
#include "Engine/Core/Collections/CollectionPoolCache.h"
|
#include "Engine/Core/Collections/CollectionPoolCache.h"
|
||||||
|
#include "Engine/Core/Math/Double4x4.h"
|
||||||
#include "Engine/Debug/Exceptions/JsonParseException.h"
|
#include "Engine/Debug/Exceptions/JsonParseException.h"
|
||||||
#include "Engine/Graphics/RenderTask.h"
|
#include "Engine/Graphics/RenderTask.h"
|
||||||
#include "Engine/Graphics/RenderView.h"
|
#include "Engine/Graphics/RenderView.h"
|
||||||
@@ -417,10 +419,21 @@ Actor* Actor::GetChild(const StringView& name) const
|
|||||||
Actor* Actor::GetChild(const MClass* type) const
|
Actor* Actor::GetChild(const MClass* type) const
|
||||||
{
|
{
|
||||||
CHECK_RETURN(type, nullptr);
|
CHECK_RETURN(type, nullptr);
|
||||||
for (auto child : Children)
|
if (type->IsInterface())
|
||||||
{
|
{
|
||||||
if (child->GetClass()->IsSubClassOf(type))
|
for (auto child : Children)
|
||||||
return child;
|
{
|
||||||
|
if (child->GetClass()->HasInterface(type))
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto child : Children)
|
||||||
|
{
|
||||||
|
if (child->GetClass()->IsSubClassOf(type))
|
||||||
|
return child;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -428,9 +441,18 @@ Actor* Actor::GetChild(const MClass* type) const
|
|||||||
Array<Actor*> Actor::GetChildren(const MClass* type) const
|
Array<Actor*> Actor::GetChildren(const MClass* type) const
|
||||||
{
|
{
|
||||||
Array<Actor*> result;
|
Array<Actor*> result;
|
||||||
for (auto child : Children)
|
if (type->IsInterface())
|
||||||
if (child->GetClass()->IsSubClassOf(type))
|
{
|
||||||
result.Add(child);
|
for (auto child : Children)
|
||||||
|
if (child->GetClass()->HasInterface(type))
|
||||||
|
result.Add(child);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto child : Children)
|
||||||
|
if (child->GetClass()->IsSubClassOf(type))
|
||||||
|
result.Add(child);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -785,6 +807,27 @@ void Actor::GetLocalToWorldMatrix(Matrix& localToWorld) const
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Actor::GetWorldToLocalMatrix(Double4x4& worldToLocal) const
|
||||||
|
{
|
||||||
|
GetLocalToWorldMatrix(worldToLocal);
|
||||||
|
worldToLocal.Invert();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Actor::GetLocalToWorldMatrix(Double4x4& localToWorld) const
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
_transform.GetWorld(localToWorld);
|
||||||
|
#else
|
||||||
|
_localTransform.GetWorld(localToWorld);
|
||||||
|
if (_parent)
|
||||||
|
{
|
||||||
|
Double4x4 parentToWorld;
|
||||||
|
_parent->GetLocalToWorldMatrix(parentToWorld);
|
||||||
|
localToWorld = localToWorld * parentToWorld;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void Actor::LinkPrefab(const Guid& prefabId, const Guid& prefabObjectId)
|
void Actor::LinkPrefab(const Guid& prefabId, const Guid& prefabObjectId)
|
||||||
{
|
{
|
||||||
ASSERT(prefabId.IsValid());
|
ASSERT(prefabId.IsValid());
|
||||||
@@ -1425,7 +1468,7 @@ Actor* Actor::FindActor(const MClass* type, bool activeOnly) const
|
|||||||
CHECK_RETURN(type, nullptr);
|
CHECK_RETURN(type, nullptr);
|
||||||
if (activeOnly && !_isActive)
|
if (activeOnly && !_isActive)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (GetClass()->IsSubClassOf(type))
|
if ((GetClass()->IsSubClassOf(type) || GetClass()->HasInterface(type)))
|
||||||
return const_cast<Actor*>(this);
|
return const_cast<Actor*>(this);
|
||||||
for (auto child : Children)
|
for (auto child : Children)
|
||||||
{
|
{
|
||||||
@@ -1439,7 +1482,7 @@ Actor* Actor::FindActor(const MClass* type, bool activeOnly) const
|
|||||||
Actor* Actor::FindActor(const MClass* type, const StringView& name) const
|
Actor* Actor::FindActor(const MClass* type, const StringView& name) const
|
||||||
{
|
{
|
||||||
CHECK_RETURN(type, nullptr);
|
CHECK_RETURN(type, nullptr);
|
||||||
if (GetClass()->IsSubClassOf(type) && _name == name)
|
if ((GetClass()->IsSubClassOf(type) || GetClass()->HasInterface(type)) && _name == name)
|
||||||
return const_cast<Actor*>(this);
|
return const_cast<Actor*>(this);
|
||||||
for (auto child : Children)
|
for (auto child : Children)
|
||||||
{
|
{
|
||||||
@@ -1455,7 +1498,7 @@ Actor* Actor::FindActor(const MClass* type, const Tag& tag, bool activeOnly) con
|
|||||||
CHECK_RETURN(type, nullptr);
|
CHECK_RETURN(type, nullptr);
|
||||||
if (activeOnly && !_isActive)
|
if (activeOnly && !_isActive)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (GetClass()->IsSubClassOf(type) && HasTag(tag))
|
if ((GetClass()->IsSubClassOf(type) || GetClass()->HasInterface(type)) && HasTag(tag))
|
||||||
return const_cast<Actor*>(this);
|
return const_cast<Actor*>(this);
|
||||||
for (auto child : Children)
|
for (auto child : Children)
|
||||||
{
|
{
|
||||||
@@ -1469,10 +1512,21 @@ Actor* Actor::FindActor(const MClass* type, const Tag& tag, bool activeOnly) con
|
|||||||
Script* Actor::FindScript(const MClass* type) const
|
Script* Actor::FindScript(const MClass* type) const
|
||||||
{
|
{
|
||||||
CHECK_RETURN(type, nullptr);
|
CHECK_RETURN(type, nullptr);
|
||||||
for (auto script : Scripts)
|
if (type->IsInterface())
|
||||||
{
|
{
|
||||||
if (script->GetClass()->IsSubClassOf(type) || script->GetClass()->HasInterface(type))
|
for (const auto script : Scripts)
|
||||||
return script;
|
{
|
||||||
|
if (script->GetClass()->HasInterface(type))
|
||||||
|
return script;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (const auto script : Scripts)
|
||||||
|
{
|
||||||
|
if (script->GetClass()->IsSubClassOf(type))
|
||||||
|
return script;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (auto child : Children)
|
for (auto child : Children)
|
||||||
{
|
{
|
||||||
@@ -1887,8 +1941,7 @@ String Actor::ToJson()
|
|||||||
CompactJsonWriter writer(buffer);
|
CompactJsonWriter writer(buffer);
|
||||||
writer.SceneObject(this);
|
writer.SceneObject(this);
|
||||||
String result;
|
String result;
|
||||||
const char* c = buffer.GetString();
|
result.SetUTF8(buffer.GetString(), (int32)buffer.GetSize());
|
||||||
result.SetUTF8(c, (int32)buffer.GetSize());
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1916,6 +1969,41 @@ void Actor::FromJson(const StringAnsiView& json)
|
|||||||
OnTransformChanged();
|
OnTransformChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Actor* Actor::Clone()
|
||||||
|
{
|
||||||
|
// Collect actors to clone
|
||||||
|
auto actors = ActorsCache::ActorsListCache.Get();
|
||||||
|
actors->Add(this);
|
||||||
|
SceneQuery::GetAllActors(this, *actors);
|
||||||
|
|
||||||
|
// Serialize objects
|
||||||
|
MemoryWriteStream stream;
|
||||||
|
if (ToBytes(*actors, stream))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// Remap object ids into a new ones
|
||||||
|
auto modifier = Cache::ISerializeModifier.Get();
|
||||||
|
for (int32 i = 0; i < actors->Count(); i++)
|
||||||
|
{
|
||||||
|
auto actor = actors->At(i);
|
||||||
|
if (!actor)
|
||||||
|
continue;
|
||||||
|
modifier->IdsMapping.Add(actor->GetID(), Guid::New());
|
||||||
|
for (int32 j = 0; j < actor->Scripts.Count(); j++)
|
||||||
|
{
|
||||||
|
const auto script = actor->Scripts[j];
|
||||||
|
if (script)
|
||||||
|
modifier->IdsMapping.Add(script->GetID(), Guid::New());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize objects
|
||||||
|
Array<Actor*> output;
|
||||||
|
if (FromBytes(ToSpan(stream.GetHandle(), (int32)stream.GetPosition()), output, modifier.Value) || output.IsEmpty())
|
||||||
|
return nullptr;
|
||||||
|
return output[0];
|
||||||
|
}
|
||||||
|
|
||||||
void Actor::SetPhysicsScene(PhysicsScene* scene)
|
void Actor::SetPhysicsScene(PhysicsScene* scene)
|
||||||
{
|
{
|
||||||
CHECK(scene);
|
CHECK(scene);
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the child actor of the given type.
|
/// Gets the child actor of the given type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type.</param>
|
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type. Supports interface types.</param>
|
||||||
/// <returns>The child actor or null.</returns>
|
/// <returns>The child actor or null.</returns>
|
||||||
API_FUNCTION() Actor* GetChild(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type) const;
|
API_FUNCTION() Actor* GetChild(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type) const;
|
||||||
|
|
||||||
@@ -270,7 +270,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the child actors of the given type.
|
/// Gets the child actors of the given type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type.</param>
|
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type. Supports interface types.</param>
|
||||||
/// <returns>The child actors.</returns>
|
/// <returns>The child actors.</returns>
|
||||||
API_FUNCTION() Array<Actor*> GetChildren(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type) const;
|
API_FUNCTION() Array<Actor*> GetChildren(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type) const;
|
||||||
|
|
||||||
@@ -315,7 +315,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the script of the given type from this actor.
|
/// Gets the script of the given type from this actor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">Type of the script to search for. Includes any scripts derived from the type.</param>
|
/// <param name="type">Type of the script to search for. Includes any scripts derived from the type. Supports interface types.</param>
|
||||||
/// <returns>The script or null.</returns>
|
/// <returns>The script or null.</returns>
|
||||||
API_FUNCTION() Script* GetScript(API_PARAM(Attributes="TypeReference(typeof(Script))") const MClass* type) const;
|
API_FUNCTION() Script* GetScript(API_PARAM(Attributes="TypeReference(typeof(Script))") const MClass* type) const;
|
||||||
|
|
||||||
@@ -332,7 +332,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the scripts of the given type from this actor.
|
/// Gets the scripts of the given type from this actor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">Type of the script to search for. Includes any scripts derived from the type.</param>
|
/// <param name="type">Type of the script to search for. Includes any scripts derived from the type. Supports interface types.</param>
|
||||||
/// <returns>The scripts.</returns>
|
/// <returns>The scripts.</returns>
|
||||||
API_FUNCTION() Array<Script*> GetScripts(API_PARAM(Attributes="TypeReference(typeof(Script))") const MClass* type) const;
|
API_FUNCTION() Array<Script*> GetScripts(API_PARAM(Attributes="TypeReference(typeof(Script))") const MClass* type) const;
|
||||||
|
|
||||||
@@ -655,6 +655,18 @@ public:
|
|||||||
/// <param name="localToWorld">The world to local matrix.</param>
|
/// <param name="localToWorld">The world to local matrix.</param>
|
||||||
API_FUNCTION() void GetLocalToWorldMatrix(API_PARAM(Out) Matrix& localToWorld) const;
|
API_FUNCTION() void GetLocalToWorldMatrix(API_PARAM(Out) Matrix& localToWorld) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the matrix that transforms a point from the world space to local space of the actor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="worldToLocal">The world to local matrix.</param>
|
||||||
|
void GetWorldToLocalMatrix(Double4x4& worldToLocal) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the matrix that transforms a point from the local space of the actor to world space.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="localToWorld">The world to local matrix.</param>
|
||||||
|
void GetLocalToWorldMatrix(Double4x4& localToWorld) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets actor bounding sphere that defines 3D space intersecting with the actor (for determination of the visibility for actor).
|
/// Gets actor bounding sphere that defines 3D space intersecting with the actor (for determination of the visibility for actor).
|
||||||
@@ -766,7 +778,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to find the actor of the given type in this actor hierarchy (checks this actor and all children hierarchy).
|
/// Tries to find the actor of the given type in this actor hierarchy (checks this actor and all children hierarchy).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type.</param>
|
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type. Supports interface types.</param>
|
||||||
/// <param name="activeOnly">Finds only a active actor.</param>
|
/// <param name="activeOnly">Finds only a active actor.</param>
|
||||||
/// <returns>Actor instance if found, null otherwise.</returns>
|
/// <returns>Actor instance if found, null otherwise.</returns>
|
||||||
API_FUNCTION() Actor* FindActor(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type, bool activeOnly = false) const;
|
API_FUNCTION() Actor* FindActor(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type, bool activeOnly = false) const;
|
||||||
@@ -774,7 +786,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to find the actor of the given type and name in this actor hierarchy (checks this actor and all children hierarchy).
|
/// Tries to find the actor of the given type and name in this actor hierarchy (checks this actor and all children hierarchy).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type.</param>
|
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type. Supports interface types.</param>
|
||||||
/// <param name="name">The name of the actor.</param>
|
/// <param name="name">The name of the actor.</param>
|
||||||
/// <returns>Actor instance if found, null otherwise.</returns>
|
/// <returns>Actor instance if found, null otherwise.</returns>
|
||||||
API_FUNCTION() Actor* FindActor(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type, const StringView& name) const;
|
API_FUNCTION() Actor* FindActor(API_PARAM(Attributes="TypeReference(typeof(Actor))") const MClass* type, const StringView& name) const;
|
||||||
@@ -782,7 +794,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to find the actor of the given type and tag in this actor hierarchy.
|
/// Tries to find the actor of the given type and tag in this actor hierarchy.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type.</param>
|
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type. Supports interface types.</param>
|
||||||
/// <param name="tag">The tag of the actor to search for.</param>
|
/// <param name="tag">The tag of the actor to search for.</param>
|
||||||
/// <param name="activeOnly">Finds only an active actor.</param>
|
/// <param name="activeOnly">Finds only an active actor.</param>
|
||||||
/// <returns>Actor instance if found, null otherwise.</returns>
|
/// <returns>Actor instance if found, null otherwise.</returns>
|
||||||
@@ -823,7 +835,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to find the script of the given type in this actor hierarchy (checks this actor and all children hierarchy).
|
/// Tries to find the script of the given type in this actor hierarchy (checks this actor and all children hierarchy).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type.</param>
|
/// <param name="type">Type of the actor to search for. Includes any actors derived from the type. Supports interface types.</param>
|
||||||
/// <returns>Script instance if found, null otherwise.</returns>
|
/// <returns>Script instance if found, null otherwise.</returns>
|
||||||
API_FUNCTION() Script* FindScript(API_PARAM(Attributes="TypeReference(typeof(Script))") const MClass* type) const;
|
API_FUNCTION() Script* FindScript(API_PARAM(Attributes="TypeReference(typeof(Script))") const MClass* type) const;
|
||||||
|
|
||||||
@@ -982,6 +994,11 @@ public:
|
|||||||
/// <param name="json">The serialized actor data (state).</param>
|
/// <param name="json">The serialized actor data (state).</param>
|
||||||
API_FUNCTION() void FromJson(const StringAnsiView& json);
|
API_FUNCTION() void FromJson(const StringAnsiView& json);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clones actor including all scripts and any child actors (whole scene tree). Objects are duplicated via serialization (any transient/non-saved state is ignored).
|
||||||
|
/// </summary>
|
||||||
|
API_FUNCTION() Actor* Clone();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when actor gets added to game systems. Occurs on BeginPlay event or when actor gets activated in hierarchy. Use this event to register object to other game system (eg. audio).
|
/// Called when actor gets added to game systems. Occurs on BeginPlay event or when actor gets activated in hierarchy. Use this event to register object to other game system (eg. audio).
|
||||||
|
|||||||
@@ -931,9 +931,7 @@ void AnimatedModel::Draw(RenderContext& renderContext)
|
|||||||
return;
|
return;
|
||||||
if (renderContext.View.Pass == DrawPass::GlobalSurfaceAtlas)
|
if (renderContext.View.Pass == DrawPass::GlobalSurfaceAtlas)
|
||||||
return; // No supported
|
return; // No supported
|
||||||
Matrix world;
|
ACTOR_GET_WORLD_MATRIX(this, view, world);
|
||||||
GetLocalToWorldMatrix(world);
|
|
||||||
renderContext.View.GetWorldMatrix(world);
|
|
||||||
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
|
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
|
||||||
|
|
||||||
_lastMinDstSqr = Math::Min(_lastMinDstSqr, Vector3::DistanceSquared(_transform.Translation, renderContext.View.WorldPosition));
|
_lastMinDstSqr = Math::Min(_lastMinDstSqr, Vector3::DistanceSquared(_transform.Translation, renderContext.View.WorldPosition));
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ protected:
|
|||||||
position = _transform.Translation - viewOrigin;
|
position = _transform.Translation - viewOrigin;
|
||||||
if (ViewDistance > ZeroTolerance)
|
if (ViewDistance > ZeroTolerance)
|
||||||
{
|
{
|
||||||
const float dst2 = Vector3::DistanceSquared(viewPosition, position);
|
const float dst2 = (float)Vector3::DistanceSquared(viewPosition, position);
|
||||||
const float dst = Math::Sqrt(dst2);
|
const float dst = Math::Sqrt(dst2);
|
||||||
brightness *= Math::Remap(dst, 0.9f * ViewDistance, ViewDistance, 1.0f, 0.0f);
|
brightness *= Math::Remap(dst, 0.9f * ViewDistance, ViewDistance, 1.0f, 0.0f);
|
||||||
return dst < ViewDistance;
|
return dst < ViewDistance;
|
||||||
|
|||||||
@@ -476,9 +476,9 @@ void Spline::GetKeyframes(MArray* data)
|
|||||||
Platform::MemoryCopy(MCore::Array::GetAddress(data), Curve.GetKeyframes().Get(), sizeof(Keyframe) * Curve.GetKeyframes().Count());
|
Platform::MemoryCopy(MCore::Array::GetAddress(data), Curve.GetKeyframes().Get(), sizeof(Keyframe) * Curve.GetKeyframes().Count());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spline::SetKeyframes(MArray* data)
|
void Spline::SetKeyframes(MArray* data, int32 keySize)
|
||||||
{
|
{
|
||||||
Curve = Span<byte>((const byte*)MCore::Array::GetAddress(data), MCore::Array::GetLength(data));
|
Curve = Span<byte>(MCore::Array::GetAddress<byte>(data), keySize * MCore::Array::GetLength(data));
|
||||||
UpdateSpline();
|
UpdateSpline();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,19 +490,26 @@ void Spline::SetKeyframes(MArray* data)
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
void DrawSpline(Spline* spline, const Color& color, const Transform& transform, bool depthTest)
|
FORCE_INLINE float NodeSizeByDistance(const Vector3& nodePosition, bool scaleByDistance)
|
||||||
|
{
|
||||||
|
if (scaleByDistance)
|
||||||
|
return (float)(Vector3::Distance(DebugDraw::GetViewPos(), nodePosition) / 100);
|
||||||
|
return 5.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawSpline(Spline* spline, const Color& color, const Transform& transform, bool depthTest, bool scaleByDistance = false)
|
||||||
{
|
{
|
||||||
const int32 count = spline->Curve.GetKeyframes().Count();
|
const int32 count = spline->Curve.GetKeyframes().Count();
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return;
|
return;
|
||||||
Spline::Keyframe* prev = spline->Curve.GetKeyframes().Get();
|
Spline::Keyframe* prev = spline->Curve.GetKeyframes().Get();
|
||||||
Vector3 prevPos = transform.LocalToWorld(prev->Value.Translation);
|
Vector3 prevPos = transform.LocalToWorld(prev->Value.Translation);
|
||||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(prevPos, 5.0f), color, 0.0f, depthTest);
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(prevPos, NodeSizeByDistance(prevPos, scaleByDistance)), color, 0.0f, depthTest);
|
||||||
for (int32 i = 1; i < count; i++)
|
for (int32 i = 1; i < count; i++)
|
||||||
{
|
{
|
||||||
Spline::Keyframe* next = prev + 1;
|
Spline::Keyframe* next = prev + 1;
|
||||||
Vector3 nextPos = transform.LocalToWorld(next->Value.Translation);
|
Vector3 nextPos = transform.LocalToWorld(next->Value.Translation);
|
||||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(nextPos, 5.0f), color, 0.0f, depthTest);
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(nextPos, NodeSizeByDistance(nextPos, scaleByDistance)), color, 0.0f, depthTest);
|
||||||
const float d = (next->Time - prev->Time) / 3.0f;
|
const float d = (next->Time - prev->Time) / 3.0f;
|
||||||
DEBUG_DRAW_BEZIER(prevPos, prevPos + prev->TangentOut.Translation * d, nextPos + next->TangentIn.Translation * d, nextPos, color, 0.0f, depthTest);
|
DEBUG_DRAW_BEZIER(prevPos, prevPos + prev->TangentOut.Translation * d, nextPos + next->TangentIn.Translation * d, nextPos, color, 0.0f, depthTest);
|
||||||
prev = next;
|
prev = next;
|
||||||
@@ -521,7 +528,7 @@ void Spline::OnDebugDraw()
|
|||||||
|
|
||||||
void Spline::OnDebugDrawSelected()
|
void Spline::OnDebugDrawSelected()
|
||||||
{
|
{
|
||||||
DrawSpline(this, Color::White, _transform, false);
|
DrawSpline(this, Color::White, _transform, false, true);
|
||||||
|
|
||||||
// Base
|
// Base
|
||||||
Actor::OnDebugDrawSelected();
|
Actor::OnDebugDrawSelected();
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ private:
|
|||||||
// Internal bindings
|
// Internal bindings
|
||||||
#if !COMPILE_WITHOUT_CSHARP
|
#if !COMPILE_WITHOUT_CSHARP
|
||||||
API_FUNCTION(NoProxy) void GetKeyframes(MArray* data);
|
API_FUNCTION(NoProxy) void GetKeyframes(MArray* data);
|
||||||
API_FUNCTION(NoProxy) void SetKeyframes(MArray* data);
|
API_FUNCTION(NoProxy) void SetKeyframes(MArray* data, int32 keySize);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -337,9 +337,7 @@ void StaticModel::Draw(RenderContext& renderContext)
|
|||||||
GlobalSurfaceAtlasPass::Instance()->RasterizeActor(this, this, _sphere, _transform, Model->LODs.Last().GetBox());
|
GlobalSurfaceAtlasPass::Instance()->RasterizeActor(this, this, _sphere, _transform, Model->LODs.Last().GetBox());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Matrix world;
|
ACTOR_GET_WORLD_MATRIX(this, view, world);
|
||||||
GetLocalToWorldMatrix(world);
|
|
||||||
renderContext.View.GetWorldMatrix(world);
|
|
||||||
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
|
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
|
||||||
if (_vertexColorsDirty)
|
if (_vertexColorsDirty)
|
||||||
FlushVertexColors();
|
FlushVertexColors();
|
||||||
@@ -375,9 +373,7 @@ void StaticModel::Draw(RenderContextBatch& renderContextBatch)
|
|||||||
if (!Model || !Model->IsLoaded())
|
if (!Model || !Model->IsLoaded())
|
||||||
return;
|
return;
|
||||||
const RenderContext& renderContext = renderContextBatch.GetMainContext();
|
const RenderContext& renderContext = renderContextBatch.GetMainContext();
|
||||||
Matrix world;
|
ACTOR_GET_WORLD_MATRIX(this, view, world);
|
||||||
GetLocalToWorldMatrix(world);
|
|
||||||
renderContext.View.GetWorldMatrix(world);
|
|
||||||
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
|
GEOMETRY_DRAW_STATE_EVENT_BEGIN(_drawState, world);
|
||||||
if (_vertexColorsDirty)
|
if (_vertexColorsDirty)
|
||||||
FlushVertexColors();
|
FlushVertexColors();
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user