Compare commits
228 Commits
c73daf422b
...
master_fix
| Author | SHA1 | Date | |
|---|---|---|---|
| 824ff7050e | |||
| 042843fe42 | |||
| 8631b389c1 | |||
| e3f5af530b | |||
|
|
e257f9e4a0 | ||
|
|
056de752ed | ||
|
|
76700c0b24 | ||
|
|
9fdcff657d | ||
|
|
2b6339c05c | ||
|
|
bb91202439 | ||
|
|
f25e9f262a | ||
|
|
ee51077f49 | ||
|
|
950e958a58 | ||
|
|
5fdbed2b56 | ||
|
|
0e627577fc | ||
|
|
4846d4b024 | ||
|
|
5e5293bf7b | ||
|
|
d88477dcae | ||
|
|
bd58bd91b4 | ||
|
|
7ce0d88bdc | ||
|
|
98bb2d40d6 | ||
|
|
f4bc620bbd | ||
|
|
0313bf32c9 | ||
|
|
0c887cd29e | ||
|
|
5bd9bce634 | ||
|
|
2a53d0a462 | ||
| 82bd915274 | |||
|
|
71391cf1cc | ||
|
|
b5286af526 | ||
|
|
9f07a2a54e | ||
|
|
c39c642b60 | ||
|
|
02cff3973a | ||
|
|
a63b97d31d | ||
|
|
ca52122656 | ||
|
|
20a7fcf6a0 | ||
|
|
43665aa7eb | ||
|
|
3b9b49950c | ||
|
|
0a8752ec0a | ||
|
|
47685dc2be | ||
|
|
517ee5bb25 | ||
|
|
3ab01d3576 | ||
|
|
31b6d4d658 | ||
|
|
08f840d642 | ||
|
|
776b6259cd | ||
|
|
5c81c71116 | ||
|
|
188b635ea0 | ||
|
|
56066a3212 | ||
|
|
ed50ce9c90 | ||
|
|
a7e77f6e21 | ||
|
|
56278b17ee | ||
|
|
bd78db72b9 | ||
|
|
32bd72fecd | ||
|
|
3a798a70fa | ||
|
|
02429266b1 | ||
|
|
77aea0c69c | ||
|
|
6a3ce862cb | ||
|
|
93217da619 | ||
|
|
63def54dad | ||
|
|
00f9a28729 | ||
|
|
56beca0db4 | ||
|
|
64cd898a65 | ||
|
|
90472a4b31 | ||
|
|
a1999183f2 | ||
|
|
1e3ce48024 | ||
|
|
0007185b5f | ||
|
|
403d2cedc0 | ||
|
|
c8839b8587 | ||
|
|
cf048c9804 | ||
|
|
bea75f51bd | ||
|
|
1bf6612002 | ||
|
|
d9a18b1d31 | ||
|
|
465f30661f | ||
|
|
a62ca5452e | ||
|
|
92254eefcc | ||
|
|
2d56411e5f | ||
|
|
f8dc8ab903 | ||
|
|
2a55cda583 | ||
|
|
7c91c03adf | ||
|
|
caa902ea9b | ||
|
|
fb07071e24 | ||
|
|
a1cb7dcbe7 | ||
|
|
032f698c7b | ||
|
|
e2aaef9b88 | ||
|
|
ee0303bcfb | ||
|
|
1523c7b4ce | ||
|
|
a16a8eaded | ||
|
|
9ff9d48ffd | ||
|
|
dfb1fb91a5 | ||
|
|
8f56ab9534 | ||
|
|
c0dda45c7b | ||
|
|
3efb981f00 | ||
|
|
ed408917c6 | ||
|
|
2ca435a414 | ||
|
|
de9e282bad | ||
|
|
c437daf9be | ||
|
|
1e4f96486f | ||
|
|
e03d0f3322 | ||
|
|
5f0e1253cc | ||
|
|
7e6b040258 | ||
|
|
329ebb6482 | ||
|
|
7a9c58003d | ||
|
|
371a16e37b | ||
|
|
95629e792d | ||
|
|
e79af2fd60 | ||
|
|
4aba0153f8 | ||
|
|
f91c33e17c | ||
|
|
6c29877b20 | ||
|
|
3abde6ecfc | ||
|
|
b42168eee5 | ||
|
|
ac3b2c0ef2 | ||
|
|
f640452b7b | ||
|
|
2f670495ac | ||
|
|
2a36edf528 | ||
|
|
5e690abd76 | ||
|
|
4008e19ca9 | ||
|
|
e9070b30a0 | ||
|
|
636a1ff930 | ||
|
|
3888c4ba21 | ||
|
|
69173803bf | ||
|
|
13e31650be | ||
|
|
3563287f17 | ||
|
|
91ee9f5e05 | ||
| 49918a1067 | |||
|
|
c7997e0c2f | ||
|
|
4805dfbdba | ||
|
|
62424215c1 | ||
|
|
97ae13759e | ||
|
|
108678d94f | ||
|
|
66dbba5c16 | ||
|
|
d84cef0c18 | ||
|
|
077cefc60e | ||
|
|
35acc668c9 | ||
|
|
ebbe0f12ed | ||
|
|
6a8b76278a | ||
|
|
8ac99ef28f | ||
|
|
547cf7f600 | ||
|
|
b8b8b118c9 | ||
|
|
76247323eb | ||
|
|
0ff20c7c85 | ||
|
|
dd690e7495 | ||
|
|
ca500548a3 | ||
|
|
c0b73375b1 | ||
|
|
9c6d6a0b07 | ||
|
|
179f6014bf | ||
|
|
b580c6ec8e | ||
|
|
dd60cf0040 | ||
|
|
cc851b29fc | ||
|
|
59643b2fb9 | ||
|
|
3a5bb81d39 | ||
|
|
5ec860015d | ||
|
|
0f701ec08e | ||
|
|
387c3ea2f4 | ||
|
|
85b134b7be | ||
|
|
5d17d2509d | ||
|
|
036d4b2f4b | ||
|
|
93f12b73d8 | ||
|
|
1091bc6e2c | ||
|
|
594c0fb8e7 | ||
| 3fc1895b56 | |||
|
|
a70d7cf1f9 | ||
|
|
1f592ba1a1 | ||
|
|
a43daf025d | ||
|
|
296a2afa95 | ||
|
|
a7e879a3a4 | ||
|
|
27b160b464 | ||
|
|
7c3c4f1a63 | ||
|
|
fbae93b532 | ||
|
|
35d6e5fd21 | ||
|
|
114828adcb | ||
|
|
053e52c91f | ||
|
|
d24bd7dfd0 | ||
| 2c8c9b1637 | |||
|
|
05a8c841da | ||
|
|
c4fcaa999c | ||
|
|
70c9dd6608 | ||
|
|
802e2ac7c2 | ||
|
|
0ca60062d9 | ||
|
|
5a587a8582 | ||
|
|
22515c37b5 | ||
|
|
38a48cf1d4 | ||
|
|
cd66d00219 | ||
|
|
c944bd9bed | ||
|
|
a0689f3f00 | ||
|
|
2ee2c97f1e | ||
|
|
fd19e83a46 | ||
|
|
755702b65a | ||
|
|
72e200a7fc | ||
|
|
6353e5f4f2 | ||
|
|
b184022d15 | ||
|
|
26dce69404 | ||
| 2841ac22df | |||
|
|
516f22c3c0 | ||
|
|
5a8c4cd0a5 | ||
|
|
f53b7e3323 | ||
|
|
c1439c646e | ||
| 280035e54f | |||
| 0d140c4f39 | |||
| 32b4efc175 | |||
|
|
d1774cac28 | ||
|
|
2629511224 | ||
|
|
bcf7226946 | ||
|
|
f5c9e00beb | ||
|
|
6353514188 | ||
|
|
8467315a1e | ||
|
|
be5dbbb95f | ||
| 6b9c727a6a | |||
| 91c0ba1986 | |||
|
|
e4bb8001b2 | ||
|
|
a9fc5f720d | ||
|
|
d323b1c7e2 | ||
|
|
d93c32db9c | ||
|
|
08abdc159e | ||
|
|
708b9c6767 | ||
|
|
ed26a4c182 | ||
|
|
a239984908 | ||
|
|
fc3ea44c69 | ||
|
|
fdecad0d29 | ||
|
|
c7437ed533 | ||
|
|
dab44f5ceb | ||
|
|
c635d93b3c | ||
|
|
7377bad721 | ||
|
|
09fa3ce4be | ||
|
|
bd0daf7580 | ||
|
|
e1b3429b4c | ||
|
|
efa963be68 | ||
|
|
df28b0d977 | ||
|
|
59fb83a469 | ||
|
|
7544500be1 |
2
.github/ISSUE_TEMPLATE/1-bug.yaml
vendored
2
.github/ISSUE_TEMPLATE/1-bug.yaml
vendored
@@ -31,7 +31,7 @@ body:
|
||||
- '1.10'
|
||||
- '1.11'
|
||||
- master branch
|
||||
default: 2
|
||||
default: 3
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
4
.github/workflows/build_ios.yml
vendored
4
.github/workflows/build_ios.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
dotnet-version: 9.0.x
|
||||
- name: Setup .NET Workload
|
||||
run: |
|
||||
dotnet workload install ios
|
||||
@@ -33,4 +33,4 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -dotnet=8 -arch=ARM64 -platform=iOS -configuration=Release -buildtargets=FlaxGame
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -dotnet=9 -arch=ARM64 -platform=iOS -configuration=Release -buildtargets=FlaxGame
|
||||
|
||||
BIN
Content/Editor/Primitives/Cube.flax
(Stored with Git LFS)
BIN
Content/Editor/Primitives/Cube.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/ColorGrading.flax
(Stored with Git LFS)
BIN
Content/Shaders/ColorGrading.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/GI/GlobalSurfaceAtlas.flax
(Stored with Git LFS)
BIN
Content/Shaders/GI/GlobalSurfaceAtlas.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/GlobalSignDistanceField.flax
(Stored with Git LFS)
BIN
Content/Shaders/GlobalSignDistanceField.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/MotionBlur.flax
(Stored with Git LFS)
BIN
Content/Shaders/MotionBlur.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/SDF.flax
(Stored with Git LFS)
BIN
Content/Shaders/SDF.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/VolumetricFog.flax
(Stored with Git LFS)
BIN
Content/Shaders/VolumetricFog.flax
(Stored with Git LFS)
Binary file not shown.
@@ -4,7 +4,7 @@
|
||||
"Major": 1,
|
||||
"Minor": 11,
|
||||
"Revision": 0,
|
||||
"Build": 6801
|
||||
"Build": 6805
|
||||
},
|
||||
"Company": "Flax",
|
||||
"Copyright": "Copyright (c) 2012-2025 Wojciech Figat. All rights reserved.",
|
||||
|
||||
@@ -49,7 +49,7 @@ Follow the instructions below to compile and run the engine from source.
|
||||
* Fedora: `sudo dnf 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/))
|
||||
* Ubuntu: `sudo apt install vulkan-sdk`
|
||||
* Ubuntu: `sudo apt install vulkan-sdk` (deprecated, follow official docs)
|
||||
* Fedora: `sudo dnf install vulkan-headers vulkan-tools vulkan-validation-layers`
|
||||
* Arch: `sudo pacman -S vulkan-headers vulkan-tools vulkan-validation-layers`
|
||||
* Install Git with LFS
|
||||
@@ -60,7 +60,7 @@ Follow the instructions below to compile and run the engine from source.
|
||||
* Ubuntu: `sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev zlib1g-dev`
|
||||
* Fedora: `sudo dnf install libX11-devel libXcursor-devel libXinerama-devel ghc-zlib-devel`
|
||||
* Arch: `sudo pacman -S base-devel libx11 libxcursor libxinerama zlib`
|
||||
* Install Clang compiler (version 6 or later):
|
||||
* Install Clang compiler (version 14 or later):
|
||||
* Ubuntu: `sudo apt-get install clang lldb lld`
|
||||
* Fedora: `sudo dnf install clang llvm lldb lld`
|
||||
* Arch: `sudo pacman -S clang lldb lld`
|
||||
|
||||
@@ -281,6 +281,13 @@ namespace FlaxEditor.Content
|
||||
|
||||
private void CacheData()
|
||||
{
|
||||
if (!_asset)
|
||||
{
|
||||
_parameters = Utils.GetEmptyArray<ScriptMemberInfo>();
|
||||
_methods = Utils.GetEmptyArray<ScriptMemberInfo>();
|
||||
_attributes = Utils.GetEmptyArray<Attribute>();
|
||||
return;
|
||||
}
|
||||
if (_parameters != null)
|
||||
return;
|
||||
if (_asset.WaitForLoaded())
|
||||
@@ -344,13 +351,13 @@ namespace FlaxEditor.Content
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Path.GetFileNameWithoutExtension(_asset.Path);
|
||||
public string Name => _asset ? Path.GetFileNameWithoutExtension(_asset.Path) : null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Namespace => string.Empty;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string TypeName => JsonSerializer.GetStringID(_asset.ID);
|
||||
public string TypeName => _asset ? JsonSerializer.GetStringID(_asset.ID) : null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsPublic => true;
|
||||
|
||||
@@ -130,6 +130,11 @@ namespace FlaxEditor.Content
|
||||
eyeAdaptation.Mode = EyeAdaptationMode.None;
|
||||
eyeAdaptation.OverrideFlags |= EyeAdaptationSettingsOverride.Mode;
|
||||
preview.PostFxVolume.EyeAdaptation = eyeAdaptation;
|
||||
|
||||
var antiAliasing = preview.PostFxVolume.AntiAliasing;
|
||||
antiAliasing.Mode = AntialiasingMode.FastApproximateAntialiasing;
|
||||
antiAliasing.OverrideFlags |= AntiAliasingSettingsOverride.Mode;
|
||||
preview.PostFxVolume.AntiAliasing = antiAliasing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,26 +15,32 @@
|
||||
#include "Editor/ProjectInfo.h"
|
||||
#include "Editor/Utilities/EditorUtilities.h"
|
||||
|
||||
GDKPlatformTools::GDKPlatformTools()
|
||||
String GetGDK()
|
||||
{
|
||||
// Find GDK
|
||||
Platform::GetEnvironmentVariable(TEXT("GameDKLatest"), _gdkPath);
|
||||
if (_gdkPath.IsEmpty() || !FileSystem::DirectoryExists(_gdkPath))
|
||||
String gdk;
|
||||
Platform::GetEnvironmentVariable(TEXT("GameDKLatest"), gdk);
|
||||
if (gdk.IsEmpty() || !FileSystem::DirectoryExists(gdk))
|
||||
{
|
||||
_gdkPath.Clear();
|
||||
Platform::GetEnvironmentVariable(TEXT("GRDKLatest"), _gdkPath);
|
||||
if (_gdkPath.IsEmpty() || !FileSystem::DirectoryExists(_gdkPath))
|
||||
gdk.Clear();
|
||||
Platform::GetEnvironmentVariable(TEXT("GRDKLatest"), gdk);
|
||||
if (gdk.IsEmpty() || !FileSystem::DirectoryExists(gdk))
|
||||
{
|
||||
_gdkPath.Clear();
|
||||
gdk.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_gdkPath.EndsWith(TEXT("GRDK\\")))
|
||||
_gdkPath.Remove(_gdkPath.Length() - 6);
|
||||
else if (_gdkPath.EndsWith(TEXT("GRDK")))
|
||||
_gdkPath.Remove(_gdkPath.Length() - 5);
|
||||
if (gdk.EndsWith(TEXT("GRDK\\")))
|
||||
gdk.Remove(gdk.Length() - 6);
|
||||
else if (gdk.EndsWith(TEXT("GRDK")))
|
||||
gdk.Remove(gdk.Length() - 5);
|
||||
}
|
||||
}
|
||||
return gdk;
|
||||
}
|
||||
|
||||
GDKPlatformTools::GDKPlatformTools()
|
||||
{
|
||||
_gdkPath = GetGDK();
|
||||
}
|
||||
|
||||
DotNetAOTModes GDKPlatformTools::UseAOT() const
|
||||
@@ -121,7 +127,7 @@ bool GDKPlatformTools::OnPostProcess(CookingData& data, GDKPlatformSettings* pla
|
||||
validName.Add('\0');
|
||||
|
||||
sb.Append(TEXT("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
|
||||
sb.Append(TEXT("<Game configVersion=\"0\">\n"));
|
||||
sb.Append(TEXT("<Game configVersion=\"1\">\n"));
|
||||
sb.AppendFormat(TEXT(" <Identity Name=\"{0}\" Publisher=\"{1}\" Version=\"{2}\"/>\n"),
|
||||
validName.Get(),
|
||||
platformSettings->PublisherName.HasChars() ? platformSettings->PublisherName : TEXT("CN=") + gameSettings->CompanyName,
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
#include "Engine/Serialization/JsonTools.h"
|
||||
#include "Engine/Serialization/JsonWriters.h"
|
||||
#include "Editor/Cooker/PlatformTools.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Editor/Editor.h"
|
||||
#include "Editor/ProjectInfo.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Editor/Utilities/EditorUtilities.h"
|
||||
#if PLATFORM_MAC
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
@@ -127,7 +128,7 @@ bool CompileScriptsStep::DeployBinaries(CookingData& data, const String& path, c
|
||||
const String dst = dstPath / StringUtils::GetFileName(file);
|
||||
if (dst == file)
|
||||
continue;
|
||||
if (FileSystem::CopyFile(dst, file))
|
||||
if (EditorUtilities::CopyFileIfNewer(dst, file))
|
||||
{
|
||||
data.Error(String::Format(TEXT("Failed to copy file from {0} to {1}."), file, dst));
|
||||
return true;
|
||||
|
||||
@@ -526,6 +526,7 @@ bool ProcessShaderBase(CookAssetsStep::AssetCookData& data, ShaderAssetBase* ass
|
||||
#if PLATFORM_TOOLS_XBOX_SCARLETT
|
||||
case BuildPlatform::XboxScarlett:
|
||||
{
|
||||
options.Platform = PlatformType::XboxScarlett;
|
||||
const char* platformDefineName = "PLATFORM_XBOX_SCARLETT";
|
||||
COMPILE_PROFILE(DirectX_SM6, SHADER_FILE_CHUNK_INTERNAL_D3D_SM6_CACHE);
|
||||
break;
|
||||
@@ -1367,7 +1368,10 @@ bool CookAssetsStep::Perform(CookingData& data)
|
||||
{
|
||||
typeName = e.TypeName;
|
||||
}
|
||||
LOG(Info, "{0}: {1:>4} assets of total size {2}", typeName, e.Count, Utilities::BytesToText(e.ContentSize));
|
||||
if (e.Count == 1)
|
||||
LOG(Info, "{0}: 1 asset of total size {1}", typeName, Utilities::BytesToText(e.ContentSize));
|
||||
else
|
||||
LOG(Info, "{0}: {1:>4} assets of total size {2}", typeName, e.Count, Utilities::BytesToText(e.ContentSize));
|
||||
}
|
||||
LOG(Info, "");
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
}
|
||||
if (version.IsEmpty())
|
||||
{
|
||||
data.Error(String::Format(TEXT("Failed to find supported .NET {} version (min {}) for the current host platform."), maxVer, minVer));
|
||||
data.Error(String::Format(TEXT("Failed to find supported .NET {} version (min {}) for {} platform."), maxVer, minVer, platformName));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ bool PrecompileAssembliesStep::Perform(CookingData& data)
|
||||
data.StepProgress(infoMsg, 0);
|
||||
|
||||
// Override Newtonsoft.Json with AOT-version (one that doesn't use System.Reflection.Emit)
|
||||
// TODO: remove it since EngineModule does properly reference AOT lib now
|
||||
EditorUtilities::CopyFileIfNewer(data.ManagedCodeOutputPath / TEXT("Newtonsoft.Json.dll"), Globals::StartupFolder / TEXT("Source/Platforms/DotNet/AOT/Newtonsoft.Json.dll"));
|
||||
FileSystem::DeleteFile(data.ManagedCodeOutputPath / TEXT("Newtonsoft.Json.xml"));
|
||||
FileSystem::DeleteFile(data.ManagedCodeOutputPath / TEXT("Newtonsoft.Json.pdb"));
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
@@ -11,7 +12,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
[CustomEditor(typeof(EnvironmentProbe)), DefaultEditor]
|
||||
public class EnvironmentProbeEditor : ActorEditor
|
||||
{
|
||||
private FlaxEngine.GUI.Button _bake;
|
||||
private Button _bake;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
@@ -20,8 +21,9 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
|
||||
if (Values.HasDifferentTypes == false)
|
||||
{
|
||||
layout.Space(10);
|
||||
_bake = layout.Button("Bake").Button;
|
||||
var group = layout.Group("Bake");
|
||||
group.Panel.ItemsMargin = new Margin(Utilities.Constants.UIMargin * 2);
|
||||
_bake = group.Button("Bake").Button;
|
||||
_bake.Clicked += BakeButtonClicked;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -914,9 +914,11 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
// Remove drop down arrows and containment lines if no objects in the group
|
||||
if (group.Children.Count == 0)
|
||||
{
|
||||
group.Panel.Close();
|
||||
group.Panel.ArrowImageOpened = null;
|
||||
group.Panel.ArrowImageClosed = null;
|
||||
group.Panel.EnableContainmentLines = false;
|
||||
group.Panel.CanOpenClose = false;
|
||||
}
|
||||
|
||||
// Scripts arrange bar
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
@@ -19,8 +20,9 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
if (Values.HasDifferentTypes == false)
|
||||
{
|
||||
// Add 'Bake' button
|
||||
layout.Space(10);
|
||||
var button = layout.Button("Bake");
|
||||
var group = layout.Group("Bake");
|
||||
group.Panel.ItemsMargin = new Margin(Utilities.Constants.UIMargin * 2);
|
||||
var button = group.Button("Bake");
|
||||
button.Button.Clicked += BakeButtonClicked;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +123,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
if (Picker == null)
|
||||
return;
|
||||
var differentValues = HasDifferentValues;
|
||||
Picker.DifferentValues = differentValues;
|
||||
if (!differentValues)
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
menu.AddButton("Copy", linkedEditor.Copy);
|
||||
var b = menu.AddButton("Duplicate", () => Editor.Duplicate(Index));
|
||||
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly && Editor._canResize;
|
||||
b.Enabled = !Editor._readOnly && Editor._canResize;
|
||||
b = menu.AddButton("Paste", linkedEditor.Paste);
|
||||
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
|
||||
|
||||
@@ -407,7 +407,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
menu.AddButton("Copy", linkedEditor.Copy);
|
||||
var b = menu.AddButton("Duplicate", () => Editor.Duplicate(Index));
|
||||
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly && Editor._canResize;
|
||||
b.Enabled = !Editor._readOnly && Editor._canResize;
|
||||
var paste = menu.AddButton("Paste", linkedEditor.Paste);
|
||||
paste.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
|
||||
|
||||
@@ -650,7 +650,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
panel.Panel.Size = new Float2(0, 18);
|
||||
panel.Panel.Margin = new Margin(0, 0, Utilities.Constants.UIMargin, 0);
|
||||
|
||||
var removeButton = panel.Button("-", "Remove the last item");
|
||||
var removeButton = panel.Button("-", "Remove the last item.");
|
||||
removeButton.Button.Size = new Float2(16, 16);
|
||||
removeButton.Button.Enabled = size > _minCount;
|
||||
removeButton.Button.AnchorPreset = AnchorPresets.TopRight;
|
||||
@@ -661,7 +661,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
Resize(Count - 1);
|
||||
};
|
||||
|
||||
var addButton = panel.Button("+", "Add a new item");
|
||||
var addButton = panel.Button("+", "Add a new item.");
|
||||
addButton.Button.Size = new Float2(16, 16);
|
||||
addButton.Button.Enabled = (!NotNullItems || size > 0) && size < _maxCount;
|
||||
addButton.Button.AnchorPreset = AnchorPresets.TopRight;
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
public event Action<TypePickerControl> TypePickerValueChanged;
|
||||
|
||||
/// <summary>
|
||||
/// The custom callback for types validation. Cane be used to implement a rule for types to pick.
|
||||
/// The custom callback for types validation. Can be used to implement a rule for types to pick.
|
||||
/// </summary>
|
||||
public Func<ScriptType, bool> CheckValid;
|
||||
|
||||
@@ -353,7 +353,13 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
if (!string.IsNullOrEmpty(typeReference.CheckMethod))
|
||||
{
|
||||
var parentType = ParentEditor.Values[0].GetType();
|
||||
var parentEditor = ParentEditor;
|
||||
// Find actual parent editor if parent editor is collection editor
|
||||
while (parentEditor.GetType().IsAssignableTo(typeof(CollectionEditor)))
|
||||
parentEditor = parentEditor.ParentEditor;
|
||||
|
||||
var parentType = parentEditor.Values[0].GetType();
|
||||
|
||||
var method = parentType.GetMethod(typeReference.CheckMethod, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
if (method != null)
|
||||
{
|
||||
|
||||
@@ -1390,6 +1390,7 @@ namespace FlaxEditor
|
||||
public void BuildAllMeshesSDF()
|
||||
{
|
||||
var models = new List<Model>();
|
||||
var forceRebuild = Input.GetKey(KeyboardKeys.F);
|
||||
Scene.ExecuteOnGraph(node =>
|
||||
{
|
||||
if (node is StaticModelNode staticModelNode && staticModelNode.Actor is StaticModel staticModel)
|
||||
@@ -1399,7 +1400,7 @@ namespace FlaxEditor
|
||||
model != null &&
|
||||
!models.Contains(model) &&
|
||||
!model.IsVirtual &&
|
||||
model.SDF.Texture == null)
|
||||
(forceRebuild || model.SDF.Texture == null))
|
||||
{
|
||||
models.Add(model);
|
||||
}
|
||||
@@ -1412,7 +1413,17 @@ namespace FlaxEditor
|
||||
{
|
||||
var model = models[i];
|
||||
Log($"[{i}/{models.Count}] Generating SDF for {model}");
|
||||
if (!model.GenerateSDF())
|
||||
float resolutionScale = 1.0f, backfacesThreshold = 0.6f;
|
||||
int lodIndex = 6;
|
||||
bool useGPU = true;
|
||||
var sdf = model.SDF;
|
||||
if (sdf.Texture != null)
|
||||
{
|
||||
// Preserve options set on this model
|
||||
resolutionScale = sdf.ResolutionScale;
|
||||
lodIndex = sdf.LOD;
|
||||
}
|
||||
if (!model.GenerateSDF(resolutionScale, lodIndex, true, backfacesThreshold, useGPU))
|
||||
model.Save();
|
||||
}
|
||||
});
|
||||
@@ -1587,7 +1598,7 @@ namespace FlaxEditor
|
||||
if (dockedTo != null && dockedTo.SelectedTab != gameWin && dockedTo.SelectedTab != null)
|
||||
result = dockedTo.SelectedTab.Size;
|
||||
else
|
||||
result = gameWin.Viewport.Size;
|
||||
result = gameWin.Viewport.ContentSize;
|
||||
|
||||
result *= root.DpiScale;
|
||||
result = Float2.Round(result);
|
||||
|
||||
@@ -447,8 +447,8 @@ namespace FlaxEditor.GUI.Tree
|
||||
// Select previous parent child
|
||||
var select = nodeParent.GetChild(myIndex - 1) as TreeNode;
|
||||
|
||||
// Select last child if is valid and expanded and has any children
|
||||
if (select != null && select.IsExpanded && select.HasAnyVisibleChild)
|
||||
// Get bottom most child node
|
||||
while (select != null && select.IsExpanded && select.HasAnyVisibleChild)
|
||||
{
|
||||
select = select.GetChild(select.ChildrenCount - 1) as TreeNode;
|
||||
}
|
||||
|
||||
@@ -714,6 +714,7 @@ namespace FlaxEditor.Modules
|
||||
_menuToolsBuildCSGMesh = cm.AddButton("Build CSG mesh", inputOptions.BuildCSG, Editor.BuildCSG);
|
||||
_menuToolsBuildNavMesh = cm.AddButton("Build Nav Mesh", inputOptions.BuildNav, Editor.BuildNavMesh);
|
||||
_menuToolsBuildAllMeshesSDF = cm.AddButton("Build all meshes SDF", inputOptions.BuildSDF, Editor.BuildAllMeshesSDF);
|
||||
_menuToolsBuildAllMeshesSDF.LinkTooltip("Generates Sign Distance Field texture for all meshes used in loaded scenes. Use with 'F' key pressed to force rebuild SDF for meshes with existing one.");
|
||||
cm.AddSeparator();
|
||||
cm.AddButton("Game Cooker", Editor.Windows.GameCookerWin.FocusOrShow);
|
||||
_menuToolsCancelBuilding = cm.AddButton("Cancel building game", () => GameCooker.Cancel());
|
||||
|
||||
@@ -896,9 +896,11 @@ namespace FlaxEditor.Modules
|
||||
|
||||
if (type.IsAssignableTo(typeof(AssetEditorWindow)))
|
||||
{
|
||||
var ctor = type.GetConstructor(new Type[] { typeof(Editor), typeof(AssetItem) });
|
||||
var assetItem = Editor.ContentDatabase.FindAsset(winData.AssetItemID);
|
||||
var assetType = assetItem.GetType();
|
||||
var ctor = type.GetConstructor(new Type[] { typeof(Editor), assetType });
|
||||
var win = (AssetEditorWindow)ctor.Invoke(new object[] { Editor.Instance, assetItem });
|
||||
|
||||
win.Show(winData.DockState, winData.DockState != DockState.Float ? winData.DockedTo : null, winData.SelectOnShow, winData.SplitterValue);
|
||||
if (winData.DockState == DockState.Float)
|
||||
{
|
||||
|
||||
@@ -406,6 +406,8 @@ namespace FlaxEngine.Utilities
|
||||
{
|
||||
if (type == ScriptType.Null)
|
||||
return null;
|
||||
if (type.BaseType == null)
|
||||
return type.Type;
|
||||
while (type.Type == null)
|
||||
type = type.BaseType;
|
||||
return type.Type;
|
||||
|
||||
@@ -726,7 +726,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
|
||||
private void OnSurfaceMouseUp(ref Float2 mouse, MouseButton buttons, ref bool handled)
|
||||
{
|
||||
if (handled)
|
||||
if (handled || Surface.Context != Context)
|
||||
return;
|
||||
|
||||
// Check click over the connection
|
||||
@@ -751,7 +751,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
|
||||
private void OnSurfaceMouseDoubleClick(ref Float2 mouse, MouseButton buttons, ref bool handled)
|
||||
{
|
||||
if (handled)
|
||||
if (handled || Surface.Context != Context)
|
||||
return;
|
||||
|
||||
// Check double click over the connection
|
||||
|
||||
@@ -2,11 +2,8 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using FlaxEditor.CustomEditors;
|
||||
using FlaxEditor.CustomEditors.Editors;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
@@ -18,6 +15,7 @@ namespace FlaxEditor.Surface
|
||||
class AttributesEditor : ContextMenuBase
|
||||
{
|
||||
private CustomEditorPresenter _presenter;
|
||||
private Proxy _proxy;
|
||||
private byte[] _oldData;
|
||||
|
||||
private class Proxy
|
||||
@@ -72,11 +70,11 @@ namespace FlaxEditor.Surface
|
||||
/// Initializes a new instance of the <see cref="AttributesEditor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="attributes">The attributes list to edit.</param>
|
||||
/// <param name="attributeType">The allowed attribute types to use.</param>
|
||||
public AttributesEditor(Attribute[] attributes, IList<Type> attributeType)
|
||||
/// <param name="attributeTypes">The allowed attribute types to use.</param>
|
||||
public AttributesEditor(Attribute[] attributes, IList<Type> attributeTypes)
|
||||
{
|
||||
// Context menu dimensions
|
||||
const float width = 340.0f;
|
||||
const float width = 375.0f;
|
||||
const float height = 370.0f;
|
||||
Size = new Float2(width, height);
|
||||
|
||||
@@ -88,61 +86,68 @@ namespace FlaxEditor.Surface
|
||||
Parent = this
|
||||
};
|
||||
|
||||
// Buttons
|
||||
float buttonsWidth = (width - 16.0f) * 0.5f;
|
||||
// Ok and Cancel Buttons
|
||||
float buttonsWidth = (width - 12.0f) * 0.5f;
|
||||
float buttonsHeight = 20.0f;
|
||||
var cancelButton = new Button(4.0f, title.Bottom + 4.0f, buttonsWidth, buttonsHeight)
|
||||
var okButton = new Button(4.0f, Bottom - 4.0f - buttonsHeight, buttonsWidth, buttonsHeight)
|
||||
{
|
||||
Text = "Ok",
|
||||
Parent = this
|
||||
};
|
||||
okButton.Clicked += OnOkButtonClicked;
|
||||
var cancelButton = new Button(okButton.Right + 4.0f, okButton.Y, buttonsWidth, buttonsHeight)
|
||||
{
|
||||
Text = "Cancel",
|
||||
Parent = this
|
||||
};
|
||||
cancelButton.Clicked += Hide;
|
||||
var okButton = new Button(cancelButton.Right + 4.0f, cancelButton.Y, buttonsWidth, buttonsHeight)
|
||||
{
|
||||
Text = "OK",
|
||||
Parent = this
|
||||
};
|
||||
okButton.Clicked += OnOkButtonClicked;
|
||||
|
||||
// Actual panel
|
||||
// Actual panel used to display attributes
|
||||
var panel1 = new Panel(ScrollBars.Vertical)
|
||||
{
|
||||
Bounds = new Rectangle(0, okButton.Bottom + 4.0f, width, height - okButton.Bottom - 2.0f),
|
||||
Bounds = new Rectangle(0, title.Bottom + 4.0f, width, height - buttonsHeight - title.Height - 14.0f),
|
||||
Parent = this
|
||||
};
|
||||
var editor = new CustomEditorPresenter(null);
|
||||
editor.Panel.AnchorPreset = AnchorPresets.HorizontalStretchTop;
|
||||
editor.Panel.IsScrollable = true;
|
||||
editor.Panel.Parent = panel1;
|
||||
editor.Panel.Tag = attributeType;
|
||||
editor.Panel.Tag = attributeTypes;
|
||||
_presenter = editor;
|
||||
|
||||
// Cache 'previous' state to check if attributes were edited after operation
|
||||
_oldData = SurfaceMeta.GetAttributesData(attributes);
|
||||
|
||||
editor.Select(new Proxy
|
||||
_proxy = new Proxy
|
||||
{
|
||||
Value = attributes,
|
||||
});
|
||||
};
|
||||
editor.Select(_proxy);
|
||||
|
||||
_presenter.Modified += OnPresenterModified;
|
||||
OnPresenterModified();
|
||||
}
|
||||
|
||||
private void OnPresenterModified()
|
||||
{
|
||||
if (_proxy.Value.Length == 0)
|
||||
{
|
||||
var label = _presenter.Label("No attributes.\nPress the \"+\" button to add a new one and then select an attribute type using the \"Type\" dropdown.", TextAlignment.Center);
|
||||
label.Label.Wrapping = TextWrapping.WrapWords;
|
||||
label.Control.Height = 35f;
|
||||
label.Label.Margin = new Margin(10f);
|
||||
label.Label.TextColor = label.Label.TextColorHighlighted = Style.Current.ForegroundGrey;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnOkButtonClicked()
|
||||
{
|
||||
var newValue = ((Proxy)_presenter.Selection[0]).Value;
|
||||
for (int i = 0; i < newValue.Length; i++)
|
||||
{
|
||||
if (newValue[i] == null)
|
||||
{
|
||||
MessageBox.Show("One of the attributes is null. Please set it to the valid object.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
newValue = newValue.Where(v => v != null).ToArray();
|
||||
|
||||
var newData = SurfaceMeta.GetAttributesData(newValue);
|
||||
if (!_oldData.SequenceEqual(newData))
|
||||
{
|
||||
Edited?.Invoke(newValue);
|
||||
}
|
||||
|
||||
Hide();
|
||||
}
|
||||
@@ -183,7 +188,9 @@ namespace FlaxEditor.Surface
|
||||
{
|
||||
_presenter = null;
|
||||
_oldData = null;
|
||||
_proxy = null;
|
||||
Edited = null;
|
||||
_presenter.Modified -= OnPresenterModified;
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
@@ -412,7 +412,7 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
{
|
||||
group.UnlockChildrenRecursive();
|
||||
// TODO: Improve filtering to be based on boxes with the most common things instead of first box
|
||||
if (_contextSensitiveSearchEnabled && _selectedBoxes[0] != null)
|
||||
if (_contextSensitiveSearchEnabled && _selectedBoxes.Count > 0 && _selectedBoxes[0] != null)
|
||||
UpdateFilters();
|
||||
else
|
||||
SortGroups();
|
||||
@@ -424,7 +424,7 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
OnSearchFilterChanged();
|
||||
}
|
||||
}
|
||||
else if (_contextSensitiveSearchEnabled)
|
||||
else if (_contextSensitiveSearchEnabled && _selectedBoxes.Count > 0)
|
||||
{
|
||||
// TODO: Filtering could be improved here as well
|
||||
group.EvaluateVisibilityWithBox(_selectedBoxes[0]);
|
||||
@@ -462,7 +462,7 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
Parent = group
|
||||
};
|
||||
}
|
||||
if (_contextSensitiveSearchEnabled)
|
||||
if (_contextSensitiveSearchEnabled && _selectedBoxes.Count > 0)
|
||||
group.EvaluateVisibilityWithBox(_selectedBoxes[0]);
|
||||
group.SortChildren();
|
||||
if (ShowExpanded)
|
||||
@@ -476,7 +476,7 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
|
||||
if (!isLayoutLocked)
|
||||
{
|
||||
if (_contextSensitiveSearchEnabled && _selectedBoxes[0] != null)
|
||||
if (_contextSensitiveSearchEnabled && _selectedBoxes.Count != 0 && _selectedBoxes[0] != null)
|
||||
UpdateFilters();
|
||||
else
|
||||
SortGroups();
|
||||
|
||||
@@ -214,22 +214,25 @@ namespace FlaxEditor.Surface
|
||||
if (!_isRenaming)
|
||||
Render2D.DrawText(style.FontLarge, Title, _headerRect, style.Foreground, TextAlignment.Center, TextAlignment.Center);
|
||||
|
||||
// Close button
|
||||
Render2D.DrawSprite(style.Cross, _closeButtonRect, _closeButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey);
|
||||
|
||||
// Color button
|
||||
Render2D.DrawSprite(style.Settings, _colorButtonRect, _colorButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey);
|
||||
|
||||
// Check if is resizing
|
||||
if (_isResizing)
|
||||
if (Surface.CanEdit)
|
||||
{
|
||||
// Draw overlay
|
||||
Render2D.FillRectangle(_resizeButtonRect, style.Selection);
|
||||
Render2D.DrawRectangle(_resizeButtonRect, style.SelectionBorder);
|
||||
}
|
||||
// Close button
|
||||
Render2D.DrawSprite(style.Cross, _closeButtonRect, _closeButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey);
|
||||
|
||||
// Resize button
|
||||
Render2D.DrawSprite(style.Scale, _resizeButtonRect, _resizeButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey);
|
||||
// Color button
|
||||
Render2D.DrawSprite(style.Settings, _colorButtonRect, _colorButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey);
|
||||
|
||||
// Check if is resizing
|
||||
if (_isResizing)
|
||||
{
|
||||
// Draw overlay
|
||||
Render2D.FillRectangle(_resizeButtonRect, style.Selection);
|
||||
Render2D.DrawRectangle(_resizeButtonRect, style.SelectionBorder);
|
||||
}
|
||||
|
||||
// Resize button
|
||||
Render2D.DrawSprite(style.Scale, _resizeButtonRect, _resizeButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey);
|
||||
}
|
||||
|
||||
// Selection outline
|
||||
if (_isSelected)
|
||||
|
||||
@@ -431,27 +431,6 @@ namespace FlaxEditor.Surface
|
||||
/// </summary>
|
||||
public bool HasIndependentBoxes => Archetype.IndependentBoxes != null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this node has dependent boxes with assigned valid types. Otherwise any box has no dependent type assigned.
|
||||
/// </summary>
|
||||
public bool HasDependentBoxesSetup
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Archetype.DependentBoxes == null || Archetype.IndependentBoxes == null)
|
||||
return true;
|
||||
|
||||
for (int i = 0; i < Archetype.DependentBoxes.Length; i++)
|
||||
{
|
||||
var b = GetBox(Archetype.DependentBoxes[i]);
|
||||
if (b != null && b.CurrentType == b.DefaultType)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly List<SurfaceNode> UpdateStack = new List<SurfaceNode>();
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -400,7 +400,7 @@ namespace FlaxEditor.Surface
|
||||
return scriptType.GetGenericTypeDefinition() == typeof(Dictionary<,>);
|
||||
}
|
||||
var managedType = TypeUtils.GetType(scriptType);
|
||||
return !TypeUtils.IsDelegate(managedType);
|
||||
return managedType != null && !TypeUtils.IsDelegate(managedType);
|
||||
}
|
||||
|
||||
internal static bool IsValidVisualScriptFunctionType(ScriptType scriptType)
|
||||
@@ -408,7 +408,7 @@ namespace FlaxEditor.Surface
|
||||
if (scriptType.IsGenericType || scriptType.IsStatic || !scriptType.IsPublic || scriptType.HasAttribute(typeof(HideInEditorAttribute), true))
|
||||
return false;
|
||||
var managedType = TypeUtils.GetType(scriptType);
|
||||
return !TypeUtils.IsDelegate(managedType);
|
||||
return managedType != null && !TypeUtils.IsDelegate(managedType);
|
||||
}
|
||||
|
||||
internal static string GetVisualScriptTypeDescription(ScriptType type)
|
||||
|
||||
@@ -469,7 +469,8 @@ namespace FlaxEditor.Surface
|
||||
bool handled = base.OnMouseDown(location, button);
|
||||
if (!handled)
|
||||
CustomMouseDown?.Invoke(ref location, button, ref handled);
|
||||
if (handled)
|
||||
var root = Root;
|
||||
if (handled || root == null)
|
||||
{
|
||||
// Clear flags
|
||||
_isMovingSelection = false;
|
||||
@@ -523,11 +524,11 @@ namespace FlaxEditor.Surface
|
||||
if (_leftMouseDown && controlUnderMouse.CanSelect(ref cLocation))
|
||||
{
|
||||
// Check if user is pressing control
|
||||
if (Root.GetKey(KeyboardKeys.Control))
|
||||
if (root.GetKey(KeyboardKeys.Control))
|
||||
{
|
||||
AddToSelection(controlUnderMouse);
|
||||
}
|
||||
else if (Root.GetKey(KeyboardKeys.Shift))
|
||||
else if (root.GetKey(KeyboardKeys.Shift))
|
||||
{
|
||||
RemoveFromSelection(controlUnderMouse);
|
||||
}
|
||||
@@ -539,7 +540,7 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
|
||||
// Start moving selected nodes
|
||||
if (!Root.GetKey(KeyboardKeys.Shift))
|
||||
if (!root.GetKey(KeyboardKeys.Shift))
|
||||
{
|
||||
StartMouseCapture();
|
||||
_movingSelectionViewPos = _rootControl.Location;
|
||||
@@ -559,7 +560,7 @@ namespace FlaxEditor.Surface
|
||||
// Start selecting or commenting
|
||||
StartMouseCapture();
|
||||
|
||||
if (!Root.GetKey(KeyboardKeys.Control) && !Root.GetKey(KeyboardKeys.Shift))
|
||||
if (!root.GetKey(KeyboardKeys.Control) && !root.GetKey(KeyboardKeys.Shift))
|
||||
{
|
||||
ClearSelection();
|
||||
}
|
||||
|
||||
@@ -178,19 +178,31 @@ namespace FlaxEditor.Surface
|
||||
|
||||
// Update boxes types for nodes that dependant box types based on incoming connections
|
||||
{
|
||||
bool keepUpdating = false;
|
||||
int updateLimit = 100;
|
||||
bool keepUpdating = true;
|
||||
int updatesMin = 2, updatesMax = 100;
|
||||
do
|
||||
{
|
||||
keepUpdating = false;
|
||||
for (int i = 0; i < RootControl.Children.Count; i++)
|
||||
{
|
||||
if (RootControl.Children[i] is SurfaceNode node && !node.HasDependentBoxesSetup)
|
||||
if (RootControl.Children[i] is SurfaceNode node)
|
||||
{
|
||||
node.UpdateBoxesTypes();
|
||||
keepUpdating = true;
|
||||
var arch = node.Archetype;
|
||||
if (arch.DependentBoxes != null && arch.IndependentBoxes != null)
|
||||
{
|
||||
foreach (var boxId in arch.DependentBoxes)
|
||||
{
|
||||
var b = node.GetBox(boxId);
|
||||
if (b != null && b.CurrentType == b.DefaultType)
|
||||
{
|
||||
keepUpdating = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (keepUpdating && updateLimit-- > 0);
|
||||
} while ((keepUpdating && --updatesMax > 0) || --updatesMin > 0);
|
||||
}
|
||||
|
||||
Loaded?.Invoke(this);
|
||||
|
||||
@@ -74,11 +74,6 @@ struct TextureDataResult
|
||||
PixelFormat Format;
|
||||
Int2 Mip0Size;
|
||||
BytesContainer* Mip0DataPtr;
|
||||
|
||||
TextureDataResult()
|
||||
: Lock(FlaxStorage::LockData::Invalid)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
bool GetTextureDataForSampling(Texture* texture, TextureDataResult& data, bool hdr = false)
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace FlaxEditor.Viewport
|
||||
private PrefabUIEditorRoot _uiRoot;
|
||||
private bool _showUI = false;
|
||||
|
||||
private int _defaultScaleActiveIndex = 0;
|
||||
private int _defaultScaleActiveIndex = -1;
|
||||
private int _customScaleActiveIndex = -1;
|
||||
private ContextMenuButton _uiModeButton;
|
||||
private ContextMenuChildMenu _uiViewOptions;
|
||||
@@ -257,16 +257,23 @@ namespace FlaxEditor.Viewport
|
||||
/// </summary>
|
||||
public void SaveActiveUIScalingOption()
|
||||
{
|
||||
var defaultKey = $"{Prefab.ID}:DefaultViewportScalingIndex";
|
||||
if (!Prefab)
|
||||
return;
|
||||
var id = Prefab.ID;
|
||||
var defaultKey = $"{id}:DefaultViewportScalingIndex";
|
||||
Editor.Instance.ProjectCache.SetCustomData(defaultKey, _defaultScaleActiveIndex.ToString());
|
||||
var customKey = $"{Prefab.ID}:CustomViewportScalingIndex";
|
||||
var customKey = $"{id}:CustomViewportScalingIndex";
|
||||
Editor.Instance.ProjectCache.SetCustomData(customKey, _customScaleActiveIndex.ToString());
|
||||
}
|
||||
|
||||
private void LoadCustomUIScalingOption()
|
||||
{
|
||||
if (!Prefab)
|
||||
return;
|
||||
var id = Prefab.ID;
|
||||
Prefab.WaitForLoaded();
|
||||
var defaultKey = $"{Prefab.ID}:DefaultViewportScalingIndex";
|
||||
|
||||
var defaultKey = $"{id}:DefaultViewportScalingIndex";
|
||||
if (Editor.Instance.ProjectCache.TryGetCustomData(defaultKey, out string defaultData))
|
||||
{
|
||||
if (int.TryParse(defaultData, out var index))
|
||||
@@ -286,7 +293,7 @@ namespace FlaxEditor.Viewport
|
||||
}
|
||||
}
|
||||
|
||||
var customKey = $"{Prefab.ID}:CustomViewportScalingIndex";
|
||||
var customKey = $"{id}:CustomViewportScalingIndex";
|
||||
if (Editor.Instance.ProjectCache.TryGetCustomData(customKey, out string data))
|
||||
{
|
||||
if (int.TryParse(data, out var index))
|
||||
|
||||
@@ -140,7 +140,7 @@ namespace FlaxEditor.Windows
|
||||
}
|
||||
|
||||
private string _cacheFolder;
|
||||
private Guid _assetId;
|
||||
private AssetItem _item;
|
||||
private Surface _surface;
|
||||
private Label _loadingLabel;
|
||||
private CancellationTokenSource _token;
|
||||
@@ -163,13 +163,13 @@ namespace FlaxEditor.Windows
|
||||
public AssetReferencesGraphWindow(Editor editor, AssetItem assetItem)
|
||||
: base(editor, false, ScrollBars.None)
|
||||
{
|
||||
Title = assetItem.ShortName + " References";
|
||||
_item = assetItem;
|
||||
Title = _item.ShortName + " References";
|
||||
|
||||
_tempFolder = StringUtils.NormalizePath(Path.GetDirectoryName(Globals.TemporaryFolder));
|
||||
_cacheFolder = Path.Combine(Globals.ProjectCacheFolder, "References");
|
||||
if (!Directory.Exists(_cacheFolder))
|
||||
Directory.CreateDirectory(_cacheFolder);
|
||||
_assetId = assetItem.ID;
|
||||
_surface = new Surface(this)
|
||||
{
|
||||
AnchorPreset = AnchorPresets.StretchAll,
|
||||
@@ -194,6 +194,7 @@ namespace FlaxEditor.Windows
|
||||
_nodesAssets.Add(assetId);
|
||||
var node = new AssetNode((uint)_nodes.Count + 1, _surface.Context, GraphNodes[0], GraphGroups[0], assetId);
|
||||
_nodes.Add(node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -392,8 +393,7 @@ namespace FlaxEditor.Windows
|
||||
_nodesAssets = new HashSet<Guid>();
|
||||
var searchLevel = 4; // TODO: make it as an option (somewhere in window UI)
|
||||
// TODO: add option to filter assets by type (eg. show only textures as leaf nodes)
|
||||
var assetNode = SpawnNode(_assetId);
|
||||
// TODO: add some outline or tint color to the main node
|
||||
var assetNode = SpawnNode(_item.ID);
|
||||
BuildGraph(assetNode, searchLevel, false);
|
||||
ArrangeGraph(assetNode, false);
|
||||
BuildGraph(assetNode, searchLevel, true);
|
||||
@@ -402,6 +402,10 @@ namespace FlaxEditor.Windows
|
||||
return;
|
||||
_progress = 100.0f;
|
||||
|
||||
var commentRect = assetNode.EditorBounds;
|
||||
commentRect.Expand(80f);
|
||||
_surface.Context.CreateComment(ref commentRect, _item.ShortName, Color.Green);
|
||||
|
||||
// Update UI
|
||||
FlaxEngine.Scripting.InvokeOnUpdate(() =>
|
||||
{
|
||||
|
||||
@@ -14,7 +14,6 @@ using FlaxEditor.Surface;
|
||||
using FlaxEditor.Viewport.Previews;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
@@ -430,7 +429,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var p = parameters[i];
|
||||
if (p.IsOverride)
|
||||
if (p.IsOverride && p.IsPublic)
|
||||
{
|
||||
p.IsOverride = false;
|
||||
actions.Add(new EditParamOverrideAction
|
||||
|
||||
@@ -90,25 +90,15 @@ namespace FlaxEditor.Windows.Assets
|
||||
|
||||
var gpu = group.Checkbox("Bake on GPU", "If checked, SDF generation will be calculated using GPU on Compute Shader, otherwise CPU will use Job System. GPU generation is fast but result in artifacts in various meshes (eg. foliage).");
|
||||
gpu.CheckBox.Checked = sdfOptions.GPU;
|
||||
gpu.CheckBox.StateChanged += c => { Window._sdfOptions.GPU = c.Checked; };
|
||||
|
||||
var backfacesThresholdProp = group.AddPropertyItem("Backfaces Threshold", "Custom threshold (in range 0-1) for adjusting mesh internals detection based on the percentage of test rays hit triangle backfaces. Use lower value for more dense mesh.");
|
||||
var backfacesThreshold = backfacesThresholdProp.FloatValue();
|
||||
var backfacesThresholdLabel = backfacesThresholdProp.Labels.Last();
|
||||
backfacesThreshold.ValueBox.MinValue = 0.001f;
|
||||
backfacesThreshold.ValueBox.MaxValue = 1.0f;
|
||||
backfacesThreshold.ValueBox.Value = sdfOptions.BackfacesThreshold;
|
||||
backfacesThreshold.ValueBox.BoxValueChanged += b => { Window._sdfOptions.BackfacesThreshold = b.Value; };
|
||||
|
||||
// Toggle Backfaces Threshold visibility (CPU-only option)
|
||||
gpu.CheckBox.StateChanged += c =>
|
||||
{
|
||||
Window._sdfOptions.GPU = c.Checked;
|
||||
backfacesThresholdLabel.Visible = !c.Checked;
|
||||
backfacesThreshold.ValueBox.Visible = !c.Checked;
|
||||
};
|
||||
backfacesThresholdLabel.Visible = !gpu.CheckBox.Checked;
|
||||
backfacesThreshold.ValueBox.Visible = !gpu.CheckBox.Checked;
|
||||
|
||||
var lodIndex = group.IntegerValue("LOD Index", "Index of the model Level of Detail to use for SDF data building. By default uses the lowest quality LOD for fast building.");
|
||||
lodIndex.IntValue.MinValue = 0;
|
||||
lodIndex.IntValue.MaxValue = Asset.LODsCount - 1;
|
||||
|
||||
@@ -142,6 +142,7 @@ namespace FlaxEditor.Windows
|
||||
{
|
||||
Title = "Content";
|
||||
Icon = editor.Icons.Folder32;
|
||||
var style = Style.Current;
|
||||
|
||||
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
|
||||
|
||||
@@ -164,6 +165,8 @@ namespace FlaxEditor.Windows
|
||||
_navigationBar = new NavigationBar
|
||||
{
|
||||
Parent = _toolStrip,
|
||||
ScrollbarTrackColor = style.Background,
|
||||
ScrollbarThumbColor = style.ForegroundGrey,
|
||||
};
|
||||
|
||||
// Split panel
|
||||
@@ -179,7 +182,7 @@ namespace FlaxEditor.Windows
|
||||
var headerPanel = new ContainerControl
|
||||
{
|
||||
AnchorPreset = AnchorPresets.HorizontalStretchTop,
|
||||
BackgroundColor = Style.Current.Background,
|
||||
BackgroundColor = style.Background,
|
||||
IsScrollable = false,
|
||||
Offsets = new Margin(0, 0, 0, 18 + 6),
|
||||
};
|
||||
|
||||
@@ -10,17 +10,117 @@ using FlaxEditor.Modules;
|
||||
using FlaxEditor.Options;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Json;
|
||||
|
||||
namespace FlaxEditor.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Render output control with content scaling support.
|
||||
/// </summary>
|
||||
public class ScaledRenderOutputControl : RenderOutputControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom scale.
|
||||
/// </summary>
|
||||
public float ContentScale = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Actual bounds size for content (incl. scale).
|
||||
/// </summary>
|
||||
public Float2 ContentSize => Size / ContentScale;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScaledRenderOutputControl(SceneRenderTask task)
|
||||
: base(task)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
DrawSelf();
|
||||
|
||||
// Draw children with scale
|
||||
var scaling = new Float3(ContentScale, ContentScale, 1);
|
||||
Matrix3x3.Scaling(ref scaling, out Matrix3x3 scale);
|
||||
Render2D.PushTransform(scale);
|
||||
if (ClipChildren)
|
||||
{
|
||||
GetDesireClientArea(out var clientArea);
|
||||
Render2D.PushClip(ref clientArea);
|
||||
DrawChildren();
|
||||
Render2D.PopClip();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawChildren();
|
||||
}
|
||||
|
||||
Render2D.PopTransform();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void GetDesireClientArea(out Rectangle rect)
|
||||
{
|
||||
// Scale the area for the client controls
|
||||
rect = new Rectangle(Float2.Zero, Size / ContentScale);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IntersectsContent(ref Float2 locationParent, out Float2 location)
|
||||
{
|
||||
// Skip local PointFromParent but use base code
|
||||
location = base.PointFromParent(ref locationParent);
|
||||
return ContainsPoint(ref location);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IntersectsChildContent(Control child, Float2 location, out Float2 childSpaceLocation)
|
||||
{
|
||||
location /= ContentScale;
|
||||
return base.IntersectsChildContent(child, location, out childSpaceLocation);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool ContainsPoint(ref Float2 location, bool precise = false)
|
||||
{
|
||||
if (precise) // Ignore as utility-only element
|
||||
return false;
|
||||
return base.ContainsPoint(ref location, precise);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool RayCast(ref Float2 location, out Control hit)
|
||||
{
|
||||
var p = location / ContentScale;
|
||||
if (RayCastChildren(ref p, out hit))
|
||||
return true;
|
||||
return base.RayCast(ref location, out hit);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Float2 PointToParent(ref Float2 location)
|
||||
{
|
||||
var result = base.PointToParent(ref location);
|
||||
result *= ContentScale;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Float2 PointFromParent(ref Float2 location)
|
||||
{
|
||||
var result = base.PointFromParent(ref location);
|
||||
result /= ContentScale;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides in-editor play mode simulation.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Windows.EditorWindow" />
|
||||
public class GameWindow : EditorWindow
|
||||
{
|
||||
private readonly RenderOutputControl _viewport;
|
||||
private readonly ScaledRenderOutputControl _viewport;
|
||||
private readonly GameRoot _guiRoot;
|
||||
private bool _showGUI = true, _editGUI = true;
|
||||
private bool _showDebugDraw = false;
|
||||
@@ -77,7 +177,7 @@ namespace FlaxEditor.Windows
|
||||
/// <summary>
|
||||
/// Gets the viewport.
|
||||
/// </summary>
|
||||
public RenderOutputControl Viewport => _viewport;
|
||||
public ScaledRenderOutputControl Viewport => _viewport;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether show game GUI in the view or keep it hidden.
|
||||
@@ -295,7 +395,7 @@ namespace FlaxEditor.Windows
|
||||
var task = MainRenderTask.Instance;
|
||||
|
||||
// Setup viewport
|
||||
_viewport = new RenderOutputControl(task)
|
||||
_viewport = new ScaledRenderOutputControl(task)
|
||||
{
|
||||
AnchorPreset = AnchorPresets.StretchAll,
|
||||
Offsets = Margin.Zero,
|
||||
@@ -396,11 +496,8 @@ namespace FlaxEditor.Windows
|
||||
{
|
||||
if (v == null)
|
||||
return;
|
||||
|
||||
if (v.Size.Y <= 0 || v.Size.X <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(v.Label, "Free Aspect", StringComparison.Ordinal) && v.Size == new Int2(1, 1))
|
||||
{
|
||||
@@ -448,15 +545,7 @@ namespace FlaxEditor.Windows
|
||||
|
||||
private void ResizeViewport()
|
||||
{
|
||||
if (!_freeAspect)
|
||||
{
|
||||
_windowAspectRatio = Width / Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
_windowAspectRatio = 1;
|
||||
}
|
||||
|
||||
_windowAspectRatio = _freeAspect ? 1 : Width / Height;
|
||||
var scaleWidth = _viewportAspectRatio / _windowAspectRatio;
|
||||
var scaleHeight = _windowAspectRatio / _viewportAspectRatio;
|
||||
|
||||
@@ -468,6 +557,24 @@ namespace FlaxEditor.Windows
|
||||
{
|
||||
_viewport.Bounds = new Rectangle(Width * (1 - scaleWidth) / 2, 0, Width * scaleWidth, Height);
|
||||
}
|
||||
|
||||
if (_viewport.KeepAspectRatio)
|
||||
{
|
||||
var resolution = _viewport.CustomResolution.HasValue ? (Float2)_viewport.CustomResolution.Value : Size;
|
||||
if (scaleHeight < 1)
|
||||
{
|
||||
_viewport.ContentScale = _viewport.Width / resolution.X;
|
||||
}
|
||||
else
|
||||
{
|
||||
_viewport.ContentScale = _viewport.Height / resolution.Y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_viewport.ContentScale = 1;
|
||||
}
|
||||
|
||||
_viewport.SyncBackbufferSize();
|
||||
PerformLayout();
|
||||
}
|
||||
@@ -885,12 +992,12 @@ namespace FlaxEditor.Windows
|
||||
// Restore cursor visibility (could be hidden by the game)
|
||||
if (!_cursorVisible)
|
||||
Screen.CursorVisible = true;
|
||||
}
|
||||
|
||||
if (Editor.IsPlayMode && IsDocked && IsSelected && RootWindow.FocusedControl == null)
|
||||
{
|
||||
// Game UI cleared focus so regain it to maintain UI navigation just like game window does
|
||||
FlaxEngine.Scripting.InvokeOnUpdate(Focus);
|
||||
if (Editor.IsPlayMode && IsDocked && IsSelected && RootWindow.FocusedControl == null)
|
||||
{
|
||||
// Game UI cleared focus so regain it to maintain UI navigation just like game window does
|
||||
FlaxEngine.Scripting.InvokeOnUpdate(Focus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -907,6 +1014,7 @@ namespace FlaxEditor.Windows
|
||||
return child.OnNavigate(direction, Float2.Zero, this, visited);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -957,7 +1065,7 @@ namespace FlaxEditor.Windows
|
||||
else
|
||||
_defaultScaleActiveIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
if (_customScaleActiveIndex != -1)
|
||||
{
|
||||
var options = Editor.UI.CustomViewportScaleOptions;
|
||||
|
||||
@@ -296,13 +296,15 @@ namespace FlaxEditor.Windows.Profiler
|
||||
var resources = _resources.Get(_memoryUsageChart.SelectedSampleIndex);
|
||||
if (resources == null || resources.Length == 0)
|
||||
return;
|
||||
var resourcesOrdered = resources.OrderByDescending(x => x.MemoryUsage);
|
||||
var resourcesOrdered = resources.OrderByDescending(x => x?.MemoryUsage ?? 0);
|
||||
|
||||
// Add rows
|
||||
var rowColor2 = Style.Current.Background * 1.4f;
|
||||
int rowIndex = 0;
|
||||
foreach (var e in resourcesOrdered)
|
||||
{
|
||||
if (e == null)
|
||||
continue;
|
||||
ClickableRow row;
|
||||
if (_tableRowsCache.Count != 0)
|
||||
{
|
||||
|
||||
@@ -319,22 +319,22 @@ namespace FlaxEditor.Windows
|
||||
{
|
||||
if (assetItem.IsOfType<SceneAsset>())
|
||||
return true;
|
||||
return assetItem.OnEditorDrag(this);
|
||||
return assetItem.OnEditorDrag(this) && Level.IsAnySceneLoaded;
|
||||
}
|
||||
|
||||
private static bool ValidateDragActorType(ScriptType actorType)
|
||||
{
|
||||
return Editor.Instance.CodeEditing.Actors.Get().Contains(actorType);
|
||||
return Editor.Instance.CodeEditing.Actors.Get().Contains(actorType) && Level.IsAnySceneLoaded;
|
||||
}
|
||||
|
||||
private static bool ValidateDragControlType(ScriptType controlType)
|
||||
{
|
||||
return Editor.Instance.CodeEditing.Controls.Get().Contains(controlType);
|
||||
return Editor.Instance.CodeEditing.Controls.Get().Contains(controlType) && Level.IsAnySceneLoaded;
|
||||
}
|
||||
|
||||
private static bool ValidateDragScriptItem(ScriptItem script)
|
||||
{
|
||||
return Editor.Instance.CodeEditing.Actors.Get(script) != ScriptType.Null;
|
||||
return Editor.Instance.CodeEditing.Actors.Get(script) != ScriptType.Null && Level.IsAnySceneLoaded;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -490,6 +490,7 @@ namespace FlaxEditor.Windows
|
||||
if (result == DragDropEffect.None)
|
||||
{
|
||||
_isDropping = true;
|
||||
|
||||
// Drag assets
|
||||
if (_dragAssets != null && _dragAssets.HasValidDrag)
|
||||
{
|
||||
@@ -504,7 +505,7 @@ namespace FlaxEditor.Windows
|
||||
}
|
||||
var actor = item.OnEditorDrop(this);
|
||||
actor.Name = item.ShortName;
|
||||
Level.SpawnActor(actor);
|
||||
Editor.SceneEditing.Spawn(actor);
|
||||
var graphNode = Editor.Scene.GetActorNode(actor.ID);
|
||||
if (graphNode != null)
|
||||
graphNodes.Add(graphNode);
|
||||
@@ -527,7 +528,7 @@ namespace FlaxEditor.Windows
|
||||
continue;
|
||||
}
|
||||
actor.Name = item.Name;
|
||||
Level.SpawnActor(actor);
|
||||
Editor.SceneEditing.Spawn(actor);
|
||||
Editor.Scene.MarkSceneEdited(actor.Scene);
|
||||
}
|
||||
result = DragDropEffect.Move;
|
||||
@@ -549,7 +550,7 @@ namespace FlaxEditor.Windows
|
||||
Control = control,
|
||||
Name = item.Name,
|
||||
};
|
||||
Level.SpawnActor(uiControl);
|
||||
Editor.SceneEditing.Spawn(uiControl);
|
||||
Editor.Scene.MarkSceneEdited(uiControl.Scene);
|
||||
}
|
||||
result = DragDropEffect.Move;
|
||||
@@ -571,7 +572,7 @@ namespace FlaxEditor.Windows
|
||||
continue;
|
||||
}
|
||||
actor.Name = actorType.Name;
|
||||
Level.SpawnActor(actor);
|
||||
Editor.SceneEditing.Spawn(actor);
|
||||
var graphNode = Editor.Scene.GetActorNode(actor.ID);
|
||||
if (graphNode != null)
|
||||
graphNodes.Add(graphNode);
|
||||
|
||||
@@ -137,6 +137,7 @@ const Char* SplashScreenQuotes[] =
|
||||
TEXT("Good Luck Have Fun"),
|
||||
TEXT("GG Well Played"),
|
||||
TEXT("Now with documentation."),
|
||||
TEXT("We do this not because it is easy,\nbut because we thought it would be easy"),
|
||||
};
|
||||
|
||||
SplashScreen::~SplashScreen()
|
||||
|
||||
@@ -246,11 +246,19 @@ void AnimGraphExecutor::ProcessAnimEvents(AnimGraphNode* node, bool loop, float
|
||||
const float duration = k.Value.Duration > 1 ? k.Value.Duration : 0.0f;
|
||||
#define ADD_OUTGOING_EVENT(type) context.Data->OutgoingEvents.Add({ k.Value.Instance, (AnimatedModel*)context.Data->Object, anim, eventTime, eventDeltaTime, AnimGraphInstanceData::OutgoingEvent::type })
|
||||
if ((k.Time <= eventTimeMax && eventTimeMin <= k.Time + duration
|
||||
&& (Math::FloorToInt(animPos) != 0 && Math::CeilToInt(animPrevPos) != Math::CeilToInt(anim->GetDuration()) && Math::FloorToInt(animPrevPos) != 0 && Math::CeilToInt(animPos) != Math::CeilToInt(anim->GetDuration())))
|
||||
&& (Math::FloorToInt(animPos) != 0 && Math::CeilToInt(animPrevPos) != Math::CeilToInt(anim->GetDuration())
|
||||
&& Math::FloorToInt(animPrevPos) != 0 && Math::CeilToInt(animPos) != Math::CeilToInt(anim->GetDuration())))
|
||||
// Handle the edge case of an event on 0 or on max animation duration during looping
|
||||
|| (loop && duration == 0.0f && Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) && k.Time == anim->GetDuration())
|
||||
|| (!loop && duration == 0.0f && Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) && Math::CeilToInt(animPrevPos) == Math::CeilToInt(anim->GetDuration()) - 1 && Math::NearEqual(k.Time, anim->GetDuration()))
|
||||
|| (loop && Math::FloorToInt(animPos) == 0 && Math::CeilToInt(animPrevPos) == Math::CeilToInt(anim->GetDuration()) && k.Time == 0.0f)
|
||||
|| (loop && Math::FloorToInt(animPrevPos) == 0 && Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) && k.Time == 0.0f)
|
||||
|| (loop && Math::FloorToInt(animPos) == 0 && Math::CeilToInt(animPrevPos) == Math::CeilToInt(anim->GetDuration()) && Math::NearEqual(k.Time, anim->GetDuration()))
|
||||
|| (loop && Math::FloorToInt(animPrevPos) == 0 && Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) && Math::NearEqual(k.Time, anim->GetDuration()))
|
||||
|| (Math::FloorToInt(animPos) == 1 && Math::FloorToInt(animPrevPos) == 0 && k.Time == 1.0f)
|
||||
|| (Math::FloorToInt(animPos) == 0 && Math::FloorToInt(animPrevPos) == 1 && k.Time == 1.0f)
|
||||
|| (Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) && Math::CeilToInt(animPrevPos) == Math::CeilToInt(anim->GetDuration()) - 1 && Math::NearEqual(k.Time, anim->GetDuration() - 1.0f))
|
||||
|| (Math::CeilToInt(animPos) == Math::CeilToInt(anim->GetDuration()) - 1 && Math::CeilToInt(animPrevPos) == Math::CeilToInt(anim->GetDuration()) && Math::NearEqual(k.Time, anim->GetDuration() - 1.0f))
|
||||
|| (Math::FloorToInt(animPos) == 0 && Math::FloorToInt(animPrevPos) == 0 && k.Time == 0.0f)
|
||||
)
|
||||
{
|
||||
int32 stateIndex = -1;
|
||||
@@ -2433,10 +2441,14 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
{
|
||||
if (bucket.LoopsLeft == 0)
|
||||
{
|
||||
// End playing animation
|
||||
// End playing animation and reset bucket params
|
||||
value = tryGetValue(node->GetBox(1), Value::Null);
|
||||
bucket.Index = -1;
|
||||
slot.Animation = nullptr;
|
||||
bucket.TimePosition = 0.0f;
|
||||
bucket.BlendInPosition = 0.0f;
|
||||
bucket.BlendOutPosition = 0.0f;
|
||||
bucket.LoopsDone = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2545,9 +2557,15 @@ void AnimGraphExecutor::ProcessGroupFunction(Box* boxBase, Node* node, Value& va
|
||||
// Function Input
|
||||
case 1:
|
||||
{
|
||||
// Skip when graph is too small (eg. preview) and fallback with default value from the function graph
|
||||
if (context.GraphStack.Count() < 2)
|
||||
{
|
||||
value = tryGetValue(node->TryGetBox(1), Value::Zero);
|
||||
break;
|
||||
}
|
||||
|
||||
// Find the function call
|
||||
AnimGraphNode* functionCallNode = nullptr;
|
||||
ASSERT(context.GraphStack.Count() >= 2);
|
||||
Graph* graph;
|
||||
for (int32 i = context.CallStack.Count() - 1; i >= 0; i--)
|
||||
{
|
||||
|
||||
@@ -666,7 +666,7 @@ void Asset::onLoaded()
|
||||
{
|
||||
onLoaded_MainThread();
|
||||
}
|
||||
else if (OnLoaded.IsBinded())
|
||||
else if (OnLoaded.IsBinded() || _references.HasItems())
|
||||
{
|
||||
Function<void()> action;
|
||||
action.Bind<Asset, &Asset::onLoaded>(this);
|
||||
|
||||
@@ -218,10 +218,14 @@ Asset::LoadResult MaterialInstance::load()
|
||||
Guid baseMaterialId;
|
||||
headerStream.Read(baseMaterialId);
|
||||
auto baseMaterial = Content::LoadAsync<MaterialBase>(baseMaterialId);
|
||||
if (baseMaterial)
|
||||
baseMaterial->AddReference();
|
||||
|
||||
// Load parameters
|
||||
if (Params.Load(&headerStream))
|
||||
{
|
||||
if (baseMaterial)
|
||||
baseMaterial->RemoveReference();
|
||||
LOG(Warning, "Cannot load material parameters.");
|
||||
return LoadResult::CannotLoadData;
|
||||
}
|
||||
@@ -239,6 +243,8 @@ Asset::LoadResult MaterialInstance::load()
|
||||
ParamsChanged();
|
||||
}
|
||||
|
||||
if (baseMaterial)
|
||||
baseMaterial->RemoveReference();
|
||||
return LoadResult::Ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -262,6 +262,7 @@ bool Model::GenerateSDF(float resolutionScale, int32 lodIndex, bool cacheData, f
|
||||
LOG(Warning, "Cannot generate SDF for virtual models on a main thread.");
|
||||
return true;
|
||||
}
|
||||
auto chunkLocks = Storage ? Storage->Lock() : FlaxStorage::LockData();
|
||||
lodIndex = Math::Clamp(lodIndex, HighestResidentLODIndex(), LODs.Count() - 1);
|
||||
|
||||
// Generate SDF
|
||||
|
||||
@@ -61,7 +61,7 @@ public:
|
||||
model->GetLODData(_lodIndex, data);
|
||||
if (data.IsInvalid())
|
||||
{
|
||||
LOG(Warning, "Missing data chunk");
|
||||
LOG(Warning, "Missing data chunk with LOD{} for model '{}'", _lodIndex, model->ToString());
|
||||
return true;
|
||||
}
|
||||
MemoryReadStream stream(data.Get(), data.Length());
|
||||
@@ -234,6 +234,7 @@ bool ModelBase::Save(bool withMeshDataFromGpu, const StringView& path)
|
||||
LOG(Error, "To save virtual model asset you need to specify 'withMeshDataFromGpu' (it has no other storage container to get data).");
|
||||
return true;
|
||||
}
|
||||
auto chunkLocks = Storage ? Storage->Lock() : FlaxStorage::LockData();
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
// Use a temporary chunks for data storage for virtual assets
|
||||
|
||||
@@ -18,7 +18,7 @@ public:
|
||||
/// <param name="id">The asset id.</param>
|
||||
/// <returns>Loaded asset of null.</returns>
|
||||
template<typename T>
|
||||
T* LoadAsync(const Guid& id)
|
||||
T* Load(const Guid& id)
|
||||
{
|
||||
for (auto& e : *this)
|
||||
{
|
||||
@@ -26,8 +26,10 @@ public:
|
||||
return (T*)e.Get();
|
||||
}
|
||||
auto asset = (T*)::LoadAsset(id, T::TypeInitializer);
|
||||
if (asset)
|
||||
if (asset && !asset->WaitForLoaded())
|
||||
Add(asset);
|
||||
else
|
||||
asset = nullptr;
|
||||
return asset;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||
#include "Engine/Scripting/Internal/InternalCalls.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#if USE_EDITOR
|
||||
#include "Editor/Editor.h"
|
||||
@@ -346,17 +347,21 @@ int32 LoadingThread::Run()
|
||||
ContentLoadTask* task;
|
||||
ThisLoadThread = this;
|
||||
|
||||
MONO_THREAD_INFO_TYPE* monoThreadInfo = nullptr;
|
||||
while (Platform::AtomicRead(&_exitFlag) == 0)
|
||||
{
|
||||
if (LoadTasks.try_dequeue(task))
|
||||
{
|
||||
Run(task);
|
||||
MONO_THREAD_INFO_GET(monoThreadInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
MONO_ENTER_GC_SAFE_WITH_INFO(monoThreadInfo);
|
||||
LoadTasksMutex.Lock();
|
||||
LoadTasksSignal.Wait(LoadTasksMutex);
|
||||
LoadTasksMutex.Unlock();
|
||||
MONO_EXIT_GC_SAFE_WITH_INFO;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -700,6 +705,7 @@ Asset* Content::GetAsset(const StringView& outputPath)
|
||||
{
|
||||
if (outputPath.IsEmpty())
|
||||
return nullptr;
|
||||
PROFILE_CPU();
|
||||
ScopeLock lock(AssetsLocker);
|
||||
for (auto i = Assets.Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
|
||||
@@ -87,6 +87,10 @@ public:
|
||||
/// </summary>
|
||||
double LastAccessTime = 0.0;
|
||||
|
||||
/// <summary>
|
||||
/// Flag set to indicate that chunk is during loading (atomic access to sync multiple reading threads).
|
||||
/// </summary>
|
||||
int64 IsLoading = 0;
|
||||
/// <summary>
|
||||
/// The chunk data.
|
||||
/// </summary>
|
||||
@@ -146,7 +150,7 @@ public:
|
||||
/// </summary>
|
||||
FORCE_INLINE bool IsLoaded() const
|
||||
{
|
||||
return Data.IsValid();
|
||||
return Data.IsValid() && Platform::AtomicRead(&IsLoading) == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -154,7 +158,7 @@ public:
|
||||
/// </summary>
|
||||
FORCE_INLINE bool IsMissing() const
|
||||
{
|
||||
return Data.IsInvalid();
|
||||
return !IsLoaded();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "FlaxPackage.h"
|
||||
#include "ContentStorageManager.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/ScopeExit.h"
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
@@ -74,8 +75,6 @@ FlaxChunk* FlaxChunk::Clone() const
|
||||
|
||||
const int32 FlaxStorage::MagicCode = 1180124739;
|
||||
|
||||
FlaxStorage::LockData FlaxStorage::LockData::Invalid(nullptr);
|
||||
|
||||
struct Header
|
||||
{
|
||||
int32 MagicCode;
|
||||
@@ -246,6 +245,7 @@ FlaxStorage::~FlaxStorage()
|
||||
ASSERT(IsDisposed());
|
||||
CHECK(_chunksLock == 0);
|
||||
CHECK(_refCount == 0);
|
||||
CHECK(_isUnloadingData == 0);
|
||||
ASSERT(_chunks.IsEmpty());
|
||||
|
||||
#if USE_EDITOR
|
||||
@@ -261,6 +261,22 @@ FlaxStorage::~FlaxStorage()
|
||||
#endif
|
||||
}
|
||||
|
||||
void FlaxStorage::LockChunks()
|
||||
{
|
||||
RETRY:
|
||||
Platform::InterlockedIncrement(&_chunksLock);
|
||||
if (Platform::AtomicRead(&_isUnloadingData) != 0)
|
||||
{
|
||||
// Someone else is closing file handles or freeing chunks so wait for it to finish and retry
|
||||
Platform::InterlockedDecrement(&_chunksLock);
|
||||
do
|
||||
{
|
||||
Platform::Sleep(1);
|
||||
} while (Platform::AtomicRead(&_isUnloadingData) != 0);
|
||||
goto RETRY;
|
||||
}
|
||||
}
|
||||
|
||||
FlaxStorage::LockData FlaxStorage::LockSafe()
|
||||
{
|
||||
auto lock = LockData(this);
|
||||
@@ -689,7 +705,6 @@ bool FlaxStorage::LoadAssetHeader(const Guid& id, AssetInitData& data)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Load header
|
||||
return LoadAssetHeader(e, data);
|
||||
}
|
||||
|
||||
@@ -699,7 +714,10 @@ bool FlaxStorage::LoadAssetChunk(FlaxChunk* chunk)
|
||||
ASSERT(IsLoaded());
|
||||
ASSERT(chunk != nullptr && _chunks.Contains(chunk));
|
||||
|
||||
// Check if already loaded
|
||||
// Protect against loading the same chunk from multiple threads at once
|
||||
while (Platform::InterlockedCompareExchange(&chunk->IsLoading, 1, 0) != 0)
|
||||
Platform::Sleep(1);
|
||||
SCOPE_EXIT{ Platform::AtomicStore(&chunk->IsLoading, 0); };
|
||||
if (chunk->IsLoaded())
|
||||
return false;
|
||||
|
||||
@@ -776,12 +794,10 @@ bool FlaxStorage::LoadAssetChunk(FlaxChunk* chunk)
|
||||
// Raw data
|
||||
chunk->Data.Read(stream, size);
|
||||
}
|
||||
ASSERT(chunk->IsLoaded());
|
||||
chunk->RegisterUsage();
|
||||
}
|
||||
|
||||
UnlockChunks();
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
@@ -1420,10 +1436,12 @@ FileReadStream* FlaxStorage::OpenFile()
|
||||
|
||||
bool FlaxStorage::CloseFileHandles()
|
||||
{
|
||||
// Guard the whole process so if new thread wants to lock the chunks will need to wait for this to end
|
||||
Platform::InterlockedIncrement(&_isUnloadingData);
|
||||
SCOPE_EXIT{ Platform::InterlockedDecrement(&_isUnloadingData); };
|
||||
|
||||
if (Platform::AtomicRead(&_chunksLock) == 0 && Platform::AtomicRead(&_files) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false; // Early out when no files are opened
|
||||
PROFILE_CPU();
|
||||
PROFILE_MEM(ContentFiles);
|
||||
|
||||
@@ -1496,9 +1514,21 @@ void FlaxStorage::Tick(double time)
|
||||
{
|
||||
auto chunk = _chunks.Get()[i];
|
||||
const bool wasUsed = (time - chunk->LastAccessTime) < unusedDataChunksLifetime;
|
||||
if (!wasUsed && chunk->IsLoaded() && EnumHasNoneFlags(chunk->Flags, FlaxChunkFlags::KeepInMemory))
|
||||
if (!wasUsed &&
|
||||
chunk->IsLoaded() &&
|
||||
EnumHasNoneFlags(chunk->Flags, FlaxChunkFlags::KeepInMemory) &&
|
||||
Platform::AtomicRead(&chunk->IsLoading) == 0)
|
||||
{
|
||||
// Guard the unloading so if other thread wants to lock the chunks will need to wait for this to end
|
||||
Platform::InterlockedIncrement(&_isUnloadingData);
|
||||
if (Platform::AtomicRead(&_chunksLock) != 0 || Platform::AtomicRead(&chunk->IsLoading) != 0)
|
||||
{
|
||||
// Someone started loading so skip ticking
|
||||
Platform::InterlockedDecrement(&_isUnloadingData);
|
||||
return;
|
||||
}
|
||||
chunk->Unload();
|
||||
Platform::InterlockedDecrement(&_isUnloadingData);
|
||||
}
|
||||
wasAnyUsed |= wasUsed;
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ protected:
|
||||
int64 _refCount = 0;
|
||||
int64 _chunksLock = 0;
|
||||
int64 _files = 0;
|
||||
int64 _isUnloadingData = 0;
|
||||
double _lastRefLostTime;
|
||||
CriticalSection _loadLocker;
|
||||
|
||||
@@ -129,10 +130,7 @@ public:
|
||||
/// <summary>
|
||||
/// Locks the storage chunks data to prevent disposing them. Also ensures that file handles won't be closed while chunks are locked.
|
||||
/// </summary>
|
||||
FORCE_INLINE void LockChunks()
|
||||
{
|
||||
Platform::InterlockedIncrement(&_chunksLock);
|
||||
}
|
||||
void LockChunks();
|
||||
|
||||
/// <summary>
|
||||
/// Unlocks the storage chunks data.
|
||||
@@ -148,7 +146,6 @@ public:
|
||||
struct LockData
|
||||
{
|
||||
friend FlaxStorage;
|
||||
static LockData Invalid;
|
||||
|
||||
private:
|
||||
FlaxStorage* _storage;
|
||||
@@ -161,6 +158,11 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
LockData()
|
||||
: _storage(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
LockData(const LockData& other)
|
||||
: _storage(other._storage)
|
||||
{
|
||||
|
||||
@@ -658,7 +658,10 @@ public:
|
||||
--_count;
|
||||
T* data = _allocation.Get();
|
||||
if (index < _count)
|
||||
Memory::MoveAssignItems(data + index, data + (index + 1), _count - index);
|
||||
{
|
||||
for (int32 i = index; i < _count; i++)
|
||||
data[i] = MoveTemp(data[i + 1]);
|
||||
}
|
||||
Memory::DestructItems(data + _count, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -409,27 +409,36 @@ protected:
|
||||
else
|
||||
{
|
||||
// Rebuild entire table completely
|
||||
const int32 elementsCount = _elementsCount;
|
||||
const int32 oldSize = _size;
|
||||
AllocationData oldAllocation;
|
||||
AllocationUtils::MoveToEmpty<BucketType, AllocationType>(oldAllocation, _allocation, _size, _size);
|
||||
AllocationUtils::MoveToEmpty<BucketType, AllocationType>(oldAllocation, _allocation, oldSize, oldSize);
|
||||
_allocation.Allocate(_size);
|
||||
BucketType* data = _allocation.Get();
|
||||
for (int32 i = 0; i < _size; ++i)
|
||||
for (int32 i = 0; i < oldSize; ++i)
|
||||
data[i]._state = HashSetBucketState::Empty;
|
||||
BucketType* oldData = oldAllocation.Get();
|
||||
FindPositionResult pos;
|
||||
for (int32 i = 0; i < _size; ++i)
|
||||
for (int32 i = 0; i < oldSize; ++i)
|
||||
{
|
||||
BucketType& oldBucket = oldData[i];
|
||||
if (oldBucket.IsOccupied())
|
||||
{
|
||||
FindPosition(oldBucket.GetKey(), pos);
|
||||
ASSERT(pos.FreeSlotIndex != -1);
|
||||
if (pos.FreeSlotIndex == -1)
|
||||
{
|
||||
// Grow and retry to handle pathological cases (eg. heavy collisions)
|
||||
EnsureCapacity(_size + 1, true);
|
||||
FindPosition(oldBucket.GetKey(), pos);
|
||||
ASSERT(pos.FreeSlotIndex != -1);
|
||||
}
|
||||
BucketType& bucket = _allocation.Get()[pos.FreeSlotIndex];
|
||||
bucket = MoveTemp(oldBucket);
|
||||
}
|
||||
}
|
||||
for (int32 i = 0; i < _size; ++i)
|
||||
for (int32 i = 0; i < oldSize; ++i)
|
||||
oldData[i].Free();
|
||||
_elementsCount = elementsCount;
|
||||
}
|
||||
_deletedCount = 0;
|
||||
}
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
#define DLLEXPORT __attribute__ ((__visibility__ ("default")))
|
||||
#define DLLEXPORT __attribute__((__visibility__("default")))
|
||||
#define DLLIMPORT
|
||||
#define USED __attribute__((used))
|
||||
#define THREADLOCAL __thread
|
||||
#define STDCALL __attribute__((stdcall))
|
||||
#define CDECL __attribute__((cdecl))
|
||||
@@ -19,7 +20,7 @@
|
||||
#define PACK_BEGIN()
|
||||
#define PACK_END() __attribute__((__packed__))
|
||||
#define ALIGN_BEGIN(_align)
|
||||
#define ALIGN_END(_align) __attribute__( (aligned(_align) ) )
|
||||
#define ALIGN_END(_align) __attribute__((aligned(_align)))
|
||||
#define OFFSET_OF(X, Y) __builtin_offsetof(X, Y)
|
||||
#define PRAGMA_DISABLE_DEPRECATION_WARNINGS \
|
||||
_Pragma("clang diagnostic push") \
|
||||
@@ -37,8 +38,9 @@
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
#define DLLEXPORT __attribute__ ((__visibility__ ("default")))
|
||||
#define DLLEXPORT __attribute__((__visibility__("default")))
|
||||
#define DLLIMPORT
|
||||
#define USED __attribute__((used))
|
||||
#define THREADLOCAL __thread
|
||||
#define STDCALL __attribute__((stdcall))
|
||||
#define CDECL __attribute__((cdecl))
|
||||
@@ -52,7 +54,7 @@
|
||||
#define PACK_BEGIN()
|
||||
#define PACK_END() __attribute__((__packed__))
|
||||
#define ALIGN_BEGIN(_align)
|
||||
#define ALIGN_END(_align) __attribute__( (aligned(_align) ) )
|
||||
#define ALIGN_END(_align) __attribute__((aligned(_align)))
|
||||
#define OFFSET_OF(X, Y) __builtin_offsetof(X, Y)
|
||||
#define PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
#define PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
@@ -67,6 +69,7 @@
|
||||
|
||||
#define DLLEXPORT __declspec(dllexport)
|
||||
#define DLLIMPORT __declspec(dllimport)
|
||||
#define USED
|
||||
#define THREADLOCAL __declspec(thread)
|
||||
#define STDCALL __stdcall
|
||||
#define CDECL __cdecl
|
||||
|
||||
@@ -620,14 +620,9 @@ bool Collision::RayIntersectsTriangle(const Ray& ray, const Vector3& a, const Ve
|
||||
Real rayDistance = edge2.X * distanceCrossEdge1.X + edge2.Y * distanceCrossEdge1.Y + edge2.Z * distanceCrossEdge1.Z;
|
||||
rayDistance *= inverseDeterminant;
|
||||
|
||||
// Check if the triangle is behind the ray origin
|
||||
if (rayDistance < 0.0f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the triangle is in front the ray origin
|
||||
distance = rayDistance;
|
||||
return true;
|
||||
return rayDistance >= 0.0f;
|
||||
}
|
||||
|
||||
bool CollisionsHelper::RayIntersectsTriangle(const Ray& ray, const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3, Real& distance, Vector3& normal)
|
||||
|
||||
@@ -12,11 +12,6 @@ String Ray::ToString() const
|
||||
return String::Format(TEXT("{}"), *this);
|
||||
}
|
||||
|
||||
Vector3 Ray::GetPoint(Real distance) const
|
||||
{
|
||||
return Position + Direction * distance;
|
||||
}
|
||||
|
||||
Ray Ray::GetPickRay(float x, float y, const Viewport& viewport, const Matrix& vp)
|
||||
{
|
||||
Vector3 nearPoint(x, y, 0.0f);
|
||||
|
||||
@@ -79,7 +79,10 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="distance">The distance from ray origin.</param>
|
||||
/// <returns>The calculated point.</returns>
|
||||
Vector3 GetPoint(Real distance) const;
|
||||
FORCE_INLINE Vector3 GetPoint(Real distance) const
|
||||
{
|
||||
return Position + Direction * distance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if there is an intersection between ray and a point.
|
||||
|
||||
@@ -18,9 +18,7 @@ namespace AllocationUtils
|
||||
capacity |= capacity >> 8;
|
||||
capacity |= capacity >> 16;
|
||||
uint64 capacity64 = (uint64)(capacity + 1) * 2;
|
||||
if (capacity64 > MAX_int32)
|
||||
capacity64 = MAX_int32;
|
||||
return (int32)capacity64;
|
||||
return capacity64 >= MAX_int32 ? MAX_int32 : (int32)capacity64 / 2;
|
||||
}
|
||||
|
||||
// Aligns the input value to the next power of 2 to be used as bigger memory allocation block.
|
||||
@@ -208,7 +206,7 @@ public:
|
||||
typedef typename FallbackAllocation::template Data<T> FallbackData;
|
||||
|
||||
bool _useFallback = false;
|
||||
byte _data[Capacity * sizeof(T)];
|
||||
alignas(sizeof(void*)) byte _data[Capacity * sizeof(T)];
|
||||
FallbackData _fallback;
|
||||
|
||||
public:
|
||||
|
||||
@@ -215,6 +215,11 @@ public:
|
||||
return String(_data.Get(), _data.Count());
|
||||
}
|
||||
|
||||
StringAnsi ToStringAnsi() const
|
||||
{
|
||||
return StringAnsi(_data.Get(), _data.Count());
|
||||
}
|
||||
|
||||
StringView ToStringView() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -79,10 +79,11 @@ namespace FlaxEngine.Interop
|
||||
NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), NativeLibraryImportResolver);
|
||||
|
||||
// Change default culture to match with Mono runtime default culture
|
||||
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
|
||||
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture;
|
||||
System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||
var culture = CultureInfo.InvariantCulture;
|
||||
CultureInfo.DefaultThreadCurrentCulture = culture;
|
||||
CultureInfo.DefaultThreadCurrentUICulture = culture;
|
||||
System.Threading.Thread.CurrentThread.CurrentCulture = culture;
|
||||
System.Threading.Thread.CurrentThread.CurrentUICulture = culture;
|
||||
|
||||
}
|
||||
|
||||
@@ -425,6 +426,8 @@ namespace FlaxEngine.Interop
|
||||
var fieldOffsetPtr = (IntPtr*)field.FieldHandle.Value; // Pointer to MonoClassField
|
||||
fieldOffsetPtr += 3; // Skip three pointers (type, name, parent_and_flags)
|
||||
return *(int*)fieldOffsetPtr - IntPtr.Size * 2; // Load the value of a pointer (4 bytes, int32), then subtracting 16 bytes from it (2 pointers for vtable and threadsync)
|
||||
#else
|
||||
throw new NotImplementedException();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ void GPUContext::FrameBegin()
|
||||
|
||||
void GPUContext::FrameEnd()
|
||||
{
|
||||
ClearState();
|
||||
ResetState();
|
||||
FlushState();
|
||||
}
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ public:
|
||||
/// [Deprecated in v1.10]
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if depth buffer is binded; otherwise, <c>false</c>.</returns>
|
||||
DEPRECATED("IsDepthBufferBinded has been deprecated and will be removed in ")
|
||||
DEPRECATED("IsDepthBufferBinded has been deprecated and will be removed in future")
|
||||
virtual bool IsDepthBufferBinded() = 0;
|
||||
|
||||
public:
|
||||
@@ -617,8 +617,17 @@ public:
|
||||
|
||||
/// <summary>
|
||||
/// Clears the context state.
|
||||
/// [Deprecated in v1.12]
|
||||
/// </summary>
|
||||
API_FUNCTION() virtual void ClearState() = 0;
|
||||
API_FUNCTION() DEPRECATED("Use ResetState instead") void ClearState()
|
||||
{
|
||||
ResetState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the context state.
|
||||
/// </summary>
|
||||
API_FUNCTION() virtual void ResetState() = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Flushes the internal cached context state with a command buffer.
|
||||
|
||||
@@ -201,6 +201,7 @@ bool DeferredMaterialShader::Load()
|
||||
psDesc.DepthWriteEnable = true;
|
||||
psDesc.DepthEnable = true;
|
||||
psDesc.DepthFunc = ComparisonFunc::Less;
|
||||
psDesc.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::None;
|
||||
psDesc.HS = nullptr;
|
||||
psDesc.DS = nullptr;
|
||||
GPUShaderProgramVS* instancedDepthPassVS;
|
||||
|
||||
@@ -195,5 +195,10 @@ bool ForwardMaterialShader::Load()
|
||||
psDesc.VS = _shader->GetVS("VS_Skinned");
|
||||
_cache.DepthSkinned.Init(psDesc);
|
||||
|
||||
#if PLATFORM_PS5
|
||||
// Fix shader binding issues on forward shading materials on PS5
|
||||
_drawModes = DrawPass::None;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -264,5 +264,10 @@ bool ParticleMaterialShader::Load()
|
||||
// Lazy initialization
|
||||
_cacheVolumetricFog.Desc.PS = nullptr;
|
||||
|
||||
#if PLATFORM_PS5
|
||||
// Fix shader binding issues on forward shading materials on PS5
|
||||
_drawModes = DrawPass::None;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,8 @@ GPUTexture* RenderBuffers::RequestHalfResDepth(GPUContext* context)
|
||||
|
||||
PixelFormat RenderBuffers::GetOutputFormat() const
|
||||
{
|
||||
return _useAlpha ? PixelFormat::R16G16B16A16_Float : PixelFormat::R11G11B10_Float;
|
||||
// TODO: fix incorrect alpha leaking into reflections on PS5 with R11G11B10_Float
|
||||
return _useAlpha || PLATFORM_PS5 ? PixelFormat::R16G16B16A16_Float : PixelFormat::R11G11B10_Float;
|
||||
}
|
||||
|
||||
bool RenderBuffers::GetUseAlpha() const
|
||||
|
||||
@@ -450,7 +450,7 @@ public:
|
||||
/// <summary>
|
||||
/// The high-level renderer context. Used to collect the draw calls for the scene rendering. Can be used to perform a custom rendering.
|
||||
/// </summary>
|
||||
API_STRUCT(NoDefault) struct RenderContext
|
||||
API_STRUCT(NoDefault) struct FLAXENGINE_API RenderContext
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(RenderContext);
|
||||
|
||||
@@ -491,7 +491,7 @@ API_STRUCT(NoDefault) struct RenderContext
|
||||
/// <summary>
|
||||
/// The high-level renderer context batch that encapsulates multiple rendering requests within a single task (eg. optimize main view scene rendering and shadow projections at once).
|
||||
/// </summary>
|
||||
API_STRUCT(NoDefault) struct RenderContextBatch
|
||||
API_STRUCT(NoDefault) struct FLAXENGINE_API RenderContextBatch
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(RenderContextBatch);
|
||||
|
||||
|
||||
@@ -216,20 +216,21 @@ GPUVertexLayout* GPUVertexLayout::Get(const Span<GPUVertexLayout*>& layouts)
|
||||
return result;
|
||||
}
|
||||
|
||||
GPUVertexLayout* GPUVertexLayout::Merge(GPUVertexLayout* base, GPUVertexLayout* reference, bool removeUnused, bool addMissing, int32 missingSlotOverride)
|
||||
GPUVertexLayout* GPUVertexLayout::Merge(GPUVertexLayout* base, GPUVertexLayout* reference, bool removeUnused, bool addMissing, int32 missingSlotOverride, bool referenceOrder)
|
||||
{
|
||||
GPUVertexLayout* result = base ? base : reference;
|
||||
if (base && reference && base != reference)
|
||||
{
|
||||
bool elementsModified = false;
|
||||
Elements newElements = base->GetElements();
|
||||
const Elements& refElements = reference->GetElements();
|
||||
if (removeUnused)
|
||||
{
|
||||
for (int32 i = newElements.Count() - 1; i >= 0; i--)
|
||||
{
|
||||
bool missing = true;
|
||||
const VertexElement& e = newElements.Get()[i];
|
||||
for (const VertexElement& ee : reference->GetElements())
|
||||
for (const VertexElement& ee : refElements)
|
||||
{
|
||||
if (ee.Type == e.Type)
|
||||
{
|
||||
@@ -247,7 +248,7 @@ GPUVertexLayout* GPUVertexLayout::Merge(GPUVertexLayout* base, GPUVertexLayout*
|
||||
}
|
||||
if (addMissing)
|
||||
{
|
||||
for (const VertexElement& e : reference->GetElements())
|
||||
for (const VertexElement& e : refElements)
|
||||
{
|
||||
bool missing = true;
|
||||
for (const VertexElement& ee : base->GetElements())
|
||||
@@ -282,6 +283,32 @@ GPUVertexLayout* GPUVertexLayout::Merge(GPUVertexLayout* base, GPUVertexLayout*
|
||||
}
|
||||
}
|
||||
}
|
||||
if (referenceOrder)
|
||||
{
|
||||
for (int32 i = 0, j = 0; i < newElements.Count() && j < refElements.Count(); j++)
|
||||
{
|
||||
if (newElements[i].Type == refElements[j].Type)
|
||||
{
|
||||
// Elements match so move forward
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find reference element in a new list
|
||||
for (int32 k = i + 1; k < newElements.Count(); k++)
|
||||
{
|
||||
if (newElements[k].Type == refElements[j].Type)
|
||||
{
|
||||
// Move matching element to the reference position
|
||||
VertexElement e = newElements[k];
|
||||
newElements.RemoveAt(k);
|
||||
newElements.Insert(i, e);
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (elementsModified)
|
||||
result = Get(newElements, true);
|
||||
}
|
||||
|
||||
@@ -84,8 +84,9 @@ public:
|
||||
/// <param name="removeUnused">True to remove elements from base layout that don't exist in a reference layout.</param>
|
||||
/// <param name="addMissing">True to add missing elements to base layout that exist in a reference layout.</param>
|
||||
/// <param name="missingSlotOverride">Allows to override the input slot for missing elements. Use value -1 to inherit slot from the reference layout.</param>
|
||||
/// <param name="referenceOrder">True to reorder result elements to match the reference layout. For example, if input vertex buffer layout is different than vertex shader then it can match those.</param>
|
||||
/// <returns>Vertex layout object. Doesn't need to be cleared as it's cached for an application lifetime.</returns>
|
||||
static GPUVertexLayout* Merge(GPUVertexLayout* base, GPUVertexLayout* reference, bool removeUnused = false, bool addMissing = true, int32 missingSlotOverride = -1);
|
||||
static GPUVertexLayout* Merge(GPUVertexLayout* base, GPUVertexLayout* reference, bool removeUnused = false, bool addMissing = true, int32 missingSlotOverride = -1, bool referenceOrder = false);
|
||||
|
||||
public:
|
||||
// [GPUResource]
|
||||
|
||||
@@ -338,10 +338,10 @@ public:
|
||||
StreamTextureMipTask(StreamingTexture* texture, int32 mipIndex, Task* rootTask)
|
||||
: GPUUploadTextureMipTask(texture->GetTexture(), mipIndex, Span<byte>(nullptr, 0), 0, 0, false)
|
||||
, _streamingTexture(texture)
|
||||
, _rootTask(rootTask ? rootTask : this)
|
||||
, _rootTask(rootTask)
|
||||
, _dataLock(_streamingTexture->GetOwner()->LockData())
|
||||
{
|
||||
_streamingTexture->_streamingTasks.Add(_rootTask);
|
||||
_streamingTexture->_streamingTasks.Add(this);
|
||||
_texture.Released.Bind<StreamTextureMipTask, &StreamTextureMipTask::OnResourceReleased2>(this);
|
||||
}
|
||||
|
||||
@@ -357,7 +357,7 @@ private:
|
||||
if (_streamingTexture)
|
||||
{
|
||||
ScopeLock lock(_streamingTexture->GetOwner()->GetOwnerLocker());
|
||||
_streamingTexture->_streamingTasks.Remove(_rootTask);
|
||||
_streamingTexture->_streamingTasks.Remove(this);
|
||||
_streamingTexture = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -422,6 +422,15 @@ protected:
|
||||
|
||||
GPUUploadTextureMipTask::OnFail();
|
||||
}
|
||||
|
||||
void OnCancel() override
|
||||
{
|
||||
GPUUploadTextureMipTask::OnCancel();
|
||||
|
||||
// Cancel the root task too (eg. mip loading from asset)
|
||||
if (_rootTask != nullptr)
|
||||
_rootTask->Cancel();
|
||||
}
|
||||
};
|
||||
|
||||
Task* StreamingTexture::CreateStreamingTask(int32 residency)
|
||||
|
||||
@@ -771,7 +771,7 @@ Task* TextureBase::RequestMipDataAsync(int32 mipIndex)
|
||||
|
||||
FlaxStorage::LockData TextureBase::LockData()
|
||||
{
|
||||
return _parent->Storage ? _parent->Storage->Lock() : FlaxStorage::LockData::Invalid;
|
||||
return _parent->Storage ? _parent->Storage->Lock() : FlaxStorage::LockData();
|
||||
}
|
||||
|
||||
void TextureBase::GetMipData(int32 mipIndex, BytesContainer& data) const
|
||||
|
||||
@@ -724,7 +724,7 @@ void GPUContextDX11::SetState(GPUPipelineState* state)
|
||||
}
|
||||
}
|
||||
|
||||
void GPUContextDX11::ClearState()
|
||||
void GPUContextDX11::ResetState()
|
||||
{
|
||||
if (!_context)
|
||||
return;
|
||||
|
||||
@@ -158,7 +158,7 @@ public:
|
||||
void SetScissor(const Rectangle& scissorRect) override;
|
||||
GPUPipelineState* GetState() const override;
|
||||
void SetState(GPUPipelineState* state) override;
|
||||
void ClearState() override;
|
||||
void ResetState() override;
|
||||
void FlushState() override;
|
||||
void Flush() override;
|
||||
void UpdateBuffer(GPUBuffer* buffer, const void* data, uint32 size, uint32 offset) override;
|
||||
|
||||
@@ -92,9 +92,8 @@ float GPUTimerQueryDX11::GetResult()
|
||||
{
|
||||
if (!_finalized)
|
||||
{
|
||||
#if BUILD_DEBUG
|
||||
ASSERT(HasResult());
|
||||
#endif
|
||||
if (!HasResult())
|
||||
return 0;
|
||||
|
||||
UINT64 timeStart, timeEnd;
|
||||
auto context = _device->GetIM();
|
||||
|
||||
@@ -143,6 +143,8 @@ void CommandQueueDX12::WaitForFence(uint64 fenceValue)
|
||||
|
||||
void CommandQueueDX12::WaitForGPU()
|
||||
{
|
||||
PROFILE_CPU();
|
||||
ZoneColor(TracyWaitZoneColor);
|
||||
const uint64 value = _fence.Signal(this);
|
||||
_fence.WaitCPU(value);
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ bool GPUBufferDX12::OnInit()
|
||||
// Create resource
|
||||
ID3D12Resource* resource;
|
||||
#if PLATFORM_WINDOWS
|
||||
D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;
|
||||
D3D12_HEAP_FLAGS heapFlags = EnumHasAnyFlags(_desc.Flags, GPUBufferFlags::VertexBuffer | GPUBufferFlags::IndexBuffer) || _desc.InitData ? D3D12_HEAP_FLAG_CREATE_NOT_ZEROED : D3D12_HEAP_FLAG_NONE;
|
||||
#else
|
||||
D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;
|
||||
#endif
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "GPUVertexLayoutDX12.h"
|
||||
#include "CommandQueueDX12.h"
|
||||
#include "DescriptorHeapDX12.h"
|
||||
#include "RootSignatureDX12.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h"
|
||||
#include "Engine/Debug/Exceptions/NotImplementedException.h"
|
||||
@@ -307,6 +308,7 @@ void GPUContextDX12::Reset()
|
||||
_device->DummyVB = _device->CreateBuffer(TEXT("DummyVertexBuffer"));
|
||||
auto* layout = GPUVertexLayout::Get({ { VertexElement::Types::Attribute3, 0, 0, 0, PixelFormat::R32G32B32A32_Float } });
|
||||
_device->DummyVB->Init(GPUBufferDescription::Vertex(layout, sizeof(Color), 1, &Color::Transparent));
|
||||
SetResourceState(_device->DummyVB, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, 0);
|
||||
}
|
||||
((GPUBufferDX12*)_device->DummyVB)->GetVBView(dummyVBView);
|
||||
_commandList->IASetVertexBuffers(GPU_MAX_VB_BINDED, 1, &dummyVBView);
|
||||
@@ -491,7 +493,7 @@ void GPUContextDX12::flushUAVs()
|
||||
ASSERT(uaCount <= GPU_MAX_UA_BINDED);
|
||||
|
||||
// Fill table with source descriptors
|
||||
DxShaderHeader& header = _currentCompute ? ((GPUShaderProgramCSDX12*)_currentCompute)->Header : _currentState->Header;
|
||||
DxShaderHeader& header = _isCompute ? ((GPUShaderProgramCSDX12*)_currentCompute)->Header : _currentState->Header;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE srcDescriptorRangeStarts[GPU_MAX_UA_BINDED];
|
||||
for (uint32 i = 0; i < uaCount; i++)
|
||||
{
|
||||
@@ -628,7 +630,9 @@ void GPUContextDX12::flushPS()
|
||||
LOG(Error, "Missing Vertex Layout (not assigned to GPUBuffer). Vertex Shader won't read valid data resulting incorrect visuals.");
|
||||
}
|
||||
#endif
|
||||
_commandList->SetPipelineState(_currentState->GetState(_rtDepth, _rtCount, _rtHandles, _vertexLayout));
|
||||
ID3D12PipelineState* pso = _currentState->GetState(_rtDepth, _rtCount, _rtHandles, _vertexLayout);
|
||||
ASSERT(pso);
|
||||
_commandList->SetPipelineState(pso);
|
||||
if (_primitiveTopology != _currentState->PrimitiveTopology)
|
||||
{
|
||||
_primitiveTopology = _currentState->PrimitiveTopology;
|
||||
@@ -1300,7 +1304,7 @@ void GPUContextDX12::SetState(GPUPipelineState* state)
|
||||
}
|
||||
}
|
||||
|
||||
void GPUContextDX12::ClearState()
|
||||
void GPUContextDX12::ResetState()
|
||||
{
|
||||
if (!_commandList)
|
||||
return;
|
||||
|
||||
@@ -201,7 +201,7 @@ public:
|
||||
void SetScissor(const Rectangle& scissorRect) override;
|
||||
GPUPipelineState* GetState() const override;
|
||||
void SetState(GPUPipelineState* state) override;
|
||||
void ClearState() override;
|
||||
void ResetState() override;
|
||||
void FlushState() override;
|
||||
void Flush() override;
|
||||
void UpdateBuffer(GPUBuffer* buffer, const void* data, uint32 size, uint32 offset) override;
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
#include "GPUSamplerDX12.h"
|
||||
#include "GPUVertexLayoutDX12.h"
|
||||
#include "GPUSwapChainDX12.h"
|
||||
#include "RootSignatureDX12.h"
|
||||
#include "UploadBufferDX12.h"
|
||||
#include "CommandQueueDX12.h"
|
||||
#include "Engine/Engine/Engine.h"
|
||||
#include "Engine/Engine/CommandLine.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
@@ -21,20 +24,23 @@
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Config/PlatformSettings.h"
|
||||
#include "UploadBufferDX12.h"
|
||||
#include "CommandQueueDX12.h"
|
||||
#include "Engine/Core/Types/StringBuilder.h"
|
||||
#include "Engine/Core/Utilities.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "CommandSignatureDX12.h"
|
||||
|
||||
static bool CheckDX12Support(IDXGIAdapter* adapter)
|
||||
{
|
||||
#if PLATFORM_XBOX_SCARLETT || PLATFORM_XBOX_ONE
|
||||
return true;
|
||||
#else
|
||||
// Try to create device
|
||||
if (SUCCEEDED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
GPUVertexLayoutDX12::GPUVertexLayoutDX12(GPUDeviceDX12* device, const Elements& elements, bool explicitOffsets)
|
||||
@@ -55,6 +61,310 @@ GPUVertexLayoutDX12::GPUVertexLayoutDX12(GPUDeviceDX12* device, const Elements&
|
||||
}
|
||||
}
|
||||
|
||||
RootSignatureDX12::RootSignatureDX12()
|
||||
{
|
||||
// Clear structures
|
||||
Platform::MemoryClear(this, sizeof(*this));
|
||||
|
||||
// Descriptor tables
|
||||
{
|
||||
// SRVs
|
||||
D3D12_DESCRIPTOR_RANGE& range = _ranges[0];
|
||||
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
||||
range.NumDescriptors = GPU_MAX_SR_BINDED;
|
||||
range.BaseShaderRegister = 0;
|
||||
range.RegisterSpace = 0;
|
||||
range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
}
|
||||
{
|
||||
// UAVs
|
||||
D3D12_DESCRIPTOR_RANGE& range = _ranges[1];
|
||||
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
|
||||
range.NumDescriptors = GPU_MAX_UA_BINDED;
|
||||
range.BaseShaderRegister = 0;
|
||||
range.RegisterSpace = 0;
|
||||
range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
}
|
||||
{
|
||||
// Samplers
|
||||
D3D12_DESCRIPTOR_RANGE& range = _ranges[2];
|
||||
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
|
||||
range.NumDescriptors = GPU_MAX_SAMPLER_BINDED - GPU_STATIC_SAMPLERS_COUNT;
|
||||
range.BaseShaderRegister = GPU_STATIC_SAMPLERS_COUNT;
|
||||
range.RegisterSpace = 0;
|
||||
range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
}
|
||||
|
||||
// Root parameters
|
||||
for (int32 i = 0; i < GPU_MAX_CB_BINDED; i++)
|
||||
{
|
||||
// CBs
|
||||
D3D12_ROOT_PARAMETER& param = _parameters[DX12_ROOT_SIGNATURE_CB + i];
|
||||
param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
||||
param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
param.Descriptor.ShaderRegister = i;
|
||||
param.Descriptor.RegisterSpace = 0;
|
||||
}
|
||||
{
|
||||
// SRVs
|
||||
D3D12_ROOT_PARAMETER& param = _parameters[DX12_ROOT_SIGNATURE_SR];
|
||||
param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
param.DescriptorTable.NumDescriptorRanges = 1;
|
||||
param.DescriptorTable.pDescriptorRanges = &_ranges[0];
|
||||
}
|
||||
{
|
||||
// UAVs
|
||||
D3D12_ROOT_PARAMETER& param = _parameters[DX12_ROOT_SIGNATURE_UA];
|
||||
param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
param.DescriptorTable.NumDescriptorRanges = 1;
|
||||
param.DescriptorTable.pDescriptorRanges = &_ranges[1];
|
||||
}
|
||||
{
|
||||
// Samplers
|
||||
D3D12_ROOT_PARAMETER& param = _parameters[DX12_ROOT_SIGNATURE_SAMPLER];
|
||||
param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
param.DescriptorTable.NumDescriptorRanges = 1;
|
||||
param.DescriptorTable.pDescriptorRanges = &_ranges[2];
|
||||
}
|
||||
|
||||
// Static samplers
|
||||
static_assert(GPU_STATIC_SAMPLERS_COUNT == ARRAY_COUNT(_staticSamplers), "Update static samplers setup.");
|
||||
// Linear Clamp
|
||||
InitSampler(0, D3D12_FILTER_MIN_MAG_MIP_LINEAR, D3D12_TEXTURE_ADDRESS_MODE_CLAMP);
|
||||
// Point Clamp
|
||||
InitSampler(1, D3D12_FILTER_MIN_MAG_MIP_POINT, D3D12_TEXTURE_ADDRESS_MODE_CLAMP);
|
||||
// Linear Wrap
|
||||
InitSampler(2, D3D12_FILTER_MIN_MAG_MIP_LINEAR, D3D12_TEXTURE_ADDRESS_MODE_WRAP);
|
||||
// Point Wrap
|
||||
InitSampler(3, D3D12_FILTER_MIN_MAG_MIP_POINT, D3D12_TEXTURE_ADDRESS_MODE_WRAP);
|
||||
// Shadow
|
||||
InitSampler(4, D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_COMPARISON_FUNC_LESS_EQUAL);
|
||||
// Shadow PCF
|
||||
InitSampler(5, D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR, D3D12_TEXTURE_ADDRESS_MODE_CLAMP, D3D12_COMPARISON_FUNC_LESS_EQUAL);
|
||||
|
||||
// Init
|
||||
_desc.NumParameters = ARRAY_COUNT(_parameters);
|
||||
_desc.pParameters = _parameters;
|
||||
_desc.NumStaticSamplers = ARRAY_COUNT(_staticSamplers);
|
||||
_desc.pStaticSamplers = _staticSamplers;
|
||||
_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
|
||||
}
|
||||
|
||||
void RootSignatureDX12::InitSampler(int32 i, D3D12_FILTER filter, D3D12_TEXTURE_ADDRESS_MODE address, D3D12_COMPARISON_FUNC comparisonFunc)
|
||||
{
|
||||
auto& sampler = _staticSamplers[i];
|
||||
sampler.Filter = filter;
|
||||
sampler.AddressU = address;
|
||||
sampler.AddressV = address;
|
||||
sampler.AddressW = address;
|
||||
sampler.MipLODBias = 0.0f;
|
||||
sampler.MaxAnisotropy = 1;
|
||||
sampler.ComparisonFunc = comparisonFunc;
|
||||
sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK;
|
||||
sampler.MinLOD = 0;
|
||||
sampler.MaxLOD = D3D12_FLOAT32_MAX;
|
||||
sampler.ShaderRegister = i;
|
||||
sampler.RegisterSpace = 0;
|
||||
sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
}
|
||||
|
||||
ComPtr<ID3DBlob> RootSignatureDX12::Serialize() const
|
||||
{
|
||||
ComPtr<ID3DBlob> signature;
|
||||
ComPtr<ID3DBlob> error;
|
||||
VALIDATE_DIRECTX_CALL(D3D12SerializeRootSignature(&_desc, D3D_ROOT_SIGNATURE_VERSION_1_0, &signature, &error));
|
||||
if (error.Get())
|
||||
{
|
||||
LOG(Error, "D3D12SerializeRootSignature failed with error: {}", String((const char*)error->GetBufferPointer()));
|
||||
}
|
||||
return signature;
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
const Char* GetRootSignatureShaderVisibility(D3D12_SHADER_VISIBILITY visibility)
|
||||
{
|
||||
switch (visibility)
|
||||
{
|
||||
case D3D12_SHADER_VISIBILITY_VERTEX:
|
||||
return TEXT(", visibility=SHADER_VISIBILITY_VERTEX");
|
||||
case D3D12_SHADER_VISIBILITY_HULL:
|
||||
return TEXT(", visibility=SHADER_VISIBILITY_HULL");
|
||||
case D3D12_SHADER_VISIBILITY_DOMAIN:
|
||||
return TEXT(", visibility=SHADER_VISIBILITY_DOMAIN");
|
||||
case D3D12_SHADER_VISIBILITY_GEOMETRY:
|
||||
return TEXT(", visibility=SHADER_VISIBILITY_GEOMETRY");
|
||||
case D3D12_SHADER_VISIBILITY_PIXEL:
|
||||
return TEXT(", visibility=SHADER_VISIBILITY_PIXEL");
|
||||
case D3D12_SHADER_VISIBILITY_AMPLIFICATION:
|
||||
return TEXT(", visibility=SHADER_VISIBILITY_AMPLIFICATION");
|
||||
case D3D12_SHADER_VISIBILITY_MESH:
|
||||
return TEXT(", visibility=SHADER_VISIBILITY_MESH");
|
||||
case D3D12_SHADER_VISIBILITY_ALL:
|
||||
default:
|
||||
return TEXT(""); // Default
|
||||
}
|
||||
}
|
||||
|
||||
const Char* GetRootSignatureSamplerFilter(D3D12_FILTER filter)
|
||||
{
|
||||
switch (filter)
|
||||
{
|
||||
case D3D12_FILTER_MIN_MAG_MIP_POINT:
|
||||
return TEXT("FILTER_MIN_MAG_MIP_POINT");
|
||||
case D3D12_FILTER_MIN_MAG_MIP_LINEAR:
|
||||
return TEXT("FILTER_MIN_MAG_MIP_LINEAR");
|
||||
case D3D12_FILTER_ANISOTROPIC:
|
||||
return TEXT("FILTER_ANISOTROPIC");
|
||||
case D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT:
|
||||
return TEXT("FILTER_COMPARISON_MIN_MAG_MIP_POINT");
|
||||
case D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR:
|
||||
return TEXT("FILTER_COMPARISON_MIN_MAG_MIP_LINEAR");
|
||||
default:
|
||||
CRASH; // Not implemented
|
||||
}
|
||||
}
|
||||
|
||||
const Char* GetRootSignatureSamplerAddress(D3D12_TEXTURE_ADDRESS_MODE address)
|
||||
{
|
||||
switch (address)
|
||||
{
|
||||
case D3D12_TEXTURE_ADDRESS_MODE_WRAP:
|
||||
return TEXT("TEXTURE_ADDRESS_WRAP");
|
||||
case D3D12_TEXTURE_ADDRESS_MODE_MIRROR:
|
||||
return TEXT("TEXTURE_ADDRESS_MIRROR");
|
||||
case D3D12_TEXTURE_ADDRESS_MODE_CLAMP:
|
||||
return TEXT("TEXTURE_ADDRESS_CLAMP");
|
||||
case D3D12_TEXTURE_ADDRESS_MODE_BORDER:
|
||||
return TEXT("TEXTURE_ADDRESS_BORDER");
|
||||
case D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE:
|
||||
return TEXT("TEXTURE_ADDRESS_MIRROR_ONCE");
|
||||
default:
|
||||
return TEXT("");
|
||||
}
|
||||
}
|
||||
|
||||
const Char* GetRootSignatureSamplerComparisonFunc(D3D12_COMPARISON_FUNC func)
|
||||
{
|
||||
switch (func)
|
||||
{
|
||||
case D3D12_COMPARISON_FUNC_NEVER:
|
||||
return TEXT("COMPARISON_NEVER");
|
||||
case D3D12_COMPARISON_FUNC_LESS:
|
||||
return TEXT("COMPARISON_LESS");
|
||||
case D3D12_COMPARISON_FUNC_EQUAL:
|
||||
return TEXT("COMPARISON_EQUAL");
|
||||
case D3D12_COMPARISON_FUNC_LESS_EQUAL:
|
||||
return TEXT("COMPARISON_LESS_EQUAL");
|
||||
case D3D12_COMPARISON_FUNC_GREATER:
|
||||
return TEXT("COMPARISON_GREATER");
|
||||
case D3D12_COMPARISON_FUNC_NOT_EQUAL:
|
||||
return TEXT("COMPARISON_NOT_EQUAL");
|
||||
case D3D12_COMPARISON_FUNC_GREATER_EQUAL:
|
||||
return TEXT("COMPARISON_GREATER_EQUAL");
|
||||
case D3D12_COMPARISON_FUNC_ALWAYS:
|
||||
default:
|
||||
return TEXT("COMPARISON_ALWAYS");
|
||||
}
|
||||
}
|
||||
|
||||
void RootSignatureDX12::ToString(StringBuilder& sb, bool singleLine) const
|
||||
{
|
||||
// Flags
|
||||
sb.Append(TEXT("RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT)"));
|
||||
|
||||
// Parameters
|
||||
const Char newLine = singleLine ? ' ' : '\n';
|
||||
for (const D3D12_ROOT_PARAMETER& param : _parameters)
|
||||
{
|
||||
const Char* visibility = GetRootSignatureShaderVisibility(param.ShaderVisibility);
|
||||
switch (param.ParameterType)
|
||||
{
|
||||
case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:
|
||||
sb.AppendFormat(TEXT(",{}DescriptorTable("), newLine);
|
||||
for (uint32 rangeIndex = 0; rangeIndex < param.DescriptorTable.NumDescriptorRanges; rangeIndex++)
|
||||
{
|
||||
if (rangeIndex)
|
||||
sb.Append(TEXT(", "));
|
||||
const D3D12_DESCRIPTOR_RANGE& range = param.DescriptorTable.pDescriptorRanges[rangeIndex];
|
||||
switch (range.RangeType)
|
||||
{
|
||||
case D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
|
||||
sb.AppendFormat(TEXT("SRV(t{}"), range.BaseShaderRegister);
|
||||
break;
|
||||
case D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
|
||||
sb.AppendFormat(TEXT("UAV(u{}"), range.BaseShaderRegister);
|
||||
break;
|
||||
case D3D12_DESCRIPTOR_RANGE_TYPE_CBV:
|
||||
sb.AppendFormat(TEXT("CBV(b{}"), range.BaseShaderRegister);
|
||||
break;
|
||||
case D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER:
|
||||
sb.AppendFormat(TEXT("Sampler(s{}"), range.BaseShaderRegister);
|
||||
break;
|
||||
}
|
||||
if (range.NumDescriptors != 1)
|
||||
{
|
||||
if (range.NumDescriptors == UINT_MAX)
|
||||
sb.Append(TEXT(", numDescriptors=unbounded"));
|
||||
else
|
||||
sb.AppendFormat(TEXT(", numDescriptors={}"), range.NumDescriptors);
|
||||
}
|
||||
if (range.OffsetInDescriptorsFromTableStart != D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND)
|
||||
sb.AppendFormat(TEXT(", offset={}"), range.OffsetInDescriptorsFromTableStart);
|
||||
sb.Append(')');
|
||||
}
|
||||
sb.AppendFormat(TEXT("{})"), visibility);
|
||||
break;
|
||||
case D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS:
|
||||
sb.AppendFormat(TEXT(",{}RootConstants(num32BitConstants={}, b{}{})"), newLine, param.Constants.Num32BitValues, param.Constants.ShaderRegister, visibility);
|
||||
break;
|
||||
case D3D12_ROOT_PARAMETER_TYPE_CBV:
|
||||
sb.AppendFormat(TEXT(",{}CBV(b{}{})"), newLine, param.Descriptor.ShaderRegister, visibility);
|
||||
break;
|
||||
case D3D12_ROOT_PARAMETER_TYPE_SRV:
|
||||
sb.AppendFormat(TEXT(",{}SRV(t{}{})"), newLine, param.Descriptor.ShaderRegister, visibility);
|
||||
break;
|
||||
case D3D12_ROOT_PARAMETER_TYPE_UAV:
|
||||
sb.AppendFormat(TEXT(",{}UAV(u{}{})"), newLine, param.Descriptor.ShaderRegister, visibility);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Static Samplers
|
||||
for (const D3D12_STATIC_SAMPLER_DESC& sampler : _staticSamplers)
|
||||
{
|
||||
const Char* visibility = GetRootSignatureShaderVisibility(sampler.ShaderVisibility);
|
||||
sb.AppendFormat(TEXT(",{}StaticSampler(s{}"), newLine, sampler.ShaderRegister);
|
||||
sb.AppendFormat(TEXT(", filter={}"), GetRootSignatureSamplerFilter(sampler.Filter));
|
||||
sb.AppendFormat(TEXT(", addressU={}"), GetRootSignatureSamplerAddress(sampler.AddressU));
|
||||
sb.AppendFormat(TEXT(", addressV={}"), GetRootSignatureSamplerAddress(sampler.AddressV));
|
||||
sb.AppendFormat(TEXT(", addressW={}"), GetRootSignatureSamplerAddress(sampler.AddressW));
|
||||
sb.AppendFormat(TEXT(", comparisonFunc={}"), GetRootSignatureSamplerComparisonFunc(sampler.ComparisonFunc));
|
||||
sb.AppendFormat(TEXT(", maxAnisotropy={}"), sampler.MaxAnisotropy);
|
||||
sb.Append(TEXT(", borderColor=STATIC_BORDER_COLOR_OPAQUE_BLACK"));
|
||||
sb.AppendFormat(TEXT("{})"), visibility);
|
||||
}
|
||||
}
|
||||
|
||||
String RootSignatureDX12::ToString() const
|
||||
{
|
||||
StringBuilder sb;
|
||||
ToString(sb);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
StringAnsi RootSignatureDX12::ToStringAnsi() const
|
||||
{
|
||||
StringBuilder sb;
|
||||
ToString(sb);
|
||||
return sb.ToStringAnsi();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
GPUDevice* GPUDeviceDX12::Create()
|
||||
{
|
||||
#if PLATFORM_XBOX_SCARLETT || PLATFORM_XBOX_ONE
|
||||
@@ -318,6 +628,7 @@ bool GPUDeviceDX12::Init()
|
||||
VALIDATE_DIRECTX_CALL(dxgiAdapter->EnumOutputs(0, dxgiOutput.GetAddressOf()));
|
||||
DXGI_FORMAT backbufferFormat = RenderToolsDX::ToDxgiFormat(GPU_BACK_BUFFER_PIXEL_FORMAT);
|
||||
UINT modesCount = 0;
|
||||
#ifdef _GAMING_XBOX_SCARLETT
|
||||
VALIDATE_DIRECTX_CALL(dxgiOutput->GetDisplayModeList(backbufferFormat, 0, &modesCount, NULL));
|
||||
Array<DXGIXBOX_MODE_DESC> modes;
|
||||
modes.Resize((int32)modesCount);
|
||||
@@ -332,6 +643,11 @@ bool GPUDeviceDX12::Init()
|
||||
videoOutput.RefreshRate = Math::Max(videoOutput.RefreshRate, mode.RefreshRate.Numerator / (float)mode.RefreshRate.Denominator);
|
||||
}
|
||||
modes.Resize(0);
|
||||
#else
|
||||
videoOutput.Width = 1920;
|
||||
videoOutput.Height = 1080;
|
||||
videoOutput.RefreshRate = 60;
|
||||
#endif
|
||||
|
||||
#if PLATFORM_GDK
|
||||
GDKPlatform::Suspended.Bind<GPUDeviceDX12, &GPUDeviceDX12::OnSuspended>(this);
|
||||
@@ -561,170 +877,10 @@ bool GPUDeviceDX12::Init()
|
||||
}
|
||||
|
||||
// Create root signature
|
||||
// TODO: maybe create set of different root signatures? for UAVs, for compute, for simple drawing, for post fx?
|
||||
{
|
||||
// Descriptor tables
|
||||
D3D12_DESCRIPTOR_RANGE r[3]; // SRV+UAV+Sampler
|
||||
{
|
||||
D3D12_DESCRIPTOR_RANGE& range = r[0];
|
||||
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
||||
range.NumDescriptors = GPU_MAX_SR_BINDED;
|
||||
range.BaseShaderRegister = 0;
|
||||
range.RegisterSpace = 0;
|
||||
range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
}
|
||||
{
|
||||
D3D12_DESCRIPTOR_RANGE& range = r[1];
|
||||
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
|
||||
range.NumDescriptors = GPU_MAX_UA_BINDED;
|
||||
range.BaseShaderRegister = 0;
|
||||
range.RegisterSpace = 0;
|
||||
range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
}
|
||||
{
|
||||
D3D12_DESCRIPTOR_RANGE& range = r[2];
|
||||
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
|
||||
range.NumDescriptors = GPU_MAX_SAMPLER_BINDED - GPU_STATIC_SAMPLERS_COUNT;
|
||||
range.BaseShaderRegister = GPU_STATIC_SAMPLERS_COUNT;
|
||||
range.RegisterSpace = 0;
|
||||
range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
}
|
||||
|
||||
// Root parameters
|
||||
D3D12_ROOT_PARAMETER rootParameters[GPU_MAX_CB_BINDED + 3];
|
||||
for (int32 i = 0; i < GPU_MAX_CB_BINDED; i++)
|
||||
{
|
||||
// CB
|
||||
D3D12_ROOT_PARAMETER& rootParam = rootParameters[DX12_ROOT_SIGNATURE_CB + i];
|
||||
rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
||||
rootParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
rootParam.Descriptor.ShaderRegister = i;
|
||||
rootParam.Descriptor.RegisterSpace = 0;
|
||||
}
|
||||
{
|
||||
// SRVs
|
||||
D3D12_ROOT_PARAMETER& rootParam = rootParameters[DX12_ROOT_SIGNATURE_SR];
|
||||
rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
rootParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
rootParam.DescriptorTable.NumDescriptorRanges = 1;
|
||||
rootParam.DescriptorTable.pDescriptorRanges = &r[0];
|
||||
}
|
||||
{
|
||||
// UAVs
|
||||
D3D12_ROOT_PARAMETER& rootParam = rootParameters[DX12_ROOT_SIGNATURE_UA];
|
||||
rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
rootParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
rootParam.DescriptorTable.NumDescriptorRanges = 1;
|
||||
rootParam.DescriptorTable.pDescriptorRanges = &r[1];
|
||||
}
|
||||
{
|
||||
// Samplers
|
||||
D3D12_ROOT_PARAMETER& rootParam = rootParameters[DX12_ROOT_SIGNATURE_SAMPLER];
|
||||
rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
rootParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
rootParam.DescriptorTable.NumDescriptorRanges = 1;
|
||||
rootParam.DescriptorTable.pDescriptorRanges = &r[2];
|
||||
}
|
||||
|
||||
// Static samplers
|
||||
D3D12_STATIC_SAMPLER_DESC staticSamplers[6];
|
||||
static_assert(GPU_STATIC_SAMPLERS_COUNT == ARRAY_COUNT(staticSamplers), "Update static samplers setup.");
|
||||
// Linear Clamp
|
||||
staticSamplers[0].Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
staticSamplers[0].AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
staticSamplers[0].AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
staticSamplers[0].AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
staticSamplers[0].MipLODBias = 0.0f;
|
||||
staticSamplers[0].MaxAnisotropy = 1;
|
||||
staticSamplers[0].BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK;
|
||||
staticSamplers[0].MinLOD = 0;
|
||||
staticSamplers[0].MaxLOD = D3D12_FLOAT32_MAX;
|
||||
staticSamplers[0].ShaderRegister = 0;
|
||||
staticSamplers[0].RegisterSpace = 0;
|
||||
staticSamplers[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
// Point Clamp
|
||||
staticSamplers[1].Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||||
staticSamplers[1].AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
staticSamplers[1].AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
staticSamplers[1].AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
staticSamplers[1].MipLODBias = 0.0f;
|
||||
staticSamplers[1].MaxAnisotropy = 1;
|
||||
staticSamplers[1].BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK;
|
||||
staticSamplers[1].MinLOD = 0;
|
||||
staticSamplers[1].MaxLOD = D3D12_FLOAT32_MAX;
|
||||
staticSamplers[1].ShaderRegister = 1;
|
||||
staticSamplers[1].RegisterSpace = 0;
|
||||
staticSamplers[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
// Linear Wrap
|
||||
staticSamplers[2].Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
staticSamplers[2].AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
staticSamplers[2].AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
staticSamplers[2].AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
staticSamplers[2].MipLODBias = 0.0f;
|
||||
staticSamplers[2].MaxAnisotropy = 1;
|
||||
staticSamplers[2].BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK;
|
||||
staticSamplers[2].MinLOD = 0;
|
||||
staticSamplers[2].MaxLOD = D3D12_FLOAT32_MAX;
|
||||
staticSamplers[2].ShaderRegister = 2;
|
||||
staticSamplers[2].RegisterSpace = 0;
|
||||
staticSamplers[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
// Point Wrap
|
||||
staticSamplers[3].Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||||
staticSamplers[3].AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
staticSamplers[3].AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
staticSamplers[3].AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||
staticSamplers[3].MipLODBias = 0.0f;
|
||||
staticSamplers[3].MaxAnisotropy = 1;
|
||||
staticSamplers[3].BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK;
|
||||
staticSamplers[3].MinLOD = 0;
|
||||
staticSamplers[3].MaxLOD = D3D12_FLOAT32_MAX;
|
||||
staticSamplers[3].ShaderRegister = 3;
|
||||
staticSamplers[3].RegisterSpace = 0;
|
||||
staticSamplers[3].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
// Shadow
|
||||
staticSamplers[4].Filter = D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT;
|
||||
staticSamplers[4].AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
staticSamplers[4].AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
staticSamplers[4].AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
staticSamplers[4].MipLODBias = 0.0f;
|
||||
staticSamplers[4].MaxAnisotropy = 1;
|
||||
staticSamplers[4].ComparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
|
||||
staticSamplers[4].BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK;
|
||||
staticSamplers[4].MinLOD = 0;
|
||||
staticSamplers[4].MaxLOD = D3D12_FLOAT32_MAX;
|
||||
staticSamplers[4].ShaderRegister = 4;
|
||||
staticSamplers[4].RegisterSpace = 0;
|
||||
staticSamplers[4].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
// Shadow PCF
|
||||
staticSamplers[5].Filter = D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR;
|
||||
staticSamplers[5].AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
staticSamplers[5].AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
staticSamplers[5].AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
staticSamplers[5].MipLODBias = 0.0f;
|
||||
staticSamplers[5].MaxAnisotropy = 1;
|
||||
staticSamplers[5].ComparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
|
||||
staticSamplers[5].BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK;
|
||||
staticSamplers[5].MinLOD = 0;
|
||||
staticSamplers[5].MaxLOD = D3D12_FLOAT32_MAX;
|
||||
staticSamplers[5].ShaderRegister = 5;
|
||||
staticSamplers[5].RegisterSpace = 0;
|
||||
staticSamplers[5].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
|
||||
// Init
|
||||
D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc;
|
||||
rootSignatureDesc.NumParameters = ARRAY_COUNT(rootParameters);
|
||||
rootSignatureDesc.pParameters = rootParameters;
|
||||
rootSignatureDesc.NumStaticSamplers = ARRAY_COUNT(staticSamplers);
|
||||
rootSignatureDesc.pStaticSamplers = staticSamplers;
|
||||
rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
|
||||
|
||||
// Serialize
|
||||
ComPtr<ID3DBlob> signature;
|
||||
ComPtr<ID3DBlob> error;
|
||||
VALIDATE_DIRECTX_CALL(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error));
|
||||
|
||||
// Create
|
||||
VALIDATE_DIRECTX_CALL(_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&_rootSignature)));
|
||||
RootSignatureDX12 signature;
|
||||
ComPtr<ID3DBlob> signatureBlob = signature.Serialize();
|
||||
VALIDATE_DIRECTX_CALL(_device->CreateRootSignature(0, signatureBlob->GetBufferPointer(), signatureBlob->GetBufferSize(), IID_PPV_ARGS(&_rootSignature)));
|
||||
}
|
||||
|
||||
if (TimestampQueryHeap.Init())
|
||||
|
||||
@@ -18,11 +18,6 @@
|
||||
#define DX12_BACK_BUFFER_COUNT 2
|
||||
#endif
|
||||
|
||||
#define DX12_ROOT_SIGNATURE_CB 0
|
||||
#define DX12_ROOT_SIGNATURE_SR (GPU_MAX_CB_BINDED+0)
|
||||
#define DX12_ROOT_SIGNATURE_UA (GPU_MAX_CB_BINDED+1)
|
||||
#define DX12_ROOT_SIGNATURE_SAMPLER (GPU_MAX_CB_BINDED+2)
|
||||
|
||||
class Engine;
|
||||
class WindowsWindow;
|
||||
class GPUContextDX12;
|
||||
|
||||
@@ -159,7 +159,7 @@ bool GPUTextureDX12::OnInit()
|
||||
initialState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
||||
|
||||
// Create texture
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS && 0
|
||||
D3D12_HEAP_FLAGS heapFlags = useRTV || useDSV ? D3D12_HEAP_FLAG_CREATE_NOT_ZEROED : D3D12_HEAP_FLAG_NONE;
|
||||
#else
|
||||
D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Graphics/Config.h"
|
||||
#include "../IncludeDirectXHeaders.h"
|
||||
|
||||
#define DX12_ROOT_SIGNATURE_CB 0
|
||||
#define DX12_ROOT_SIGNATURE_SR (GPU_MAX_CB_BINDED+0)
|
||||
#define DX12_ROOT_SIGNATURE_UA (GPU_MAX_CB_BINDED+1)
|
||||
#define DX12_ROOT_SIGNATURE_SAMPLER (GPU_MAX_CB_BINDED+2)
|
||||
|
||||
struct RootSignatureDX12
|
||||
{
|
||||
private:
|
||||
D3D12_ROOT_SIGNATURE_DESC _desc;
|
||||
D3D12_DESCRIPTOR_RANGE _ranges[3];
|
||||
D3D12_ROOT_PARAMETER _parameters[GPU_MAX_CB_BINDED + 3];
|
||||
D3D12_STATIC_SAMPLER_DESC _staticSamplers[6];
|
||||
|
||||
public:
|
||||
RootSignatureDX12();
|
||||
|
||||
ComPtr<ID3DBlob> Serialize() const;
|
||||
#if USE_EDITOR
|
||||
void ToString(class StringBuilder& sb, bool singleLine = false) const;
|
||||
String ToString() const;
|
||||
StringAnsi ToStringAnsi() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
void InitSampler(int32 i, D3D12_FILTER filter, D3D12_TEXTURE_ADDRESS_MODE address, D3D12_COMPARISON_FUNC comparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL);
|
||||
};
|
||||
@@ -177,7 +177,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void ClearState() override
|
||||
void ResetState() override
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ GPUContextVulkan::GPUContextVulkan(GPUDeviceVulkan* device, QueueVulkan* queue)
|
||||
#if GPU_ENABLE_TRACY
|
||||
#if VK_EXT_calibrated_timestamps && VK_EXT_host_query_reset && !PLATFORM_SWITCH
|
||||
// Use calibrated timestamps extension
|
||||
if (vkResetQueryPoolEXT && vkGetCalibratedTimestampsEXT)
|
||||
if (vkResetQueryPoolEXT && vkGetCalibratedTimestampsEXT && _device->PhysicalDeviceFeatures12.hostQueryReset)
|
||||
{
|
||||
_tracyContext = tracy::CreateVkContext(_device->Adapter->Gpu, _device->Device, vkResetQueryPoolEXT, vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, vkGetCalibratedTimestampsEXT);
|
||||
}
|
||||
@@ -192,6 +192,7 @@ void GPUContextVulkan::AddImageBarrier(VkImage image, VkImageLayout srcLayout, V
|
||||
|
||||
void GPUContextVulkan::AddImageBarrier(GPUTextureViewVulkan* handle, VkImageLayout dstLayout)
|
||||
{
|
||||
ASSERT(handle->Owner);
|
||||
auto& state = handle->Owner->State;
|
||||
const auto subresourceIndex = handle->SubresourceIndex;
|
||||
if (subresourceIndex == -1)
|
||||
@@ -516,7 +517,7 @@ void GPUContextVulkan::UpdateDescriptorSets(const SpirvShaderDescriptorInfo& des
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
||||
{
|
||||
auto handle = (GPUTextureViewVulkan*)handles[slot];
|
||||
if (!handle)
|
||||
if (!handle || !handle->Owner)
|
||||
{
|
||||
const auto dummy = _device->HelperResources.GetDummyTexture(descriptor.ResourceType);
|
||||
switch (descriptor.ResourceType)
|
||||
@@ -1328,7 +1329,7 @@ void GPUContextVulkan::SetState(GPUPipelineState* state)
|
||||
}
|
||||
}
|
||||
|
||||
void GPUContextVulkan::ClearState()
|
||||
void GPUContextVulkan::ResetState()
|
||||
{
|
||||
ResetRenderTarget();
|
||||
ResetSR();
|
||||
|
||||
@@ -193,7 +193,7 @@ public:
|
||||
void SetScissor(const Rectangle& scissorRect) override;
|
||||
GPUPipelineState* GetState() const override;
|
||||
void SetState(GPUPipelineState* state) override;
|
||||
void ClearState() override;
|
||||
void ResetState() override;
|
||||
void FlushState() override;
|
||||
void Flush() override;
|
||||
void UpdateBuffer(GPUBuffer* buffer, const void* data, uint32 size, uint32 offset) override;
|
||||
|
||||
@@ -1568,7 +1568,15 @@ bool GPUDeviceVulkan::Init()
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queueCount, QueueFamilyProps.Get());
|
||||
|
||||
// Query device features
|
||||
RenderToolsVulkan::ZeroStruct(PhysicalDeviceFeatures12, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES);
|
||||
vkGetPhysicalDeviceFeatures(gpu, &PhysicalDeviceFeatures);
|
||||
if (vkGetPhysicalDeviceFeatures2)
|
||||
{
|
||||
VkPhysicalDeviceFeatures2 features2;
|
||||
RenderToolsVulkan::ZeroStruct(features2, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2);
|
||||
features2.pNext = &PhysicalDeviceFeatures12;
|
||||
vkGetPhysicalDeviceFeatures2(gpu, &features2);
|
||||
}
|
||||
|
||||
// Get extensions and layers
|
||||
Array<const char*> deviceExtensions;
|
||||
@@ -1671,6 +1679,16 @@ bool GPUDeviceVulkan::Init()
|
||||
VulkanPlatform::RestrictEnabledPhysicalDeviceFeatures(PhysicalDeviceFeatures, enabledFeatures);
|
||||
deviceInfo.pEnabledFeatures = &enabledFeatures;
|
||||
|
||||
#if GPU_ENABLE_TRACY && VK_EXT_calibrated_timestamps && VK_EXT_host_query_reset
|
||||
VkPhysicalDeviceHostQueryResetFeatures resetFeatures;
|
||||
if (PhysicalDeviceFeatures12.hostQueryReset)
|
||||
{
|
||||
RenderToolsVulkan::ZeroStruct(resetFeatures, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES);
|
||||
resetFeatures.hostQueryReset = VK_TRUE;
|
||||
deviceInfo.pNext = &resetFeatures;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Create the device
|
||||
VALIDATE_VULKAN_RESULT(vkCreateDevice(gpu, &deviceInfo, nullptr, &Device));
|
||||
|
||||
|
||||
@@ -496,6 +496,7 @@ public:
|
||||
/// The physical device enabled features.
|
||||
/// </summary>
|
||||
VkPhysicalDeviceFeatures PhysicalDeviceFeatures;
|
||||
VkPhysicalDeviceVulkan12Features PhysicalDeviceFeatures12;
|
||||
|
||||
Array<BufferedQueryPoolVulkan*> TimestampQueryPools;
|
||||
Array<BufferedQueryPoolVulkan*> OcclusionQueryPools;
|
||||
|
||||
@@ -554,10 +554,11 @@ void AnimatedModel::StopSlotAnimation(const StringView& slotName, Animation* ani
|
||||
{
|
||||
for (auto& slot : GraphInstance.Slots)
|
||||
{
|
||||
if (slot.Animation == anim && slot.Name == slotName)
|
||||
if ((slot.Animation == anim || anim == nullptr) && slot.Name == slotName)
|
||||
{
|
||||
//slot.Animation = nullptr; // TODO: make an immediate version of this method and set the animation to nullptr.
|
||||
slot.Reset = true;
|
||||
if (slot.Animation != nullptr)
|
||||
slot.Reset = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -573,7 +574,7 @@ void AnimatedModel::PauseSlotAnimation(const StringView& slotName, Animation* an
|
||||
{
|
||||
for (auto& slot : GraphInstance.Slots)
|
||||
{
|
||||
if (slot.Animation == anim && slot.Name == slotName)
|
||||
if ((slot.Animation == anim || anim == nullptr) && slot.Name == slotName)
|
||||
{
|
||||
slot.Pause = true;
|
||||
break;
|
||||
@@ -595,7 +596,7 @@ bool AnimatedModel::IsPlayingSlotAnimation(const StringView& slotName, Animation
|
||||
{
|
||||
for (auto& slot : GraphInstance.Slots)
|
||||
{
|
||||
if (slot.Animation == anim && slot.Name == slotName && !slot.Pause)
|
||||
if ((slot.Animation == anim || anim == nullptr) && slot.Name == slotName && !slot.Pause)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -412,8 +412,8 @@ public:
|
||||
/// Stops the animation playback on the slot in Anim Graph.
|
||||
/// </summary>
|
||||
/// <param name="slotName">The name of the slot.</param>
|
||||
/// <param name="anim">The animation to stop.</param>
|
||||
API_FUNCTION() void StopSlotAnimation(const StringView& slotName, Animation* anim);
|
||||
/// <param name="anim">The animation to check. Null to use slot name only.</param>
|
||||
API_FUNCTION() void StopSlotAnimation(const StringView& slotName, Animation* anim = nullptr);
|
||||
|
||||
/// <summary>
|
||||
/// Pauses all the animations playback on the all slots in Anim Graph.
|
||||
@@ -424,8 +424,8 @@ public:
|
||||
/// Pauses the animation playback on the slot in Anim Graph.
|
||||
/// </summary>
|
||||
/// <param name="slotName">The name of the slot.</param>
|
||||
/// <param name="anim">The animation to pause.</param>
|
||||
API_FUNCTION() void PauseSlotAnimation(const StringView& slotName, Animation* anim);
|
||||
/// <param name="anim">The animation to check. Null to use slot name only.</param>
|
||||
API_FUNCTION() void PauseSlotAnimation(const StringView& slotName, Animation* anim = nullptr);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if any animation playback is active on any slot in Anim Graph (not paused).
|
||||
@@ -436,8 +436,8 @@ public:
|
||||
/// Checks if the animation playback is active on the slot in Anim Graph (not paused).
|
||||
/// </summary>
|
||||
/// <param name="slotName">The name of the slot.</param>
|
||||
/// <param name="anim">The animation to check.</param>
|
||||
API_FUNCTION() bool IsPlayingSlotAnimation(const StringView& slotName, Animation* anim);
|
||||
/// <param name="anim">The animation to check. Null to use slot name only.</param>
|
||||
API_FUNCTION() bool IsPlayingSlotAnimation(const StringView& slotName, Animation* anim = nullptr);
|
||||
|
||||
private:
|
||||
void ApplyRootMotion(const Transform& rootMotionDelta);
|
||||
|
||||
@@ -42,38 +42,38 @@ public:
|
||||
/// <summary>
|
||||
/// The reflections texture resolution.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(0), EditorDisplay(\"Probe\")")
|
||||
API_FIELD(Attributes="EditorOrder(0), EditorDisplay(\"Quality\")")
|
||||
ProbeCubemapResolution CubemapResolution = ProbeCubemapResolution::UseGraphicsSettings;
|
||||
|
||||
/// <summary>
|
||||
/// The probe update mode.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes = "EditorOrder(10), EditorDisplay(\"Quality\")")
|
||||
ProbeUpdateMode UpdateMode = ProbeUpdateMode::Manual;
|
||||
|
||||
/// <summary>
|
||||
/// The reflections brightness.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(10), Limit(0, 1000, 0.01f), EditorDisplay(\"Probe\")")
|
||||
API_FIELD(Attributes="EditorOrder(0), Limit(0, 1000, 0.01f), EditorDisplay(\"Probe\")")
|
||||
float Brightness = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The probe rendering order. The higher values are render later (on top).
|
||||
/// </summary>
|
||||
API_FIELD(Attributes = "EditorOrder(25), EditorDisplay(\"Probe\")")
|
||||
API_FIELD(Attributes = "EditorOrder(20), EditorDisplay(\"Probe\")")
|
||||
int32 SortOrder = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The probe update mode.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(30), EditorDisplay(\"Probe\")")
|
||||
ProbeUpdateMode UpdateMode = ProbeUpdateMode::Manual;
|
||||
|
||||
/// <summary>
|
||||
/// The probe capture camera near plane distance.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(30), Limit(0, float.MaxValue, 0.01f), EditorDisplay(\"Probe\")")
|
||||
API_FIELD(Attributes="EditorOrder(25), Limit(0, float.MaxValue, 0.01f), EditorDisplay(\"Probe\")")
|
||||
float CaptureNearPlane = 10.0f;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Gets the probe radius.
|
||||
/// </summary>
|
||||
API_PROPERTY(Attributes="EditorOrder(20), DefaultValue(3000.0f), Limit(0), EditorDisplay(\"Probe\")")
|
||||
API_PROPERTY(Attributes="EditorOrder(15), DefaultValue(3000.0f), Limit(0), EditorDisplay(\"Probe\")")
|
||||
float GetRadius() const;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -518,7 +518,7 @@ namespace
|
||||
Vector3 nextPos = transform.LocalToWorld(next->Value.Translation);
|
||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(nextPos, NodeSizeByDistance(nextPos, scaleByDistance)), color, 0.0f, depthTest);
|
||||
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, transform.LocalToWorld(prev->Value.Translation + prev->TangentOut.Translation * d), transform.LocalToWorld(next->Value.Translation + next->TangentIn.Translation * d), nextPos, color, 0.0f, depthTest);
|
||||
prev = next;
|
||||
prevPos = nextPos;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ const Char* GetCommandLine(int argc, char* argv[])
|
||||
const Char* cmdLine;
|
||||
if (length != 0)
|
||||
{
|
||||
Char* str = (Char*)malloc(length * sizeof(Char));
|
||||
Char* str = (Char*)malloc((length + 1) * sizeof(Char));
|
||||
cmdLine = str;
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#endif
|
||||
|
||||
// Internal version number of networking implementation. Updated once engine changes serialization or connection rules.
|
||||
#define NETWORK_PROTOCOL_VERSION 4
|
||||
#define NETWORK_PROTOCOL_VERSION 5
|
||||
|
||||
// Enables encoding object ids and typenames via uint32 keys rather than full data send.
|
||||
#define USE_NETWORK_KEYS 1
|
||||
@@ -29,6 +29,7 @@ enum class NetworkMessageIDs : uint8
|
||||
ObjectDespawn,
|
||||
ObjectRole,
|
||||
ObjectRpc,
|
||||
ObjectRpcPart,
|
||||
|
||||
MAX,
|
||||
};
|
||||
@@ -48,6 +49,7 @@ public:
|
||||
static void OnNetworkMessageObjectDespawn(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
||||
static void OnNetworkMessageObjectRole(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
||||
static void OnNetworkMessageObjectRpc(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
||||
static void OnNetworkMessageObjectRpcPart(NetworkEvent& event, NetworkClient* client, NetworkPeer* peer);
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
|
||||
|
||||
@@ -391,6 +391,7 @@ namespace
|
||||
NetworkInternal::OnNetworkMessageObjectDespawn,
|
||||
NetworkInternal::OnNetworkMessageObjectRole,
|
||||
NetworkInternal::OnNetworkMessageObjectRpc,
|
||||
NetworkInternal::OnNetworkMessageObjectRpcPart,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user