Compare commits
126 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3bf3264f48 | |||
| b043490413 | |||
| 48f302b4fd | |||
| d9c787a661 | |||
| ec9f05fe11 | |||
| b039e3779d | |||
| fc8a9b69d2 | |||
| b38f6c5721 | |||
| 0c1af2f243 | |||
| 7f2ba7a81e | |||
| fb21ffd3be | |||
| 7127ccda37 | |||
| ead71e6836 | |||
| 241441d5b9 | |||
| 14b0fb355a | |||
| 4489f43777 | |||
| c17a9f653e | |||
| e7fd901807 | |||
| bdabcd5e43 | |||
| 6cc8f693f3 | |||
| 1079791bed | |||
| 627f3a2dec | |||
| 2f05a0987e | |||
| 6335bcdc93 | |||
| 650fa781d3 | |||
| 000d786d49 | |||
| 3eb85000aa | |||
| 9c5daf419b | |||
| 9a85ae7142 | |||
| fad0f7a345 | |||
| aac399c6a1 | |||
| 4c5035e433 | |||
| b14c2cfc74 | |||
| cbcfa4013b | |||
| 429f8e5336 | |||
| 6cc0edf0eb | |||
| f7d8f36add | |||
| 2e98300693 | |||
| 83de99877c | |||
| 7a569d4f14 | |||
| 24675ace93 | |||
| 3a5d831e71 | |||
| 0aecb35ab1 | |||
| c4bb39aeac | |||
| 61431a6400 | |||
| d4da1d80d0 | |||
| 3bede1d6bc | |||
| ce4ad8aa71 | |||
| 75bd206416 | |||
| 578af12f2b | |||
| acbbd34ecf | |||
| c8b06ba7ec | |||
| ad46b74f6a | |||
| 47a9d76938 | |||
| 442cb8f2dd | |||
| 45e121bf77 | |||
| 8e76d0d9d8 | |||
| f4905cfccc | |||
| bf9a015959 | |||
| 4fd7f51fdf | |||
| f5e483069d | |||
| 0bd28ecb65 | |||
| 9eec54171c | |||
| 486781661e | |||
| b201897ae6 | |||
| c33ada2715 | |||
| dcb9b5150f | |||
| f905b4013b | |||
| b0033a35b7 | |||
| f47a2909fe | |||
| b1c76ec7f9 | |||
| db2130f340 | |||
| edb3badcb3 | |||
| c33b2cc11e | |||
| 135110387d | |||
| 6b3502675a | |||
| 615e847e01 | |||
| 468e05c6e8 | |||
| a46402df6b | |||
| 1fa9aadebd | |||
| c0f52235c6 | |||
| c782f07b76 | |||
| dc9a8a2f84 | |||
| 49943e13de | |||
| 1988fae929 | |||
| 804315bb3e | |||
| 0cacc58b53 | |||
| 7437b69d52 | |||
| f5f4fb29f2 | |||
| 33617a702a | |||
| 84b53bb9c8 | |||
| c3ea883b21 | |||
| f41d01f4a9 | |||
| 141a8de0da | |||
| 63b6fafa1b | |||
| 2ce1103530 | |||
| 6121a6fadf | |||
| 145134f145 | |||
| 3f78e47918 | |||
| 7b4a9f1a63 | |||
| 561d40fd71 | |||
| 133340b2ea | |||
| 344665e34f | |||
| 5d188c8c2d | |||
| 9447f3d569 | |||
| df8dc9173a | |||
| b186d19faa | |||
| ea749f12a3 | |||
| 74750fd604 | |||
| b52e8bad4c | |||
| 44f8e86245 | |||
| b036692154 | |||
| 5d050ca020 | |||
| 1b6a31b6e5 | |||
| ab4743fdb1 | |||
| 49629222c1 | |||
| 9d6778ff1e | |||
| ce73394531 | |||
| 463c8dba0d | |||
| 9bb6104cf7 | |||
| 151f4a4923 | |||
| 36f588a792 | |||
| 07c7a250cc | |||
| eab4a8c404 | |||
| cde3e3d710 | |||
| a8dc67a1b2 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
+3
-2
@@ -2,9 +2,9 @@
|
||||
"Name": "Flax",
|
||||
"Version": {
|
||||
"Major": 1,
|
||||
"Minor": 12,
|
||||
"Minor": 13,
|
||||
"Revision": 0,
|
||||
"Build": 6912
|
||||
"Build": 7003
|
||||
},
|
||||
"Company": "Flax",
|
||||
"Copyright": "Copyright (c) 2012-2026 Wojciech Figat. All rights reserved.",
|
||||
@@ -13,6 +13,7 @@
|
||||
"Configuration": {
|
||||
"UseCSharp": true,
|
||||
"UseLargeWorlds": false,
|
||||
"UseReverseZ": true,
|
||||
"UseDotNet": true,
|
||||
"Windows": {
|
||||
"UseSDL": false,
|
||||
|
||||
@@ -257,6 +257,7 @@
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/GrammarAndSpelling/GrammarChecking/Exceptions/=Try_0020to_0020scripting/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/GrammarAndSpelling/GrammarChecking/Exceptions/=will_0020fallback/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:String x:Key="/Default/GrammarAndSpelling/GrammarChecking/RulesStates/=LanguageTool_002EEN_002EE_005FG/@EntryIndexedValue">DisabledByUser</s:String>
|
||||
<s:Boolean x:Key="/Default/PatternsAndTemplates/Todo/TodoPatterns/=EEA05B0ED8200E4BA9D2D3F1052EBFFD/@KeyIndexDefined">True</s:Boolean>
|
||||
<s:String x:Key="/Default/PatternsAndTemplates/Todo/TodoPatterns/=EEA05B0ED8200E4BA9D2D3F1052EBFFD/Color/@EntryValue">Blue</s:String>
|
||||
|
||||
@@ -360,6 +360,11 @@ public:
|
||||
/// </summary>
|
||||
Array<BinaryModuleInfo, InlinedAllocation<64>> BinaryModules;
|
||||
|
||||
/// <summary>
|
||||
/// Cached version of the built binaries from project Version Control.
|
||||
/// </summary>
|
||||
String VersionControlInfo;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -42,6 +42,13 @@ bool CompileScriptsStep::DeployBinaries(CookingData& data, const String& path, c
|
||||
return true;
|
||||
}
|
||||
|
||||
// Metadata
|
||||
auto versionControlInfoMember = document.FindMember("VersionControlInfo");
|
||||
if (versionControlInfoMember != document.MemberEnd() && data.VersionControlInfo.IsEmpty())
|
||||
{
|
||||
data.VersionControlInfo = versionControlInfoMember->value.GetText();
|
||||
}
|
||||
|
||||
// Deploy all references
|
||||
auto referencesMember = document.FindMember("References");
|
||||
if (referencesMember != document.MemberEnd())
|
||||
@@ -245,8 +252,15 @@ bool CompileScriptsStep::Perform(CookingData& data)
|
||||
writer.String(target);
|
||||
writer.JKEY("Platform");
|
||||
writer.String(platform);
|
||||
writer.JKEY("Architecture");
|
||||
writer.String(architecture);
|
||||
writer.JKEY("Configuration");
|
||||
writer.String(configuration);
|
||||
if (data.VersionControlInfo.HasChars())
|
||||
{
|
||||
writer.JKEY("VersionControlInfo");
|
||||
writer.String(data.VersionControlInfo);
|
||||
}
|
||||
|
||||
writer.JKEY("BinaryModules");
|
||||
writer.StartArray();
|
||||
|
||||
@@ -50,6 +50,10 @@
|
||||
#endif
|
||||
#include "FlaxEngine.Gen.h"
|
||||
|
||||
#ifndef REVERSE_Z
|
||||
#define REVERSE_Z 0
|
||||
#endif
|
||||
|
||||
Dictionary<String, CookAssetsStep::ProcessAssetFunc> CookAssetsStep::AssetProcessors;
|
||||
|
||||
void IBuildCache::InvalidateCacheShaders()
|
||||
@@ -233,6 +237,11 @@ void CookAssetsStep::CacheData::Load(CookingData& data)
|
||||
LOG(Info, "{0} option has been modified.", TEXT("ShadersGenerateDebugData"));
|
||||
invalidateShaders = true;
|
||||
}
|
||||
if (REVERSE_Z != Settings.Global.ShadersReverseZ)
|
||||
{
|
||||
LOG(Info, "{0} option has been modified.", TEXT("ShadersReverseZ"));
|
||||
invalidateShaders = true;
|
||||
}
|
||||
#if PLATFORM_TOOLS_WINDOWS
|
||||
if (data.Platform == BuildPlatform::Windows32 || data.Platform == BuildPlatform::Windows64)
|
||||
{
|
||||
@@ -1076,6 +1085,7 @@ bool CookAssetsStep::Perform(CookingData& data)
|
||||
{
|
||||
cache.Settings.Global.ShadersNoOptimize = buildSettings->ShadersNoOptimize;
|
||||
cache.Settings.Global.ShadersGenerateDebugData = buildSettings->ShadersGenerateDebugData;
|
||||
cache.Settings.Global.ShadersReverseZ = REVERSE_Z;
|
||||
cache.Settings.Global.StreamingSettingsAssetId = gameSettings->Streaming;
|
||||
cache.Settings.Global.ShadersVersion = GPU_SHADER_CACHE_VERSION;
|
||||
cache.Settings.Global.MaterialGraphVersion = MATERIAL_GRAPH_VERSION;
|
||||
|
||||
@@ -97,6 +97,7 @@ public:
|
||||
{
|
||||
bool ShadersNoOptimize;
|
||||
bool ShadersGenerateDebugData;
|
||||
bool ShadersReverseZ;
|
||||
Guid StreamingSettingsAssetId;
|
||||
int32 ShadersVersion;
|
||||
int32 MaterialGraphVersion;
|
||||
|
||||
@@ -261,6 +261,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
public static List<ItemInfo> GetItemsForType(ScriptType type, bool useProperties, bool useFields, bool usePropertiesWithoutSetter = false)
|
||||
{
|
||||
var items = new List<ItemInfo>();
|
||||
var isPlayMode = Editor.IsPlayMode;
|
||||
|
||||
if (useProperties)
|
||||
{
|
||||
@@ -278,7 +279,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
continue;
|
||||
|
||||
// Skip hidden fields, handle special attributes
|
||||
if ((!p.IsPublic && !showInEditor) || attributes.Any(x => x is HideInEditorAttribute))
|
||||
if ((!p.IsPublic && !showInEditor) || attributes.Any(x => x is HideInEditorAttribute hide && (!isPlayMode || !hide.ShowInPlayMode)))
|
||||
continue;
|
||||
|
||||
items.Add(new ItemInfo(p, attributes));
|
||||
@@ -293,11 +294,10 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
for (int i = 0; i < fields.Length; i++)
|
||||
{
|
||||
var f = fields[i];
|
||||
|
||||
var attributes = f.GetAttributes(true);
|
||||
|
||||
// Skip hidden fields, handle special attributes
|
||||
if ((!f.IsPublic && !attributes.Any(x => x is ShowInEditorAttribute)) || attributes.Any(x => x is HideInEditorAttribute))
|
||||
if ((!f.IsPublic && !attributes.Any(x => x is ShowInEditorAttribute)) || attributes.Any(x => x is HideInEditorAttribute hide && (!isPlayMode || !hide.ShowInPlayMode)))
|
||||
continue;
|
||||
|
||||
items.Add(new ItemInfo(f, attributes));
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using System;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
/// <summary>
|
||||
/// Default implementation of the inspector used to edit TimeSpan value type properties.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(TimeSpan)), DefaultEditor]
|
||||
class TimeSpanEditor : CustomEditor
|
||||
{
|
||||
private TextBox _textBox;
|
||||
private bool _isRefreshing;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DisplayStyle Style => DisplayStyle.Inline;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
if (HasDifferentTypes)
|
||||
return;
|
||||
|
||||
_textBox = layout.Custom<TextBox>().CustomControl;
|
||||
_textBox.EditEnd += OnEditEnd;
|
||||
}
|
||||
|
||||
private void OnEditEnd()
|
||||
{
|
||||
if (_isRefreshing)
|
||||
return;
|
||||
if (TimeSpan.TryParse(_textBox.Text, out var timeSpan))
|
||||
SetValue(timeSpan);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
_isRefreshing = true;
|
||||
_textBox.Text = HasDifferentValues ? "Multiple Values" : ((TimeSpan)Values[0]).ToString("G");
|
||||
_isRefreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default implementation of the inspector used to edit DateTime value type properties.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(DateTime)), DefaultEditor]
|
||||
class DateTimeEditor : CustomEditor
|
||||
{
|
||||
private TextBox _textBox;
|
||||
private bool _isRefreshing;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DisplayStyle Style => DisplayStyle.Inline;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
if (HasDifferentTypes)
|
||||
return;
|
||||
|
||||
_textBox = layout.Custom<TextBox>().CustomControl;
|
||||
_textBox.EditEnd += OnEditEnd;
|
||||
}
|
||||
|
||||
private void OnEditEnd()
|
||||
{
|
||||
if (_isRefreshing)
|
||||
return;
|
||||
if (DateTime.TryParse(_textBox.Text, out var timeSpan))
|
||||
SetValue(timeSpan);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
_isRefreshing = true;
|
||||
_textBox.Text = HasDifferentValues ? "Multiple Values" : ((DateTime)Values[0]).ToString("g");
|
||||
_isRefreshing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,15 +139,11 @@ namespace FlaxEditor.Gizmo
|
||||
DrawSelectionDepth(context, renderContext.Task, customDepth);
|
||||
_actors.Clear();
|
||||
|
||||
var near = renderContext.View.Near;
|
||||
var far = renderContext.View.Far;
|
||||
var projection = renderContext.View.Projection;
|
||||
|
||||
// Render outline
|
||||
_material.SetParameterValue("OutlineColor0", _color0);
|
||||
_material.SetParameterValue("OutlineColor1", _color1);
|
||||
_material.SetParameterValue("CustomDepth", customDepth);
|
||||
_material.SetParameterValue("ViewInfo", new Float4(1.0f / projection.M11, 1.0f / projection.M22, far / (far - near), (-far * near) / (far - near) / far));
|
||||
_material.SetParameterValue("ViewInfo", renderContext.View.ViewInfo);
|
||||
Renderer.DrawPostFxMaterial(context, ref renderContext, _material, output, input.View());
|
||||
|
||||
// Cleanup
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace FlaxEditor.Modules
|
||||
private bool _rebuildInitFlag;
|
||||
private int _itemsCreated;
|
||||
private int _itemsDeleted;
|
||||
private readonly HashSet<MainContentFolderTreeNode> _dirtyNodes = new HashSet<MainContentFolderTreeNode>();
|
||||
private readonly HashSet<ContentFolderTreeNode> _dirtyNodes = new HashSet<ContentFolderTreeNode>();
|
||||
|
||||
/// <summary>
|
||||
/// The project directory.
|
||||
@@ -1309,26 +1309,31 @@ namespace FlaxEditor.Modules
|
||||
|
||||
internal void OnDirectoryEvent(MainContentFolderTreeNode node, FileSystemEventArgs e)
|
||||
{
|
||||
// Ensure to be ready for external events
|
||||
// Ignore events during fast setup
|
||||
if (_isDuringFastSetup)
|
||||
return;
|
||||
ContentFolderTreeNode dirtyNode = node;
|
||||
|
||||
// TODO: maybe we could make it faster! since we have a path so it would be easy to just create or delete given file. but remember about subdirectories
|
||||
// Filter the node based on modified path
|
||||
// (eg. if we have event for 'Content/Folder1/Folder2' and node is 'Content/Folder1' then we should process but skip other 'Content' subfolders)
|
||||
var path = StringUtils.NormalizePath(Path.GetDirectoryName(e.FullPath));
|
||||
var pathItem = node.Folder.Find(path) as ContentFolder;
|
||||
if (pathItem != null)
|
||||
{
|
||||
dirtyNode = pathItem.Node;
|
||||
}
|
||||
|
||||
// Switch type
|
||||
switch (e.ChangeType)
|
||||
{
|
||||
case WatcherChangeTypes.Created:
|
||||
case WatcherChangeTypes.Deleted:
|
||||
case WatcherChangeTypes.Renamed:
|
||||
{
|
||||
lock (_dirtyNodes)
|
||||
{
|
||||
_dirtyNodes.Add(node);
|
||||
_dirtyNodes.Add(dirtyNode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnScriptsReload()
|
||||
@@ -1383,14 +1388,15 @@ namespace FlaxEditor.Modules
|
||||
// Update all dirty content tree nodes
|
||||
lock (_dirtyNodes)
|
||||
{
|
||||
Profiler.BeginEvent("ContentDatabase.Refresh");
|
||||
foreach (var node in _dirtyNodes)
|
||||
{
|
||||
LoadFolder(node, true);
|
||||
|
||||
if (_enableEvents)
|
||||
WorkspaceModified?.Invoke();
|
||||
}
|
||||
if (_enableEvents && _dirtyNodes.Count != 0)
|
||||
WorkspaceModified?.Invoke();
|
||||
_dirtyNodes.Clear();
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
|
||||
// Lazy-rebuilds
|
||||
|
||||
@@ -465,6 +465,8 @@ namespace FlaxEditor.Modules
|
||||
|
||||
internal void ProgressFailed(string message)
|
||||
{
|
||||
if (StatusBar == null)
|
||||
return;
|
||||
_progressFailed = true;
|
||||
StatusBar.StatusColor = Style.Current.Statusbar.Failed;
|
||||
StatusBar.Text = message;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace FlaxEditor.Tools.Foliage
|
||||
private int _selectedInstanceIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// The foliage painting gizmo.
|
||||
/// The foliage editing gizmo.
|
||||
/// </summary>
|
||||
public EditFoliageGizmo Gizmo;
|
||||
|
||||
@@ -66,8 +66,6 @@ namespace FlaxEditor.Tools.Foliage
|
||||
base.Init(owner);
|
||||
|
||||
Gizmo = new EditFoliageGizmo(owner, this);
|
||||
SelectionOutline = FlaxEngine.Object.New<EditFoliageSelectionOutline>();
|
||||
SelectionOutline.GizmoMode = this;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -84,6 +82,11 @@ namespace FlaxEditor.Tools.Foliage
|
||||
base.OnActivated();
|
||||
|
||||
Owner.Gizmos.Active = Gizmo;
|
||||
if (SelectionOutline == null)
|
||||
{
|
||||
SelectionOutline = FlaxEngine.Object.New<EditFoliageSelectionOutline>();
|
||||
SelectionOutline.GizmoMode = this;
|
||||
}
|
||||
((MainEditorGizmoViewport)Owner).OverrideSelectionOutline(SelectionOutline);
|
||||
SelectedInstanceIndex = -1;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using FlaxEngine;
|
||||
namespace FlaxEditor.Tools.Foliage
|
||||
{
|
||||
/// <summary>
|
||||
/// The custom outline for drawing the selected foliage instances outlines.
|
||||
/// The custom outline for drawing the selected foliage instance.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Gizmo.SelectionOutline" />
|
||||
[HideInEditor]
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.Collections.Generic;
|
||||
using FlaxEditor.GUI.Tabs;
|
||||
using FlaxEditor.Modules;
|
||||
using FlaxEditor.SceneGraph.Actors;
|
||||
using FlaxEditor.Viewport.Modes;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
@@ -214,7 +213,7 @@ namespace FlaxEditor.Tools.Foliage
|
||||
|
||||
private void InitSculptMode()
|
||||
{
|
||||
var tab = _modes.AddTab(FoliageTypes = new FoliageTypesTab(this));
|
||||
var tab = _modes.AddTab(FoliageTypes = new FoliageTypesTab(this, Editor.Windows.EditWin.Viewport.EditFoliageTypesGizmo));
|
||||
tab.Selected += OnTabSelected;
|
||||
}
|
||||
|
||||
@@ -251,7 +250,7 @@ namespace FlaxEditor.Tools.Foliage
|
||||
switch (_modes.SelectedTabIndex)
|
||||
{
|
||||
case 0:
|
||||
Editor.Windows.EditWin.Viewport.Gizmos.SetActiveMode<NoGizmoMode>();
|
||||
Editor.Windows.EditWin.Viewport.Gizmos.SetActiveMode<FoliageTypesGizmoMode>();
|
||||
break;
|
||||
case 1:
|
||||
Editor.Windows.EditWin.Viewport.Gizmos.SetActiveMode<PaintFoliageGizmoMode>();
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEditor.Gizmo;
|
||||
|
||||
namespace FlaxEditor.Tools.Foliage
|
||||
{
|
||||
/// <summary>
|
||||
/// Gizmo for editing foliage types.
|
||||
/// </summary>
|
||||
public sealed class FoliageTypesGizmo : GizmoBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The parent mode.
|
||||
/// </summary>
|
||||
public readonly FoliageTypesGizmoMode GizmoMode;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EditFoliageGizmo"/> class.
|
||||
/// </summary>
|
||||
/// <param name="owner">The owner.</param>
|
||||
/// <param name="mode">The mode.</param>
|
||||
public FoliageTypesGizmo(IGizmoOwner owner, FoliageTypesGizmoMode mode)
|
||||
: base(owner)
|
||||
{
|
||||
GizmoMode = mode;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Pick()
|
||||
{
|
||||
// Get mouse ray and try to hit foliage instance
|
||||
var foliage = GizmoMode.SelectedFoliage;
|
||||
if (!foliage)
|
||||
return;
|
||||
var ray = Owner.MouseRay;
|
||||
if (foliage.Intersects(ref ray, out _, out _, out var instanceIndex))
|
||||
{
|
||||
// Select hit instance type
|
||||
var instance = foliage.GetInstance(instanceIndex);
|
||||
GizmoMode.SelectedTypeIndex = instance.Type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEditor.Gizmo;
|
||||
using FlaxEditor.SceneGraph.Actors;
|
||||
using FlaxEditor.Viewport;
|
||||
using FlaxEditor.Viewport.Modes;
|
||||
|
||||
namespace FlaxEditor.Tools.Foliage
|
||||
{
|
||||
/// <summary>
|
||||
/// Foliage types editing mode.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Viewport.Modes.EditorGizmoMode" />
|
||||
public class FoliageTypesGizmoMode : EditorGizmoMode
|
||||
{
|
||||
/// <summary>
|
||||
/// The foliage types gizmo.
|
||||
/// </summary>
|
||||
public FoliageTypesGizmo Gizmo;
|
||||
|
||||
/// <summary>
|
||||
/// The foliage type editing selection outline.
|
||||
/// </summary>
|
||||
public FoliageTypesOutline SelectionOutline;
|
||||
|
||||
/// <summary>
|
||||
/// The selected foliage type index.
|
||||
/// </summary>
|
||||
public int SelectedTypeIndex
|
||||
{
|
||||
get => Editor.Instance.Windows.ToolboxWin.Foliage.SelectedFoliageTypeIndex;
|
||||
set => Editor.Instance.Windows.ToolboxWin.Foliage.SelectedFoliageTypeIndex = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the selected foliage actor (see <see cref="Modules.SceneEditingModule"/>).
|
||||
/// </summary>
|
||||
public FlaxEngine.Foliage SelectedFoliage
|
||||
{
|
||||
get
|
||||
{
|
||||
var sceneEditing = Editor.Instance.SceneEditing;
|
||||
var foliageNode = sceneEditing.SelectionCount == 1 ? sceneEditing.Selection[0] as FoliageNode : null;
|
||||
return (FlaxEngine.Foliage)foliageNode?.Actor;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Init(IGizmoOwner owner)
|
||||
{
|
||||
base.Init(owner);
|
||||
|
||||
Gizmo = new FoliageTypesGizmo(owner, this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Dispose()
|
||||
{
|
||||
FlaxEngine.Object.Destroy(ref SelectionOutline);
|
||||
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnActivated()
|
||||
{
|
||||
base.OnActivated();
|
||||
|
||||
Owner.Gizmos.Active = Gizmo;
|
||||
if (SelectionOutline == null)
|
||||
{
|
||||
SelectionOutline = FlaxEngine.Object.New<FoliageTypesOutline>();
|
||||
SelectionOutline.GizmoMode = this;
|
||||
}
|
||||
((MainEditorGizmoViewport)Owner).OverrideSelectionOutline(SelectionOutline);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDeactivated()
|
||||
{
|
||||
((MainEditorGizmoViewport)Owner).OverrideSelectionOutline(null);
|
||||
|
||||
base.OnDeactivated();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEditor.Gizmo;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Tools.Foliage
|
||||
{
|
||||
/// <summary>
|
||||
/// The custom outline for drawing the selected foliage type.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Gizmo.SelectionOutline" />
|
||||
[HideInEditor]
|
||||
public class FoliageTypesOutline : SelectionOutline
|
||||
{
|
||||
/// <summary>
|
||||
/// The parent mode.
|
||||
/// </summary>
|
||||
public FoliageTypesGizmoMode GizmoMode;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanRender()
|
||||
{
|
||||
if (!HasDataReady)
|
||||
return false;
|
||||
|
||||
var foliage = GizmoMode.SelectedFoliage;
|
||||
if (!foliage)
|
||||
return false;
|
||||
var typeIndex = GizmoMode.SelectedTypeIndex;
|
||||
if (typeIndex < 0 || typeIndex >= foliage.FoliageTypesCount)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Render(GPUContext context, ref RenderContext renderContext, GPUTexture input, GPUTexture output)
|
||||
{
|
||||
base.Render(context, ref renderContext, input, output);
|
||||
|
||||
// Restore debug option
|
||||
var foliage = GizmoMode.SelectedFoliage;
|
||||
if (foliage)
|
||||
foliage._drawFoliageType = -1;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void DrawSelectionDepth(GPUContext context, SceneRenderTask task, GPUTexture customDepth)
|
||||
{
|
||||
var foliage = GizmoMode.SelectedFoliage;
|
||||
if (!foliage)
|
||||
return;
|
||||
var typeIndex = GizmoMode.SelectedTypeIndex;
|
||||
if (typeIndex < 0 || typeIndex >= foliage.FoliageTypesCount)
|
||||
return;
|
||||
|
||||
// Draw instances of the given type
|
||||
foliage._drawFoliageType = typeIndex;
|
||||
_actors.Add(foliage);
|
||||
Renderer.DrawSceneDepth(context, task, customDepth, _actors);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -334,7 +334,8 @@ namespace FlaxEditor.Tools.Foliage
|
||||
/// Initializes a new instance of the <see cref="FoliageTypesTab"/> class.
|
||||
/// </summary>
|
||||
/// <param name="tab">The parent tab.</param>
|
||||
public FoliageTypesTab(FoliageTab tab)
|
||||
/// <param name="mode">The gizmo mode.</param>
|
||||
public FoliageTypesTab(FoliageTab tab, FoliageTypesGizmoMode mode)
|
||||
: base("Foliage Types")
|
||||
{
|
||||
Tab = tab;
|
||||
|
||||
@@ -1514,9 +1514,14 @@ namespace FlaxEditor.Viewport
|
||||
Matrix.Multiply(ref v, ref p, out var ivp);
|
||||
ivp.Invert();
|
||||
|
||||
// Create near and far points
|
||||
var nearPoint = new Vector3(mousePosition, _nearPlane);
|
||||
var farPoint = new Vector3(mousePosition, _farPlane);
|
||||
// Create near and far points, with device depth of 1 and 0 respectively
|
||||
#if REVERSE_Z
|
||||
var nearPoint = new Vector3(mousePosition, 1.0f);
|
||||
var farPoint = new Vector3(mousePosition, 0.0f);
|
||||
#else
|
||||
var nearPoint = new Vector3(mousePosition, 0.0f);
|
||||
var farPoint = new Vector3(mousePosition, 1.0f);
|
||||
#endif
|
||||
viewport.Unproject(ref nearPoint, ref ivp, out nearPoint);
|
||||
viewport.Unproject(ref farPoint, ref ivp, out farPoint);
|
||||
|
||||
|
||||
@@ -179,12 +179,17 @@ namespace FlaxEditor.Viewport
|
||||
public Tools.Terrain.EditTerrainGizmoMode EditTerrainGizmo;
|
||||
|
||||
/// <summary>
|
||||
/// The paint foliage gizmo.
|
||||
/// The edit foliage types gizmo.
|
||||
/// </summary>
|
||||
public Tools.Foliage.FoliageTypesGizmoMode EditFoliageTypesGizmo;
|
||||
|
||||
/// <summary>
|
||||
/// The paint foliage instances gizmo.
|
||||
/// </summary>
|
||||
public Tools.Foliage.PaintFoliageGizmoMode PaintFoliageGizmo;
|
||||
|
||||
/// <summary>
|
||||
/// The edit foliage gizmo.
|
||||
/// The edit foliage instances gizmo.
|
||||
/// </summary>
|
||||
public Tools.Foliage.EditFoliageGizmoMode EditFoliageGizmo;
|
||||
|
||||
@@ -276,6 +281,7 @@ namespace FlaxEditor.Viewport
|
||||
Gizmos.AddMode(SculptTerrainGizmo = new Tools.Terrain.SculptTerrainGizmoMode());
|
||||
Gizmos.AddMode(PaintTerrainGizmo = new Tools.Terrain.PaintTerrainGizmoMode());
|
||||
Gizmos.AddMode(EditTerrainGizmo = new Tools.Terrain.EditTerrainGizmoMode());
|
||||
Gizmos.AddMode(EditFoliageTypesGizmo = new Tools.Foliage.FoliageTypesGizmoMode());
|
||||
Gizmos.AddMode(PaintFoliageGizmo = new Tools.Foliage.PaintFoliageGizmoMode());
|
||||
Gizmos.AddMode(EditFoliageGizmo = new Tools.Foliage.EditFoliageGizmoMode());
|
||||
|
||||
@@ -343,10 +349,12 @@ namespace FlaxEditor.Viewport
|
||||
/// <param name="customSelectionOutline">The custom selection outline or null if use default one.</param>
|
||||
public void OverrideSelectionOutline(SelectionOutline customSelectionOutline)
|
||||
{
|
||||
if (Task == null)
|
||||
return;
|
||||
|
||||
if (_customSelectionOutline != null)
|
||||
{
|
||||
Task.RemoveCustomPostFx(_customSelectionOutline);
|
||||
Object.Destroy(ref _customSelectionOutline);
|
||||
Task.AddCustomPostFx(customSelectionOutline ? customSelectionOutline : SelectionOutline);
|
||||
}
|
||||
else if (customSelectionOutline != null)
|
||||
@@ -530,7 +538,7 @@ namespace FlaxEditor.Viewport
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggles game view view mode on or off.
|
||||
/// Toggles view mode on/off.
|
||||
/// </summary>
|
||||
public void ToggleGameView()
|
||||
{
|
||||
@@ -547,9 +555,9 @@ namespace FlaxEditor.Viewport
|
||||
// Set flags & values
|
||||
Task.ViewFlags = _gameViewActive ? _preGameViewFlags : ViewFlags.DefaultGame;
|
||||
Task.ViewMode = _gameViewActive ? _preGameViewViewMode : ViewMode.Default;
|
||||
ShowFpsCounter = _gameViewActive ? _gameViewWasFpsCounterShown : false;
|
||||
ShowNavigation = _gameViewActive ? _gameViewWasNavigationShown : false;
|
||||
Grid.Enabled = _gameViewActive ? _gameViewWasGridShown : false;
|
||||
ShowFpsCounter = _gameViewActive && _gameViewWasFpsCounterShown;
|
||||
ShowNavigation = _gameViewActive && _gameViewWasNavigationShown;
|
||||
Grid.Enabled = _gameViewActive && _gameViewWasGridShown;
|
||||
|
||||
_gameViewActive = !_gameViewActive;
|
||||
|
||||
@@ -730,6 +738,20 @@ namespace FlaxEditor.Viewport
|
||||
base.OnLeftMouseButtonUp();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnKeyDown(KeyboardKeys key)
|
||||
{
|
||||
if (base.OnKeyDown(key))
|
||||
return true;
|
||||
|
||||
if (key == KeyboardKeys.Escape)
|
||||
{
|
||||
_editor.SceneEditing.Deselect();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
@@ -843,8 +865,8 @@ namespace FlaxEditor.Viewport
|
||||
if (_task != null)
|
||||
{
|
||||
// Release if task is not used to save screenshot for project icon
|
||||
ReleaseTaskResources();
|
||||
Object.Destroy(ref _task);
|
||||
ReleaseResources();
|
||||
}
|
||||
|
||||
base.OnDestroy();
|
||||
@@ -860,6 +882,7 @@ namespace FlaxEditor.Viewport
|
||||
_savedTask = _task;
|
||||
_savedBackBuffer = _backBuffer;
|
||||
|
||||
ReleaseTaskResources();
|
||||
_task = null;
|
||||
_backBuffer = null;
|
||||
}
|
||||
@@ -870,20 +893,20 @@ namespace FlaxEditor.Viewport
|
||||
{
|
||||
_savedTask.Enabled = false;
|
||||
Object.Destroy(_savedTask);
|
||||
ReleaseResources();
|
||||
ReleaseTaskResources();
|
||||
_savedTask = null;
|
||||
}
|
||||
Object.Destroy(ref _savedBackBuffer);
|
||||
}
|
||||
|
||||
private void ReleaseResources()
|
||||
private void ReleaseTaskResources()
|
||||
{
|
||||
if (Task)
|
||||
if (_task)
|
||||
{
|
||||
Task.RemoveCustomPostFx(SelectionOutline);
|
||||
Task.RemoveCustomPostFx(EditorPrimitives);
|
||||
Task.RemoveCustomPostFx(_editorSpritesRenderer);
|
||||
Task.RemoveCustomPostFx(_customSelectionOutline);
|
||||
_task.RemoveCustomPostFx(SelectionOutline);
|
||||
_task.RemoveCustomPostFx(EditorPrimitives);
|
||||
_task.RemoveCustomPostFx(_editorSpritesRenderer);
|
||||
_task.RemoveCustomPostFx(_customSelectionOutline);
|
||||
}
|
||||
Object.Destroy(ref SelectionOutline);
|
||||
Object.Destroy(ref EditorPrimitives);
|
||||
|
||||
@@ -233,7 +233,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
var materialInstance = proxy.Window?.Asset;
|
||||
if (materialInstance == null)
|
||||
{
|
||||
layout.Label("No parameters");
|
||||
layout.Label("No parameters", TextAlignment.Center);
|
||||
return;
|
||||
}
|
||||
if (!materialInstance.IsLoaded || (materialInstance.BaseMaterial && !materialInstance.BaseMaterial.IsLoaded))
|
||||
@@ -246,7 +246,10 @@ namespace FlaxEditor.Windows.Assets
|
||||
base.Initialize(layout);
|
||||
|
||||
if (parameters.Length == 0)
|
||||
{
|
||||
layout.Label("No parameters", TextAlignment.Center);
|
||||
return;
|
||||
}
|
||||
|
||||
var parametersGroup = SurfaceUtils.InitGraphParametersGroup(layout);
|
||||
var settingButton = parametersGroup.AddSettingsButton();
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace FlaxEditor.Windows.Profiler
|
||||
{
|
||||
Title = "Draw (GPU)",
|
||||
AnchorPreset = AnchorPresets.HorizontalStretchTop,
|
||||
Offsets = new Margin(0, 0, _drawTimeCPU.Height + 2, 0),
|
||||
Offsets = new Margin(0, 0, _drawTimeCPU.Height + 2, SingleChart.DefaultHeight),
|
||||
FormatSample = v => (Mathf.RoundToInt(v * 10.0f) / 10.0f) + " ms",
|
||||
Parent = mainPanel,
|
||||
};
|
||||
|
||||
@@ -429,6 +429,9 @@ void Asset::Reload()
|
||||
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
// Cancel any still-running loading task (e.g. if WaitForLoaded timed out)
|
||||
Platform::AtomicStore(&_loadingTask, 0);
|
||||
|
||||
if (IsLoaded())
|
||||
{
|
||||
// Unload current data
|
||||
@@ -611,6 +614,13 @@ bool Asset::onLoad(LoadAssetTask* task)
|
||||
|
||||
Locker.Lock();
|
||||
|
||||
// Re-check after acquiring lock (loading task may have been cleared by Reload, or replaced by a new task)
|
||||
if (Platform::AtomicRead(&_loadingTask) == 0)
|
||||
{
|
||||
Locker.Unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Load asset
|
||||
LoadResult result;
|
||||
#if USE_EDITOR
|
||||
|
||||
@@ -101,9 +101,9 @@ bool Material::CanUseLightmap() const
|
||||
return _materialShader && _materialShader->CanUseLightmap();
|
||||
}
|
||||
|
||||
bool Material::CanUseInstancing(InstancingHandler& handler) const
|
||||
bool Material::CanUseInstancing(const RenderContext& renderContext, InstancingHandler& handler) const
|
||||
{
|
||||
return _materialShader && _materialShader->CanUseInstancing(handler);
|
||||
return _materialShader && _materialShader->CanUseInstancing(renderContext, handler);
|
||||
}
|
||||
|
||||
void Material::Bind(BindParameters& params)
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
bool IsReady() const override;
|
||||
DrawPass GetDrawModes() const override;
|
||||
bool CanUseLightmap() const override;
|
||||
bool CanUseInstancing(InstancingHandler& handler) const override;
|
||||
bool CanUseInstancing(const RenderContext& renderContext, InstancingHandler& handler) const override;
|
||||
void Bind(BindParameters& params) override;
|
||||
|
||||
// [ShaderAssetBase]
|
||||
|
||||
@@ -168,9 +168,9 @@ bool MaterialInstance::CanUseLightmap() const
|
||||
return _baseMaterial && _baseMaterial->CanUseLightmap();
|
||||
}
|
||||
|
||||
bool MaterialInstance::CanUseInstancing(InstancingHandler& handler) const
|
||||
bool MaterialInstance::CanUseInstancing(const RenderContext& renderContext, InstancingHandler& handler) const
|
||||
{
|
||||
return _baseMaterial && _baseMaterial->CanUseInstancing(handler);
|
||||
return _baseMaterial && _baseMaterial->CanUseInstancing(renderContext, handler);
|
||||
}
|
||||
|
||||
void MaterialInstance::Bind(BindParameters& params)
|
||||
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
bool IsReady() const override;
|
||||
DrawPass GetDrawModes() const override;
|
||||
bool CanUseLightmap() const override;
|
||||
bool CanUseInstancing(InstancingHandler& handler) const override;
|
||||
bool CanUseInstancing(const RenderContext& renderContext, InstancingHandler& handler) const override;
|
||||
void Bind(BindParameters& params) override;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -27,6 +27,17 @@ API_STRUCT(NoDefault) struct FLAXENGINE_API SceneReference
|
||||
{
|
||||
return ID != other.ID;
|
||||
}
|
||||
|
||||
FORCE_INLINE SceneReference& operator=(const Guid& id)
|
||||
{
|
||||
ID = id;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FORCE_INLINE operator Guid() const
|
||||
{
|
||||
return ID;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Engine/Level/Types.h"
|
||||
#include "Engine/Debug/Exceptions/JsonParseException.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Core/Collections/HashSet.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
@@ -20,17 +21,66 @@ bool JsonStorageProxy::IsValidExtension(const StringView& extension)
|
||||
return extension == DEFAULT_SCENE_EXTENSION || extension == DEFAULT_PREFAB_EXTENSION || extension == DEFAULT_JSON_EXTENSION;
|
||||
}
|
||||
|
||||
StringAnsiView ParseJsonString(const StringAnsiView& json, int32 start)
|
||||
{
|
||||
while (start < json.Length() && json[start] != '\"')
|
||||
start++;
|
||||
int32 end = start + 1;
|
||||
while (end < json.Length() && json[end] != '\"')
|
||||
end++;
|
||||
return json.Substring(start + 1, end - start - 1);
|
||||
}
|
||||
|
||||
bool JsonStorageProxy::GetAssetInfo(const StringView& path, Guid& resultId, String& resultDataTypeName)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
// TODO: we could just open file and start reading until we find 'ID:..' without parsing whole file - could be much more faster
|
||||
PROFILE_MEM(Content);
|
||||
ZoneText(*path, path.Length());
|
||||
|
||||
// Read the first part of the file to get asset metadata (ID and TypeName)
|
||||
auto file = File::Open(path, FileMode::OpenExisting, FileAccess::Read, FileShare::All);
|
||||
if (!file)
|
||||
return false;
|
||||
Array<byte> fileData;
|
||||
fileData.Resize(256);
|
||||
uint32 read = 0;
|
||||
file->Read(fileData.Get(), fileData.Count(), &read);
|
||||
Delete(file);
|
||||
file = nullptr;
|
||||
if (read != 0)
|
||||
{
|
||||
// Naive Json parsing to get ID and TypeName without full parsing
|
||||
StringAnsiView json((const char*)fileData.Get(), read);
|
||||
StringAnsiView idStart("\"ID\": ");
|
||||
StringAnsiView typenameStart("\"TypeName\": ");
|
||||
bool hasOneOfThem = false;
|
||||
for (int32 i = 0; i < json.Length() - 7; i++)
|
||||
{
|
||||
if (json.Substring(i).StartsWith(idStart))
|
||||
{
|
||||
StringAnsiView value = ParseJsonString(json, i + idStart.Length());
|
||||
if (Guid::Parse(value, resultId))
|
||||
continue;
|
||||
if (hasOneOfThem)
|
||||
return true;
|
||||
hasOneOfThem = true;
|
||||
i += value.Length() + idStart.Length() + 2;
|
||||
}
|
||||
if (json.Substring(i).StartsWith(typenameStart))
|
||||
{
|
||||
StringAnsiView value = ParseJsonString(json, i + typenameStart.Length());
|
||||
resultDataTypeName = String(value);
|
||||
if (hasOneOfThem)
|
||||
return true;
|
||||
hasOneOfThem = true;
|
||||
i += value.Length() + typenameStart.Length() + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load file
|
||||
Array<byte> fileData;
|
||||
if (File::ReadAllBytes(path, fileData))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse data
|
||||
rapidjson_flax::Document document;
|
||||
@@ -89,11 +139,8 @@ void FindObjectIds(const rapidjson_flax::Value& obj, const rapidjson_flax::Docum
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool JsonStorageProxy::ChangeId(const StringView& path, const Guid& newId)
|
||||
{
|
||||
#if USE_EDITOR
|
||||
PROFILE_CPU();
|
||||
|
||||
// Load file
|
||||
@@ -140,8 +187,6 @@ bool JsonStorageProxy::ChangeId(const StringView& path, const Guid& newId)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
#else
|
||||
LOG(Warning, "Editing cooked content is invalid.");
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
/// <returns>True if found any asset, otherwise false.</returns>
|
||||
static bool GetAssetInfo(const StringView& path, Guid& resultId, String& resultDataTypeName);
|
||||
|
||||
#if USE_EDITOR
|
||||
/// <summary>
|
||||
/// Changes asset ID.
|
||||
/// </summary>
|
||||
@@ -37,4 +38,5 @@ public:
|
||||
/// <param name="newId">Asset ID to set</param>
|
||||
/// <returns>True if found any asset, otherwise false.</returns>
|
||||
static bool ChangeId(const StringView& path, const Guid& newId);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -113,6 +113,8 @@ CreateAssetContext::CreateAssetContext(const StringView& inputPath, const String
|
||||
|
||||
CreateAssetResult CreateAssetContext::Run(const CreateAssetFunction& callback)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
PROFILE_MEM(Content);
|
||||
ASSERT(callback.IsBinded());
|
||||
|
||||
// Call action
|
||||
@@ -207,6 +209,9 @@ void CreateAssetContext::AddMeta(JsonWriter& writer) const
|
||||
|
||||
void CreateAssetContext::ApplyChanges()
|
||||
{
|
||||
PROFILE_CPU();
|
||||
PROFILE_MEM(Content);
|
||||
|
||||
// Get access
|
||||
auto storage = ContentStorageManager::TryGetStorage(TargetAssetPath);
|
||||
if (storage && storage->IsLoaded())
|
||||
@@ -274,6 +279,8 @@ bool AssetsImportingManager::Create(const String& tag, const StringView& outputP
|
||||
|
||||
bool AssetsImportingManager::Import(const StringView& inputPath, const StringView& outputPath, Guid& assetId, void* arg)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
PROFILE_MEM(Content);
|
||||
LOG(Info, "Importing file '{0}' to '{1}'...", inputPath, outputPath);
|
||||
|
||||
// Check if input file exists
|
||||
@@ -347,6 +354,7 @@ String AssetsImportingManager::GetImportPath(const String& path)
|
||||
bool AssetsImportingManager::Create(const Function<CreateAssetResult(CreateAssetContext&)>& callback, const StringView& inputPath, const StringView& outputPath, Guid& assetId, void* arg)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
PROFILE_MEM(Content);
|
||||
ZoneText(*outputPath, outputPath.Length());
|
||||
const auto startTime = Platform::GetTimeSeconds();
|
||||
|
||||
|
||||
@@ -44,12 +44,32 @@ public:
|
||||
IMPLEMENT_ENGINE_SETTINGS_GETTER(BuildSettings, GameCooking);
|
||||
|
||||
#include "Engine/Content/Deprecated.h"
|
||||
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS;
|
||||
|
||||
bool GraphicsSettings::GetUeeHDRProbes() const
|
||||
{
|
||||
return UseHDRProbes;
|
||||
}
|
||||
|
||||
void GraphicsSettings::SetUeeHDRProbes(bool value)
|
||||
{
|
||||
MARK_CONTENT_DEPRECATED();
|
||||
UseHDRProbes = value;
|
||||
DefaultProbeCubemapFormat = value ? ProbeCubemapFormats::R11G11B10 : ProbeCubemapFormats::R8G8B8A8;
|
||||
}
|
||||
|
||||
bool GraphicsSettings::GetUseHDRProbes() const
|
||||
{
|
||||
return UseHDRProbes;
|
||||
}
|
||||
|
||||
void GraphicsSettings::SetUseHDRProbes(bool value)
|
||||
{
|
||||
DefaultProbeCubemapFormat = value ? ProbeCubemapFormats::R11G11B10 : ProbeCubemapFormats::R8G8B8A8;
|
||||
}
|
||||
|
||||
PRAGMA_ENABLE_DEPRECATION_WARNINGS;
|
||||
|
||||
void GraphicsSettings::OnDeserializing(const CallbackContext& context)
|
||||
{
|
||||
#if 0 // TODO: move to Linear color space as default once it's ready for production
|
||||
|
||||
@@ -31,6 +31,22 @@ public:
|
||||
R16G16B16A16,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The environment probes cubemap texture storage formats.
|
||||
/// </summary>
|
||||
API_ENUM(Attributes = "EnumDisplay(EnumDisplayAttribute.FormatMode.None)")
|
||||
enum class ProbeCubemapFormats
|
||||
{
|
||||
// LDR uncompressed format (32-bit per pixel).
|
||||
R8G8B8A8,
|
||||
// HDR uncompressed format (32-bit per pixel, no alpha).
|
||||
R11G11B10,
|
||||
// HDR compressed format (8-bit per pixel, no alpha). Converted into ASTC/Basis for mobile/web. Realtime probes will fallback to R11G11B10.
|
||||
BC6,
|
||||
// HDR compressed format (8-bit per pixel). Converted into ASTC/Basis for mobile/web. Realtime probes will fallback to R11G11B10.
|
||||
BC7,
|
||||
};
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Enables rendering synchronization with the refresh rate of the display device to avoid "tearing" artifacts.
|
||||
@@ -87,9 +103,16 @@ public:
|
||||
ProbeCubemapResolution DefaultProbeResolution = ProbeCubemapResolution::_128;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, Environment Probes will use HDR texture format. Improves quality in very bright scenes at cost of higher memory usage.
|
||||
/// Environment Probes texture storage format. Controls the quality fo reflections and memory usage of probes data.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(1502), EditorDisplay(\"Quality\")")
|
||||
ProbeCubemapFormats DefaultProbeCubemapFormat = ProbeCubemapFormats::BC6;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, Environment Probes will use HDR texture format. Improves quality in very bright scenes at cost of higher memory usage.
|
||||
/// [Deprecated in v1.13]
|
||||
/// </summary>
|
||||
DEPRECATED("Use DefaultProbeCubemapFormat instead.")
|
||||
bool UseHDRProbes = false;
|
||||
|
||||
/// <summary>
|
||||
@@ -127,7 +150,7 @@ public:
|
||||
/// <summary>
|
||||
/// The Global Illumination probes spacing distance (in world units). Defines the quality of the GI resolution. Adjust to 200-500 to improve performance and lower frequency GI data.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(2120), Limit(50, 1000), EditorDisplay(\"Global Illumination\")")
|
||||
API_FIELD(Attributes="EditorOrder(2120), Limit(50, 1000), EditorDisplay(\"Global Illumination\"), ValueCategory(Utils.ValueCategory.Distance)")
|
||||
float GIProbesSpacing = 100;
|
||||
|
||||
/// <summary>
|
||||
@@ -175,8 +198,10 @@ private:
|
||||
/// Renamed UeeHDRProbes into UseHDRProbes
|
||||
/// [Deprecated on 12.10.2022, expires on 12.10.2024]
|
||||
/// </summary>
|
||||
API_PROPERTY(Attributes="Serialize, Obsolete, NoUndo") DEPRECATED("Use UseHDRProbes instead.") bool GetUeeHDRProbes() const { return UseHDRProbes; }
|
||||
API_PROPERTY(Attributes="Serialize, Obsolete, NoUndo") DEPRECATED("Use UseHDRProbes instead.") void SetUeeHDRProbes(bool value);
|
||||
API_PROPERTY(Attributes="Serialize, Obsolete, NoUndo") DEPRECATED("Use DefaultProbeCubemapFormat instead.") bool GetUeeHDRProbes() const;
|
||||
API_PROPERTY(Attributes="Serialize, Obsolete, NoUndo") DEPRECATED("Use DefaultProbeCubemapFormat instead.") void SetUeeHDRProbes(bool value);
|
||||
API_PROPERTY(Attributes="Serialize, Obsolete, NoUndo") DEPRECATED("Use DefaultProbeCubemapFormat instead.") bool GetUseHDRProbes() const;
|
||||
API_PROPERTY(Attributes="Serialize, Obsolete, NoUndo") DEPRECATED("Use DefaultProbeCubemapFormat instead.") void SetUseHDRProbes(bool value);
|
||||
API_FUNCTION(Attributes="OnDeserializing", Hidden) void OnDeserializing(const CallbackContext& context);
|
||||
|
||||
public:
|
||||
|
||||
@@ -59,6 +59,11 @@ void BoundingFrustum::SetMatrix(const Matrix& matrix)
|
||||
_pFar.Normal.Z = matrix.M34 - matrix.M33;
|
||||
_pFar.D = matrix.M44 - matrix.M43;
|
||||
_pFar.Normalize();
|
||||
|
||||
#if REVERSE_Z
|
||||
// Swap far and near planes if reverse z
|
||||
Swap(_pFar, _pNear);
|
||||
#endif
|
||||
}
|
||||
|
||||
Plane BoundingFrustum::GetPlane(int32 index) const
|
||||
|
||||
@@ -243,6 +243,11 @@ namespace FlaxEngine
|
||||
far.Normal.Z = matrix.M34 - matrix.M33;
|
||||
far.D = matrix.M44 - matrix.M43;
|
||||
far.Normalize();
|
||||
|
||||
#if REVERSE_Z
|
||||
// Swap far and near planes if reverse z
|
||||
(near, far) = (far, near);
|
||||
#endif
|
||||
}
|
||||
|
||||
private static Vector3 Get3PlanesInterPoint(ref Plane p1, ref Plane p2, ref Plane p3)
|
||||
|
||||
@@ -66,6 +66,12 @@ public:
|
||||
double Values[4][4];
|
||||
double Raw[16];
|
||||
};
|
||||
public:
|
||||
/// <summary>A matrix with all of its components set to zero.</summary>
|
||||
static const Double4x4 Zero;
|
||||
|
||||
/// <summary>The identity matrix.</summary>
|
||||
static const Double4x4 Identity;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
@@ -73,6 +79,32 @@ public:
|
||||
/// </summary>
|
||||
Double4x4() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Matrix"/> struct.
|
||||
/// </summary>
|
||||
Double4x4(double m11, double m12, double m13, double m14,
|
||||
double m21, double m22, double m23, double m24,
|
||||
double m31, double m32, double m33, double m34,
|
||||
double m41, double m42, double m43, double m44)
|
||||
: M11(m11)
|
||||
, M12(m12)
|
||||
, M13(m13)
|
||||
, M14(m14)
|
||||
, M21(m21)
|
||||
, M22(m22)
|
||||
, M23(m23)
|
||||
, M24(m24)
|
||||
, M31(m31)
|
||||
, M32(m32)
|
||||
, M33(m33)
|
||||
, M34(m34)
|
||||
, M41(m41)
|
||||
, M42(m42)
|
||||
, M43(m43)
|
||||
, M44(m44)
|
||||
{
|
||||
}
|
||||
|
||||
Double4x4(const Matrix& matrix);
|
||||
|
||||
public:
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "../Types/String.h"
|
||||
|
||||
static_assert(sizeof(Matrix) == 4 * 4 * 4, "Invalid Matrix type size.");
|
||||
static_assert(sizeof(Double4x4) == 8 * 4 * 4, "Invalid Double4x4 type size.");
|
||||
|
||||
const Matrix Matrix::Zero(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
const Matrix Matrix::Identity(
|
||||
@@ -18,6 +19,13 @@ const Matrix Matrix::Identity(
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
const Double4x4 Double4x4::Zero(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
|
||||
const Double4x4 Double4x4::Identity(
|
||||
1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0);
|
||||
|
||||
Matrix::Matrix(const Matrix3x3& matrix)
|
||||
{
|
||||
Platform::MemoryCopy(&M11, &matrix.M11, sizeof(Float3));
|
||||
@@ -514,10 +522,15 @@ void Matrix::OrthoOffCenter(float left, float right, float bottom, float top, fl
|
||||
result = Identity;
|
||||
result.M11 = 2.0f / (right - left);
|
||||
result.M22 = 2.0f / (top - bottom);
|
||||
result.M33 = zRange;
|
||||
result.M41 = (left + right) / (left - right);
|
||||
result.M42 = (top + bottom) / (bottom - top);
|
||||
#if REVERSE_Z
|
||||
result.M33 = -zRange;
|
||||
result.M43 = zFar * zRange;
|
||||
#else
|
||||
result.M33 = zRange;
|
||||
result.M43 = -zNear * zRange;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Matrix::PerspectiveFov(float fov, float aspect, float zNear, float zFar, Matrix& result)
|
||||
@@ -533,16 +546,21 @@ void Matrix::PerspectiveFov(float fov, float aspect, float zNear, float zFar, Ma
|
||||
|
||||
void Matrix::PerspectiveOffCenter(float left, float right, float bottom, float top, float zNear, float zFar, Matrix& result)
|
||||
{
|
||||
const float zRange = zFar / (zFar - zNear);
|
||||
const float zRange = 1.0f / (zFar - zNear);
|
||||
|
||||
result = Zero;
|
||||
result.M11 = 2.0f * zNear / (right - left);
|
||||
result.M22 = 2.0f * zNear / (top - bottom);
|
||||
result.M31 = (left + right) / (left - right);
|
||||
result.M32 = (top + bottom) / (bottom - top);
|
||||
result.M33 = zRange;
|
||||
result.M34 = 1.0f;
|
||||
result.M43 = -zNear * zRange;
|
||||
#if REVERSE_Z
|
||||
result.M33 = -zNear * zRange;
|
||||
result.M43 = zFar * zNear * zRange;
|
||||
#else
|
||||
result.M33 = zFar * zRange;
|
||||
result.M43 = -zFar * zNear * zRange;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Matrix::RotationX(float angle, Matrix& result)
|
||||
|
||||
@@ -2176,10 +2176,15 @@ namespace FlaxEngine
|
||||
result = Identity;
|
||||
result.M11 = 2.0f / (right - left);
|
||||
result.M22 = 2.0f / (top - bottom);
|
||||
result.M33 = zRange;
|
||||
result.M41 = (left + right) / (left - right);
|
||||
result.M42 = (top + bottom) / (bottom - top);
|
||||
#if REVERSE_Z
|
||||
result.M33 = -zRange;
|
||||
result.M43 = zfar * zRange;
|
||||
#else
|
||||
result.M33 = zRange;
|
||||
result.M43 = -znear * zRange;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2238,14 +2243,19 @@ namespace FlaxEngine
|
||||
public static void PerspectiveFov(float fov, float aspect, float znear, float zfar, out Matrix result)
|
||||
{
|
||||
var yScale = (float)(1.0f / Math.Tan(fov * 0.5f));
|
||||
var q = zfar / (zfar - znear);
|
||||
var zRange = 1.0f / (zfar - znear);
|
||||
result = new Matrix
|
||||
{
|
||||
M11 = yScale / aspect,
|
||||
M22 = yScale,
|
||||
M33 = q,
|
||||
M34 = 1.0f,
|
||||
M43 = -q * znear,
|
||||
#if REVERSE_Z
|
||||
M33 = -znear * zRange,
|
||||
M43 = znear * zfar * zRange,
|
||||
#else
|
||||
M33 = zfar * zRange,
|
||||
M43 = -znear * zfar * zRange,
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2275,16 +2285,21 @@ namespace FlaxEngine
|
||||
/// <param name="result">When the method completes, contains the created projection matrix.</param>
|
||||
public static void PerspectiveOffCenter(float left, float right, float bottom, float top, float znear, float zfar, out Matrix result)
|
||||
{
|
||||
float zRange = zfar / (zfar - znear);
|
||||
float zRange = 1.0f / (zfar - znear);
|
||||
result = new Matrix
|
||||
{
|
||||
M11 = 2.0f * znear / (right - left),
|
||||
M22 = 2.0f * znear / (top - bottom),
|
||||
M31 = (left + right) / (left - right),
|
||||
M32 = (top + bottom) / (bottom - top),
|
||||
M33 = zRange,
|
||||
M34 = 1.0f,
|
||||
M43 = -znear * zRange,
|
||||
#if REVERSE_Z
|
||||
M33 = -znear * zRange,
|
||||
M43 = znear * zfar * zRange,
|
||||
#else
|
||||
M33 = zfar * zRange,
|
||||
M43 = -znear * zfar * zRange,
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,15 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Rectangle"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="packed">The location and size packed.</param>
|
||||
Rectangle(const Float4& packed)
|
||||
{
|
||||
Platform::MemoryCopy(this, &packed, sizeof(*this));
|
||||
}
|
||||
|
||||
public:
|
||||
String ToString() const;
|
||||
|
||||
|
||||
@@ -150,11 +150,18 @@ void Transform::LocalToWorldVector(const Vector3& vector, Vector3& result) const
|
||||
Vector3::Transform(tmp, Orientation, result);
|
||||
}
|
||||
|
||||
void Transform::LocalToWorld(const Vector3& point, Vector3& result) const
|
||||
void Transform::LocalToWorld(const Float3& point, Float3& result) const
|
||||
{
|
||||
Vector3 tmp = point * Scale;
|
||||
Vector3::Transform(tmp, Orientation, tmp);
|
||||
Vector3::Add(tmp, Translation, result);
|
||||
Float3 tmp = point * Scale;
|
||||
Float3::Transform(tmp, Orientation, tmp);
|
||||
Float3::Add(tmp, Translation, result);
|
||||
}
|
||||
|
||||
void Transform::LocalToWorld(const Double3& point, Double3& result) const
|
||||
{
|
||||
Double3 tmp = point * Scale;
|
||||
Double3::Transform(tmp, Orientation, tmp);
|
||||
Double3::Add(tmp, Translation, result);
|
||||
}
|
||||
|
||||
void Transform::WorldToLocal(const Transform& other, Transform& result) const
|
||||
|
||||
@@ -219,7 +219,14 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="point">The local space point.</param>
|
||||
/// <param name="result">The world space point.</param>
|
||||
void LocalToWorld(const Vector3& point, Vector3& result) const;
|
||||
void LocalToWorld(const Float3& point, Float3& result) const;
|
||||
|
||||
/// <summary>
|
||||
/// Performs transformation of the given point in local space to the world space of this transform.
|
||||
/// </summary>
|
||||
/// <param name="point">The local space point.</param>
|
||||
/// <param name="result">The world space point.</param>
|
||||
void LocalToWorld(const Double3& point, Double3& result) const;
|
||||
|
||||
/// <summary>
|
||||
/// Performs transformation of the given transform in local space to the world space of this transform.
|
||||
|
||||
@@ -296,15 +296,13 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Converts a screen space point into a corresponding point in world space.
|
||||
/// </summary>
|
||||
/// <param name="source">The vector to project.</param>
|
||||
/// <param name="source">The vector to project, screen uv and device depth.</param>
|
||||
/// <param name="projection">The projection matrix.</param>
|
||||
/// <param name="view">The view matrix.</param>
|
||||
/// <param name="world">The world matrix.</param>
|
||||
/// <returns>The unprojected Vector.</returns>
|
||||
public Vector3 Unproject(Vector3 source, Matrix projection, Matrix view, Matrix world)
|
||||
public Vector3 Unproject(Vector3 source, Matrix projection, Matrix view)
|
||||
{
|
||||
Matrix.Multiply(ref world, ref view, out Matrix matrix);
|
||||
Matrix.Multiply(ref matrix, ref projection, out matrix);
|
||||
Matrix.Multiply(ref view, ref projection, out Matrix matrix);
|
||||
Matrix.Invert(ref matrix, out matrix);
|
||||
|
||||
Unproject(ref source, ref matrix, out Vector3 vector);
|
||||
@@ -314,8 +312,8 @@ namespace FlaxEngine
|
||||
/// <summary>
|
||||
/// Converts a screen space point into a corresponding point in world space.
|
||||
/// </summary>
|
||||
/// <param name="source">The vector to project.</param>
|
||||
/// <param name="matrix">An inverted combined WorldViewProjection matrix.</param>
|
||||
/// <param name="source">The vector to project, screen uv and device depth.</param>
|
||||
/// <param name="matrix">An inverted combined ViewProjection matrix.</param>
|
||||
/// <param name="vector">The unprojected vector.</param>
|
||||
public void Unproject(ref Vector3 source, ref Matrix matrix, out Vector3 vector)
|
||||
{
|
||||
|
||||
@@ -127,6 +127,7 @@ bool GameBase::Init()
|
||||
if (!gameSettings)
|
||||
return true;
|
||||
GameBaseImpl::FirstScene = gameSettings->FirstScene;
|
||||
Level::PreloadSceneAsync(GameBaseImpl::FirstScene.GetID());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace
|
||||
Nullable<bool> Fullscreen;
|
||||
Nullable<Float2> Size;
|
||||
bool CursorVisible = true;
|
||||
CursorType CachedCursorType = CursorType::Default;
|
||||
CursorLockMode CursorLock = CursorLockMode::None;
|
||||
CursorLockMode PendingCursorLock = CursorLockMode::None;
|
||||
bool LastGameViewportFocus = false;
|
||||
@@ -107,10 +108,17 @@ void Screen::SetCursorVisible(const bool value)
|
||||
#else
|
||||
const auto win = Engine::MainWindow;
|
||||
#endif
|
||||
if (!value && win)
|
||||
{
|
||||
// Cache cursor used before hiding it to restore it later (eg. if game uses image cursor and hides it for a while)
|
||||
CachedCursorType = win->GetCursor();
|
||||
if (CachedCursorType == CursorType::Hidden)
|
||||
CachedCursorType = CursorType::Default;
|
||||
}
|
||||
if (win && Engine::HasGameViewportFocus())
|
||||
win->SetCursor(value ? CursorType::Default : CursorType::Hidden);
|
||||
win->SetCursor(value ? CachedCursorType : CursorType::Hidden);
|
||||
else if (win)
|
||||
win->SetCursor(CursorType::Default);
|
||||
win->SetCursor(CachedCursorType);
|
||||
CursorVisible = value;
|
||||
}
|
||||
|
||||
|
||||
+461
-257
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@
|
||||
#include "FoliageInstance.h"
|
||||
#include "FoliageCluster.h"
|
||||
#include "FoliageType.h"
|
||||
#include "Engine/Core/Math/BoundingFrustum.h"
|
||||
#include "Engine/Core/Memory/ArenaAllocation.h"
|
||||
#include "Engine/Level/Actor.h"
|
||||
|
||||
@@ -19,6 +20,7 @@ API_CLASS() class FLAXENGINE_API Foliage final : public Actor
|
||||
private:
|
||||
bool _disableFoliageTypeEvents;
|
||||
int32 _sceneRenderingKey = -1;
|
||||
Vector3 _cachedDrawWorldOrigin = Vector3::Zero;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
@@ -158,15 +160,25 @@ public:
|
||||
|
||||
private:
|
||||
void AddToCluster(ChunkedArray<FoliageCluster, FOLIAGE_CLUSTER_CHUNKS_SIZE>& clusters, FoliageCluster* cluster, FoliageInstance& instance);
|
||||
|
||||
struct DrawContext
|
||||
{
|
||||
RenderContext& RenderContext;
|
||||
const RenderView& LodView;
|
||||
const FoliageType& FoliageType;
|
||||
Model* FoliageTypeModel;
|
||||
Vector3 ViewOrigin;
|
||||
float MinObjectPixelSizeSq;
|
||||
float ViewScreenSizeSq;
|
||||
Float3 LodViewOrigin;
|
||||
float MinObjectPixelSizeSq;
|
||||
Float3 LodViewPosition;
|
||||
int32 MinLOD, MaxLOD;
|
||||
BoundingFrustum CullingFrustum;
|
||||
|
||||
FORCE_INLINE int32 ClampLODIndex(int32 index) const
|
||||
{
|
||||
return index < MinLOD ? MinLOD : index < MaxLOD ? index : MaxLOD;
|
||||
}
|
||||
};
|
||||
|
||||
#if !FOLIAGE_USE_SINGLE_QUAD_TREE && FOLIAGE_USE_DRAW_CALLS_BATCHING
|
||||
struct DrawKey
|
||||
{
|
||||
@@ -190,7 +202,7 @@ private:
|
||||
|
||||
typedef Array<struct DrawCall, InlinedAllocation<8>> DrawCallsList;
|
||||
typedef Dictionary<DrawKey, struct BatchedDrawCall, ConcurrentArenaAllocation> BatchedDrawCalls;
|
||||
void DrawInstance(DrawContext& context, FoliageInstance& instance, Model* model, int32 lod, float lodDitherFactor, DrawCallsList* drawCallsLists, BatchedDrawCalls& result) const;
|
||||
void DrawInstance(DrawContext& context, FoliageInstance& instance, int32 lod, float lodDitherFactor, DrawCallsList* drawCallsLists, BatchedDrawCalls& result) const;
|
||||
void DrawCluster(DrawContext& context, FoliageCluster* cluster, DrawCallsList* drawCallsLists, BatchedDrawCalls& result) const;
|
||||
void DrawType(RenderContext& renderContext, const FoliageType& type, DrawCallsList* drawCallsLists);
|
||||
#else
|
||||
@@ -204,7 +216,9 @@ private:
|
||||
RenderContextBatch* _renderContextBatch;
|
||||
#endif
|
||||
|
||||
void InitType(const RenderView& view, FoliageType& type);
|
||||
void PreDraw(const RenderView& view);
|
||||
void InitType(const RenderView& view, int32 typeIndex);
|
||||
void UpdateBounds();
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
@@ -217,6 +231,12 @@ public:
|
||||
/// <returns>True whether the two objects intersected, otherwise false.</returns>
|
||||
API_FUNCTION() bool Intersects(API_PARAM(Ref) const Ray& ray, API_PARAM(Out) Real& distance, API_PARAM(Out) Vector3& normal, API_PARAM(Out) int32& instanceIndex);
|
||||
|
||||
private:
|
||||
#if USE_EDITOR
|
||||
// Debug filter to draw only specific foliage type (in editor).
|
||||
API_FIELD(Internal) int32 _drawFoliageType = -1;
|
||||
#endif
|
||||
|
||||
public:
|
||||
// [Actor]
|
||||
void Draw(RenderContext& renderContext) override;
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
|
||||
#include "Engine/Core/Math/Transform.h"
|
||||
#include "Engine/Core/Math/BoundingSphere.h"
|
||||
#include "Engine/Renderer/DrawCall.h"
|
||||
#include "Engine/Level/Scene/Lightmap.h"
|
||||
#include "Engine/Core/Math/Half.h"
|
||||
#include "Engine/Core/Math/Matrix.h"
|
||||
|
||||
/// <summary>
|
||||
/// Foliage instanced mesh instance. Packed data with very little of logic. Managed by the foliage chunks and foliage actor itself.
|
||||
/// </summary>
|
||||
API_STRUCT(NoPod) struct FLAXENGINE_API FoliageInstance
|
||||
API_STRUCT(NoPod, NoDefault) struct FLAXENGINE_API FoliageInstance
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(FoliageInstance);
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(FoliageInstance);
|
||||
|
||||
/// <summary>
|
||||
/// The local-space transformation of the mesh relative to the foliage actor.
|
||||
@@ -20,14 +20,39 @@ API_STRUCT(NoPod) struct FLAXENGINE_API FoliageInstance
|
||||
API_FIELD() Transform Transform;
|
||||
|
||||
/// <summary>
|
||||
/// The model drawing state.
|
||||
/// The cached instance bounds (in world space).
|
||||
/// </summary>
|
||||
GeometryDrawStateData DrawState;
|
||||
API_FIELD() BoundingSphere Bounds;
|
||||
|
||||
/// <summary>
|
||||
/// The previous frame index. In sync with Engine::FrameCount used to detect new frames and rendering gaps to reset state.
|
||||
/// </summary>
|
||||
uint64 DrawStatePrevFrame = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The foliage type index. Foliage types are hold in foliage actor and shared by instances using the same model.
|
||||
/// </summary>
|
||||
API_FIELD() int32 Type;
|
||||
API_FIELD() uint16 Type;
|
||||
|
||||
/// <summary>
|
||||
/// The lightmap index for the foliage instance. -1 if unused.
|
||||
/// </summary>
|
||||
int8 LightmapTextureIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// The previous frame model LOD index used. It's locked during LOD transition to cache the transition start LOD.
|
||||
/// </summary>
|
||||
char DrawStatePrevLOD = -1;
|
||||
|
||||
/// <summary>
|
||||
/// The LOD transition timer.
|
||||
/// </summary>
|
||||
byte DrawStateLODTransition = 255;
|
||||
|
||||
/// <summary>
|
||||
/// Flag used to indicate whether CachedDrawWorld contains valid data.
|
||||
/// </summary>
|
||||
byte CachedDrawWorldValid = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The per-instance random value from range [0;1].
|
||||
@@ -40,14 +65,14 @@ API_STRUCT(NoPod) struct FLAXENGINE_API FoliageInstance
|
||||
float CullDistance;
|
||||
|
||||
/// <summary>
|
||||
/// The cached instance bounds (in world space).
|
||||
/// Lightmap UVs area that entry occupies (packed Rectangle into Half4).
|
||||
/// </summary>
|
||||
API_FIELD() BoundingSphere Bounds;
|
||||
Half4 LightmapUVsArea;
|
||||
|
||||
/// <summary>
|
||||
/// The lightmap entry for the foliage instance.
|
||||
/// Cached local-to-world transformation matrix for the instance used during rendering. Relative to the last rendering context origin. Valid only if CachedDrawWorldValid flag is set.
|
||||
/// </summary>
|
||||
LightmapEntry Lightmap;
|
||||
Matrix CachedDrawWorld;
|
||||
|
||||
public:
|
||||
bool operator==(const FoliageInstance& v) const
|
||||
@@ -60,7 +85,7 @@ public:
|
||||
/// </summary>
|
||||
FORCE_INLINE bool HasLightmap() const
|
||||
{
|
||||
return Lightmap.TextureIndex != INVALID_INDEX;
|
||||
return LightmapTextureIndex != INVALID_INDEX;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -68,6 +93,6 @@ public:
|
||||
/// </summary>
|
||||
FORCE_INLINE void RemoveLightmap()
|
||||
{
|
||||
Lightmap.TextureIndex = INVALID_INDEX;
|
||||
LightmapTextureIndex = INVALID_INDEX;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Graphics/GPUPass.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Profiler/ProfilerGPU.h"
|
||||
|
||||
DefaultGPUTasksExecutor::DefaultGPUTasksExecutor()
|
||||
: _context(nullptr)
|
||||
@@ -33,6 +34,7 @@ void DefaultGPUTasksExecutor::FrameBegin()
|
||||
const int32 count = GPUDevice::Instance->GetTasksManager()->RequestWork(buffer, 32);
|
||||
if (count == 0)
|
||||
return;
|
||||
PROFILE_GPU("GPUTasks");
|
||||
GPUMemoryPass pass(_context->GPU);
|
||||
for (int32 i = 0; i < count; i++)
|
||||
{
|
||||
|
||||
@@ -629,6 +629,17 @@ public:
|
||||
|
||||
uint32 GetHash(const BlendingMode& key);
|
||||
|
||||
// Temp defines to put them into ComparisonFunc enum conditionally
|
||||
#if REVERSE_Z
|
||||
#define REVERSE_Z_COMP_DEFAULT 5
|
||||
#define REVERSE_Z_COMP_DEFAULT_INV 2
|
||||
#define REVERSE_Z_COMP_DEFAULT_EQ 7
|
||||
#else
|
||||
#define REVERSE_Z_COMP_DEFAULT 2
|
||||
#define REVERSE_Z_COMP_DEFAULT_INV 5
|
||||
#define REVERSE_Z_COMP_DEFAULT_EQ 4
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Comparison function modes
|
||||
/// </summary>
|
||||
@@ -651,9 +662,21 @@ API_ENUM() enum class ComparisonFunc : byte
|
||||
// Always pass the comparison.
|
||||
Always = 8,
|
||||
|
||||
API_ENUM(Attributes="HideInEditor") MAX
|
||||
API_ENUM(Attributes="HideInEditor") MAX,
|
||||
|
||||
// Default comparision when rendering scene objects (Less or Greater).
|
||||
API_ENUM(Attributes="HideInEditor") Default = REVERSE_Z_COMP_DEFAULT,
|
||||
// Default comparision when rendering scene objects inverted (Greater or Less).
|
||||
API_ENUM(Attributes="HideInEditor") DefaultInv = REVERSE_Z_COMP_DEFAULT_INV,
|
||||
// Default comparision when rendering scene objects with equal (LessEqual or GreaterEqual).
|
||||
API_ENUM(Attributes="HideInEditor") DefaultEqual = REVERSE_Z_COMP_DEFAULT_EQ,
|
||||
};
|
||||
|
||||
// Remove temp defines to plug conditional value into the enum
|
||||
#undef REVERSE_Z_COMP_DEFAULT
|
||||
#undef REVERSE_Z_COMP_DEFAULT_INV
|
||||
#undef REVERSE_Z_COMP_DEFAULT_EQ
|
||||
|
||||
/// <summary>
|
||||
/// Rendering quality levels.
|
||||
/// </summary>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "GPUContext.h"
|
||||
#include "GPUDevice.h"
|
||||
#include "GPUPass.h"
|
||||
#include "RenderTask.h"
|
||||
#include "Textures/GPUTexture.h"
|
||||
|
||||
@@ -94,8 +95,10 @@ void GPUContext::Draw(GPUTexture* dst, GPUTexture* src)
|
||||
ResetRenderTarget();
|
||||
const float width = (float)dst->Width();
|
||||
const float height = (float)dst->Height();
|
||||
auto rt = dst->View();
|
||||
auto rtAction = GPUDrawPassAction::Store;
|
||||
GPUDrawPass drawPass(this, ToSpan(&rt, 1), ToSpan(&rtAction, 1));
|
||||
SetViewport(width, height);
|
||||
SetRenderTarget(dst->View());
|
||||
BindSR(0, src->View());
|
||||
SetState(_device->GetCopyLinearPS());
|
||||
DrawFullscreenTriangle();
|
||||
@@ -107,8 +110,10 @@ void GPUContext::Draw(GPUTexture* dst, GPUTextureView* src)
|
||||
ResetRenderTarget();
|
||||
const float width = (float)dst->Width();
|
||||
const float height = (float)dst->Height();
|
||||
auto rt = dst->View();
|
||||
auto rtAction = GPUDrawPassAction::Store;
|
||||
GPUDrawPass drawPass(this, ToSpan(&rt, 1), ToSpan(&rtAction, 1));
|
||||
SetViewport(width, height);
|
||||
SetRenderTarget(dst->View());
|
||||
BindSR(0, src);
|
||||
SetState(_device->GetCopyLinearPS());
|
||||
DrawFullscreenTriangle();
|
||||
@@ -137,3 +142,8 @@ void GPUContext::SetResourceState(GPUResource* resource, uint64 state, int32 sub
|
||||
void GPUContext::ForceRebindDescriptors()
|
||||
{
|
||||
}
|
||||
|
||||
void GPUContext::BeginDrawPass(GPUDrawPass& pass)
|
||||
{
|
||||
SetRenderTarget(pass.DepthBuffer, ToSpan(pass.RenderTargets, pass.RenderTargetsCount));
|
||||
}
|
||||
|
||||
@@ -14,6 +14,16 @@
|
||||
#undef MemoryBarrier
|
||||
#endif
|
||||
|
||||
#if REVERSE_Z
|
||||
#define GPU_DEPTH_RANGE_MIN 1.0f
|
||||
#define GPU_DEPTH_RANGE_MAX 0.0f
|
||||
#define GPU_DEPTH_RANGE_BOUNDS(min, max) max, min
|
||||
#else
|
||||
#define GPU_DEPTH_RANGE_MIN 0.0f
|
||||
#define GPU_DEPTH_RANGE_MAX 1.0f
|
||||
#define GPU_DEPTH_RANGE_BOUNDS(min, max) min, max
|
||||
#endif
|
||||
|
||||
class GPUConstantBuffer;
|
||||
class GPUShaderProgramCS;
|
||||
class GPUBuffer;
|
||||
@@ -27,6 +37,7 @@ class GPUTextureView;
|
||||
class GPUBufferView;
|
||||
class GPUVertexLayout;
|
||||
struct GPUPass;
|
||||
struct GPUDrawPass;
|
||||
enum class GPUResourceAccess;
|
||||
enum class GPUQueryType;
|
||||
|
||||
@@ -207,7 +218,7 @@ public:
|
||||
/// <param name="depthBuffer">The depth buffer to clear.</param>
|
||||
/// <param name="depthValue">The clear depth value.</param>
|
||||
/// <param name="stencilValue">The clear stencil value.</param>
|
||||
API_FUNCTION() virtual void ClearDepth(GPUTextureView* depthBuffer, float depthValue = 1.0f, uint8 stencilValue = 0) = 0;
|
||||
API_FUNCTION() virtual void ClearDepth(GPUTextureView* depthBuffer, float depthValue = GPU_DEPTH_RANGE_MAX, uint8 stencilValue = 0) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Clears an unordered access buffer with a float value.
|
||||
@@ -627,9 +638,10 @@ public:
|
||||
/// <summary>
|
||||
/// Sets the minimum and maximum depth values for depth bounds test.
|
||||
/// </summary>
|
||||
/// <remarks>Both values must be between 0.0 and 1.0, MinDepth must be less than or equal to MaxDepth.</remarks>
|
||||
/// <param name="minDepth">The minimum value for depth bound test.</param>
|
||||
/// <param name="maxDepth">The maximum value for depth bound test.</param>
|
||||
API_FUNCTION() virtual void SetDepthBounds(float minDepth, float maxDepth) = 0;
|
||||
API_FUNCTION() virtual void SetDepthBounds(float minDepth = 0.0f, float maxDepth = 1.0f) = 0;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
@@ -697,4 +709,12 @@ public:
|
||||
virtual void OverlapUA(bool end)
|
||||
{
|
||||
}
|
||||
|
||||
// Begins draw pass rendering. See GPUDrawPass.
|
||||
virtual void BeginDrawPass(GPUDrawPass& pass);
|
||||
|
||||
// Ends draw pass rendering. See GPUDrawPass.
|
||||
virtual void EndDrawPass()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -160,7 +160,7 @@ GPUPipelineState::Description GPUPipelineState::Description::Default =
|
||||
true, // DepthWriteEnable
|
||||
true, // DepthClipEnable
|
||||
false, // DepthBoundsEnable
|
||||
ComparisonFunc::Less, // DepthFunc
|
||||
ComparisonFunc::Default, // DepthFunc
|
||||
false, // StencilEnable
|
||||
0xff, // StencilReadMask
|
||||
0xff, // StencilWriteMask
|
||||
@@ -185,7 +185,7 @@ GPUPipelineState::Description GPUPipelineState::Description::DefaultNoDepth =
|
||||
false, // DepthWriteEnable
|
||||
false, // DepthClipEnable
|
||||
false, // DepthBoundsEnable
|
||||
ComparisonFunc::Less, // DepthFunc
|
||||
ComparisonFunc::Default, // DepthFunc
|
||||
false, // StencilEnable
|
||||
0xff, // StencilReadMask
|
||||
0xff, // StencilWriteMask
|
||||
@@ -210,7 +210,7 @@ GPUPipelineState::Description GPUPipelineState::Description::DefaultFullscreenTr
|
||||
false, // DepthWriteEnable
|
||||
false, // DepthClipEnable
|
||||
false, // DepthBoundsEnable
|
||||
ComparisonFunc::Less, // DepthFunc
|
||||
ComparisonFunc::Default, // DepthFunc
|
||||
false, // StencilEnable
|
||||
0xff, // StencilReadMask
|
||||
0xff, // StencilWriteMask
|
||||
@@ -361,8 +361,7 @@ void GPUDevice::OnRequestingExit()
|
||||
Engine::FatalError != FatalErrorType::GPUHang &&
|
||||
Engine::FatalError != FatalErrorType::GPUOutOfMemory)
|
||||
return;
|
||||
// TODO: get and log actual GPU memory used by the engine (API-specific)
|
||||
DumpResourcesToLog();
|
||||
OnCrash();
|
||||
}
|
||||
|
||||
GPUDevice::GPUDevice(RendererType type, ShaderProfile profile)
|
||||
@@ -623,6 +622,16 @@ void GPUDevice::DumpResources()
|
||||
|
||||
extern void ClearVertexLayoutCache();
|
||||
|
||||
bool UseVSync()
|
||||
{
|
||||
bool vsync = Graphics::UseVSync;
|
||||
if (CommandLine::Options.NoVSync.HasValue())
|
||||
vsync = !CommandLine::Options.NoVSync.GetValue();
|
||||
else if (CommandLine::Options.VSync.HasValue())
|
||||
vsync = CommandLine::Options.VSync.GetValue();
|
||||
return vsync;
|
||||
}
|
||||
|
||||
void GPUDevice::preDispose()
|
||||
{
|
||||
Locker.Lock();
|
||||
@@ -666,26 +675,26 @@ void GPUDevice::DrawEnd()
|
||||
{
|
||||
PROFILE_CPU_NAMED("Present");
|
||||
|
||||
// Check if use VSync
|
||||
bool useVSync = Graphics::UseVSync;
|
||||
if (CommandLine::Options.NoVSync.HasValue())
|
||||
useVSync = !CommandLine::Options.NoVSync.GetValue();
|
||||
else if (CommandLine::Options.VSync.HasValue())
|
||||
useVSync = CommandLine::Options.VSync.GetValue();
|
||||
|
||||
// Find index of the last rendered window task (use vsync only on the last window)
|
||||
int32 lastWindowIndex = -1;
|
||||
// Check if use VSync (prioritize the last window, in case of multi-window in Editor)
|
||||
bool useVSync = UseVSync();
|
||||
int32 vsyncTask = -1;
|
||||
for (int32 i = RenderTask::Tasks.Count() - 1; i >= 0; i--)
|
||||
{
|
||||
const auto task = RenderTask::Tasks[i];
|
||||
if (task && task->LastUsedFrame == Engine::FrameCount && task->SwapChain && task->SwapChain->IsReady())
|
||||
{
|
||||
lastWindowIndex = i;
|
||||
vsyncTask = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_rendererType == RendererType::Vulkan && RenderTask::Tasks.Contains(_lastVSyncTask))
|
||||
{
|
||||
// On Vulkan, maintain the last window that was VSynced to avoid recreating swapchain too often (eg. when using context menus or tooltips)
|
||||
vsyncTask = RenderTask::Tasks.Find(_lastVSyncTask);
|
||||
}
|
||||
|
||||
// Call present on all used tasks
|
||||
_lastVSyncTask = nullptr;
|
||||
int32 presentCount = 0;
|
||||
bool anyVSync = false;
|
||||
#if COMPILE_WITH_PROFILER
|
||||
@@ -697,7 +706,7 @@ void GPUDevice::DrawEnd()
|
||||
if (task && task->LastUsedFrame == Engine::FrameCount && task->SwapChain && task->SwapChain->IsReady())
|
||||
{
|
||||
bool vsync = useVSync;
|
||||
if (lastWindowIndex != i)
|
||||
if (vsyncTask != i)
|
||||
{
|
||||
// Perform VSync only on the last window
|
||||
vsync = false;
|
||||
@@ -712,6 +721,8 @@ void GPUDevice::DrawEnd()
|
||||
|
||||
anyVSync |= vsync;
|
||||
task->OnPresent(vsync);
|
||||
if (vsync)
|
||||
_lastVSyncTask = task;
|
||||
presentCount++;
|
||||
}
|
||||
}
|
||||
@@ -751,6 +762,11 @@ void GPUDevice::RenderEnd()
|
||||
#endif
|
||||
}
|
||||
|
||||
void GPUDevice::OnCrash()
|
||||
{
|
||||
DumpResourcesToLog();
|
||||
}
|
||||
|
||||
GPUTasksContext* GPUDevice::CreateTasksContext()
|
||||
{
|
||||
return New<GPUTasksContext>(this);
|
||||
@@ -822,6 +838,16 @@ uint64 GPUDevice::GetMemoryUsage() const
|
||||
return result;
|
||||
}
|
||||
|
||||
GPUMemoryStats GPUDevice::GetMemoryStats()
|
||||
{
|
||||
GPUMemoryStats stats;
|
||||
stats.UsedDedicatedMemory = GetMemoryUsage();
|
||||
stats.TotalDedicatedMemory = TotalGraphicsMemory;
|
||||
stats.UsedSystemMemory = 0;
|
||||
stats.TotalSystemMemory = 0;
|
||||
return stats;
|
||||
}
|
||||
|
||||
Array<GPUResource*> GPUDevice::GetResources() const
|
||||
{
|
||||
_resourcesLock.Lock();
|
||||
|
||||
@@ -33,6 +33,34 @@ class Model;
|
||||
class Material;
|
||||
class MaterialBase;
|
||||
|
||||
/// <summary>
|
||||
/// Contains information about current GPU memory usage and budget.
|
||||
/// </summary>
|
||||
API_STRUCT(NoDefault) struct GPUMemoryStats
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(GPUMemoryStats);
|
||||
|
||||
/// <summary>
|
||||
/// Amount of used dedicated video memory in bytes. Memory local to the device, and represents the fastest available memory to the GPU.
|
||||
/// </summary>
|
||||
API_FIELD() uint64 UsedDedicatedMemory = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Total amount of dedicated memory budget in bytes. Memory local to the device, and represents the fastest available memory to the GPU.
|
||||
/// </summary>
|
||||
API_FIELD() uint64 TotalDedicatedMemory = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Amount of used system video memory in bytes. Memory non-local to the device, and may have slower performance than the dedicated/local.
|
||||
/// </summary>
|
||||
API_FIELD() uint64 UsedSystemMemory = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Total amount of system memory budget in bytes. Memory non-local to the device, and may have slower performance than the dedicated/local.
|
||||
/// </summary>
|
||||
API_FIELD() uint64 TotalSystemMemory = 0;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Graphics device object for rendering on GPU.
|
||||
/// </summary>
|
||||
@@ -134,6 +162,7 @@ protected:
|
||||
PrivateData* _res;
|
||||
Array<GPUResource*> _resources;
|
||||
CriticalSection _resourcesLock;
|
||||
RenderTask* _lastVSyncTask = nullptr;
|
||||
|
||||
void OnRequestingExit();
|
||||
|
||||
@@ -272,10 +301,15 @@ public:
|
||||
API_PROPERTY() virtual void* GetNativePtr() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of memory usage by all the GPU resources (in bytes).
|
||||
/// Gets the amount of memory usage by all the GPU resources (in bytes). Returned value is estimated based on resources created by the engine and might not be accurate. Use GPUMemoryStats for more detailed memory budget usage.
|
||||
/// </summary>
|
||||
API_PROPERTY() uint64 GetMemoryUsage() const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current GPU memory stats.
|
||||
/// </summary>
|
||||
API_PROPERTY() virtual GPUMemoryStats GetMemoryStats();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list with all active GPU resources.
|
||||
/// </summary>
|
||||
@@ -417,6 +451,11 @@ protected:
|
||||
/// </summary>
|
||||
virtual void RenderEnd();
|
||||
|
||||
/// <summary>
|
||||
/// Called when program crashed due to GPU error (out of memory, hang, error - see Engine::FatalError). By default, it logs all GPU resources to the log. Can be used to update platform-specific stats or extract crash-info.
|
||||
/// </summary>
|
||||
virtual void OnCrash();
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Creates the texture.
|
||||
|
||||
@@ -71,4 +71,99 @@ struct FLAXENGINE_API GPUComputePass : GPUPass
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: add GPUDrawPass for render targets and depth/stencil setup with optimized clear for faster drawing on tiled-GPUs (mobile)
|
||||
/// <summary>
|
||||
/// GPU pass operations on attached render targets and depth buffer. Defines the load/store actions for each attachment to optimize GPU rendering by reducing memory bandwidth usage.
|
||||
/// </summary>
|
||||
enum class GPUDrawPassAction
|
||||
{
|
||||
// No action, the content of the render target or depth buffer is undefined. Discards the resulting value of the render pass for this attachment.
|
||||
None = 0,
|
||||
|
||||
// Loads the existing value for this attachment into the draw pass.
|
||||
Load = 1,
|
||||
|
||||
// Loads the clear value for this attachment into the draw pass. Clear value is provided by the GPUContext::Clear performed on the texture before pass begins.
|
||||
Clear = 2,
|
||||
|
||||
// Stores the resulting value of the render pass for this attachment.
|
||||
Store = 4,
|
||||
|
||||
// Resolves the resulting MSAA value and stores final value into the attachment.
|
||||
ResolveMultisample = 8,
|
||||
|
||||
// Mask of flags allowed by load operation (reading data from attachment).
|
||||
LoadMask = None | Load | Clear,
|
||||
|
||||
// Mask of flags allowed by store operation (writing data to attachment).
|
||||
StoreMask = None | Store | ResolveMultisample,
|
||||
|
||||
// Loads the existing value for this attachment into the draw pass and stores the resulting value of the render pass for this attachment.
|
||||
LoadStore = Load | Store,
|
||||
|
||||
// Loads the clear value for this attachment into the draw pass and stores the resulting value of the render pass for this attachment.
|
||||
ClearStore = Clear | Store,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// GPU pass that explicitly defines render targets and depth buffer within a rendering pass. Can be used to optimize GPU rendering on tiled GPUs with manual control over attachment operations (load, store, clear, discard, etc.) that reduce memory bandwidth usage.
|
||||
/// </summary>
|
||||
/// <remarks>Draw Pass discards any render targets or depth buffer bound to the context (reduces state-tracking).</remarks>
|
||||
struct FLAXENGINE_API GPUDrawPass : GPUPass
|
||||
{
|
||||
GPUTextureView* DepthBuffer;
|
||||
GPUTextureView** RenderTargets;
|
||||
GPUDrawPassAction* RenderTargetsActions;
|
||||
int32 RenderTargetsCount;
|
||||
GPUDrawPassAction DepthAction;
|
||||
|
||||
GPUDrawPass(GPUContext* context, Span<GPUTextureView*> renderTargets)
|
||||
: GPUPass(context)
|
||||
, DepthBuffer(nullptr)
|
||||
, RenderTargets(renderTargets.Get())
|
||||
, RenderTargetsActions(nullptr)
|
||||
, RenderTargetsCount(renderTargets.Length())
|
||||
, DepthAction(GPUDrawPassAction::None)
|
||||
{
|
||||
Context->BeginDrawPass(*this);
|
||||
}
|
||||
|
||||
GPUDrawPass(GPUContext* context, GPUTextureView* depthBuffer, Span<GPUTextureView*> renderTargets)
|
||||
: GPUPass(context)
|
||||
, DepthBuffer(depthBuffer)
|
||||
, RenderTargets(renderTargets.Get())
|
||||
, RenderTargetsActions(nullptr)
|
||||
, RenderTargetsCount(renderTargets.Length())
|
||||
, DepthAction(GPUDrawPassAction::LoadStore)
|
||||
{
|
||||
Context->BeginDrawPass(*this);
|
||||
}
|
||||
|
||||
GPUDrawPass(GPUContext* context, GPUTextureView* depthBuffer, GPUDrawPassAction depthAction, Span<GPUTextureView*> renderTargets, Span<GPUDrawPassAction> renderTargetsActions)
|
||||
: GPUPass(context)
|
||||
, DepthBuffer(depthBuffer)
|
||||
, RenderTargets(renderTargets.Get())
|
||||
, RenderTargetsActions(renderTargetsActions.Get())
|
||||
, RenderTargetsCount(renderTargets.Length())
|
||||
, DepthAction(depthAction)
|
||||
{
|
||||
ASSERT_LOW_LAYER(renderTargets.Length() == renderTargetsActions.Length());
|
||||
Context->BeginDrawPass(*this);
|
||||
}
|
||||
|
||||
GPUDrawPass(GPUContext* context, Span<GPUTextureView*> renderTargets, Span<GPUDrawPassAction> renderTargetsActions)
|
||||
: GPUPass(context)
|
||||
, DepthBuffer(nullptr)
|
||||
, RenderTargets(renderTargets.Get())
|
||||
, RenderTargetsActions(renderTargetsActions.Get())
|
||||
, RenderTargetsCount(renderTargets.Length())
|
||||
, DepthAction(GPUDrawPassAction::None)
|
||||
{
|
||||
ASSERT_LOW_LAYER(renderTargets.Length() == renderTargetsActions.Length());
|
||||
Context->BeginDrawPass(*this);
|
||||
}
|
||||
|
||||
~GPUDrawPass()
|
||||
{
|
||||
Context->EndDrawPass();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ template<int Size>
|
||||
class GPUPipelineStatePermutations
|
||||
{
|
||||
public:
|
||||
enum { StaticSize = Size };
|
||||
GPUPipelineState* States[Size];
|
||||
|
||||
public:
|
||||
@@ -97,13 +98,13 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
bool Create(GPUPipelineState::Description& desc, GPUShader* shader, const StringAnsiView& psName)
|
||||
bool Create(GPUPipelineState::Description& desc, GPUShader* shader, const StringAnsiView& psName, int32 permutationOffset = 0)
|
||||
{
|
||||
for (int i = 0; i < Size; i++)
|
||||
{
|
||||
ASSERT(Base::States[i]);
|
||||
|
||||
desc.PS = shader->GetPS(psName, i);
|
||||
desc.PS = shader->GetPS(psName, i + permutationOffset);
|
||||
if (Base::States[i]->Init(desc))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ bool Graphics::SpreadWorkload = true;
|
||||
#if !BUILD_RELEASE || USE_EDITOR
|
||||
float Graphics::TestValue = 0.0f;
|
||||
#endif
|
||||
float Graphics::MotionVectors::MinObjectScreenSize = 0.02f;
|
||||
float Graphics::Shadows::MinObjectPixelSize = 2.0f;
|
||||
bool Graphics::PostProcessing::ColorGradingVolumeLUT = true;
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
API_FIELD() static Quality VolumetricFogQuality;
|
||||
|
||||
/// <summary>
|
||||
/// The shadows quality. Available values are: Low, Medium, High, Ultra (or 0, 1, 2, 3).
|
||||
/// The shadows filtering quality (sampling). Available values are: Low, Medium, High, Ultra (or 0, 1, 2, 3).
|
||||
/// </summary>
|
||||
API_FIELD() static Quality ShadowsQuality;
|
||||
|
||||
@@ -110,6 +110,15 @@ public:
|
||||
API_FIELD() static float MinObjectPixelSize;
|
||||
};
|
||||
|
||||
// Motion Vectors rendering configuration.
|
||||
API_CLASS(Static, Attributes="DebugCommand") class FLAXENGINE_API MotionVectors
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(MotionVectors);
|
||||
|
||||
// The minimum screen size of objects to draw motion vectors. Improves performance by skipping too small objects (eg. sub-pixel) from rendering motion vectors.
|
||||
API_FIELD() static float MinObjectScreenSize;
|
||||
};
|
||||
|
||||
// Post Processing effects rendering configuration.
|
||||
API_CLASS(Static, Attributes="DebugCommand") class FLAXENGINE_API PostProcessing
|
||||
{
|
||||
|
||||
@@ -26,10 +26,10 @@ bool DeferredMaterialShader::CanUseLightmap() const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeferredMaterialShader::CanUseInstancing(InstancingHandler& handler) const
|
||||
bool DeferredMaterialShader::CanUseInstancing(const RenderContext& renderContext, InstancingHandler& handler) const
|
||||
{
|
||||
handler = { SurfaceDrawCallHandler::GetHash, SurfaceDrawCallHandler::CanBatch, };
|
||||
return _instanced;
|
||||
return _instanced || renderContext.View.Pass == DrawPass::Depth;
|
||||
}
|
||||
|
||||
void DeferredMaterialShader::Bind(BindParameters& params)
|
||||
@@ -182,7 +182,7 @@ bool DeferredMaterialShader::Load()
|
||||
// Motion Vectors pass
|
||||
psDesc.DepthWriteEnable = false;
|
||||
psDesc.DepthEnable = true;
|
||||
psDesc.DepthFunc = ComparisonFunc::LessEqual;
|
||||
psDesc.DepthFunc = ComparisonFunc::DefaultEqual;
|
||||
psDesc.VS = _shader->GetVS("VS");
|
||||
psDesc.PS = _shader->GetPS("PS_MotionVectors");
|
||||
_cache.MotionVectors.Init(psDesc);
|
||||
@@ -200,7 +200,7 @@ bool DeferredMaterialShader::Load()
|
||||
psDesc.DepthClipEnable = false;
|
||||
psDesc.DepthWriteEnable = true;
|
||||
psDesc.DepthEnable = true;
|
||||
psDesc.DepthFunc = ComparisonFunc::Less;
|
||||
psDesc.DepthFunc = ComparisonFunc::Default;
|
||||
psDesc.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::None;
|
||||
psDesc.HS = nullptr;
|
||||
psDesc.DS = nullptr;
|
||||
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
// [MaterialShader]
|
||||
DrawPass GetDrawModes() const override;
|
||||
bool CanUseLightmap() const override;
|
||||
bool CanUseInstancing(InstancingHandler& handler) const override;
|
||||
bool CanUseInstancing(const RenderContext& renderContext, InstancingHandler& handler) const override;
|
||||
void Bind(BindParameters& params) override;
|
||||
void Unload() override;
|
||||
|
||||
|
||||
@@ -178,7 +178,11 @@ bool DeformableMaterialShader::Load()
|
||||
psDesc.DepthClipEnable = false;
|
||||
psDesc.DepthWriteEnable = true;
|
||||
psDesc.DepthEnable = true;
|
||||
#if REVERSE_Z
|
||||
psDesc.DepthFunc = ComparisonFunc::Greater;
|
||||
#else
|
||||
psDesc.DepthFunc = ComparisonFunc::Less;
|
||||
#endif
|
||||
psDesc.HS = nullptr;
|
||||
psDesc.DS = nullptr;
|
||||
_cache.Depth.Init(psDesc);
|
||||
|
||||
@@ -22,10 +22,11 @@ DrawPass ForwardMaterialShader::GetDrawModes() const
|
||||
return _drawModes;
|
||||
}
|
||||
|
||||
bool ForwardMaterialShader::CanUseInstancing(InstancingHandler& handler) const
|
||||
bool ForwardMaterialShader::CanUseInstancing(const RenderContext& renderContext, InstancingHandler& handler) const
|
||||
{
|
||||
handler = { SurfaceDrawCallHandler::GetHash, SurfaceDrawCallHandler::CanBatch, };
|
||||
return false; // TODO: support instancing when using ForwardShadingFeature
|
||||
// TODO: support instancing when using ForwardShadingFeature
|
||||
return renderContext.View.Pass == DrawPass::Depth;
|
||||
}
|
||||
|
||||
void ForwardMaterialShader::Bind(BindParameters& params)
|
||||
@@ -184,7 +185,7 @@ bool ForwardMaterialShader::Load()
|
||||
psDesc.DepthClipEnable = false;
|
||||
psDesc.DepthWriteEnable = true;
|
||||
psDesc.DepthEnable = true;
|
||||
psDesc.DepthFunc = ComparisonFunc::Less;
|
||||
psDesc.DepthFunc = ComparisonFunc::Default;
|
||||
psDesc.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::None;
|
||||
psDesc.HS = nullptr;
|
||||
psDesc.DS = nullptr;
|
||||
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
public:
|
||||
// [MaterialShader]
|
||||
DrawPass GetDrawModes() const override;
|
||||
bool CanUseInstancing(InstancingHandler& handler) const override;
|
||||
bool CanUseInstancing(const RenderContext& renderContext, InstancingHandler& handler) const override;
|
||||
void Bind(BindParameters& params) override;
|
||||
void Unload() override;
|
||||
|
||||
|
||||
@@ -126,9 +126,10 @@ public:
|
||||
/// <summary>
|
||||
/// Returns true if material can use draw calls instancing.
|
||||
/// </summary>
|
||||
/// <param name="renderContext">The rendering context.</param>
|
||||
/// <param name="handler">The output data for the instancing handling used to hash, batch and write draw calls. Valid only when function returns true.</param>
|
||||
/// <returns>True if can use instancing, otherwise false.</returns>
|
||||
virtual bool CanUseInstancing(InstancingHandler& handler) const
|
||||
virtual bool CanUseInstancing(const RenderContext& renderContext, InstancingHandler& handler) const
|
||||
{
|
||||
#if BUILD_DEBUG
|
||||
handler = { nullptr, nullptr };
|
||||
|
||||
@@ -78,7 +78,7 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
|
||||
for (int32 i = 0; i < cache->EnvironmentProbes.Count(); i++)
|
||||
{
|
||||
const RenderEnvironmentProbeData& probe = cache->EnvironmentProbes.Get()[i];
|
||||
const float sphereCullDistance = objectBounds.Radius + probe.Radius;
|
||||
const float sphereCullDistance = (float)objectBounds.Radius + probe.Radius;
|
||||
const float distanceSq = Float3::DistanceSquared(probe.Position, objectBounds.Center);
|
||||
if (distanceSq <= sphereCullDistance * sphereCullDistance && distanceSq < minDistanceSq)
|
||||
{
|
||||
|
||||
@@ -189,7 +189,7 @@ bool TerrainMaterialShader::Load()
|
||||
psDesc.DepthClipEnable = false;
|
||||
psDesc.DepthWriteEnable = true;
|
||||
psDesc.DepthEnable = true;
|
||||
psDesc.DepthFunc = ComparisonFunc::Less;
|
||||
psDesc.DepthFunc = ComparisonFunc::Default;
|
||||
psDesc.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::None;
|
||||
psDesc.HS = nullptr;
|
||||
psDesc.DS = nullptr;
|
||||
|
||||
@@ -305,7 +305,7 @@ void Mesh::Draw(const RenderContext& renderContext, const DrawInfo& info, float
|
||||
drawCall.Surface.GeometrySize = _box.GetSize();
|
||||
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
|
||||
drawCall.Surface.Lightmap = (info.Flags & StaticFlags::Lightmap) != StaticFlags::None ? info.Lightmap : nullptr;
|
||||
drawCall.Surface.LightmapUVsArea = info.LightmapUVs ? *info.LightmapUVs : Rectangle::Empty;
|
||||
drawCall.Surface.LightmapUVsArea = info.LightmapUVs ? *info.LightmapUVs : Half4::Zero;
|
||||
drawCall.Surface.LODDitherFactor = lodDitherFactor;
|
||||
drawCall.PerInstanceRandom = info.PerInstanceRandom;
|
||||
drawCall.StencilValue = info.StencilValue;
|
||||
@@ -368,7 +368,7 @@ void Mesh::Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& in
|
||||
drawCall.Surface.GeometrySize = _box.GetSize();
|
||||
drawCall.Surface.PrevWorld = info.DrawState->PrevWorld;
|
||||
drawCall.Surface.Lightmap = (info.Flags & StaticFlags::Lightmap) != StaticFlags::None ? info.Lightmap : nullptr;
|
||||
drawCall.Surface.LightmapUVsArea = info.LightmapUVs ? *info.LightmapUVs : Rectangle::Empty;
|
||||
drawCall.Surface.LightmapUVsArea = info.LightmapUVs ? *info.LightmapUVs : Half4::Zero;
|
||||
drawCall.Surface.LODDitherFactor = lodDitherFactor;
|
||||
drawCall.PerInstanceRandom = info.PerInstanceRandom;
|
||||
drawCall.StencilValue = info.StencilValue;
|
||||
|
||||
@@ -375,7 +375,7 @@ public:
|
||||
/// <summary>
|
||||
/// The lightmap UVs.
|
||||
/// </summary>
|
||||
const Rectangle* LightmapUVs;
|
||||
const Half4* LightmapUVs;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -382,7 +382,7 @@ API_STRUCT() struct FLAXENGINE_API GlobalIlluminationSettings : ISerializable
|
||||
/// <summary>
|
||||
/// Draw distance of the Global Illumination effect. Scene outside the range will use fallback irradiance.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(30), Limit(1000), PostProcessSetting((int)GlobalIlluminationSettingsOverride.Distance)")
|
||||
API_FIELD(Attributes="EditorOrder(30), Limit(1000), PostProcessSetting((int)GlobalIlluminationSettingsOverride.Distance), ValueCategory(Utils.ValueCategory.Distance)")
|
||||
float Distance = 20000.0f;
|
||||
|
||||
/// <summary>
|
||||
@@ -1819,17 +1819,17 @@ API_STRUCT() struct FLAXENGINE_API ScreenSpaceReflectionsSettings : ISerializabl
|
||||
/// <summary>
|
||||
/// The effect fade out end distance from camera (in world units).
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="Limit(0), EditorOrder(31), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.FadeOutDistance)")
|
||||
API_FIELD(Attributes="Limit(0), EditorOrder(31), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.FadeOutDistance), ValueCategory(Utils.ValueCategory.Distance)")
|
||||
float FadeOutDistance = 5000.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The effect fade distance (in world units). Defines the size of the effect fade from fully visible to fully invisible at FadeOutDistance.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="Limit(0), EditorOrder(32), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.FadeDistance)")
|
||||
API_FIELD(Attributes="Limit(0), EditorOrder(32), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.FadeDistance), ValueCategory(Utils.ValueCategory.Distance)")
|
||||
float FadeDistance = 500.0f;
|
||||
|
||||
/// <summary>
|
||||
/// "The input color buffer downscale mode that uses blurred mipmaps when resolving the reflection color. Produces more realistic results by blurring distant parts of reflections in rough (low-gloss) materials. It also improves performance on most platforms but uses more memory.
|
||||
/// The input color buffer downscale mode that uses blurred mipmaps when resolving the reflection color. Produces more realistic results by blurring distant parts of reflections in rough (low-gloss) materials. It also improves performance on most platforms but uses more memory.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(40), PostProcessSetting((int)ScreenSpaceReflectionsSettingsOverride.UseColorBufferMips), EditorDisplay(null, \"Use Color Buffer Mips\")")
|
||||
bool UseColorBufferMips = true;
|
||||
@@ -1953,7 +1953,7 @@ API_STRUCT() struct FLAXENGINE_API AntiAliasingSettings : ISerializable
|
||||
/// The anti-aliasing effect mode.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(0), PostProcessSetting((int)AntiAliasingSettingsOverride.Mode)")
|
||||
AntialiasingMode Mode = AntialiasingMode::FastApproximateAntialiasing;
|
||||
AntialiasingMode Mode = AntialiasingMode::TemporalAntialiasing;
|
||||
|
||||
/// <summary>
|
||||
/// The diameter (in texels) inside which jitter samples are spread. Smaller values result in crisper but more aliased output, while larger values result in more stable but blurrier output.
|
||||
|
||||
@@ -684,6 +684,20 @@ float RenderTools::TemporalHalton(int32 index, int32 base)
|
||||
|
||||
Float2 RenderTools::GetDepthBounds(const RenderView& view, const Float3& nearPoint, const Float3& farPoint)
|
||||
{
|
||||
#if REVERSE_Z
|
||||
Float3 viewNearPoint = Float3::Transform(nearPoint, view.View);
|
||||
Float3 viewFarPoint = Float3::Transform(farPoint, view.View);
|
||||
|
||||
viewNearPoint.Z = Math::Max(viewNearPoint.Z, view.Near);
|
||||
viewFarPoint.Z = Math::Min(viewFarPoint.Z, view.Far);
|
||||
|
||||
Float4 clipNearPoint = Matrix::TransformPosition(view.Projection, Float4(0, 0, viewNearPoint.Z, 1));
|
||||
Float4 clipFarPoint = Matrix::TransformPosition(view.Projection, Float4(0, 0, viewFarPoint.Z, 1));
|
||||
clipNearPoint /= clipNearPoint.W;
|
||||
clipFarPoint /= clipFarPoint.W;
|
||||
|
||||
return Float2(clipNearPoint.Z, clipFarPoint.Z);
|
||||
#else
|
||||
// Point closest the view
|
||||
const Float4 nearPointClip = Matrix::TransformPosition(view.ViewProjection(), Float4(nearPoint, 1.0));
|
||||
float nearDepth = nearPointClip.Z / nearPointClip.W;
|
||||
@@ -700,8 +714,8 @@ Float2 RenderTools::GetDepthBounds(const RenderView& view, const Float3& nearPoi
|
||||
nearDepth = Math::Clamp(nearDepth, 0.0f, 1.0f);
|
||||
farDepth = Math::Clamp(farDepth, nearDepth, 1.0f);
|
||||
|
||||
// TODO: swap depths when using reversed depth buffer
|
||||
return Float2(nearDepth, farDepth);
|
||||
#endif
|
||||
}
|
||||
|
||||
Float2 RenderTools::GetDepthBounds(const RenderView& view, const BoundingSphere& bounds)
|
||||
@@ -713,6 +727,24 @@ Float2 RenderTools::GetDepthBounds(const RenderView& view, const BoundingSphere&
|
||||
|
||||
Float2 RenderTools::GetDepthBounds(const RenderView& view, const Span<Float3>& points)
|
||||
{
|
||||
#if REVERSE_Z
|
||||
// Find min and max view depth range for list of points
|
||||
float nearDepth = view.Far, farDepth = view.Near;
|
||||
for (int32 i = 0; i < points.Length(); i++)
|
||||
{
|
||||
const Float3 viewPoint = Float3::Transform(points[i], view.View);
|
||||
nearDepth = Math::Min(nearDepth, viewPoint.Z);
|
||||
farDepth = Math::Max(farDepth, viewPoint.Z);
|
||||
}
|
||||
|
||||
// Project end points to clip space
|
||||
Float4 clipNearPoint = Matrix::TransformPosition(view.Projection, Float4(0, 0, nearDepth, 1));
|
||||
Float4 clipFarPoint = Matrix::TransformPosition(view.Projection, Float4(0, 0, farDepth, 1));
|
||||
clipNearPoint /= clipNearPoint.W;
|
||||
clipFarPoint /= clipFarPoint.W;
|
||||
|
||||
return Float2(clipNearPoint.Z, clipFarPoint.Z);
|
||||
#else
|
||||
// Find min and max depth range for list of points
|
||||
float nearDepth = 1.0f, farDepth = 0.0f;
|
||||
for (int32 i = 0; i < points.Length(); i++)
|
||||
@@ -729,8 +761,8 @@ Float2 RenderTools::GetDepthBounds(const RenderView& view, const Span<Float3>& p
|
||||
nearDepth = Math::Clamp(nearDepth, 0.0f, 1.0f);
|
||||
farDepth = Math::Clamp(farDepth, nearDepth, 1.0f);
|
||||
|
||||
// TODO: swap depths when using reversed depth buffer
|
||||
return Float2(nearDepth, farDepth);
|
||||
#endif
|
||||
}
|
||||
|
||||
Float2 RenderTools::GetDepthBounds(const RenderView& view, const BoundingBox& bounds)
|
||||
@@ -749,11 +781,21 @@ Float2 RenderTools::GetDepthBounds(const RenderView& view, const OrientedBoundin
|
||||
|
||||
float RenderTools::GetDepthBounds(const RenderView& view, const Float3& point, bool near)
|
||||
{
|
||||
#if REVERSE_Z
|
||||
Float3 viewPoint = Float3::Transform(point, view.View);
|
||||
viewPoint.Z = Math::Clamp(viewPoint.Z, view.Near, view.Far);
|
||||
|
||||
Float4 clipPoint = Matrix::TransformPosition(view.Projection, Float4(0, 0, viewPoint.Z, 1));
|
||||
clipPoint /= clipPoint.W;
|
||||
|
||||
return clipPoint.Z;
|
||||
#else
|
||||
const Float4 pointClip = Matrix::TransformPosition(view.ViewProjection(), Float4(point, 1.0));
|
||||
float depth = pointClip.Z / pointClip.W;
|
||||
if (depth >= 1.0f)
|
||||
depth = near ? 0.0f : 1.0f; // Point is behind the view
|
||||
return Math::Clamp(depth, 0.0f, 1.0f);
|
||||
#endif
|
||||
}
|
||||
|
||||
float RenderTools::GetDepthBounds(const RenderView& view, float viewDistance, bool near)
|
||||
|
||||
@@ -173,7 +173,12 @@ public:
|
||||
static Float2 GetDepthBounds(const RenderView& view, const OrientedBoundingBox& bounds);
|
||||
static float GetDepthBounds(const RenderView& view, const Float3& point, bool near);
|
||||
static float GetDepthBounds(const RenderView& view, float viewDistance, bool near);
|
||||
static constexpr float DepthBoundMaxBackground = 1.0f - 0.0000001f; // Skip background/sky pixels from shading
|
||||
// Skip background/sky pixels from shading
|
||||
#if REVERSE_Z
|
||||
static constexpr float DepthBoundMaxBackground = 0.0000001f;
|
||||
#else
|
||||
static constexpr float DepthBoundMaxBackground = 1.0f - 0.0000001f;
|
||||
#endif
|
||||
|
||||
// Calculates error for a given render target format to reduce floating-point precision artifacts via QuantizeColor (from Noise.hlsl).
|
||||
static Float3 GetColorQuantizationError(PixelFormat format);
|
||||
|
||||
@@ -65,7 +65,11 @@ void RenderView::Prepare(RenderContext& renderContext)
|
||||
void RenderView::PrepareCache(const RenderContext& renderContext, float width, float height, const Float2& temporalAAJitter, const RenderView* mainView)
|
||||
{
|
||||
// The same format used by the Flax common shaders and postFx materials
|
||||
ViewInfo = Float4(1.0f / Projection.M11, 1.0f / Projection.M22, Far / (Far - Near), (-Far * Near) / (Far - Near) / Far);
|
||||
#if REVERSE_Z
|
||||
ViewInfo = Float4(1.0f / Projection.M11, 1.0f / Projection.M22, -Near / (Far - Near), (Far * Near) / (Far - Near) / Far);
|
||||
#else
|
||||
ViewInfo = Float4(1.0f / Projection.M11, 1.0f / Projection.M22, Far / (Far - Near), -(Far * Near) / (Far - Near) / Far);
|
||||
#endif
|
||||
ScreenSize = Float4(width, height, 1.0f / width, 1.0f / height);
|
||||
|
||||
TemporalAAJitter.Z = TemporalAAJitter.X;
|
||||
|
||||
@@ -188,17 +188,41 @@ bool ShaderCacheManagerService::Init()
|
||||
int32 ShaderCacheVersion = -1;
|
||||
int32 MaterialGraphVersion = -1;
|
||||
int32 ParticleGraphVersion = -1;
|
||||
bool ShaderDebug;
|
||||
bool ShaderProfile;
|
||||
};
|
||||
CacheVersion cacheVersion;
|
||||
const String cacheVerFile = rootDir / TEXT("CacheVersion");
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32 ShaderDebug : 1;
|
||||
uint32 ShaderProfile : 1;
|
||||
uint32 ReverseZ : 1;
|
||||
};
|
||||
uint32 Flags;
|
||||
};
|
||||
|
||||
CacheVersion()
|
||||
{
|
||||
Platform::MemoryClear(this, sizeof(*this));
|
||||
}
|
||||
|
||||
void InitDefault()
|
||||
{
|
||||
EngineVersion = FLAXENGINE_VERSION_BUILD;
|
||||
ShaderCacheVersion = GPU_SHADER_CACHE_VERSION;
|
||||
MaterialGraphVersion = MATERIAL_GRAPH_VERSION;
|
||||
ParticleGraphVersion = PARTICLE_GPU_GRAPH_VERSION;
|
||||
Flags = 0;
|
||||
#if USE_EDITOR
|
||||
const bool shaderDebug = CommandLine::Options.ShaderDebug.IsTrue();
|
||||
const bool shaderProfile = CommandLine::Options.ShaderProfile.IsTrue();
|
||||
#else
|
||||
const bool shaderDebug = false;
|
||||
ShaderDebug = CommandLine::Options.ShaderDebug.IsTrue();
|
||||
ShaderProfile = CommandLine::Options.ShaderProfile.IsTrue();
|
||||
#endif
|
||||
#if REVERSE_Z
|
||||
ReverseZ = true;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
CacheVersion cacheVersion, cacheVersionDefault;
|
||||
cacheVersionDefault.InitDefault();
|
||||
const String cacheVerFile = rootDir / TEXT("CacheVersion");
|
||||
if (FileSystem::FileExists(cacheVerFile))
|
||||
{
|
||||
if (File::ReadAllBytes(cacheVerFile, (byte*)&cacheVersion, sizeof(cacheVersion)))
|
||||
@@ -207,34 +231,25 @@ bool ShaderCacheManagerService::Init()
|
||||
LOG(Warning, "Failed to read the shaders cache database version file.");
|
||||
}
|
||||
}
|
||||
if (cacheVersion.EngineVersion != FLAXENGINE_VERSION_BUILD
|
||||
|| cacheVersion.ShaderCacheVersion != GPU_SHADER_CACHE_VERSION
|
||||
|| cacheVersion.MaterialGraphVersion != MATERIAL_GRAPH_VERSION
|
||||
|| cacheVersion.ParticleGraphVersion != PARTICLE_GPU_GRAPH_VERSION
|
||||
|| cacheVersion.ShaderDebug != shaderDebug
|
||||
|| cacheVersion.ShaderProfile != shaderProfile
|
||||
if (cacheVersion.EngineVersion != cacheVersionDefault.EngineVersion
|
||||
|| cacheVersion.ShaderCacheVersion != cacheVersionDefault.ShaderCacheVersion
|
||||
|| cacheVersion.MaterialGraphVersion != cacheVersionDefault.MaterialGraphVersion
|
||||
|| cacheVersion.ParticleGraphVersion != cacheVersionDefault.ParticleGraphVersion
|
||||
|| cacheVersion.Flags != cacheVersionDefault.Flags
|
||||
)
|
||||
{
|
||||
LOG(Warning, "Shaders cache database is invalid. Performing reset.");
|
||||
|
||||
if (FileSystem::DirectoryExists(rootDir) && FileSystem::DeleteDirectory(rootDir))
|
||||
{
|
||||
LOG(Warning, "Failed to reset the shaders cache database.");
|
||||
LOG(Warning, "Failed to reset shaders cache database.");
|
||||
}
|
||||
if (FileSystem::CreateDirectory(rootDir))
|
||||
{
|
||||
LOG(Error, "Failed to createe the shaders cache database directory.");
|
||||
LOG(Error, "Failed to create shaders cache database directory.");
|
||||
}
|
||||
|
||||
cacheVersion.EngineVersion = FLAXENGINE_VERSION_BUILD;
|
||||
cacheVersion.ShaderCacheVersion = GPU_SHADER_CACHE_VERSION;
|
||||
cacheVersion.MaterialGraphVersion = MATERIAL_GRAPH_VERSION;
|
||||
cacheVersion.ParticleGraphVersion = PARTICLE_GPU_GRAPH_VERSION;
|
||||
cacheVersion.ShaderDebug = shaderDebug;
|
||||
cacheVersion.ShaderProfile = shaderProfile;
|
||||
if (File::WriteAllBytes(cacheVerFile, (byte*)&cacheVersion, sizeof(cacheVersion)))
|
||||
if (File::WriteAllBytes(cacheVerFile, (byte*)&cacheVersionDefault, sizeof(cacheVersionDefault)))
|
||||
{
|
||||
LOG(Error, "Failed to create the shaders cache database version file.");
|
||||
LOG(Error, "Failed to create shaders cache database version file.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@ API_ENUM() enum class GPUSamplerCompareFunction
|
||||
Never = 0,
|
||||
/// <summary>If the source data is less than the destination data, the comparison passes.</summary>
|
||||
Less = 1,
|
||||
/// <summary>If the source data is greater than the destination data, the comparison passes.</summary>
|
||||
Greater = 2,
|
||||
|
||||
API_ENUM(Attributes="HideInEditor") MAX
|
||||
};
|
||||
|
||||
@@ -535,7 +535,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="result">The destination texture data container.</param>
|
||||
/// <returns>True if cannot download data, otherwise false.</returns>
|
||||
API_FUNCTION() bool DownloadData(TextureData& result);
|
||||
API_FUNCTION() bool DownloadData(API_PARAM(Out) TextureData& result);
|
||||
|
||||
/// <summary>
|
||||
/// Creates GPU async task that will gather texture data from the GPU.
|
||||
|
||||
@@ -101,6 +101,30 @@ bool TextureMipData::GetPixels(Array<Color32>& pixels, int32 width, int32 height
|
||||
src += srcRowSize;
|
||||
}
|
||||
}
|
||||
if (PixelFormatExtensions::IsBGRAOrder(format))
|
||||
{
|
||||
// BGRA -> RGBA
|
||||
for (int32 y = 0; y < height; y++)
|
||||
{
|
||||
for (int32 x = 0; x < width; x++)
|
||||
{
|
||||
auto& color = *((Color32*)(dst + y * RowPitch + x * sizeof(Color32)));
|
||||
color = Color32(color.B, color.G, color.R, color.A);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (PixelFormatExtensions::IsSRGB(format))
|
||||
{
|
||||
// sRGB -> Linear
|
||||
for (int32 y = 0; y < height; y++)
|
||||
{
|
||||
for (int32 x = 0; x < width; x++)
|
||||
{
|
||||
auto& color = *((Color32*)(dst + y * RowPitch + x * sizeof(Color32)));
|
||||
color = Color32(Color::SrgbToLinear(Color(color)));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
@@ -118,7 +142,10 @@ bool TextureMipData::GetPixels(Array<Color32>& pixels, int32 width, int32 height
|
||||
}
|
||||
return false;
|
||||
}
|
||||
LOG(Error, "Unsupported texture data format {0}.", ScriptingEnum::ToString(format));
|
||||
if (PixelFormatExtensions::IsCompressed(format))
|
||||
LOG(Error, "Unsupported texture data format {0}. Compressed texture data cannot be accessed directly without decompressing first.", ScriptingEnum::ToString(format));
|
||||
else
|
||||
LOG(Error, "Unsupported texture data format {0}.", ScriptingEnum::ToString(format));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -221,7 +248,7 @@ void TextureData::Clear()
|
||||
Items.Resize(0, false);
|
||||
}
|
||||
|
||||
bool TextureData::GetPixels(Array<Color32>& pixels, int32 mipIndex, int32 arrayIndex)
|
||||
bool TextureData::GetPixels(Array<Color32>& pixels, int32 mipIndex, int32 arrayIndex) const
|
||||
{
|
||||
if (Items.IsValidIndex(arrayIndex) && Items.Get()[arrayIndex].Mips.IsValidIndex(mipIndex))
|
||||
{
|
||||
@@ -232,7 +259,7 @@ bool TextureData::GetPixels(Array<Color32>& pixels, int32 mipIndex, int32 arrayI
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TextureData::GetPixels(Array<Color>& pixels, int32 mipIndex, int32 arrayIndex)
|
||||
bool TextureData::GetPixels(Array<Color>& pixels, int32 mipIndex, int32 arrayIndex) const
|
||||
{
|
||||
if (Items.IsValidIndex(arrayIndex) && Items.Get()[arrayIndex].Mips.IsValidIndex(mipIndex))
|
||||
{
|
||||
@@ -726,6 +753,17 @@ bool TextureBase::InitCSharp(void* ptr)
|
||||
return Init(initData);
|
||||
}
|
||||
|
||||
TextureData* TextureBase::GetTextureData()
|
||||
{
|
||||
auto result = New<TextureData>();
|
||||
if (GetTextureData(*result, false))
|
||||
{
|
||||
Delete(result);
|
||||
result = nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
uint64 TextureBase::GetMemoryUsage() const
|
||||
|
||||
@@ -5,20 +5,6 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
partial class GPUTexture
|
||||
{
|
||||
/// <summary>
|
||||
/// Downloads the texture data to be accessible from CPU. For frequent access, use staging textures, otherwise current thread will be stalled to wait for the GPU frame to copy data into staging buffer.
|
||||
/// </summary>
|
||||
/// <returns>Downloaded texture data container, or nul if failed.</returns>
|
||||
[Unmanaged]
|
||||
public TextureData DownloadData()
|
||||
{
|
||||
var result = new TextureData();
|
||||
return DownloadData(result) ? null : result;
|
||||
}
|
||||
}
|
||||
|
||||
partial class TextureBase
|
||||
{
|
||||
/// <summary>
|
||||
@@ -36,6 +22,16 @@ namespace FlaxEngine
|
||||
/// </summary>
|
||||
public const int MaxArraySize = 512;
|
||||
|
||||
/// <summary>
|
||||
/// Loads the texture data from the asset.
|
||||
/// </summary>
|
||||
/// <remarks>Use with caution as this operation loads texture data from the file.</remarks>
|
||||
/// <returns>The loaded texture data or null if failed.</returns>
|
||||
public TextureData GetTextureData()
|
||||
{
|
||||
return Internal_GetTextureData(__unmanagedPtr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The texture data initialization container.
|
||||
/// </summary>
|
||||
|
||||
@@ -162,6 +162,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the mip data.
|
||||
/// </summary>
|
||||
/// <remarks>Use with caution as this operation loads texture data from the file.</remarks>
|
||||
/// <param name="mipIndex">The mip index (zero-based).</param>
|
||||
/// <param name="rowPitch">The data row pitch (in bytes).</param>
|
||||
/// <param name="slicePitch">The data slice pitch (in bytes).</param>
|
||||
@@ -171,6 +172,7 @@ public:
|
||||
/// <summary>
|
||||
/// Loads the texture data from the asset.
|
||||
/// </summary>
|
||||
/// <remarks>Use with caution as this operation loads texture data from the file.</remarks>
|
||||
/// <param name="result">The result data.</param>
|
||||
/// <param name="copyData">True if copy asset data to the result buffer, otherwise texture data will be linked to the internal storage (then the data is valid while asset is loaded and there is no texture data copy operations - faster).</param>
|
||||
/// <returns>True if cannot load data, otherwise false.</returns>
|
||||
@@ -179,6 +181,7 @@ public:
|
||||
/// <summary>
|
||||
/// Loads the texture data from the asset (single mip).
|
||||
/// </summary>
|
||||
/// <remarks>Use with caution as this operation loads texture data from the file.</remarks>
|
||||
/// <param name="result">The result data.</param>
|
||||
/// <param name="mipIndex">The mip index (zero-based).</param>
|
||||
/// <param name="arrayIndex">The array or depth slice index (zero-based).</param>
|
||||
@@ -189,6 +192,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the texture pixels as Color32 array.
|
||||
/// </summary>
|
||||
/// <remarks>Use with caution as this operation loads texture data from the file.</remarks>
|
||||
/// <remarks>Supported only for 'basic' texture formats (uncompressed, single plane).</remarks>
|
||||
/// <param name="pixels">The result texture pixels array.</param>
|
||||
/// <param name="mipIndex">The mip index (zero-based).</param>
|
||||
@@ -199,6 +203,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the texture pixels as Color array.
|
||||
/// </summary>
|
||||
/// <remarks>Use with caution as this operation loads texture data from the file.</remarks>
|
||||
/// <remarks>Supported only for 'basic' texture formats (uncompressed, single plane).</remarks>
|
||||
/// <param name="pixels">The result texture pixels array.</param>
|
||||
/// <param name="mipIndex">The mip index (zero-based).</param>
|
||||
@@ -252,6 +257,7 @@ private:
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
// Internal bindings
|
||||
API_FUNCTION(NoProxy) bool InitCSharp(void* ptr);
|
||||
API_FUNCTION(NoProxy) TextureData* GetTextureData();
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
@@ -132,7 +132,7 @@ public:
|
||||
/// <param name="mipIndex">The mip index (zero-based).</param>
|
||||
/// <param name="arrayIndex">The array or depth slice index (zero-based).</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
API_FUNCTION() bool GetPixels(API_PARAM(Out) Array<Color32>& pixels, int32 mipIndex = 0, int32 arrayIndex = 0);
|
||||
API_FUNCTION() bool GetPixels(API_PARAM(Out) Array<Color32>& pixels, int32 mipIndex = 0, int32 arrayIndex = 0) const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the texture pixels as Color array.
|
||||
@@ -142,5 +142,5 @@ public:
|
||||
/// <param name="mipIndex">The mip index (zero-based).</param>
|
||||
/// <param name="arrayIndex">The array or depth slice index (zero-based).</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
API_FUNCTION() bool GetPixels(API_PARAM(Out) Array<Color>& pixels, int32 mipIndex = 0, int32 arrayIndex = 0);
|
||||
API_FUNCTION() bool GetPixels(API_PARAM(Out) Array<Color>& pixels, int32 mipIndex = 0, int32 arrayIndex = 0) const;
|
||||
};
|
||||
|
||||
@@ -499,6 +499,7 @@ void GPUContextDX11::UpdateCB(GPUConstantBuffer* cb, const void* data)
|
||||
return;
|
||||
|
||||
_context->UpdateSubresource(cbDX11->GetBuffer(), 0, nullptr, data, size, 1);
|
||||
RENDER_STAT_DATA_UPLOAD(size);
|
||||
}
|
||||
|
||||
void GPUContextDX11::Dispatch(GPUShaderProgramCS* shader, uint32 threadGroupCountX, uint32 threadGroupCountY, uint32 threadGroupCountZ)
|
||||
@@ -904,6 +905,7 @@ void GPUContextDX11::UpdateBuffer(GPUBuffer* buffer, const void* data, uint32 si
|
||||
box.bottom = 1;
|
||||
_context->UpdateSubresource(bufferDX11->GetResource(), 0, &box, data, size, 0);
|
||||
}
|
||||
RENDER_STAT_DATA_UPLOAD(size);
|
||||
}
|
||||
|
||||
void GPUContextDX11::CopyBuffer(GPUBuffer* dstBuffer, GPUBuffer* srcBuffer, uint32 size, uint32 dstOffset, uint32 srcOffset)
|
||||
@@ -934,6 +936,7 @@ void GPUContextDX11::UpdateTexture(GPUTexture* texture, int32 arrayIndex, int32
|
||||
if (texture->IsVolume())
|
||||
depthPitch /= Math::Max(1, texture->Depth() >> mipIndex);
|
||||
_context->UpdateSubresource(textureDX11->GetResource(), subresourceIndex, nullptr, data, (UINT)rowPitch, (UINT)depthPitch);
|
||||
RENDER_STAT_DATA_UPLOAD(slicePitch);
|
||||
|
||||
//D3D11_MAPPED_SUBRESOURCE mapped;
|
||||
//_device->GetIM()->Map(_resource, textureMipIndex, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
bool EnableNvapi = false;
|
||||
#endif
|
||||
#if COMPILE_WITH_AGS
|
||||
#define AGS_EXCLUDE_DIRECTX_12
|
||||
#include <ThirdParty/AGS/amd_ags.h>
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
@@ -87,6 +88,37 @@ static D3D11_STENCIL_OP ToDX11(StencilOperation value)
|
||||
}
|
||||
}
|
||||
|
||||
static RendererType GetRendererType(GPUAdapterDX* adapter)
|
||||
{
|
||||
switch (adapter->MaxFeatureLevel)
|
||||
{
|
||||
case D3D_FEATURE_LEVEL_10_0:
|
||||
return RendererType::DirectX10;
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
return RendererType::DirectX10_1;
|
||||
case D3D_FEATURE_LEVEL_11_0:
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
return RendererType::DirectX11;
|
||||
default:
|
||||
return RendererType::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
static ShaderProfile GetShaderProfile(GPUAdapterDX* adapter)
|
||||
{
|
||||
switch (adapter->MaxFeatureLevel)
|
||||
{
|
||||
case D3D_FEATURE_LEVEL_10_0:
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
return ShaderProfile::DirectX_SM4;
|
||||
case D3D_FEATURE_LEVEL_11_0:
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
return ShaderProfile::DirectX_SM5;
|
||||
default:
|
||||
return ShaderProfile::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
static bool TryCreateDevice(IDXGIAdapter* adapter, D3D_FEATURE_LEVEL maxFeatureLevel, D3D_FEATURE_LEVEL* featureLevel)
|
||||
{
|
||||
ID3D11Device* device = nullptr;
|
||||
@@ -335,7 +367,7 @@ GPUDevice* GPUDeviceDX11::Create()
|
||||
}
|
||||
|
||||
GPUDeviceDX11::GPUDeviceDX11(IDXGIFactory* dxgiFactory, GPUAdapterDX* adapter)
|
||||
: GPUDeviceDX(getRendererType(adapter), getShaderProfile(adapter), adapter)
|
||||
: GPUDeviceDX(::GetRendererType(adapter), ::GetShaderProfile(adapter), adapter)
|
||||
, _factoryDXGI(dxgiFactory)
|
||||
{
|
||||
Platform::MemoryClear(RasterizerStates, sizeof(RasterizerStates));
|
||||
@@ -726,7 +758,11 @@ bool GPUDeviceDX11::Init()
|
||||
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
|
||||
samplerDesc.MipLODBias = 0.0f;
|
||||
samplerDesc.MaxAnisotropy = 1;
|
||||
#if REVERSE_Z
|
||||
samplerDesc.ComparisonFunc = D3D11_COMPARISON_GREATER;
|
||||
#else
|
||||
samplerDesc.ComparisonFunc = D3D11_COMPARISON_LESS_EQUAL;
|
||||
#endif
|
||||
|
||||
// Linear Clamp
|
||||
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
|
||||
@@ -77,6 +77,9 @@ bool GPUSamplerDX11::OnInit()
|
||||
case GPUSamplerCompareFunction::Less:
|
||||
samplerDesc.ComparisonFunc = D3D11_COMPARISON_LESS;
|
||||
break;
|
||||
case GPUSamplerCompareFunction::Greater:
|
||||
samplerDesc.ComparisonFunc = D3D11_COMPARISON_GREATER;
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Engine/Graphics/PixelFormatExtensions.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Graphics/Async/Tasks/GPUUploadBufferTask.h"
|
||||
#include <ThirdParty/D3D12MemoryAllocator/D3D12MemAlloc.h>
|
||||
|
||||
void GPUBufferViewDX12::SetSRV(D3D12_SHADER_RESOURCE_VIEW_DESC& srvDesc)
|
||||
{
|
||||
@@ -115,34 +116,24 @@ bool GPUBufferDX12::OnInit()
|
||||
resourceDesc.Flags |= D3D12XBOX_RESOURCE_FLAG_ALLOW_INDIRECT_BUFFER;
|
||||
#endif
|
||||
|
||||
// Create allocation description
|
||||
D3D12_HEAP_PROPERTIES heapProperties;
|
||||
// Create resource
|
||||
D3D12MA::ALLOCATION_DESC allocationDesc = {};
|
||||
switch (_desc.Usage)
|
||||
{
|
||||
case GPUResourceUsage::StagingUpload:
|
||||
case GPUResourceUsage::Staging:
|
||||
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
allocationDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
|
||||
break;
|
||||
case GPUResourceUsage::StagingReadback:
|
||||
heapProperties.Type = D3D12_HEAP_TYPE_READBACK;
|
||||
allocationDesc.HeapType = D3D12_HEAP_TYPE_READBACK;
|
||||
break;
|
||||
default:
|
||||
heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
|
||||
}
|
||||
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapProperties.CreationNodeMask = 1;
|
||||
heapProperties.VisibleNodeMask = 1;
|
||||
|
||||
// Create resource
|
||||
ID3D12Resource* resource;
|
||||
#if PLATFORM_WINDOWS
|
||||
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
|
||||
D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON;
|
||||
VALIDATE_DIRECTX_CALL(_device->GetDevice()->CreateCommittedResource(&heapProperties, heapFlags, &resourceDesc, initialState, nullptr, IID_PPV_ARGS(&resource)));
|
||||
HRESULT result = _device->Allocator->CreateResource(&allocationDesc, &resourceDesc, initialState, nullptr, &_allocation, IID_PPV_ARGS(&resource));
|
||||
LOG_DIRECTX_RESULT_WITH_RETURN(result, true);
|
||||
|
||||
// Set state
|
||||
initResource(resource, initialState, 1);
|
||||
|
||||
@@ -269,6 +269,7 @@ void GPUContextDX12::Reset()
|
||||
_currentAllocator = _device->GetCommandQueue()->RequestAllocator();
|
||||
_commandList->Reset(_currentAllocator, nullptr);
|
||||
}
|
||||
IsOpen = true;
|
||||
|
||||
// Setup initial state
|
||||
_currentState = nullptr;
|
||||
@@ -310,6 +311,11 @@ void GPUContextDX12::Reset()
|
||||
_commandList->IASetVertexBuffers(GPU_MAX_VB_BINDED, 1, &dummyVBView);
|
||||
|
||||
ForceRebindDescriptors();
|
||||
|
||||
// Discard resources not created during rendering
|
||||
for (auto* resource : _device->PendingResourceDiscards)
|
||||
_commandList->DiscardResource(resource, nullptr);
|
||||
_device->PendingResourceDiscards.Clear();
|
||||
}
|
||||
|
||||
uint64 GPUContextDX12::Execute(bool waitForCompletion)
|
||||
@@ -322,6 +328,7 @@ uint64 GPUContextDX12::Execute(bool waitForCompletion)
|
||||
_currentState = nullptr;
|
||||
|
||||
// Execute commands
|
||||
IsOpen = false;
|
||||
const uint64 fenceValue = queue->ExecuteCommandList(_commandList);
|
||||
|
||||
// Cleanup used allocator
|
||||
@@ -1124,6 +1131,7 @@ void GPUContextDX12::UpdateCB(GPUConstantBuffer* cb, const void* data)
|
||||
|
||||
// Allocate bytes for the buffer
|
||||
auto allocation = _device->UploadBuffer.Allocate(size, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
|
||||
RENDER_STAT_DATA_UPLOAD(size);
|
||||
|
||||
// Copy data
|
||||
Platform::MemoryCopy(allocation.CPUAddress, data, allocation.Size);
|
||||
@@ -1381,6 +1389,7 @@ void GPUContextDX12::UpdateBuffer(GPUBuffer* buffer, const void* data, uint32 si
|
||||
flushRBs();
|
||||
|
||||
_device->UploadBuffer.UploadBuffer(GetCommandList(), bufferDX12->GetResource(), offset, data, size);
|
||||
RENDER_STAT_DATA_UPLOAD(size);
|
||||
}
|
||||
|
||||
void GPUContextDX12::CopyBuffer(GPUBuffer* dstBuffer, GPUBuffer* srcBuffer, uint32 size, uint32 dstOffset, uint32 srcOffset)
|
||||
@@ -1407,6 +1416,7 @@ void GPUContextDX12::UpdateTexture(GPUTexture* texture, int32 arrayIndex, int32
|
||||
flushRBs();
|
||||
|
||||
_device->UploadBuffer.UploadTexture(GetCommandList(), textureDX12->GetResource(), data, rowPitch, slicePitch, mipIndex, arrayIndex);
|
||||
RENDER_STAT_DATA_UPLOAD(slicePitch);
|
||||
}
|
||||
|
||||
void GPUContextDX12::CopyTexture(GPUTexture* dstResource, uint32 dstSubresource, uint32 dstX, uint32 dstY, uint32 dstZ, GPUTexture* srcResource, uint32 srcSubresource)
|
||||
@@ -1462,6 +1472,7 @@ void GPUContextDX12::ResetCounter(GPUBuffer* buffer)
|
||||
|
||||
uint32 value = 0;
|
||||
_device->UploadBuffer.UploadBuffer(GetCommandList(), counter->GetResource(), 0, &value, 4);
|
||||
RENDER_STAT_DATA_UPLOAD(4);
|
||||
|
||||
SetResourceState(counter, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user