Merge branch 'master' into 1.8
This commit is contained in:
@@ -133,6 +133,8 @@ void PS_Forward(
|
|||||||
// Add lighting (apply ambient occlusion)
|
// Add lighting (apply ambient occlusion)
|
||||||
output.rgb += light.rgb * gBuffer.AO;
|
output.rgb += light.rgb * gBuffer.AO;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#if USE_FOG
|
#if USE_FOG
|
||||||
// Calculate exponential height fog
|
// Calculate exponential height fog
|
||||||
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0);
|
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0);
|
||||||
@@ -148,7 +150,5 @@ void PS_Forward(
|
|||||||
output = float4(lerp(float3(1, 1, 1), output.rgb, fog.aaa * fog.aaa), output.a);
|
output = float4(lerp(float3(1, 1, 1), output.rgb, fog.aaa * fog.aaa), output.a);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,22 @@ namespace FlaxEditor.Content
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract string TypeName { get; }
|
public abstract string TypeName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this instance is virtual Proxy not linked to any asset.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual bool IsVirtual { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether [is virtual proxy].
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if [is virtual proxy]; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public bool IsVirtualProxy()
|
||||||
|
{
|
||||||
|
return IsVirtual && CanExport == false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if this proxy supports the given asset type id at the given path.
|
/// Checks if this proxy supports the given asset type id at the given path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using FlaxEditor.CustomEditors;
|
using FlaxEditor.CustomEditors;
|
||||||
|
using FlaxEditor.GUI.Docking;
|
||||||
using FlaxEditor.Windows;
|
using FlaxEditor.Windows;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
using DockState = FlaxEditor.GUI.Docking.DockState;
|
|
||||||
|
|
||||||
namespace FlaxEditor
|
namespace FlaxEditor
|
||||||
{
|
{
|
||||||
@@ -97,9 +97,12 @@ namespace FlaxEditor
|
|||||||
/// Shows the window.
|
/// Shows the window.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Initial window state.</param>
|
/// <param name="state">Initial window state.</param>
|
||||||
public void Show(DockState state = DockState.Float)
|
/// <param name="toDock">The panel to dock to, if any.</param>
|
||||||
|
/// <param name="autoSelect">Only used if <paramref name="toDock"/> is set. If true the window will be selected after docking it.</param>
|
||||||
|
/// <param name="splitterValue">The splitter value to use if toDock is not null. If not specified, a default value will be used.</param>
|
||||||
|
public void Show(DockState state = DockState.Float, DockPanel toDock = null, bool autoSelect = true, float? splitterValue = null)
|
||||||
{
|
{
|
||||||
_win.Show(state);
|
_win.Show(state, toDock, autoSelect, splitterValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FlaxEditor.CustomEditors.Elements;
|
using FlaxEditor.CustomEditors.Elements;
|
||||||
using FlaxEditor.GUI.Dialogs;
|
using FlaxEditor.GUI.Dialogs;
|
||||||
|
using FlaxEditor.GUI.Input;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
|
|
||||||
@@ -17,6 +18,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
private FloatValueElement _yElement;
|
private FloatValueElement _yElement;
|
||||||
private FloatValueElement _zElement;
|
private FloatValueElement _zElement;
|
||||||
private FloatValueElement _wElement;
|
private FloatValueElement _wElement;
|
||||||
|
private ColorValueBox _colorBox;
|
||||||
private CustomElement<ColorSelector> _trackball;
|
private CustomElement<ColorSelector> _trackball;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -53,7 +55,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
gridControl.SlotPadding = new Margin(4, 2, 2, 2);
|
gridControl.SlotPadding = new Margin(4, 2, 2, 2);
|
||||||
gridControl.ClipChildren = false;
|
gridControl.ClipChildren = false;
|
||||||
gridControl.SlotsHorizontally = 1;
|
gridControl.SlotsHorizontally = 1;
|
||||||
gridControl.SlotsVertically = 4;
|
gridControl.SlotsVertically = 5;
|
||||||
|
|
||||||
LimitAttribute limit = null;
|
LimitAttribute limit = null;
|
||||||
var attributes = Values.GetAttributes();
|
var attributes = Values.GetAttributes();
|
||||||
@@ -61,7 +63,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
{
|
{
|
||||||
limit = (LimitAttribute)attributes.FirstOrDefault(x => x is LimitAttribute);
|
limit = (LimitAttribute)attributes.FirstOrDefault(x => x is LimitAttribute);
|
||||||
}
|
}
|
||||||
|
_colorBox = grid.Custom<ColorValueBox>().CustomControl;
|
||||||
|
_colorBox.ValueChanged += OnColorBoxChanged;
|
||||||
_xElement = CreateFloatEditor(grid, limit, Color.Red);
|
_xElement = CreateFloatEditor(grid, limit, Color.Red);
|
||||||
_yElement = CreateFloatEditor(grid, limit, Color.Green);
|
_yElement = CreateFloatEditor(grid, limit, Color.Green);
|
||||||
_zElement = CreateFloatEditor(grid, limit, Color.Blue);
|
_zElement = CreateFloatEditor(grid, limit, Color.Blue);
|
||||||
@@ -93,6 +96,13 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
SetValue(value, token);
|
SetValue(value, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnColorBoxChanged()
|
||||||
|
{
|
||||||
|
var token = _colorBox.IsSliding ? this : null;
|
||||||
|
var color = _colorBox.Value;
|
||||||
|
SetValue(new Float4(color.R, color.G, color.B, color.A), token);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnValueChanged()
|
private void OnValueChanged()
|
||||||
{
|
{
|
||||||
if (IsSetBlocked)
|
if (IsSetBlocked)
|
||||||
@@ -130,6 +140,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
_yElement.Value = color.Y;
|
_yElement.Value = color.Y;
|
||||||
_zElement.Value = color.Z;
|
_zElement.Value = color.Z;
|
||||||
_wElement.Value = scale;
|
_wElement.Value = scale;
|
||||||
|
_colorBox.Value = new Color(color.X, color.Y, color.Z, scale);
|
||||||
_trackball.CustomControl.Color = Float3.Abs(color);
|
_trackball.CustomControl.Color = Float3.Abs(color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
_element.Value = asFloat;
|
_element.Value = asFloat;
|
||||||
else if (value is double asDouble)
|
else if (value is double asDouble)
|
||||||
_element.Value = (float)asDouble;
|
_element.Value = (float)asDouble;
|
||||||
|
else if (value is int asInt)
|
||||||
|
_element.Value = (float)asInt;
|
||||||
else
|
else
|
||||||
throw new Exception(string.Format("Invalid value type {0}.", value?.GetType().ToString() ?? "<null>"));
|
throw new Exception(string.Format("Invalid value type {0}.", value?.GetType().ToString() ?? "<null>"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,9 +66,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
public HeaderAttribute Header;
|
public HeaderAttribute Header;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The visible if attribute.
|
/// The visible if attributes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public VisibleIfAttribute VisibleIf;
|
public VisibleIfAttribute[] VisibleIfs;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The read-only attribute usage flag.
|
/// The read-only attribute usage flag.
|
||||||
@@ -128,7 +128,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
CustomEditorAlias = (CustomEditorAliasAttribute)attributes.FirstOrDefault(x => x is CustomEditorAliasAttribute);
|
CustomEditorAlias = (CustomEditorAliasAttribute)attributes.FirstOrDefault(x => x is CustomEditorAliasAttribute);
|
||||||
Space = (SpaceAttribute)attributes.FirstOrDefault(x => x is SpaceAttribute);
|
Space = (SpaceAttribute)attributes.FirstOrDefault(x => x is SpaceAttribute);
|
||||||
Header = (HeaderAttribute)attributes.FirstOrDefault(x => x is HeaderAttribute);
|
Header = (HeaderAttribute)attributes.FirstOrDefault(x => x is HeaderAttribute);
|
||||||
VisibleIf = (VisibleIfAttribute)attributes.FirstOrDefault(x => x is VisibleIfAttribute);
|
VisibleIfs = attributes.OfType<VisibleIfAttribute>().ToArray();
|
||||||
IsReadOnly = attributes.FirstOrDefault(x => x is ReadOnlyAttribute) != null;
|
IsReadOnly = attributes.FirstOrDefault(x => x is ReadOnlyAttribute) != null;
|
||||||
ExpandGroups = attributes.FirstOrDefault(x => x is ExpandGroupsAttribute) != null;
|
ExpandGroups = attributes.FirstOrDefault(x => x is ExpandGroupsAttribute) != null;
|
||||||
|
|
||||||
@@ -210,17 +210,24 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
private struct VisibleIfCache
|
private struct VisibleIfCache
|
||||||
{
|
{
|
||||||
public ScriptMemberInfo Target;
|
public ScriptMemberInfo Target;
|
||||||
public ScriptMemberInfo Source;
|
public ScriptMemberInfo[] Sources;
|
||||||
public PropertiesListElement PropertiesList;
|
public PropertiesListElement PropertiesList;
|
||||||
public GroupElement Group;
|
public GroupElement Group;
|
||||||
public bool Invert;
|
public bool[] InversionList;
|
||||||
public int LabelIndex;
|
public int LabelIndex;
|
||||||
|
|
||||||
public bool GetValue(object instance)
|
public bool GetValue(object instance)
|
||||||
{
|
{
|
||||||
var value = (bool)Source.GetValue(instance);
|
bool value = true;
|
||||||
if (Invert)
|
|
||||||
value = !value;
|
for (int i = 0; i < Sources.Length; i++)
|
||||||
|
{
|
||||||
|
bool currentValue = (bool)Sources[i].GetValue(instance);
|
||||||
|
if (InversionList[i])
|
||||||
|
currentValue = !currentValue;
|
||||||
|
|
||||||
|
value = value && currentValue;
|
||||||
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -298,40 +305,48 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ScriptMemberInfo GetVisibleIfSource(ScriptType type, VisibleIfAttribute visibleIf)
|
private static ScriptMemberInfo[] GetVisibleIfSources(ScriptType type, VisibleIfAttribute[] visibleIfs)
|
||||||
{
|
{
|
||||||
var property = type.GetProperty(visibleIf.MemberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
|
ScriptMemberInfo[] members = Array.Empty<ScriptMemberInfo>();
|
||||||
if (property != ScriptMemberInfo.Null)
|
|
||||||
|
for (int i = 0; i < visibleIfs.Length; i++)
|
||||||
{
|
{
|
||||||
if (!property.HasGet)
|
var property = type.GetProperty(visibleIfs[i].MemberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
|
||||||
|
if (property != ScriptMemberInfo.Null)
|
||||||
{
|
{
|
||||||
Debug.LogError("Invalid VisibleIf rule. Property has missing getter " + visibleIf.MemberName);
|
if (!property.HasGet)
|
||||||
return ScriptMemberInfo.Null;
|
{
|
||||||
|
Debug.LogError("Invalid VisibleIf rule. Property has missing getter " + visibleIfs[i].MemberName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (property.ValueType.Type != typeof(bool))
|
||||||
|
{
|
||||||
|
Debug.LogError("Invalid VisibleIf rule. Property has to return bool type " + visibleIfs[i].MemberName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
members = members.Append(property).ToArray();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (property.ValueType.Type != typeof(bool))
|
var field = type.GetField(visibleIfs[i].MemberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
|
||||||
|
if (field != ScriptMemberInfo.Null)
|
||||||
{
|
{
|
||||||
Debug.LogError("Invalid VisibleIf rule. Property has to return bool type " + visibleIf.MemberName);
|
if (field.ValueType.Type != typeof(bool))
|
||||||
return ScriptMemberInfo.Null;
|
{
|
||||||
|
Debug.LogError("Invalid VisibleIf rule. Field has to be bool type " + visibleIfs[i].MemberName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
members = members.Append(field).ToArray();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return property;
|
Debug.LogError("Invalid VisibleIf rule. Cannot find member " + visibleIfs[i].MemberName);
|
||||||
}
|
}
|
||||||
|
|
||||||
var field = type.GetField(visibleIf.MemberName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
|
return members;
|
||||||
if (field != ScriptMemberInfo.Null)
|
|
||||||
{
|
|
||||||
if (field.ValueType.Type != typeof(bool))
|
|
||||||
{
|
|
||||||
Debug.LogError("Invalid VisibleIf rule. Field has to be bool type " + visibleIf.MemberName);
|
|
||||||
return ScriptMemberInfo.Null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug.LogError("Invalid VisibleIf rule. Cannot find member " + visibleIf.MemberName);
|
|
||||||
return ScriptMemberInfo.Null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GroupPanelCheckIfCanRevert(LayoutElementsContainer layout, ref bool canRevertReference, ref bool canRevertDefault)
|
private static void GroupPanelCheckIfCanRevert(LayoutElementsContainer layout, ref bool canRevertReference, ref bool canRevertDefault)
|
||||||
@@ -575,7 +590,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
protected virtual void SpawnProperty(LayoutElementsContainer itemLayout, ValueContainer itemValues, ItemInfo item)
|
protected virtual void SpawnProperty(LayoutElementsContainer itemLayout, ValueContainer itemValues, ItemInfo item)
|
||||||
{
|
{
|
||||||
int labelIndex = 0;
|
int labelIndex = 0;
|
||||||
if ((item.IsReadOnly || item.VisibleIf != null) &&
|
if ((item.IsReadOnly || item.VisibleIfs.Length > 0) &&
|
||||||
itemLayout.Children.Count > 0 &&
|
itemLayout.Children.Count > 0 &&
|
||||||
itemLayout.Children[itemLayout.Children.Count - 1] is PropertiesListElement propertiesListElement)
|
itemLayout.Children[itemLayout.Children.Count - 1] is PropertiesListElement propertiesListElement)
|
||||||
{
|
{
|
||||||
@@ -616,7 +631,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (item.VisibleIf != null && itemLayout.Children.Count > 0)
|
if (item.VisibleIfs.Length > 0 && itemLayout.Children.Count > 0)
|
||||||
{
|
{
|
||||||
PropertiesListElement list = null;
|
PropertiesListElement list = null;
|
||||||
GroupElement group = null;
|
GroupElement group = null;
|
||||||
@@ -628,8 +643,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Get source member used to check rule
|
// Get source member used to check rule
|
||||||
var sourceMember = GetVisibleIfSource(item.Info.DeclaringType, item.VisibleIf);
|
var sourceMembers = GetVisibleIfSources(item.Info.DeclaringType, item.VisibleIfs);
|
||||||
if (sourceMember == ScriptType.Null)
|
if (sourceMembers.Length == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Resize cache
|
// Resize cache
|
||||||
@@ -645,11 +660,11 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
_visibleIfCaches[count] = new VisibleIfCache
|
_visibleIfCaches[count] = new VisibleIfCache
|
||||||
{
|
{
|
||||||
Target = item.Info,
|
Target = item.Info,
|
||||||
Source = sourceMember,
|
Sources = sourceMembers,
|
||||||
PropertiesList = list,
|
PropertiesList = list,
|
||||||
Group = group,
|
Group = group,
|
||||||
LabelIndex = labelIndex,
|
LabelIndex = labelIndex,
|
||||||
Invert = item.VisibleIf.Invert,
|
InversionList = item.VisibleIfs.Select((x, i) => x.Invert).ToArray(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using FlaxEditor.CustomEditors.Elements;
|
using FlaxEditor.CustomEditors.Elements;
|
||||||
|
using FlaxEditor.GUI;
|
||||||
|
using FlaxEditor.Scripting;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
|
using FlaxEngine.Utilities;
|
||||||
|
|
||||||
namespace FlaxEditor.CustomEditors.Editors
|
namespace FlaxEditor.CustomEditors.Editors
|
||||||
{
|
{
|
||||||
@@ -13,6 +17,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
public sealed class GuidEditor : CustomEditor
|
public sealed class GuidEditor : CustomEditor
|
||||||
{
|
{
|
||||||
private TextBoxElement _element;
|
private TextBoxElement _element;
|
||||||
|
private AssetPicker _picker;
|
||||||
|
private bool _isReference;
|
||||||
|
private bool _isRefreshing;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override DisplayStyle Style => DisplayStyle.Inline;
|
public override DisplayStyle Style => DisplayStyle.Inline;
|
||||||
@@ -20,8 +27,55 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Initialize(LayoutElementsContainer layout)
|
public override void Initialize(LayoutElementsContainer layout)
|
||||||
{
|
{
|
||||||
_element = layout.TextBox();
|
var attributes = Values.GetAttributes();
|
||||||
_element.TextBox.EditEnd += OnEditEnd;
|
var assetReference = (AssetReferenceAttribute)attributes?.FirstOrDefault(x => x is AssetReferenceAttribute);
|
||||||
|
if (assetReference != null)
|
||||||
|
{
|
||||||
|
_picker = layout.Custom<AssetPicker>().CustomControl;
|
||||||
|
ScriptType assetType = new ScriptType();
|
||||||
|
|
||||||
|
float height = 48;
|
||||||
|
if (assetReference.UseSmallPicker)
|
||||||
|
height = 32;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(assetReference.TypeName))
|
||||||
|
{
|
||||||
|
assetType = ScriptType.Void;
|
||||||
|
}
|
||||||
|
else if (assetReference.TypeName.Length > 1 && assetReference.TypeName[0] == '.')
|
||||||
|
{
|
||||||
|
// Generic file picker
|
||||||
|
assetType = ScriptType.Null;
|
||||||
|
_picker.Validator.FileExtension = assetReference.TypeName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var customType = TypeUtils.GetType(assetReference.TypeName);
|
||||||
|
if (customType != ScriptType.Null)
|
||||||
|
assetType = customType;
|
||||||
|
else if (!Content.Settings.GameSettings.OptionalPlatformSettings.Contains(assetReference.TypeName))
|
||||||
|
Debug.LogWarning(string.Format("Unknown asset type '{0}' to use for asset picker filter.", assetReference.TypeName));
|
||||||
|
else
|
||||||
|
assetType = ScriptType.Void;
|
||||||
|
}
|
||||||
|
|
||||||
|
_picker.Validator.AssetType = assetType;
|
||||||
|
_picker.Height = height;
|
||||||
|
_picker.SelectedItemChanged += OnSelectedItemChanged;
|
||||||
|
_isReference = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_element = layout.TextBox();
|
||||||
|
_element.TextBox.EditEnd += OnEditEnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSelectedItemChanged()
|
||||||
|
{
|
||||||
|
if (_isRefreshing)
|
||||||
|
return;
|
||||||
|
SetValue(_picker.Validator.SelectedID);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEditEnd()
|
private void OnEditEnd()
|
||||||
@@ -36,17 +90,32 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
public override void Refresh()
|
public override void Refresh()
|
||||||
{
|
{
|
||||||
base.Refresh();
|
base.Refresh();
|
||||||
|
_isRefreshing = true;
|
||||||
if (HasDifferentValues)
|
if (HasDifferentValues)
|
||||||
{
|
{
|
||||||
_element.TextBox.Text = string.Empty;
|
if (_isReference)
|
||||||
_element.TextBox.WatermarkText = "Different values";
|
{
|
||||||
|
// Not supported
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_element.TextBox.Text = string.Empty;
|
||||||
|
_element.TextBox.WatermarkText = "Different values";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_element.TextBox.Text = ((Guid)Values[0]).ToString("D");
|
if (_isReference)
|
||||||
_element.TextBox.WatermarkText = string.Empty;
|
{
|
||||||
|
_picker.Validator.SelectedID = (Guid)Values[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_element.TextBox.Text = ((Guid)Values[0]).ToString("D");
|
||||||
|
_element.TextBox.WatermarkText = string.Empty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
_isRefreshing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -518,9 +518,9 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal virtual void DockWindowInternal(DockState state, DockWindow window)
|
internal virtual void DockWindowInternal(DockState state, DockWindow window, bool autoSelect = true, float? splitterValue = null)
|
||||||
{
|
{
|
||||||
DockWindow(state, window);
|
DockWindow(state, window, autoSelect, splitterValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -528,7 +528,9 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">The state.</param>
|
/// <param name="state">The state.</param>
|
||||||
/// <param name="window">The window.</param>
|
/// <param name="window">The window.</param>
|
||||||
protected virtual void DockWindow(DockState state, DockWindow window)
|
/// <param name="autoSelect">Whether or not to automatically select the window after docking it.</param>
|
||||||
|
/// <param name="splitterValue">The splitter value to use when docking to window.</param>
|
||||||
|
protected virtual void DockWindow(DockState state, DockWindow window, bool autoSelect = true, float? splitterValue = null)
|
||||||
{
|
{
|
||||||
CreateTabsProxy();
|
CreateTabsProxy();
|
||||||
|
|
||||||
@@ -536,12 +538,12 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
if (state == DockState.DockFill)
|
if (state == DockState.DockFill)
|
||||||
{
|
{
|
||||||
// Add tab
|
// Add tab
|
||||||
AddTab(window);
|
AddTab(window, autoSelect);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Create child panel
|
// Create child panel
|
||||||
var dockPanel = CreateChildPanel(state, DefaultSplitterValue);
|
var dockPanel = CreateChildPanel(state, splitterValue ?? DefaultSplitterValue);
|
||||||
|
|
||||||
// Dock window as a tab in a child panel
|
// Dock window as a tab in a child panel
|
||||||
dockPanel.DockWindow(DockState.DockFill, window);
|
dockPanel.DockWindow(DockState.DockFill, window);
|
||||||
|
|||||||
@@ -63,12 +63,9 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
public bool IsHidden => !Visible || _dockedTo == null;
|
public bool IsHidden => !Visible || _dockedTo == null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the default window size.
|
/// Gets the default window size (in UI units, unscaled by DPI which is handled by windowing system).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
public virtual Float2 DefaultSize => new Float2(900, 580);
|
||||||
/// Scaled by the DPI, because the window should be large enough for its content on every monitor
|
|
||||||
/// </remarks>
|
|
||||||
public virtual Float2 DefaultSize => new Float2(900, 580) * DpiScale;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the serialization typename.
|
/// Gets the serialization typename.
|
||||||
@@ -217,7 +214,9 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">Initial window state.</param>
|
/// <param name="state">Initial window state.</param>
|
||||||
/// <param name="toDock">Panel to dock to it.</param>
|
/// <param name="toDock">Panel to dock to it.</param>
|
||||||
public void Show(DockState state = DockState.Float, DockPanel toDock = null)
|
/// <param name="autoSelect">Only used if <paramref name="toDock"/> is set. If true the window will be selected after docking it.</param>
|
||||||
|
/// <param name="splitterValue">Only used if <paramref name="toDock"/> is set. The splitter value to use. If not specified, a default value will be used.</param>
|
||||||
|
public void Show(DockState state = DockState.Float, DockPanel toDock = null, bool autoSelect = true, float? splitterValue = null)
|
||||||
{
|
{
|
||||||
if (state == DockState.Hidden)
|
if (state == DockState.Hidden)
|
||||||
{
|
{
|
||||||
@@ -235,7 +234,7 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
Undock();
|
Undock();
|
||||||
|
|
||||||
// Then dock
|
// Then dock
|
||||||
(toDock ?? _masterPanel).DockWindowInternal(state, this);
|
(toDock ?? _masterPanel).DockWindowInternal(state, this, autoSelect, splitterValue);
|
||||||
OnShow();
|
OnShow();
|
||||||
PerformLayout();
|
PerformLayout();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,11 @@ namespace FlaxEditor.GUI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public object[] Values { get; set; }
|
public object[] Values { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the cell background colors. Null if unused, transparent values are ignored.
|
||||||
|
/// </summary>
|
||||||
|
public Color[] BackgroundColors { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the row depth level.
|
/// Gets or sets the row depth level.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -58,6 +63,7 @@ namespace FlaxEditor.GUI
|
|||||||
{
|
{
|
||||||
float x = 0;
|
float x = 0;
|
||||||
int end = Mathf.Min(Values.Length, _table.Columns.Length);
|
int end = Mathf.Min(Values.Length, _table.Columns.Length);
|
||||||
|
var backgroundColors = BackgroundColors;
|
||||||
for (int i = 0; i < end; i++)
|
for (int i = 0; i < end; i++)
|
||||||
{
|
{
|
||||||
var column = _table.Columns[i];
|
var column = _table.Columns[i];
|
||||||
@@ -98,6 +104,8 @@ namespace FlaxEditor.GUI
|
|||||||
rect.Width -= leftDepthMargin;
|
rect.Width -= leftDepthMargin;
|
||||||
|
|
||||||
Render2D.PushClip(rect);
|
Render2D.PushClip(rect);
|
||||||
|
if (backgroundColors != null && backgroundColors[i].A > 0)
|
||||||
|
Render2D.FillRectangle(rect, backgroundColors[i]);
|
||||||
Render2D.DrawText(style.FontMedium, text, rect, style.Foreground, column.CellAlignment, TextAlignment.Center);
|
Render2D.DrawText(style.FontMedium, text, rect, style.Foreground, column.CellAlignment, TextAlignment.Center);
|
||||||
Render2D.PopClip();
|
Render2D.PopClip();
|
||||||
|
|
||||||
|
|||||||
@@ -196,6 +196,25 @@ namespace FlaxEditor.Modules
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the virtual proxy object from given path.
|
||||||
|
/// <br></br>use case if the asset u trying to display is not a flax asset but u like to add custom functionality
|
||||||
|
/// <br></br>to context menu,or display it the asset
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The asset path.</param>
|
||||||
|
/// <returns>Asset proxy or null if cannot find.</returns>
|
||||||
|
public AssetProxy GetAssetVirtuallProxy(string path)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Proxy.Count; i++)
|
||||||
|
{
|
||||||
|
if (Proxy[i] is AssetProxy proxy && proxy.IsVirtualProxy() && path.EndsWith(proxy.FileExtension, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Refreshes the given item folder. Tries to find new content items and remove not existing ones.
|
/// Refreshes the given item folder. Tries to find new content items and remove not existing ones.
|
||||||
@@ -996,7 +1015,14 @@ namespace FlaxEditor.Modules
|
|||||||
item = proxy?.ConstructItem(path, assetInfo.TypeName, ref assetInfo.ID);
|
item = proxy?.ConstructItem(path, assetInfo.TypeName, ref assetInfo.ID);
|
||||||
}
|
}
|
||||||
if (item == null)
|
if (item == null)
|
||||||
item = new FileItem(path);
|
{
|
||||||
|
var proxy = GetAssetVirtuallProxy(path);
|
||||||
|
item = proxy?.ConstructItem(path, assetInfo.TypeName, ref assetInfo.ID);
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
item = new FileItem(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Link
|
// Link
|
||||||
item.ParentFolder = parent.Folder;
|
item.ParentFolder = parent.Folder;
|
||||||
|
|||||||
@@ -36,6 +36,22 @@ namespace FlaxEditor.Modules
|
|||||||
{
|
{
|
||||||
public string AssemblyName;
|
public string AssemblyName;
|
||||||
public string TypeName;
|
public string TypeName;
|
||||||
|
|
||||||
|
public DockState DockState;
|
||||||
|
public DockPanel DockedTo;
|
||||||
|
public float? SplitterValue = null;
|
||||||
|
|
||||||
|
public bool SelectOnShow = false;
|
||||||
|
|
||||||
|
public bool Maximize;
|
||||||
|
public bool Minimize;
|
||||||
|
public Float2 FloatSize;
|
||||||
|
public Float2 FloatPosition;
|
||||||
|
|
||||||
|
// Constructor, to allow for default values
|
||||||
|
public WindowRestoreData()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<WindowRestoreData> _restoreWindows = new List<WindowRestoreData>();
|
private readonly List<WindowRestoreData> _restoreWindows = new List<WindowRestoreData>();
|
||||||
@@ -676,7 +692,9 @@ namespace FlaxEditor.Modules
|
|||||||
if (newLocation == DockState.Float)
|
if (newLocation == DockState.Float)
|
||||||
{
|
{
|
||||||
// Check if there is a floating window that has the same size
|
// Check if there is a floating window that has the same size
|
||||||
var defaultSize = window.DefaultSize;
|
var dpi = (float)Platform.Dpi / 96.0f;
|
||||||
|
var dpiScale = Platform.CustomDpiScale;
|
||||||
|
var defaultSize = window.DefaultSize * dpi;
|
||||||
for (var i = 0; i < Editor.UI.MasterPanel.FloatingPanels.Count; i++)
|
for (var i = 0; i < Editor.UI.MasterPanel.FloatingPanels.Count; i++)
|
||||||
{
|
{
|
||||||
var win = Editor.UI.MasterPanel.FloatingPanels[i];
|
var win = Editor.UI.MasterPanel.FloatingPanels[i];
|
||||||
@@ -688,7 +706,7 @@ namespace FlaxEditor.Modules
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.ShowFloating(defaultSize);
|
window.ShowFloating(defaultSize * dpiScale);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -800,10 +818,38 @@ namespace FlaxEditor.Modules
|
|||||||
if (constructor == null || type.IsGenericType)
|
if (constructor == null || type.IsGenericType)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
WindowRestoreData winData;
|
var winData = new WindowRestoreData();
|
||||||
|
var panel = win.Window.ParentDockPanel;
|
||||||
|
|
||||||
|
// Ensure that this window is only selected following recompilation
|
||||||
|
// if it was the active tab in its dock panel. Otherwise, there is a
|
||||||
|
// risk of interrupting the user's workflow by potentially selecting
|
||||||
|
// background tabs.
|
||||||
|
winData.SelectOnShow = panel.SelectedTab == win.Window;
|
||||||
|
if (panel is FloatWindowDockPanel)
|
||||||
|
{
|
||||||
|
winData.DockState = DockState.Float;
|
||||||
|
var window = win.Window.RootWindow.Window;
|
||||||
|
winData.FloatPosition = window.Position;
|
||||||
|
winData.FloatSize = window.ClientSize;
|
||||||
|
winData.Maximize = window.IsMaximized;
|
||||||
|
winData.Minimize = window.IsMinimized;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (panel.TabsCount > 1)
|
||||||
|
{
|
||||||
|
winData.DockState = DockState.DockFill;
|
||||||
|
winData.DockedTo = panel;
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
winData.DockState = panel.TryGetDockState(out var splitterValue);
|
||||||
|
winData.DockedTo = panel.ParentDockPanel;
|
||||||
|
winData.SplitterValue = splitterValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
winData.AssemblyName = type.Assembly.GetName().Name;
|
winData.AssemblyName = type.Assembly.GetName().Name;
|
||||||
winData.TypeName = type.FullName;
|
winData.TypeName = type.FullName;
|
||||||
// TODO: cache and restore docking info
|
|
||||||
_restoreWindows.Add(winData);
|
_restoreWindows.Add(winData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -822,7 +868,24 @@ namespace FlaxEditor.Modules
|
|||||||
if (type != null)
|
if (type != null)
|
||||||
{
|
{
|
||||||
var win = (CustomEditorWindow)Activator.CreateInstance(type);
|
var win = (CustomEditorWindow)Activator.CreateInstance(type);
|
||||||
win.Show();
|
win.Show(winData.DockState, winData.DockedTo, winData.SelectOnShow, winData.SplitterValue);
|
||||||
|
if (winData.DockState == DockState.Float)
|
||||||
|
{
|
||||||
|
var window = win.Window.RootWindow.Window;
|
||||||
|
window.Position = winData.FloatPosition;
|
||||||
|
if (winData.Maximize)
|
||||||
|
{
|
||||||
|
window.Maximize();
|
||||||
|
}
|
||||||
|
else if (winData.Minimize)
|
||||||
|
{
|
||||||
|
window.Minimize();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
window.ClientSize = winData.FloatSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1310,8 +1310,17 @@ namespace FlaxEditor.Utilities
|
|||||||
inputActions.Add(options => options.BuildSDF, Editor.Instance.BuildAllMeshesSDF);
|
inputActions.Add(options => options.BuildSDF, Editor.Instance.BuildAllMeshesSDF);
|
||||||
inputActions.Add(options => options.TakeScreenshot, Editor.Instance.Windows.TakeScreenshot);
|
inputActions.Add(options => options.TakeScreenshot, Editor.Instance.Windows.TakeScreenshot);
|
||||||
inputActions.Add(options => options.ProfilerWindow, () => Editor.Instance.Windows.ProfilerWin.FocusOrShow());
|
inputActions.Add(options => options.ProfilerWindow, () => Editor.Instance.Windows.ProfilerWin.FocusOrShow());
|
||||||
inputActions.Add(options => options.ProfilerStartStop, () => { Editor.Instance.Windows.ProfilerWin.LiveRecording = !Editor.Instance.Windows.ProfilerWin.LiveRecording; Editor.Instance.UI.AddStatusMessage($"Profiling {(Editor.Instance.Windows.ProfilerWin.LiveRecording ? "started" : "stopped")}."); });
|
inputActions.Add(options => options.ProfilerStartStop, () =>
|
||||||
inputActions.Add(options => options.ProfilerClear, () => { Editor.Instance.Windows.ProfilerWin.Clear(); Editor.Instance.UI.AddStatusMessage($"Profiling results cleared."); });
|
{
|
||||||
|
bool recording = !Editor.Instance.Windows.ProfilerWin.LiveRecording;
|
||||||
|
Editor.Instance.Windows.ProfilerWin.LiveRecording = recording;
|
||||||
|
Editor.Instance.UI.AddStatusMessage($"Profiling {(recording ? "started" : "stopped")}.");
|
||||||
|
});
|
||||||
|
inputActions.Add(options => options.ProfilerClear, () =>
|
||||||
|
{
|
||||||
|
Editor.Instance.Windows.ProfilerWin.Clear();
|
||||||
|
Editor.Instance.UI.AddStatusMessage($"Profiling results cleared.");
|
||||||
|
});
|
||||||
inputActions.Add(options => options.SaveScenes, () => Editor.Instance.Scene.SaveScenes());
|
inputActions.Add(options => options.SaveScenes, () => Editor.Instance.Scene.SaveScenes());
|
||||||
inputActions.Add(options => options.CloseScenes, () => Editor.Instance.Scene.CloseAllScenes());
|
inputActions.Add(options => options.CloseScenes, () => Editor.Instance.Scene.CloseAllScenes());
|
||||||
inputActions.Add(options => options.OpenScriptsProject, () => Editor.Instance.CodeEditing.OpenSolution());
|
inputActions.Add(options => options.OpenScriptsProject, () => Editor.Instance.CodeEditing.OpenSolution());
|
||||||
|
|||||||
@@ -1113,7 +1113,7 @@ namespace FlaxEditor.Viewport
|
|||||||
private void OnFarPlaneChanged(FloatValueBox control)
|
private void OnFarPlaneChanged(FloatValueBox control)
|
||||||
{
|
{
|
||||||
_farPlane = control.Value;
|
_farPlane = control.Value;
|
||||||
_editor.ProjectCache.SetCustomData("CameraNearPlaneValue", _farPlane.ToString());
|
_editor.ProjectCache.SetCustomData("CameraFarPlaneValue", _farPlane.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -386,6 +386,7 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
|
|
||||||
// Spawn it
|
// Spawn it
|
||||||
Spawn(actor);
|
Spawn(actor);
|
||||||
|
Rename();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -415,6 +416,7 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
// Create undo action
|
// Create undo action
|
||||||
var action = new CustomDeleteActorsAction(new List<SceneGraphNode>(1) { actorNode }, true);
|
var action = new CustomDeleteActorsAction(new List<SceneGraphNode>(1) { actorNode }, true);
|
||||||
Undo.AddAction(action);
|
Undo.AddAction(action);
|
||||||
|
Select(actorNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnTreeRightClick(TreeNode node, Float2 location)
|
private void OnTreeRightClick(TreeNode node, Float2 location)
|
||||||
|
|||||||
@@ -452,7 +452,6 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
var data = _events.Get(_mainChart.SelectedSampleIndex);
|
var data = _events.Get(_mainChart.SelectedSampleIndex);
|
||||||
if (data == null || data.Length == 0)
|
if (data == null || data.Length == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
float totalTimeMs = _mainChart.SelectedSample;
|
float totalTimeMs = _mainChart.SelectedSample;
|
||||||
|
|
||||||
// Add rows
|
// Add rows
|
||||||
@@ -501,17 +500,24 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
row = new Row
|
row = new Row
|
||||||
{
|
{
|
||||||
Values = new object[6],
|
Values = new object[6],
|
||||||
|
BackgroundColors = new Color[6],
|
||||||
};
|
};
|
||||||
|
for (int k = 0; k < row.BackgroundColors.Length; k++)
|
||||||
|
row.BackgroundColors[k] = Color.Transparent;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// Event
|
// Event
|
||||||
row.Values[0] = name;
|
row.Values[0] = name;
|
||||||
|
|
||||||
// Total (%)
|
// Total (%)
|
||||||
row.Values[1] = (int)(time / totalTimeMs * 1000.0f) / 10.0f;
|
float rowTotalTimePerc = (float)(time / totalTimeMs);
|
||||||
|
row.Values[1] = (int)(rowTotalTimePerc * 1000.0f) / 10.0f;
|
||||||
|
row.BackgroundColors[1] = Color.Red.AlphaMultiplied(Mathf.Min(1, rowTotalTimePerc) * 0.5f);
|
||||||
|
|
||||||
// Self (%)
|
// Self (%)
|
||||||
row.Values[2] = (int)((time - subEventsTimeTotal) / time * 1000.0f) / 10.0f;
|
float rowSelfTimePerc = (float)((time - subEventsTimeTotal) / totalTimeMs);
|
||||||
|
row.Values[2] = (int)(rowSelfTimePerc * 1000.0f) / 10.0f;
|
||||||
|
row.BackgroundColors[2] = Color.Red.AlphaMultiplied(Mathf.Min(1, rowSelfTimePerc) * 0.5f);
|
||||||
|
|
||||||
// Time ms
|
// Time ms
|
||||||
row.Values[3] = (float)((time * 10000.0f) / 10000.0f);
|
row.Values[3] = (float)((time * 10000.0f) / 10000.0f);
|
||||||
|
|||||||
@@ -321,8 +321,7 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
var data = _events.Get(_drawTimeCPU.SelectedSampleIndex);
|
var data = _events.Get(_drawTimeCPU.SelectedSampleIndex);
|
||||||
if (data == null || data.Length == 0)
|
if (data == null || data.Length == 0)
|
||||||
return;
|
return;
|
||||||
|
float totalTimeMs = _drawTimeGPU.SelectedSample;
|
||||||
float totalTimeMs = _drawTimeCPU.SelectedSample;
|
|
||||||
|
|
||||||
// Add rows
|
// Add rows
|
||||||
var rowColor2 = Style.Current.Background * 1.4f;
|
var rowColor2 = Style.Current.Background * 1.4f;
|
||||||
@@ -343,14 +342,19 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
row = new Row
|
row = new Row
|
||||||
{
|
{
|
||||||
Values = new object[6],
|
Values = new object[6],
|
||||||
|
BackgroundColors = new Color[6],
|
||||||
};
|
};
|
||||||
|
for (int k = 0; k < row.BackgroundColors.Length; k++)
|
||||||
|
row.BackgroundColors[k] = Color.Transparent;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// Event
|
// Event
|
||||||
row.Values[0] = name;
|
row.Values[0] = name;
|
||||||
|
|
||||||
// Total (%)
|
// Total (%)
|
||||||
row.Values[1] = (int)(e.Time / totalTimeMs * 1000.0f) / 10.0f;
|
float rowTimePerc = (float)(e.Time / totalTimeMs);
|
||||||
|
row.Values[1] = (int)(rowTimePerc * 1000.0f) / 10.0f;
|
||||||
|
row.BackgroundColors[1] = Color.Red.AlphaMultiplied(Mathf.Min(1, rowTimePerc) * 0.5f);
|
||||||
|
|
||||||
// GPU ms
|
// GPU ms
|
||||||
row.Values[2] = (e.Time * 10000.0f) / 10000.0f;
|
row.Values[2] = (e.Time * 10000.0f) / 10000.0f;
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ namespace FlaxEditor.Windows.Profiler
|
|||||||
if (value != LiveRecording)
|
if (value != LiveRecording)
|
||||||
{
|
{
|
||||||
_liveRecordingButton.Checked = value;
|
_liveRecordingButton.Checked = value;
|
||||||
|
OnLiveRecordingChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -282,6 +282,20 @@ void AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if !BUILD_RELEASE
|
||||||
|
{
|
||||||
|
// Perform sanity check on nodes pose to prevent crashes due to NaNs
|
||||||
|
bool anyInvalid = animResult->RootMotion.IsNanOrInfinity();
|
||||||
|
for (int32 i = 0; i < animResult->Nodes.Count(); i++)
|
||||||
|
anyInvalid |= animResult->Nodes.Get()[i].IsNanOrInfinity();
|
||||||
|
if (anyInvalid)
|
||||||
|
{
|
||||||
|
LOG(Error, "Animated Model pose contains NaNs due to animations sampling/blending bug.");
|
||||||
|
context.Data = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
SkeletonData* animResultSkeleton = &skeleton;
|
SkeletonData* animResultSkeleton = &skeleton;
|
||||||
|
|
||||||
// Retarget animation when using output pose from other skeleton
|
// Retarget animation when using output pose from other skeleton
|
||||||
|
|||||||
@@ -197,6 +197,7 @@ struct FLAXENGINE_API AnimGraphSlot
|
|||||||
float BlendOutTime = 0.0f;
|
float BlendOutTime = 0.0f;
|
||||||
int32 LoopCount = 0;
|
int32 LoopCount = 0;
|
||||||
bool Pause = false;
|
bool Pause = false;
|
||||||
|
bool Reset = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1367,33 +1367,29 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use 1D blend if points are on the same line (degenerated triangle)
|
// Use 1D blend if points are on the same line (degenerated triangle)
|
||||||
// TODO: simplify this code
|
struct BlendData
|
||||||
|
{
|
||||||
|
float AlphaX, AlphaY;
|
||||||
|
Animation* AnimA, *AnimB;
|
||||||
|
const Float4* AnimAd, *AnimBd;
|
||||||
|
};
|
||||||
|
BlendData blendData;
|
||||||
if (v1.Y >= v0.Y)
|
if (v1.Y >= v0.Y)
|
||||||
{
|
{
|
||||||
if (p.Y < v0.Y && v1.Y >= v0.Y)
|
if (p.Y < v0.Y && v1.Y >= v0.Y)
|
||||||
{
|
blendData = { p.Y, v0.Y, aAnim, bAnim, &aData, &bData };
|
||||||
const float alpha = p.Y / v0.Y;
|
|
||||||
value = SampleAnimationsWithBlend(node, loop, data.Length, startTimePos, bucket.TimePosition, newTimePos, aAnim, bAnim, aData.W, bData.W, alpha);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
blendData = { p.Y - v0.Y, v1.Y - v0.Y, bAnim, cAnim, &bData, &cData };
|
||||||
const float alpha = (p.Y - v0.Y) / (v1.Y - v0.Y);
|
|
||||||
value = SampleAnimationsWithBlend(node, loop, data.Length, startTimePos, bucket.TimePosition, newTimePos, bAnim, cAnim, bData.W, cData.W, alpha);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (p.Y < v1.Y)
|
if (p.Y < v1.Y)
|
||||||
{
|
blendData = { p.Y, v1.Y, aAnim, cAnim, &aData, &cData };
|
||||||
const float alpha = p.Y / v1.Y;
|
|
||||||
value = SampleAnimationsWithBlend(node, loop, data.Length, startTimePos, bucket.TimePosition, newTimePos, aAnim, cAnim, aData.W, cData.W, alpha);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
blendData = { p.Y - v1.Y, v0.Y - v1.Y, cAnim, bAnim, &cData, &bData };
|
||||||
const float alpha = (p.Y - v1.Y) / (v0.Y - v1.Y);
|
|
||||||
value = SampleAnimationsWithBlend(node, loop, data.Length, startTimePos, bucket.TimePosition, newTimePos, cAnim, bAnim, cData.W, bData.W, alpha);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
const float alpha = Math::IsZero(blendData.AlphaY) ? 0.0f : blendData.AlphaX / blendData.AlphaY;
|
||||||
|
value = SampleAnimationsWithBlend(node, loop, data.Length, startTimePos, bucket.TimePosition, newTimePos, blendData.AnimA, blendData.AnimB, blendData.AnimAd->W, blendData.AnimBd->W, alpha);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2102,6 +2098,12 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
|||||||
auto& slot = slots[bucket.Index];
|
auto& slot = slots[bucket.Index];
|
||||||
Animation* anim = slot.Animation;
|
Animation* anim = slot.Animation;
|
||||||
ASSERT(slot.Animation && slot.Animation->IsLoaded());
|
ASSERT(slot.Animation && slot.Animation->IsLoaded());
|
||||||
|
if (slot.Reset)
|
||||||
|
{
|
||||||
|
// Start from the begining
|
||||||
|
slot.Reset = false;
|
||||||
|
bucket.TimePosition = 0.0f;
|
||||||
|
}
|
||||||
const float deltaTime = slot.Pause ? 0.0f : context.DeltaTime * slot.Speed;
|
const float deltaTime = slot.Pause ? 0.0f : context.DeltaTime * slot.Speed;
|
||||||
const float length = anim->GetLength();
|
const float length = anim->GetLength();
|
||||||
const bool loop = bucket.LoopsLeft != 0;
|
const bool loop = bucket.LoopsLeft != 0;
|
||||||
|
|||||||
@@ -150,9 +150,7 @@ void BinaryAsset::ClearDependencies()
|
|||||||
{
|
{
|
||||||
auto asset = Cast<BinaryAsset>(Content::GetAsset(e.First));
|
auto asset = Cast<BinaryAsset>(Content::GetAsset(e.First));
|
||||||
if (asset)
|
if (asset)
|
||||||
{
|
|
||||||
asset->_dependantAssets.Remove(this);
|
asset->_dependantAssets.Remove(this);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Dependencies.Clear();
|
Dependencies.Clear();
|
||||||
}
|
}
|
||||||
@@ -387,6 +385,16 @@ bool BinaryAsset::SaveToAsset(const StringView& path, AssetInitData& data, bool
|
|||||||
if (binaryAsset)
|
if (binaryAsset)
|
||||||
binaryAsset->_isSaving = false;
|
binaryAsset->_isSaving = false;
|
||||||
|
|
||||||
|
if (binaryAsset)
|
||||||
|
{
|
||||||
|
// Inform dependant asset (use cloned version because it might be modified by assets when they got reloaded)
|
||||||
|
auto dependantAssets = binaryAsset->_dependantAssets;
|
||||||
|
for (auto& e : dependantAssets)
|
||||||
|
{
|
||||||
|
e->OnDependencyModified(binaryAsset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -963,6 +963,7 @@ bool FlaxStorage::Create(WriteStream* stream, const AssetInitData* data, int32 d
|
|||||||
// Asset Dependencies
|
// Asset Dependencies
|
||||||
stream->WriteInt32(header.Dependencies.Count());
|
stream->WriteInt32(header.Dependencies.Count());
|
||||||
stream->WriteBytes(header.Dependencies.Get(), header.Dependencies.Count() * sizeof(Pair<Guid, DateTime>));
|
stream->WriteBytes(header.Dependencies.Get(), header.Dependencies.Count() * sizeof(Pair<Guid, DateTime>));
|
||||||
|
static_assert(sizeof(Pair<Guid, DateTime>) == sizeof(Guid) + sizeof(DateTime), "Invalid data size.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ASSETS_LOADING_EXTRA_VERIFICATION
|
#if ASSETS_LOADING_EXTRA_VERIFICATION
|
||||||
|
|||||||
@@ -12,22 +12,22 @@ const int32 CachedDaysToMonth[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273,
|
|||||||
DateTime::DateTime(int32 year, int32 month, int32 day, int32 hour, int32 minute, int32 second, int32 millisecond)
|
DateTime::DateTime(int32 year, int32 month, int32 day, int32 hour, int32 minute, int32 second, int32 millisecond)
|
||||||
{
|
{
|
||||||
ASSERT_LOW_LAYER(Validate(year, month, day, hour, minute, second, millisecond));
|
ASSERT_LOW_LAYER(Validate(year, month, day, hour, minute, second, millisecond));
|
||||||
int32 totalDays = 0;
|
int32 daysSum = 0;
|
||||||
if (month > 2 && IsLeapYear(year))
|
if (month > 2 && IsLeapYear(year))
|
||||||
totalDays++;
|
daysSum++;
|
||||||
year--;
|
year--;
|
||||||
month--;
|
month--;
|
||||||
totalDays += year * 365 + year / 4 - year / 100 + year / 400 + CachedDaysToMonth[month] + day - 1;
|
daysSum += year * 365 + year / 4 - year / 100 + year / 400 + CachedDaysToMonth[month] + day - 1;
|
||||||
Ticks = totalDays * Constants::TicksPerDay
|
Ticks = daysSum * TimeSpan::TicksPerDay
|
||||||
+ hour * Constants::TicksPerHour
|
+ hour * TimeSpan::TicksPerHour
|
||||||
+ minute * Constants::TicksPerMinute
|
+ minute * TimeSpan::TicksPerMinute
|
||||||
+ second * Constants::TicksPerSecond
|
+ second * TimeSpan::TicksPerSecond
|
||||||
+ millisecond * Constants::TicksPerMillisecond;
|
+ millisecond * TimeSpan::TicksPerMillisecond;
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTime DateTime::GetDate() const
|
DateTime DateTime::GetDate() const
|
||||||
{
|
{
|
||||||
return DateTime(Ticks - Ticks % Constants::TicksPerDay);
|
return DateTime(Ticks - Ticks % TimeSpan::TicksPerDay);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DateTime::GetDate(int32& year, int32& month, int32& day) const
|
void DateTime::GetDate(int32& year, int32& month, int32& day) const
|
||||||
@@ -35,8 +35,7 @@ void DateTime::GetDate(int32& year, int32& month, int32& day) const
|
|||||||
// Based on:
|
// Based on:
|
||||||
// Fliegel, H. F. and van Flandern, T. C.,
|
// Fliegel, H. F. and van Flandern, T. C.,
|
||||||
// Communications of the ACM, Vol. 11, No. 10 (October 1968).
|
// Communications of the ACM, Vol. 11, No. 10 (October 1968).
|
||||||
|
int32 l = Math::FloorToInt((float)(GetDate().GetJulianDay() + 0.5)) + 68569;
|
||||||
int32 l = Math::FloorToInt(static_cast<float>(GetJulianDay() + 0.5)) + 68569;
|
|
||||||
const int32 n = 4 * l / 146097;
|
const int32 n = 4 * l / 146097;
|
||||||
l = l - (146097 * n + 3) / 4;
|
l = l - (146097 * n + 3) / 4;
|
||||||
int32 i = 4000 * (l + 1) / 1461001;
|
int32 i = 4000 * (l + 1) / 1461001;
|
||||||
@@ -46,7 +45,6 @@ void DateTime::GetDate(int32& year, int32& month, int32& day) const
|
|||||||
l = j / 11;
|
l = j / 11;
|
||||||
j = j + 2 - 12 * l;
|
j = j + 2 - 12 * l;
|
||||||
i = 100 * (n - 49) + i + l;
|
i = 100 * (n - 49) + i + l;
|
||||||
|
|
||||||
year = i;
|
year = i;
|
||||||
month = j;
|
month = j;
|
||||||
day = k;
|
day = k;
|
||||||
@@ -61,7 +59,7 @@ int32 DateTime::GetDay() const
|
|||||||
|
|
||||||
DayOfWeek DateTime::GetDayOfWeek() const
|
DayOfWeek DateTime::GetDayOfWeek() const
|
||||||
{
|
{
|
||||||
return static_cast<DayOfWeek>((Ticks / Constants::TicksPerDay) % 7);
|
return static_cast<DayOfWeek>((Ticks / TimeSpan::TicksPerDay) % 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 DateTime::GetDayOfYear() const
|
int32 DateTime::GetDayOfYear() const
|
||||||
@@ -75,7 +73,7 @@ int32 DateTime::GetDayOfYear() const
|
|||||||
|
|
||||||
int32 DateTime::GetHour() const
|
int32 DateTime::GetHour() const
|
||||||
{
|
{
|
||||||
return static_cast<int32>(Ticks / Constants::TicksPerHour % 24);
|
return static_cast<int32>(Ticks / TimeSpan::TicksPerHour % 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 DateTime::GetHour12() const
|
int32 DateTime::GetHour12() const
|
||||||
@@ -90,7 +88,7 @@ int32 DateTime::GetHour12() const
|
|||||||
|
|
||||||
double DateTime::GetJulianDay() const
|
double DateTime::GetJulianDay() const
|
||||||
{
|
{
|
||||||
return 1721425.5 + static_cast<double>(Ticks) / Constants::TicksPerDay;
|
return 1721425.5 + static_cast<double>(Ticks) / TimeSpan::TicksPerDay;
|
||||||
}
|
}
|
||||||
|
|
||||||
double DateTime::GetModifiedJulianDay() const
|
double DateTime::GetModifiedJulianDay() const
|
||||||
@@ -100,12 +98,12 @@ double DateTime::GetModifiedJulianDay() const
|
|||||||
|
|
||||||
int32 DateTime::GetMillisecond() const
|
int32 DateTime::GetMillisecond() const
|
||||||
{
|
{
|
||||||
return static_cast<int32>(Ticks / Constants::TicksPerMillisecond % 1000);
|
return static_cast<int32>(Ticks / TimeSpan::TicksPerMillisecond % 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 DateTime::GetMinute() const
|
int32 DateTime::GetMinute() const
|
||||||
{
|
{
|
||||||
return static_cast<int32>(Ticks / Constants::TicksPerMinute % 60);
|
return static_cast<int32>(Ticks / TimeSpan::TicksPerMinute % 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 DateTime::GetMonth() const
|
int32 DateTime::GetMonth() const
|
||||||
@@ -122,12 +120,12 @@ MonthOfYear DateTime::GetMonthOfYear() const
|
|||||||
|
|
||||||
int32 DateTime::GetSecond() const
|
int32 DateTime::GetSecond() const
|
||||||
{
|
{
|
||||||
return static_cast<int32>(Ticks / Constants::TicksPerSecond % 60);
|
return static_cast<int32>(Ticks / TimeSpan::TicksPerSecond % 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeSpan DateTime::GetTimeOfDay() const
|
TimeSpan DateTime::GetTimeOfDay() const
|
||||||
{
|
{
|
||||||
return TimeSpan(Ticks % Constants::TicksPerDay);
|
return TimeSpan(Ticks % TimeSpan::TicksPerDay);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 DateTime::GetYear() const
|
int32 DateTime::GetYear() const
|
||||||
@@ -137,11 +135,6 @@ int32 DateTime::GetYear() const
|
|||||||
return year;
|
return year;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 DateTime::ToUnixTimestamp() const
|
|
||||||
{
|
|
||||||
return static_cast<int32>((Ticks - DateTime(1970, 1, 1).Ticks) / Constants::TicksPerSecond);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 DateTime::DaysInMonth(int32 year, int32 month)
|
int32 DateTime::DaysInMonth(int32 year, int32 month)
|
||||||
{
|
{
|
||||||
ASSERT_LOW_LAYER((month >= 1) && (month <= 12));
|
ASSERT_LOW_LAYER((month >= 1) && (month <= 12));
|
||||||
@@ -155,16 +148,6 @@ int32 DateTime::DaysInYear(int32 year)
|
|||||||
return IsLeapYear(year) ? 366 : 365;
|
return IsLeapYear(year) ? 366 : 365;
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTime DateTime::FromJulianDay(double julianDay)
|
|
||||||
{
|
|
||||||
return DateTime(static_cast<int64>((julianDay - 1721425.5) * Constants::TicksPerDay));
|
|
||||||
}
|
|
||||||
|
|
||||||
DateTime DateTime::FromUnixTimestamp(int32 unixTime)
|
|
||||||
{
|
|
||||||
return DateTime(1970, 1, 1) + TimeSpan(static_cast<int64>(unixTime) * Constants::TicksPerSecond);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DateTime::IsLeapYear(int32 year)
|
bool DateTime::IsLeapYear(int32 year)
|
||||||
{
|
{
|
||||||
if ((year % 4) == 0)
|
if ((year % 4) == 0)
|
||||||
@@ -176,7 +159,7 @@ bool DateTime::IsLeapYear(int32 year)
|
|||||||
|
|
||||||
DateTime DateTime::MaxValue()
|
DateTime DateTime::MaxValue()
|
||||||
{
|
{
|
||||||
return DateTime(3652059 * Constants::TicksPerDay - 1);
|
return DateTime(3652059 * TimeSpan::TicksPerDay - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTime DateTime::Now()
|
DateTime DateTime::Now()
|
||||||
|
|||||||
@@ -199,11 +199,6 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
int32 GetYear() const;
|
int32 GetYear() const;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets this date as the number of seconds since the Unix Epoch (January 1st of 1970).
|
|
||||||
/// </summary>
|
|
||||||
int32 ToUnixTimestamp() const;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the number of days in the year and month.
|
/// Gets the number of days in the year and month.
|
||||||
@@ -220,20 +215,6 @@ public:
|
|||||||
/// <returns>The number of days.</returns>
|
/// <returns>The number of days.</returns>
|
||||||
static int32 DaysInYear(int32 year);
|
static int32 DaysInYear(int32 year);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the proleptic Gregorian date for the given Julian Day.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="julianDay">The Julian Day.</param>
|
|
||||||
/// <returns>Gregorian date and time.</returns>
|
|
||||||
static DateTime FromJulianDay(double julianDay);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the date from Unix time (seconds from midnight 1970-01-01).
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="unixTime">The Unix time (seconds from midnight 1970-01-01).</param>
|
|
||||||
/// <returns>The Gregorian date and time.</returns>
|
|
||||||
static DateTime FromUnixTimestamp(int32 unixTime);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the specified year is a leap year.
|
/// Determines whether the specified year is a leap year.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -6,38 +6,53 @@
|
|||||||
TimeSpan TimeSpan::FromDays(double days)
|
TimeSpan TimeSpan::FromDays(double days)
|
||||||
{
|
{
|
||||||
ASSERT_LOW_LAYER((days >= MinValue().GetTotalDays()) && (days <= MaxValue().GetTotalDays()));
|
ASSERT_LOW_LAYER((days >= MinValue().GetTotalDays()) && (days <= MaxValue().GetTotalDays()));
|
||||||
return TimeSpan(static_cast<int64>(days * Constants::TicksPerDay));
|
return TimeSpan(static_cast<int64>(days * TicksPerDay));
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeSpan TimeSpan::FromHours(double hours)
|
TimeSpan TimeSpan::FromHours(double hours)
|
||||||
{
|
{
|
||||||
ASSERT_LOW_LAYER((hours >= MinValue().GetTotalHours()) && (hours <= MaxValue().GetTotalHours()));
|
ASSERT_LOW_LAYER((hours >= MinValue().GetTotalHours()) && (hours <= MaxValue().GetTotalHours()));
|
||||||
return TimeSpan(static_cast<int64>(hours * Constants::TicksPerHour));
|
return TimeSpan(static_cast<int64>(hours * TicksPerHour));
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeSpan TimeSpan::FromMilliseconds(double milliseconds)
|
TimeSpan TimeSpan::FromMilliseconds(double milliseconds)
|
||||||
{
|
{
|
||||||
ASSERT_LOW_LAYER((milliseconds >= MinValue().GetTotalMilliseconds()) && (milliseconds <= MaxValue().GetTotalMilliseconds()));
|
ASSERT_LOW_LAYER((milliseconds >= MinValue().GetTotalMilliseconds()) && (milliseconds <= MaxValue().GetTotalMilliseconds()));
|
||||||
return TimeSpan(static_cast<int64>(milliseconds * Constants::TicksPerMillisecond));
|
return TimeSpan(static_cast<int64>(milliseconds * TicksPerMillisecond));
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeSpan TimeSpan::FromMinutes(double minutes)
|
TimeSpan TimeSpan::FromMinutes(double minutes)
|
||||||
{
|
{
|
||||||
ASSERT_LOW_LAYER((minutes >= MinValue().GetTotalMinutes()) && (minutes <= MaxValue().GetTotalMinutes()));
|
ASSERT_LOW_LAYER((minutes >= MinValue().GetTotalMinutes()) && (minutes <= MaxValue().GetTotalMinutes()));
|
||||||
return TimeSpan(static_cast<int64>(minutes * Constants::TicksPerMinute));
|
return TimeSpan(static_cast<int64>(minutes * TicksPerMinute));
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeSpan TimeSpan::FromSeconds(double seconds)
|
TimeSpan TimeSpan::FromSeconds(double seconds)
|
||||||
{
|
{
|
||||||
ASSERT_LOW_LAYER((seconds >= MinValue().GetTotalSeconds()) && (seconds <= MaxValue().GetTotalSeconds()));
|
ASSERT_LOW_LAYER((seconds >= MinValue().GetTotalSeconds()) && (seconds <= MaxValue().GetTotalSeconds()));
|
||||||
return TimeSpan(static_cast<int64>(seconds * Constants::TicksPerSecond));
|
return TimeSpan(static_cast<int64>(seconds * TicksPerSecond));
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeSpan TimeSpan::MaxValue()
|
||||||
|
{
|
||||||
|
return TimeSpan(9223372036854775807);
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeSpan TimeSpan::MinValue()
|
||||||
|
{
|
||||||
|
return TimeSpan(-9223372036854775807 - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeSpan TimeSpan::Zero()
|
||||||
|
{
|
||||||
|
return TimeSpan(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimeSpan::Set(int32 days, int32 hours, int32 minutes, int32 seconds, int32 milliseconds)
|
void TimeSpan::Set(int32 days, int32 hours, int32 minutes, int32 seconds, int32 milliseconds)
|
||||||
{
|
{
|
||||||
const int64 totalMs = 1000 * (60 * 60 * 24 * (int64)days + 60 * 60 * (int64)hours + 60 * (int64)minutes + (int64)seconds) + (int64)milliseconds;
|
const int64 totalMs = 1000 * (60 * 60 * 24 * (int64)days + 60 * 60 * (int64)hours + 60 * (int64)minutes + (int64)seconds) + (int64)milliseconds;
|
||||||
ASSERT_LOW_LAYER((totalMs >= MinValue().GetTotalMilliseconds()) && (totalMs <= MaxValue().GetTotalMilliseconds()));
|
ASSERT_LOW_LAYER((totalMs >= MinValue().GetTotalMilliseconds()) && (totalMs <= MaxValue().GetTotalMilliseconds()));
|
||||||
Ticks = totalMs * Constants::TicksPerMillisecond;
|
Ticks = totalMs * TicksPerMillisecond;
|
||||||
}
|
}
|
||||||
|
|
||||||
String TimeSpan::ToString() const
|
String TimeSpan::ToString() const
|
||||||
|
|||||||
@@ -6,32 +6,30 @@
|
|||||||
#include "Engine/Core/Formatting.h"
|
#include "Engine/Core/Formatting.h"
|
||||||
#include "Engine/Core/Templates.h"
|
#include "Engine/Core/Templates.h"
|
||||||
|
|
||||||
namespace Constants
|
|
||||||
{
|
|
||||||
// The number of timespan ticks per day.
|
|
||||||
const int64 TicksPerDay = 864000000000;
|
|
||||||
|
|
||||||
// The number of timespan ticks per hour.
|
|
||||||
const int64 TicksPerHour = 36000000000;
|
|
||||||
|
|
||||||
// The number of timespan ticks per millisecond.
|
|
||||||
const int64 TicksPerMillisecond = 10000;
|
|
||||||
|
|
||||||
// The number of timespan ticks per minute.
|
|
||||||
const int64 TicksPerMinute = 600000000;
|
|
||||||
|
|
||||||
// The number of timespan ticks per second.
|
|
||||||
const int64 TicksPerSecond = 10000000;
|
|
||||||
|
|
||||||
// The number of timespan ticks per week.
|
|
||||||
const int64 TicksPerWeek = 6048000000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the difference between two dates and times.
|
/// Represents the difference between two dates and times.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_STRUCT(InBuild, Namespace="System") struct FLAXENGINE_API TimeSpan
|
API_STRUCT(InBuild, Namespace="System") struct FLAXENGINE_API TimeSpan
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
// The number of timespan ticks per day.
|
||||||
|
static constexpr int64 TicksPerDay = 864000000000;
|
||||||
|
|
||||||
|
// The number of timespan ticks per hour.
|
||||||
|
static constexpr int64 TicksPerHour = 36000000000;
|
||||||
|
|
||||||
|
// The number of timespan ticks per millisecond.
|
||||||
|
static constexpr int64 TicksPerMillisecond = 10000;
|
||||||
|
|
||||||
|
// The number of timespan ticks per minute.
|
||||||
|
static constexpr int64 TicksPerMinute = 600000000;
|
||||||
|
|
||||||
|
// The number of timespan ticks per second.
|
||||||
|
static constexpr int64 TicksPerSecond = 10000000;
|
||||||
|
|
||||||
|
// The number of timespan ticks per week.
|
||||||
|
static constexpr int64 TicksPerWeek = 6048000000000;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Time span in 100 nanoseconds resolution.
|
/// Time span in 100 nanoseconds resolution.
|
||||||
@@ -170,7 +168,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE int32 GetDays() const
|
FORCE_INLINE int32 GetDays() const
|
||||||
{
|
{
|
||||||
return (int32)(Ticks / Constants::TicksPerDay);
|
return (int32)(Ticks / TicksPerDay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -186,7 +184,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE int32 GetHours() const
|
FORCE_INLINE int32 GetHours() const
|
||||||
{
|
{
|
||||||
return (int32)(Ticks / Constants::TicksPerHour % 24);
|
return (int32)(Ticks / TicksPerHour % 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -194,7 +192,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE int32 GetMilliseconds() const
|
FORCE_INLINE int32 GetMilliseconds() const
|
||||||
{
|
{
|
||||||
return (int32)(Ticks / Constants::TicksPerMillisecond % 1000);
|
return (int32)(Ticks / TicksPerMillisecond % 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -202,7 +200,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE int32 GetMinutes() const
|
FORCE_INLINE int32 GetMinutes() const
|
||||||
{
|
{
|
||||||
return (int32)(Ticks / Constants::TicksPerMinute % 60);
|
return (int32)(Ticks / TicksPerMinute % 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -210,7 +208,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE int32 GetSeconds() const
|
FORCE_INLINE int32 GetSeconds() const
|
||||||
{
|
{
|
||||||
return (int32)(Ticks / Constants::TicksPerSecond % 60);
|
return (int32)(Ticks / TicksPerSecond % 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -218,7 +216,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE double GetTotalDays() const
|
FORCE_INLINE double GetTotalDays() const
|
||||||
{
|
{
|
||||||
return (double)Ticks / Constants::TicksPerDay;
|
return (double)Ticks / TicksPerDay;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -226,7 +224,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE double GetTotalHours() const
|
FORCE_INLINE double GetTotalHours() const
|
||||||
{
|
{
|
||||||
return (double)Ticks / Constants::TicksPerHour;
|
return (double)Ticks / TicksPerHour;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -234,7 +232,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE double GetTotalMilliseconds() const
|
FORCE_INLINE double GetTotalMilliseconds() const
|
||||||
{
|
{
|
||||||
return (double)Ticks / Constants::TicksPerMillisecond;
|
return (double)Ticks / TicksPerMillisecond;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -242,7 +240,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE double GetTotalMinutes() const
|
FORCE_INLINE double GetTotalMinutes() const
|
||||||
{
|
{
|
||||||
return (double)Ticks / Constants::TicksPerMinute;
|
return (double)Ticks / TicksPerMinute;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -250,7 +248,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE float GetTotalSeconds() const
|
FORCE_INLINE float GetTotalSeconds() const
|
||||||
{
|
{
|
||||||
return static_cast<float>(Ticks) / Constants::TicksPerSecond;
|
return static_cast<float>(Ticks) / TicksPerSecond;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -293,29 +291,17 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the maximum time span value.
|
/// Returns the maximum time span value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The time span.</returns>
|
static TimeSpan MaxValue();
|
||||||
static TimeSpan MaxValue()
|
|
||||||
{
|
|
||||||
return TimeSpan(9223372036854775807);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the minimum time span value.
|
/// Returns the minimum time span value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The time span.</returns>
|
static TimeSpan MinValue();
|
||||||
static TimeSpan MinValue()
|
|
||||||
{
|
|
||||||
return TimeSpan(-9223372036854775807 - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the zero time span value.
|
/// Returns the zero time span value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The time span.</returns>
|
static TimeSpan Zero();
|
||||||
static TimeSpan Zero()
|
|
||||||
{
|
|
||||||
return TimeSpan(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Set(int32 days, int32 hours, int32 minutes, int32 seconds, int32 milliseconds);
|
void Set(int32 days, int32 hours, int32 minutes, int32 seconds, int32 milliseconds);
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ void Time::TickData::OnBeforeRun(float targetFps, double currentTime)
|
|||||||
{
|
{
|
||||||
Time = UnscaledTime = TimeSpan::Zero();
|
Time = UnscaledTime = TimeSpan::Zero();
|
||||||
DeltaTime = UnscaledDeltaTime = targetFps > ZeroTolerance ? TimeSpan::FromSeconds(1.0f / targetFps) : TimeSpan::Zero();
|
DeltaTime = UnscaledDeltaTime = targetFps > ZeroTolerance ? TimeSpan::FromSeconds(1.0f / targetFps) : TimeSpan::Zero();
|
||||||
LastLength = static_cast<double>(DeltaTime.Ticks) / Constants::TicksPerSecond;
|
LastLength = static_cast<double>(DeltaTime.Ticks) / TimeSpan::TicksPerSecond;
|
||||||
LastBegin = currentTime - LastLength;
|
LastBegin = currentTime - LastLength;
|
||||||
LastEnd = currentTime;
|
LastEnd = currentTime;
|
||||||
NextBegin = targetFps > ZeroTolerance ? LastBegin + (1.0f / targetFps) : 0.0;
|
NextBegin = targetFps > ZeroTolerance ? LastBegin + (1.0f / targetFps) : 0.0;
|
||||||
@@ -76,7 +76,7 @@ void Time::TickData::OnBeforeRun(float targetFps, double currentTime)
|
|||||||
void Time::TickData::OnReset(float targetFps, double currentTime)
|
void Time::TickData::OnReset(float targetFps, double currentTime)
|
||||||
{
|
{
|
||||||
DeltaTime = UnscaledDeltaTime = targetFps > ZeroTolerance ? TimeSpan::FromSeconds(1.0f / targetFps) : TimeSpan::Zero();
|
DeltaTime = UnscaledDeltaTime = targetFps > ZeroTolerance ? TimeSpan::FromSeconds(1.0f / targetFps) : TimeSpan::Zero();
|
||||||
LastLength = static_cast<double>(DeltaTime.Ticks) / Constants::TicksPerSecond;
|
LastLength = static_cast<double>(DeltaTime.Ticks) / TimeSpan::TicksPerSecond;
|
||||||
LastBegin = currentTime - LastLength;
|
LastBegin = currentTime - LastLength;
|
||||||
LastEnd = currentTime;
|
LastEnd = currentTime;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -236,6 +236,27 @@ API_ENUM(Attributes="Flags") enum class ShadowsCastingMode
|
|||||||
|
|
||||||
DECLARE_ENUM_OPERATORS(ShadowsCastingMode);
|
DECLARE_ENUM_OPERATORS(ShadowsCastingMode);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The partitioning mode for shadow cascades.
|
||||||
|
/// </summary>
|
||||||
|
API_ENUM() enum class PartitionMode
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Internally defined cascade splits.
|
||||||
|
/// </summary>
|
||||||
|
Manual = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logarithmic cascade splits.
|
||||||
|
/// </summary>
|
||||||
|
Logarithmic = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// PSSM cascade splits.
|
||||||
|
/// </summary>
|
||||||
|
PSSM = 2,
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Identifies expected GPU resource use during rendering. The usage directly reflects whether a resource is accessible by the CPU and/or the GPU.
|
/// Identifies expected GPU resource use during rendering. The usage directly reflects whether a resource is accessible by the CPU and/or the GPU.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -207,13 +207,12 @@ void PostFxMaterialsSettings::BlendWith(PostFxMaterialsSettings& other, float we
|
|||||||
if (isHalf)
|
if (isHalf)
|
||||||
{
|
{
|
||||||
int32 indexSrc = 0;
|
int32 indexSrc = 0;
|
||||||
const auto materialsSrc = other.Materials.Get();
|
const AssetReference<MaterialBase>* materialsSrc = other.Materials.Get();
|
||||||
while (Materials.Count() != POST_PROCESS_SETTINGS_MAX_MATERIALS && indexSrc < other.Materials.Count())
|
while (Materials.Count() != POST_PROCESS_SETTINGS_MAX_MATERIALS && indexSrc < other.Materials.Count())
|
||||||
{
|
{
|
||||||
if (materialsSrc[indexSrc])
|
MaterialBase* mat = materialsSrc[indexSrc].Get();
|
||||||
{
|
if (mat && !Materials.Contains(mat))
|
||||||
Materials.Add(materialsSrc[indexSrc]);
|
Materials.Add(mat);
|
||||||
}
|
|
||||||
indexSrc++;
|
indexSrc++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -494,6 +494,7 @@ void AnimatedModel::StopSlotAnimation(const StringView& slotName, Animation* ani
|
|||||||
if (slot.Animation == anim && slot.Name == slotName)
|
if (slot.Animation == anim && slot.Name == slotName)
|
||||||
{
|
{
|
||||||
slot.Animation = nullptr;
|
slot.Animation = nullptr;
|
||||||
|
slot.Reset = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,12 @@ void DirectionalLight::Draw(RenderContext& renderContext)
|
|||||||
data.RenderedVolumetricFog = 0;
|
data.RenderedVolumetricFog = 0;
|
||||||
data.ShadowsMode = ShadowsMode;
|
data.ShadowsMode = ShadowsMode;
|
||||||
data.CascadeCount = CascadeCount;
|
data.CascadeCount = CascadeCount;
|
||||||
|
data.Cascade1Spacing = Cascade1Spacing;
|
||||||
|
data.Cascade2Spacing = Cascade2Spacing;
|
||||||
|
data.Cascade3Spacing = Cascade3Spacing;
|
||||||
|
data.Cascade4Spacing = Cascade4Spacing;
|
||||||
|
|
||||||
|
data.PartitionMode = PartitionMode;
|
||||||
data.ContactShadowsLength = ContactShadowsLength;
|
data.ContactShadowsLength = ContactShadowsLength;
|
||||||
data.StaticFlags = GetStaticFlags();
|
data.StaticFlags = GetStaticFlags();
|
||||||
data.ID = GetID();
|
data.ID = GetID();
|
||||||
@@ -56,6 +62,12 @@ void DirectionalLight::Serialize(SerializeStream& stream, const void* otherObj)
|
|||||||
SERIALIZE_GET_OTHER_OBJ(DirectionalLight);
|
SERIALIZE_GET_OTHER_OBJ(DirectionalLight);
|
||||||
|
|
||||||
SERIALIZE(CascadeCount);
|
SERIALIZE(CascadeCount);
|
||||||
|
SERIALIZE(Cascade1Spacing);
|
||||||
|
SERIALIZE(Cascade2Spacing);
|
||||||
|
SERIALIZE(Cascade3Spacing);
|
||||||
|
SERIALIZE(Cascade4Spacing);
|
||||||
|
|
||||||
|
SERIALIZE(PartitionMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DirectionalLight::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
|
void DirectionalLight::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
|
||||||
@@ -64,6 +76,12 @@ void DirectionalLight::Deserialize(DeserializeStream& stream, ISerializeModifier
|
|||||||
LightWithShadow::Deserialize(stream, modifier);
|
LightWithShadow::Deserialize(stream, modifier);
|
||||||
|
|
||||||
DESERIALIZE(CascadeCount);
|
DESERIALIZE(CascadeCount);
|
||||||
|
DESERIALIZE(Cascade1Spacing);
|
||||||
|
DESERIALIZE(Cascade2Spacing);
|
||||||
|
DESERIALIZE(Cascade3Spacing);
|
||||||
|
DESERIALIZE(Cascade4Spacing);
|
||||||
|
|
||||||
|
DESERIALIZE(PartitionMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DirectionalLight::IntersectsItself(const Ray& ray, Real& distance, Vector3& normal)
|
bool DirectionalLight::IntersectsItself(const Ray& ray, Real& distance, Vector3& normal)
|
||||||
|
|||||||
@@ -12,12 +12,42 @@ class FLAXENGINE_API DirectionalLight : public LightWithShadow
|
|||||||
{
|
{
|
||||||
DECLARE_SCENE_OBJECT(DirectionalLight);
|
DECLARE_SCENE_OBJECT(DirectionalLight);
|
||||||
public:
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// The partitioning mode for the shadow cascades.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(Attributes = "EditorOrder(64), DefaultValue(PartitionMode.Manual), EditorDisplay(\"Shadow\")")
|
||||||
|
PartitionMode PartitionMode = PartitionMode::Manual;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The number of cascades used for slicing the range of depth covered by the light during shadow rendering. Values are 1, 2 or 4 cascades; a typical scene uses 4 cascades.
|
/// The number of cascades used for slicing the range of depth covered by the light during shadow rendering. Values are 1, 2 or 4 cascades; a typical scene uses 4 cascades.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD(Attributes="EditorOrder(65), DefaultValue(4), Limit(1, 4), EditorDisplay(\"Shadow\")")
|
API_FIELD(Attributes="EditorOrder(65), DefaultValue(4), Limit(1, 4), EditorDisplay(\"Shadow\")")
|
||||||
int32 CascadeCount = 4;
|
int32 CascadeCount = 4;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Percentage of the shadow distance used by the first cascade.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(Attributes = "EditorOrder(66), DefaultValue(0.05f), VisibleIf(nameof(ShowCascade1)), Limit(0, 1, 0.001f), EditorDisplay(\"Shadow\")")
|
||||||
|
float Cascade1Spacing = 0.05f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Percentage of the shadow distance used by the second cascade.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(Attributes = "EditorOrder(67), DefaultValue(0.15f), VisibleIf(nameof(ShowCascade2)), Limit(0, 1, 0.001f), EditorDisplay(\"Shadow\")")
|
||||||
|
float Cascade2Spacing = 0.15f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Percentage of the shadow distance used by the third cascade.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(Attributes = "EditorOrder(68), DefaultValue(0.50f), VisibleIf(nameof(ShowCascade3)), Limit(0, 1, 0.001f), EditorDisplay(\"Shadow\")")
|
||||||
|
float Cascade3Spacing = 0.50f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Percentage of the shadow distance used by the fourth cascade.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(Attributes = "EditorOrder(69), DefaultValue(1.0f), VisibleIf(nameof(ShowCascade4)), Limit(0, 1, 0.001f), EditorDisplay(\"Shadow\")")
|
||||||
|
float Cascade4Spacing = 1.0f;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// [LightWithShadow]
|
// [LightWithShadow]
|
||||||
void Draw(RenderContext& renderContext) override;
|
void Draw(RenderContext& renderContext) override;
|
||||||
|
|||||||
10
Source/Engine/Level/DirectionalLight.cs
Normal file
10
Source/Engine/Level/DirectionalLight.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace FlaxEngine
|
||||||
|
{
|
||||||
|
public partial class DirectionalLight
|
||||||
|
{
|
||||||
|
bool ShowCascade1 => CascadeCount >= 1 && PartitionMode == PartitionMode.Manual;
|
||||||
|
bool ShowCascade2 => CascadeCount >= 2 && PartitionMode == PartitionMode.Manual;
|
||||||
|
bool ShowCascade3 => CascadeCount >= 3 && PartitionMode == PartitionMode.Manual;
|
||||||
|
bool ShowCascade4 => CascadeCount >= 4 && PartitionMode == PartitionMode.Manual;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,7 +43,7 @@ API_STRUCT(Namespace="FlaxEngine.Networking") struct FLAXENGINE_API NetworkConfi
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>Object is managed by the created network peer (will be deleted on peer shutdown).</remarks>
|
/// <remarks>Object is managed by the created network peer (will be deleted on peer shutdown).</remarks>
|
||||||
API_FIELD()
|
API_FIELD()
|
||||||
ScriptingObject* NetworkDriver;
|
ScriptingObject* NetworkDriver = nullptr;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The upper limit on how many peers can join when we're listening.
|
/// The upper limit on how many peers can join when we're listening.
|
||||||
|
|||||||
@@ -2151,6 +2151,18 @@ void NetworkInternal::OnNetworkMessageObjectRpc(NetworkEvent& event, NetworkClie
|
|||||||
NetworkMessageObjectRpc msgData;
|
NetworkMessageObjectRpc msgData;
|
||||||
event.Message.ReadStructure(msgData);
|
event.Message.ReadStructure(msgData);
|
||||||
ScopeLock lock(ObjectsLock);
|
ScopeLock lock(ObjectsLock);
|
||||||
|
|
||||||
|
// Find RPC info
|
||||||
|
NetworkRpcName name;
|
||||||
|
name.First = Scripting::FindScriptingType(msgData.RpcTypeName);
|
||||||
|
name.Second = msgData.RpcName;
|
||||||
|
const NetworkRpcInfo* info = NetworkRpcInfo::RPCsTable.TryGet(name);
|
||||||
|
if (!info)
|
||||||
|
{
|
||||||
|
NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Unknown RPC {}::{} for object {}", String(msgData.RpcTypeName), String(msgData.RpcName), msgData.ObjectId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
NetworkReplicatedObject* e = ResolveObject(msgData.ObjectId, msgData.ParentId, msgData.ObjectTypeName);
|
NetworkReplicatedObject* e = ResolveObject(msgData.ObjectId, msgData.ParentId, msgData.ObjectTypeName);
|
||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
@@ -2159,17 +2171,7 @@ void NetworkInternal::OnNetworkMessageObjectRpc(NetworkEvent& event, NetworkClie
|
|||||||
if (!obj)
|
if (!obj)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Find RPC info
|
|
||||||
NetworkRpcName name;
|
|
||||||
name.First = Scripting::FindScriptingType(msgData.RpcTypeName);
|
|
||||||
name.Second = msgData.RpcName;
|
|
||||||
const NetworkRpcInfo* info = NetworkRpcInfo::RPCsTable.TryGet(name);
|
|
||||||
if (!info)
|
|
||||||
{
|
|
||||||
NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Unknown RPC {}::{} for object {}", String(msgData.RpcTypeName), String(msgData.RpcName), msgData.ObjectId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate RPC
|
// Validate RPC
|
||||||
if (info->Server && NetworkManager::IsClient())
|
if (info->Server && NetworkManager::IsClient())
|
||||||
{
|
{
|
||||||
@@ -2192,7 +2194,7 @@ void NetworkInternal::OnNetworkMessageObjectRpc(NetworkEvent& event, NetworkClie
|
|||||||
// Execute RPC
|
// Execute RPC
|
||||||
info->Execute(obj, stream, info->Tag);
|
info->Execute(obj, stream, info->Tag);
|
||||||
}
|
}
|
||||||
else
|
else if(info->Channel != static_cast<uint8>(NetworkChannelType::Unreliable) && info->Channel != static_cast<uint8>(NetworkChannelType::UnreliableOrdered))
|
||||||
{
|
{
|
||||||
NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Unknown object {} RPC {}::{}", msgData.ObjectId, String(msgData.RpcTypeName), String(msgData.RpcName));
|
NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Unknown object {} RPC {}::{}", msgData.ObjectId, String(msgData.RpcTypeName), String(msgData.RpcName));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2260,7 +2260,13 @@ void PhysicsBackend::SetRigidActorPose(void* actor, const Vector3& position, con
|
|||||||
if (kinematic)
|
if (kinematic)
|
||||||
{
|
{
|
||||||
auto actorPhysX = (PxRigidDynamic*)actor;
|
auto actorPhysX = (PxRigidDynamic*)actor;
|
||||||
actorPhysX->setKinematicTarget(trans);
|
if (actorPhysX->getActorFlags() & PxActorFlag::eDISABLE_SIMULATION)
|
||||||
|
{
|
||||||
|
// Ensures the disabled kinematic actor ends up in the correct pose after enabling simulation
|
||||||
|
actorPhysX->setGlobalPose(trans, wakeUp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
actorPhysX->setKinematicTarget(trans);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ bool AndroidFileSystem::FileExists(const StringView& path)
|
|||||||
bool AndroidFileSystem::DeleteFile(const StringView& path)
|
bool AndroidFileSystem::DeleteFile(const StringView& path)
|
||||||
{
|
{
|
||||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||||
return unlink(pathANSI.Get()) == 0;
|
return unlink(pathANSI.Get()) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 AndroidFileSystem::GetFileSize(const StringView& path)
|
uint64 AndroidFileSystem::GetFileSize(const StringView& path)
|
||||||
@@ -517,7 +517,7 @@ DateTime AndroidFileSystem::GetFileLastEditTime(const StringView& path)
|
|||||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||||
if (stat(pathANSI.Get(), &fileInfo) == -1)
|
if (stat(pathANSI.Get(), &fileInfo) == -1)
|
||||||
return DateTime::MinValue();
|
return DateTime::MinValue();
|
||||||
const TimeSpan timeSinceEpoch(0, 0, fileInfo.st_mtime);
|
const TimeSpan timeSinceEpoch(0, 0, 0, fileInfo.st_mtime);
|
||||||
const DateTime UnixEpoch(1970, 1, 1);
|
const DateTime UnixEpoch(1970, 1, 1);
|
||||||
return UnixEpoch + timeSinceEpoch;
|
return UnixEpoch + timeSinceEpoch;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ bool AppleFileSystem::FileExists(const StringView& path)
|
|||||||
bool AppleFileSystem::DeleteFile(const StringView& path)
|
bool AppleFileSystem::DeleteFile(const StringView& path)
|
||||||
{
|
{
|
||||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||||
return unlink(pathANSI.Get()) == 0;
|
return unlink(pathANSI.Get()) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 AppleFileSystem::GetFileSize(const StringView& path)
|
uint64 AppleFileSystem::GetFileSize(const StringView& path)
|
||||||
@@ -498,7 +498,7 @@ DateTime AppleFileSystem::GetFileLastEditTime(const StringView& path)
|
|||||||
return DateTime::MinValue();
|
return DateTime::MinValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
const TimeSpan timeSinceEpoch(0, 0, fileInfo.st_mtime);
|
const TimeSpan timeSinceEpoch(0, 0, 0, fileInfo.st_mtime);
|
||||||
return UnixEpoch + timeSinceEpoch;
|
return UnixEpoch + timeSinceEpoch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -364,7 +364,7 @@ bool LinuxFileSystem::FileExists(const StringView& path)
|
|||||||
bool LinuxFileSystem::DeleteFile(const StringView& path)
|
bool LinuxFileSystem::DeleteFile(const StringView& path)
|
||||||
{
|
{
|
||||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||||
return unlink(pathANSI.Get()) == 0;
|
return unlink(pathANSI.Get()) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 LinuxFileSystem::GetFileSize(const StringView& path)
|
uint64 LinuxFileSystem::GetFileSize(const StringView& path)
|
||||||
@@ -657,7 +657,7 @@ DateTime LinuxFileSystem::GetFileLastEditTime(const StringView& path)
|
|||||||
return DateTime::MinValue();
|
return DateTime::MinValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
const TimeSpan timeSinceEpoch(0, 0, fileInfo.st_mtime);
|
const TimeSpan timeSinceEpoch(0, 0, 0, fileInfo.st_mtime);
|
||||||
return UnixEpoch + timeSinceEpoch;
|
return UnixEpoch + timeSinceEpoch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ DateTime UnixFile::GetLastWriteTime() const
|
|||||||
{
|
{
|
||||||
return DateTime::MinValue();
|
return DateTime::MinValue();
|
||||||
}
|
}
|
||||||
const TimeSpan timeSinceEpoch(0, 0, fileInfo.st_mtime);
|
const TimeSpan timeSinceEpoch(0, 0, 0, fileInfo.st_mtime);
|
||||||
const DateTime unixEpoch(1970, 1, 1);
|
const DateTime unixEpoch(1970, 1, 1);
|
||||||
return unixEpoch + timeSinceEpoch;
|
return unixEpoch + timeSinceEpoch;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,12 @@ struct RendererDirectionalLightData
|
|||||||
|
|
||||||
float ShadowsDistance;
|
float ShadowsDistance;
|
||||||
int32 CascadeCount;
|
int32 CascadeCount;
|
||||||
|
float Cascade1Spacing;
|
||||||
|
float Cascade2Spacing;
|
||||||
|
float Cascade3Spacing;
|
||||||
|
float Cascade4Spacing;
|
||||||
|
|
||||||
|
PartitionMode PartitionMode;
|
||||||
float ContactShadowsLength;
|
float ContactShadowsLength;
|
||||||
ShadowsCastingMode ShadowsMode;
|
ShadowsCastingMode ShadowsMode;
|
||||||
|
|
||||||
|
|||||||
@@ -247,19 +247,12 @@ void ShadowsPass::SetupLight(RenderContext& renderContext, RenderContextBatch& r
|
|||||||
minDistance = cameraNear;
|
minDistance = cameraNear;
|
||||||
maxDistance = cameraNear + shadowsDistance;
|
maxDistance = cameraNear + shadowsDistance;
|
||||||
|
|
||||||
// TODO: expose partition mode?
|
PartitionMode partitionMode = light.PartitionMode;
|
||||||
enum class PartitionMode
|
|
||||||
{
|
|
||||||
Manual = 0,
|
|
||||||
Logarithmic = 1,
|
|
||||||
PSSM = 2,
|
|
||||||
};
|
|
||||||
PartitionMode partitionMode = PartitionMode::Manual;
|
|
||||||
float pssmFactor = 0.5f;
|
float pssmFactor = 0.5f;
|
||||||
float splitDistance0 = 0.05f;
|
float splitDistance0 = light.Cascade1Spacing;
|
||||||
float splitDistance1 = 0.15f;
|
float splitDistance1 = Math::Max(splitDistance0, light.Cascade2Spacing);
|
||||||
float splitDistance2 = 0.50f;
|
float splitDistance2 = Math::Max(splitDistance1, light.Cascade3Spacing);
|
||||||
float splitDistance3 = 1.00f;
|
float splitDistance3 = Math::Max(splitDistance2, light.Cascade4Spacing);
|
||||||
|
|
||||||
// Compute the split distances based on the partitioning mode
|
// Compute the split distances based on the partitioning mode
|
||||||
if (partitionMode == PartitionMode::Manual)
|
if (partitionMode == PartitionMode::Manual)
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ using System;
|
|||||||
namespace FlaxEngine
|
namespace FlaxEngine
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shows property/field in the editor only if the specified member has a given value. Can be used to hide properties based on other properties (also private properties). The given member has to be bool type.
|
/// Shows property/field in the editor only if the specified member has a given value. Can be used to hide properties based on other properties (also private properties). The given member has to be bool type. Multiple VisibleIf attributes can be added for additional conditions to be met.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="System.Attribute" />
|
/// <seealso cref="System.Attribute" />
|
||||||
[Serializable]
|
[Serializable]
|
||||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
|
||||||
public sealed class VisibleIfAttribute : Attribute
|
public sealed class VisibleIfAttribute : Attribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
26
Source/Engine/Tests/TestTime.cpp
Normal file
26
Source/Engine/Tests/TestTime.cpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
#include "Engine/Core/Types/DateTime.h"
|
||||||
|
#include <ThirdParty/catch2/catch.hpp>
|
||||||
|
|
||||||
|
TEST_CASE("DateTime")
|
||||||
|
{
|
||||||
|
SECTION("Test Convertion")
|
||||||
|
{
|
||||||
|
constexpr int year = 2023;
|
||||||
|
constexpr int month = 12;
|
||||||
|
constexpr int day = 16;
|
||||||
|
constexpr int hour = 23;
|
||||||
|
constexpr int minute = 50;
|
||||||
|
constexpr int second = 13;
|
||||||
|
constexpr int millisecond = 5;
|
||||||
|
const DateTime dt1(year, month, day, hour, minute, second, millisecond);
|
||||||
|
CHECK(dt1.GetYear() == year);
|
||||||
|
CHECK(dt1.GetMonth() == month);
|
||||||
|
CHECK(dt1.GetDay() == day);
|
||||||
|
CHECK(dt1.GetHour() == hour);
|
||||||
|
CHECK(dt1.GetMinute() == minute);
|
||||||
|
CHECK(dt1.GetSecond() == second);
|
||||||
|
CHECK(dt1.GetMillisecond() == millisecond);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -584,7 +584,6 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value)
|
|||||||
{
|
{
|
||||||
// Procedural Texture Sample
|
// Procedural Texture Sample
|
||||||
textureBox->Cache = writeLocal(Value::InitForZero(ValueType::Float4), node);
|
textureBox->Cache = writeLocal(Value::InitForZero(ValueType::Float4), node);
|
||||||
createGradients(node);
|
|
||||||
auto proceduralSample = String::Format(TEXT(
|
auto proceduralSample = String::Format(TEXT(
|
||||||
" {{\n"
|
" {{\n"
|
||||||
" float3 weights;\n"
|
" float3 weights;\n"
|
||||||
@@ -613,19 +612,19 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value)
|
|||||||
" uv1 = {0} + frac(sin(mul(float2x2(127.1, 311.7, 269.5, 183.3), vertex1)) * 43758.5453);\n"
|
" uv1 = {0} + frac(sin(mul(float2x2(127.1, 311.7, 269.5, 183.3), vertex1)) * 43758.5453);\n"
|
||||||
" uv2 = {0} + frac(sin(mul(float2x2(127.1, 311.7, 269.5, 183.3), vertex2)) * 43758.5453);\n"
|
" uv2 = {0} + frac(sin(mul(float2x2(127.1, 311.7, 269.5, 183.3), vertex2)) * 43758.5453);\n"
|
||||||
" uv3 = {0} + frac(sin(mul(float2x2(127.1, 311.7, 269.5, 183.3), vertex3)) * 43758.5453);\n"
|
" uv3 = {0} + frac(sin(mul(float2x2(127.1, 311.7, 269.5, 183.3), vertex3)) * 43758.5453);\n"
|
||||||
" float4 tex1 = {1}.SampleGrad({4}, uv1, {2}, {3}, {6}) * weights.x;\n"
|
" float2 fdx = ddx({0});\n"
|
||||||
" float4 tex2 = {1}.SampleGrad({4}, uv2, {2}, {3}, {6}) * weights.y;\n"
|
" float2 fdy = ddy({0});\n"
|
||||||
" float4 tex3 = {1}.SampleGrad({4}, uv3, {2}, {3}, {6}) * weights.z;\n"
|
" float4 tex1 = {1}.SampleGrad({2}, uv1, fdx, fdy, {4}) * weights.x;\n"
|
||||||
" {5} = tex1 + tex2 + tex3;\n"
|
" float4 tex2 = {1}.SampleGrad({2}, uv2, fdx, fdy, {4}) * weights.y;\n"
|
||||||
|
" float4 tex3 = {1}.SampleGrad({2}, uv3, fdx, fdy, {4}) * weights.z;\n"
|
||||||
|
" {3} = tex1 + tex2 + tex3;\n"
|
||||||
" }}\n"
|
" }}\n"
|
||||||
),
|
),
|
||||||
uvs.Value, // {0}
|
uvs.Value, // {0}
|
||||||
texture.Value, // {1}
|
texture.Value, // {1}
|
||||||
_ddx.Value, // {2}
|
samplerName, // {2}
|
||||||
_ddy.Value, // {3}
|
textureBox->Cache.Value, // {3}
|
||||||
samplerName, // {4}
|
offset.Value // {4}
|
||||||
textureBox->Cache.Value, // {5}
|
|
||||||
offset.Value // {6}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
_writer.Write(*proceduralSample);
|
_writer.Write(*proceduralSample);
|
||||||
|
|||||||
@@ -374,6 +374,7 @@ void ModelTool::Options::Serialize(SerializeStream& stream, const void* otherObj
|
|||||||
SERIALIZE(InstanceToImportAs);
|
SERIALIZE(InstanceToImportAs);
|
||||||
SERIALIZE(ImportTextures);
|
SERIALIZE(ImportTextures);
|
||||||
SERIALIZE(RestoreMaterialsOnReimport);
|
SERIALIZE(RestoreMaterialsOnReimport);
|
||||||
|
SERIALIZE(SkipExistingMaterialsOnReimport);
|
||||||
SERIALIZE(GenerateSDF);
|
SERIALIZE(GenerateSDF);
|
||||||
SERIALIZE(SDFResolution);
|
SERIALIZE(SDFResolution);
|
||||||
SERIALIZE(SplitObjects);
|
SERIALIZE(SplitObjects);
|
||||||
@@ -422,6 +423,7 @@ void ModelTool::Options::Deserialize(DeserializeStream& stream, ISerializeModifi
|
|||||||
DESERIALIZE(InstanceToImportAs);
|
DESERIALIZE(InstanceToImportAs);
|
||||||
DESERIALIZE(ImportTextures);
|
DESERIALIZE(ImportTextures);
|
||||||
DESERIALIZE(RestoreMaterialsOnReimport);
|
DESERIALIZE(RestoreMaterialsOnReimport);
|
||||||
|
DESERIALIZE(SkipExistingMaterialsOnReimport);
|
||||||
DESERIALIZE(GenerateSDF);
|
DESERIALIZE(GenerateSDF);
|
||||||
DESERIALIZE(SDFResolution);
|
DESERIALIZE(SDFResolution);
|
||||||
DESERIALIZE(SplitObjects);
|
DESERIALIZE(SplitObjects);
|
||||||
@@ -1154,6 +1156,18 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip any materials that already exist from the model.
|
||||||
|
// This allows the use of "import as material instances" without material properties getting overridden on each import.
|
||||||
|
if (options.SkipExistingMaterialsOnReimport)
|
||||||
|
{
|
||||||
|
AssetInfo info;
|
||||||
|
if (Content::GetAssetInfo(assetPath, info))
|
||||||
|
{
|
||||||
|
material.AssetID = info.ID;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (options.ImportMaterialsAsInstances)
|
if (options.ImportMaterialsAsInstances)
|
||||||
{
|
{
|
||||||
// Create material instance
|
// Create material instance
|
||||||
|
|||||||
@@ -260,17 +260,20 @@ public:
|
|||||||
API_FIELD(Attributes="EditorOrder(400), EditorDisplay(\"Materials\"), VisibleIf(nameof(ShowGeometry))")
|
API_FIELD(Attributes="EditorOrder(400), EditorDisplay(\"Materials\"), VisibleIf(nameof(ShowGeometry))")
|
||||||
bool ImportMaterials = true;
|
bool ImportMaterials = true;
|
||||||
// If checked, the importer will create the model's materials as instances of a base material.
|
// If checked, the importer will create the model's materials as instances of a base material.
|
||||||
API_FIELD(Attributes = "EditorOrder(401), EditorDisplay(\"Materials\"), VisibleIf(nameof(ImportMaterials))")
|
API_FIELD(Attributes = "EditorOrder(401), EditorDisplay(\"Materials\"), VisibleIf(nameof(ImportMaterials)), VisibleIf(nameof(ShowGeometry))")
|
||||||
bool ImportMaterialsAsInstances = false;
|
bool ImportMaterialsAsInstances = false;
|
||||||
// The material used as the base material that will be instanced as the imported model's material.
|
// The material used as the base material that will be instanced as the imported model's material.
|
||||||
API_FIELD(Attributes = "EditorOrder(402), EditorDisplay(\"Materials\"), VisibleIf(nameof(ImportMaterialsAsInstances))")
|
API_FIELD(Attributes = "EditorOrder(402), EditorDisplay(\"Materials\"), VisibleIf(nameof(ImportMaterialsAsInstances)), VisibleIf(nameof(ShowGeometry))")
|
||||||
AssetReference<MaterialBase> InstanceToImportAs;
|
AssetReference<MaterialBase> InstanceToImportAs;
|
||||||
// If checked, the importer will import texture files used by the model and any embedded texture resources.
|
// If checked, the importer will import texture files used by the model and any embedded texture resources.
|
||||||
API_FIELD(Attributes="EditorOrder(410), EditorDisplay(\"Materials\"), VisibleIf(nameof(ShowGeometry))")
|
API_FIELD(Attributes="EditorOrder(410), EditorDisplay(\"Materials\"), VisibleIf(nameof(ShowGeometry))")
|
||||||
bool ImportTextures = true;
|
bool ImportTextures = true;
|
||||||
// If checked, the importer will try to keep the model's current material slots, instead of importing materials from the source file.
|
// If checked, the importer will try to keep the model's current overridden material slots, instead of importing materials from the source file.
|
||||||
API_FIELD(Attributes="EditorOrder(420), EditorDisplay(\"Materials\", \"Keep Material Slots on Reimport\"), VisibleIf(nameof(ShowGeometry))")
|
API_FIELD(Attributes="EditorOrder(420), EditorDisplay(\"Materials\", \"Keep Overridden Materials\"), VisibleIf(nameof(ShowGeometry))")
|
||||||
bool RestoreMaterialsOnReimport = true;
|
bool RestoreMaterialsOnReimport = true;
|
||||||
|
// If checked, the importer will not reimport any material from this model which already exist in the sub-asset folder.
|
||||||
|
API_FIELD(Attributes = "EditorOrder(421), EditorDisplay(\"Materials\", \"Skip Existing Materials\"), VisibleIf(nameof(ShowGeometry))")
|
||||||
|
bool SkipExistingMaterialsOnReimport = true;
|
||||||
|
|
||||||
public: // SDF
|
public: // SDF
|
||||||
|
|
||||||
|
|||||||
@@ -179,7 +179,10 @@ namespace Flax.Build.Projects.VisualStudio
|
|||||||
customizer.WriteVisualStudioBuildProperties(vsProject, platform, toolchain, configuration, vcProjectFileContent, vcFiltersFileContent, vcUserFileContent);
|
customizer.WriteVisualStudioBuildProperties(vsProject, platform, toolchain, configuration, vcProjectFileContent, vcFiltersFileContent, vcUserFileContent);
|
||||||
vcProjectFileContent.AppendLine(string.Format(" <IntDir>{0}</IntDir>", targetBuildOptions.IntermediateFolder));
|
vcProjectFileContent.AppendLine(string.Format(" <IntDir>{0}</IntDir>", targetBuildOptions.IntermediateFolder));
|
||||||
vcProjectFileContent.AppendLine(string.Format(" <OutDir>{0}</OutDir>", targetBuildOptions.OutputFolder));
|
vcProjectFileContent.AppendLine(string.Format(" <OutDir>{0}</OutDir>", targetBuildOptions.OutputFolder));
|
||||||
vcProjectFileContent.AppendLine(" <IncludePath />");
|
if (includePaths.Count != 0)
|
||||||
|
vcProjectFileContent.AppendLine(string.Format(" <IncludePath>$(IncludePath);{0}</IncludePath>", string.Join(";", includePaths)));
|
||||||
|
else
|
||||||
|
vcProjectFileContent.AppendLine(" <IncludePath />");
|
||||||
vcProjectFileContent.AppendLine(" <ReferencePath />");
|
vcProjectFileContent.AppendLine(" <ReferencePath />");
|
||||||
vcProjectFileContent.AppendLine(" <LibraryPath />");
|
vcProjectFileContent.AppendLine(" <LibraryPath />");
|
||||||
vcProjectFileContent.AppendLine(" <LibraryWPath />");
|
vcProjectFileContent.AppendLine(" <LibraryWPath />");
|
||||||
|
|||||||
Reference in New Issue
Block a user