Merge remote-tracking branch 'origin/master' into 1.9
# Conflicts: # Source/Engine/UI/GUI/Common/Button.cs
This commit is contained in:
@@ -296,6 +296,16 @@ namespace FlaxEditor.CustomEditors
|
|||||||
_values.Set(_parent.Values, value);
|
_values.Set(_parent.Values, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool SyncParent()
|
||||||
|
{
|
||||||
|
// TODO: add attribute for types that want to sync their contents with a parent
|
||||||
|
var type = Values.Type.Type;
|
||||||
|
if (type == typeof(LocalizedString) ||
|
||||||
|
type == typeof(FontReference))
|
||||||
|
return true;
|
||||||
|
return _parent != null && !(_parent is SyncPointEditor);
|
||||||
|
}
|
||||||
|
|
||||||
internal virtual void RefreshInternal()
|
internal virtual void RefreshInternal()
|
||||||
{
|
{
|
||||||
if (_values == null)
|
if (_values == null)
|
||||||
@@ -317,7 +327,7 @@ namespace FlaxEditor.CustomEditors
|
|||||||
|
|
||||||
// Propagate values up (eg. when member of structure gets modified, also structure should be updated as a part of the other object)
|
// Propagate values up (eg. when member of structure gets modified, also structure should be updated as a part of the other object)
|
||||||
var obj = _parent;
|
var obj = _parent;
|
||||||
while (obj._parent != null && !(obj._parent is SyncPointEditor))
|
while (obj.SyncParent())
|
||||||
{
|
{
|
||||||
obj.Values.Set(obj._parent.Values, obj.Values);
|
obj.Values.Set(obj._parent.Values, obj.Values);
|
||||||
obj = obj._parent;
|
obj = obj._parent;
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ namespace FlaxEditor.CustomEditors
|
|||||||
return new GenericEditor();
|
return new GenericEditor();
|
||||||
if (targetType.IsArray)
|
if (targetType.IsArray)
|
||||||
{
|
{
|
||||||
|
if (targetType.Type == null)
|
||||||
|
return new ArrayEditor();
|
||||||
if (targetType.Type.GetArrayRank() != 1)
|
if (targetType.Type.GetArrayRank() != 1)
|
||||||
return new GenericEditor(); // Not-supported multidimensional array
|
return new GenericEditor(); // Not-supported multidimensional array
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using FlaxEditor.CustomEditors.Editors;
|
|||||||
using FlaxEditor.CustomEditors.Elements;
|
using FlaxEditor.CustomEditors.Elements;
|
||||||
using FlaxEditor.GUI;
|
using FlaxEditor.GUI;
|
||||||
using FlaxEditor.GUI.ContextMenu;
|
using FlaxEditor.GUI.ContextMenu;
|
||||||
|
using FlaxEditor.GUI.Input;
|
||||||
using FlaxEditor.Scripting;
|
using FlaxEditor.Scripting;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
@@ -634,26 +635,29 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
LayoutElementsContainer vEl;
|
LayoutElementsContainer vEl;
|
||||||
Color axisColorX = ActorTransformEditor.AxisColorX;
|
Color axisColorX = ActorTransformEditor.AxisColorX;
|
||||||
Color axisColorY = ActorTransformEditor.AxisColorY;
|
Color axisColorY = ActorTransformEditor.AxisColorY;
|
||||||
|
FloatValueBox xV, yV, wV, hV;
|
||||||
if (xEq)
|
if (xEq)
|
||||||
{
|
{
|
||||||
xEl = UniformPanelCapsuleForObjectWithText(horUp, "X: ", xItem.GetValues(Values), axisColorX);
|
xEl = UniformPanelCapsuleForObjectWithText(horUp, "X: ", xItem.GetValues(Values), axisColorX, out xV);
|
||||||
vEl = UniformPanelCapsuleForObjectWithText(horDown, "Width: ", widthItem.GetValues(Values), axisColorX);
|
vEl = UniformPanelCapsuleForObjectWithText(horDown, "Width: ", widthItem.GetValues(Values), axisColorX, out wV);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
xEl = UniformPanelCapsuleForObjectWithText(horUp, "Left: ", leftItem.GetValues(Values), axisColorX);
|
xEl = UniformPanelCapsuleForObjectWithText(horUp, "Left: ", leftItem.GetValues(Values), axisColorX, out xV);
|
||||||
vEl = UniformPanelCapsuleForObjectWithText(horDown, "Right: ", rightItem.GetValues(Values), axisColorX);
|
vEl = UniformPanelCapsuleForObjectWithText(horDown, "Right: ", rightItem.GetValues(Values), axisColorX, out wV);
|
||||||
}
|
}
|
||||||
if (yEq)
|
if (yEq)
|
||||||
{
|
{
|
||||||
yEl = UniformPanelCapsuleForObjectWithText(horUp, "Y: ", yItem.GetValues(Values), axisColorY);
|
yEl = UniformPanelCapsuleForObjectWithText(horUp, "Y: ", yItem.GetValues(Values), axisColorY, out yV);
|
||||||
hEl = UniformPanelCapsuleForObjectWithText(horDown, "Height: ", heightItem.GetValues(Values), axisColorY);
|
hEl = UniformPanelCapsuleForObjectWithText(horDown, "Height: ", heightItem.GetValues(Values), axisColorY, out hV);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
yEl = UniformPanelCapsuleForObjectWithText(horUp, "Top: ", topItem.GetValues(Values), axisColorY);
|
yEl = UniformPanelCapsuleForObjectWithText(horUp, "Top: ", topItem.GetValues(Values), axisColorY, out yV);
|
||||||
hEl = UniformPanelCapsuleForObjectWithText(horDown, "Bottom: ", bottomItem.GetValues(Values), axisColorY);
|
hEl = UniformPanelCapsuleForObjectWithText(horDown, "Bottom: ", bottomItem.GetValues(Values), axisColorY, out hV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Anchors
|
||||||
xEl.Control.AnchorMin = new Float2(0, xEl.Control.AnchorMin.Y);
|
xEl.Control.AnchorMin = new Float2(0, xEl.Control.AnchorMin.Y);
|
||||||
xEl.Control.AnchorMax = new Float2(0.5f, xEl.Control.AnchorMax.Y);
|
xEl.Control.AnchorMax = new Float2(0.5f, xEl.Control.AnchorMax.Y);
|
||||||
|
|
||||||
@@ -665,6 +669,15 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
|
|
||||||
hEl.Control.AnchorMin = new Float2(0.5f, xEl.Control.AnchorMin.Y);
|
hEl.Control.AnchorMin = new Float2(0.5f, xEl.Control.AnchorMin.Y);
|
||||||
hEl.Control.AnchorMax = new Float2(1, xEl.Control.AnchorMax.Y);
|
hEl.Control.AnchorMax = new Float2(1, xEl.Control.AnchorMax.Y);
|
||||||
|
|
||||||
|
// Navigation path
|
||||||
|
xV.NavTargetRight = yV;
|
||||||
|
yV.NavTargetRight = wV;
|
||||||
|
wV.NavTargetRight = hV;
|
||||||
|
|
||||||
|
yV.NavTargetLeft = xV;
|
||||||
|
wV.NavTargetLeft = yV;
|
||||||
|
hV.NavTargetLeft = wV;
|
||||||
}
|
}
|
||||||
|
|
||||||
private VerticalPanelElement VerticalPanelWithoutMargin(LayoutElementsContainer cont)
|
private VerticalPanelElement VerticalPanelWithoutMargin(LayoutElementsContainer cont)
|
||||||
@@ -684,17 +697,19 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
return grid;
|
return grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CustomElementsContainer<UniformGridPanel> UniformPanelCapsuleForObjectWithText(LayoutElementsContainer el, string text, ValueContainer values, Color borderColor)
|
private CustomElementsContainer<UniformGridPanel> UniformPanelCapsuleForObjectWithText(LayoutElementsContainer el, string text, ValueContainer values, Color borderColor, out FloatValueBox valueBox)
|
||||||
{
|
{
|
||||||
|
valueBox = null;
|
||||||
var grid = UniformGridTwoByOne(el);
|
var grid = UniformGridTwoByOne(el);
|
||||||
grid.CustomControl.SlotPadding = new Margin(5, 5, 1, 1);
|
grid.CustomControl.SlotPadding = new Margin(5, 5, 1, 1);
|
||||||
var label = grid.Label(text, TextAlignment.Far);
|
var label = grid.Label(text, TextAlignment.Far);
|
||||||
var editor = grid.Object(values);
|
var editor = grid.Object(values);
|
||||||
if (editor is FloatEditor floatEditor && floatEditor.Element is FloatValueElement floatEditorElement)
|
if (editor is FloatEditor floatEditor && floatEditor.Element is FloatValueElement floatEditorElement)
|
||||||
{
|
{
|
||||||
|
valueBox = floatEditorElement.ValueBox;
|
||||||
var back = FlaxEngine.GUI.Style.Current.TextBoxBackground;
|
var back = FlaxEngine.GUI.Style.Current.TextBoxBackground;
|
||||||
floatEditorElement.ValueBox.BorderColor = Color.Lerp(borderColor, back, ActorTransformEditor.AxisGreyOutFactor);
|
valueBox.BorderColor = Color.Lerp(borderColor, back, ActorTransformEditor.AxisGreyOutFactor);
|
||||||
floatEditorElement.ValueBox.BorderSelectedColor = borderColor;
|
valueBox.BorderSelectedColor = borderColor;
|
||||||
}
|
}
|
||||||
return grid;
|
return grid;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
|
|
||||||
private void OnValueChanged()
|
private void OnValueChanged()
|
||||||
{
|
{
|
||||||
if (IsSetBlocked)
|
if (IsSetBlocked || Values == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var isSliding = XElement.IsSliding || YElement.IsSliding;
|
var isSliding = XElement.IsSliding || YElement.IsSliding;
|
||||||
@@ -158,7 +158,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
|
|
||||||
private void OnValueChanged()
|
private void OnValueChanged()
|
||||||
{
|
{
|
||||||
if (IsSetBlocked)
|
if (IsSetBlocked || Values == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var isSliding = XElement.IsSliding || YElement.IsSliding;
|
var isSliding = XElement.IsSliding || YElement.IsSliding;
|
||||||
@@ -247,7 +247,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
|
|
||||||
private void OnValueChanged()
|
private void OnValueChanged()
|
||||||
{
|
{
|
||||||
if (IsSetBlocked)
|
if (IsSetBlocked || Values == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var isSliding = XElement.IsSliding || YElement.IsSliding;
|
var isSliding = XElement.IsSliding || YElement.IsSliding;
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
|
|
||||||
private void OnValueChanged()
|
private void OnValueChanged()
|
||||||
{
|
{
|
||||||
if (IsSetBlocked)
|
if (IsSetBlocked || Values == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var xValue = XElement.ValueBox.Value;
|
var xValue = XElement.ValueBox.Value;
|
||||||
@@ -318,7 +318,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
|
|
||||||
private void OnValueChanged()
|
private void OnValueChanged()
|
||||||
{
|
{
|
||||||
if (IsSetBlocked)
|
if (IsSetBlocked || Values == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var isSliding = XElement.IsSliding || YElement.IsSliding || ZElement.IsSliding;
|
var isSliding = XElement.IsSliding || YElement.IsSliding || ZElement.IsSliding;
|
||||||
@@ -418,7 +418,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
|
|
||||||
private void OnValueChanged()
|
private void OnValueChanged()
|
||||||
{
|
{
|
||||||
if (IsSetBlocked)
|
if (IsSetBlocked || Values == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var isSliding = XElement.IsSliding || YElement.IsSliding || ZElement.IsSliding;
|
var isSliding = XElement.IsSliding || YElement.IsSliding || ZElement.IsSliding;
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
|
|
||||||
private void OnValueChanged()
|
private void OnValueChanged()
|
||||||
{
|
{
|
||||||
if (IsSetBlocked)
|
if (IsSetBlocked || Values == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var isSliding = XElement.IsSliding || YElement.IsSliding || ZElement.IsSliding || WElement.IsSliding;
|
var isSliding = XElement.IsSliding || YElement.IsSliding || ZElement.IsSliding || WElement.IsSliding;
|
||||||
@@ -200,7 +200,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
|
|
||||||
private void OnValueChanged()
|
private void OnValueChanged()
|
||||||
{
|
{
|
||||||
if (IsSetBlocked)
|
if (IsSetBlocked || Values == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var isSliding = XElement.IsSliding || YElement.IsSliding || ZElement.IsSliding || WElement.IsSliding;
|
var isSliding = XElement.IsSliding || YElement.IsSliding || ZElement.IsSliding || WElement.IsSliding;
|
||||||
@@ -311,7 +311,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
|
|
||||||
private void OnValueChanged()
|
private void OnValueChanged()
|
||||||
{
|
{
|
||||||
if (IsSetBlocked)
|
if (IsSetBlocked || Values == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var isSliding = XElement.IsSliding || YElement.IsSliding || ZElement.IsSliding || WElement.IsSliding;
|
var isSliding = XElement.IsSliding || YElement.IsSliding || ZElement.IsSliding || WElement.IsSliding;
|
||||||
|
|||||||
@@ -218,6 +218,13 @@ namespace FlaxEditor.GUI
|
|||||||
Render2D.FillRectangle(bounds, style.Selection);
|
Render2D.FillRectangle(bounds, style.Selection);
|
||||||
Render2D.DrawRectangle(bounds, style.SelectionBorder);
|
Render2D.DrawRectangle(bounds, style.SelectionBorder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Navigation focus highlight
|
||||||
|
if (IsNavFocused)
|
||||||
|
{
|
||||||
|
var bounds = new Rectangle(Float2.Zero, Size);
|
||||||
|
Render2D.DrawRectangle(bounds, style.BackgroundSelected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -286,35 +293,7 @@ namespace FlaxEditor.GUI
|
|||||||
else if (Button1Rect.Contains(location))
|
else if (Button1Rect.Contains(location))
|
||||||
{
|
{
|
||||||
Focus();
|
Focus();
|
||||||
if (Validator.AssetType != ScriptType.Null)
|
OnSubmit();
|
||||||
{
|
|
||||||
// Show asset picker popup
|
|
||||||
var popup = AssetSearchPopup.Show(this, Button1Rect.BottomLeft, Validator.IsValid, item =>
|
|
||||||
{
|
|
||||||
Validator.SelectedItem = item;
|
|
||||||
RootWindow.Focus();
|
|
||||||
Focus();
|
|
||||||
});
|
|
||||||
if (Validator.SelectedAsset != null)
|
|
||||||
{
|
|
||||||
var selectedAssetName = Path.GetFileNameWithoutExtension(Validator.SelectedAsset.Path);
|
|
||||||
popup.ScrollToAndHighlightItemByName(selectedAssetName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Show content item picker popup
|
|
||||||
var popup = ContentSearchPopup.Show(this, Button1Rect.BottomLeft, Validator.IsValid, item =>
|
|
||||||
{
|
|
||||||
Validator.SelectedItem = item;
|
|
||||||
RootWindow.Focus();
|
|
||||||
Focus();
|
|
||||||
});
|
|
||||||
if (Validator.SelectedItem != null)
|
|
||||||
{
|
|
||||||
popup.ScrollToAndHighlightItemByName(Validator.SelectedItem.ShortName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (Validator.SelectedAsset != null || Validator.SelectedItem != null)
|
else if (Validator.SelectedAsset != null || Validator.SelectedItem != null)
|
||||||
{
|
{
|
||||||
@@ -412,5 +391,41 @@ namespace FlaxEditor.GUI
|
|||||||
|
|
||||||
return DragDropEffect.Move;
|
return DragDropEffect.Move;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnSubmit()
|
||||||
|
{
|
||||||
|
base.OnSubmit();
|
||||||
|
|
||||||
|
if (Validator.AssetType != ScriptType.Null)
|
||||||
|
{
|
||||||
|
// Show asset picker popup
|
||||||
|
var popup = AssetSearchPopup.Show(this, Button1Rect.BottomLeft, Validator.IsValid, item =>
|
||||||
|
{
|
||||||
|
Validator.SelectedItem = item;
|
||||||
|
RootWindow.Focus();
|
||||||
|
Focus();
|
||||||
|
});
|
||||||
|
if (Validator.SelectedAsset != null)
|
||||||
|
{
|
||||||
|
var selectedAssetName = Path.GetFileNameWithoutExtension(Validator.SelectedAsset.Path);
|
||||||
|
popup.ScrollToAndHighlightItemByName(selectedAssetName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Show content item picker popup
|
||||||
|
var popup = ContentSearchPopup.Show(this, Button1Rect.BottomLeft, Validator.IsValid, item =>
|
||||||
|
{
|
||||||
|
Validator.SelectedItem = item;
|
||||||
|
RootWindow.Focus();
|
||||||
|
Focus();
|
||||||
|
});
|
||||||
|
if (Validator.SelectedItem != null)
|
||||||
|
{
|
||||||
|
popup.ScrollToAndHighlightItemByName(Validator.SelectedItem.ShortName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,6 +155,11 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly CachedTypesCollection All = new CachedAllTypesCollection(8096, ScriptType.Null, type => true, HasAssemblyValidAnyTypes);
|
public readonly CachedTypesCollection All = new CachedAllTypesCollection(8096, ScriptType.Null, type => true, HasAssemblyValidAnyTypes);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The all types collection from all assemblies (including C# system libraries).
|
||||||
|
/// </summary>
|
||||||
|
public readonly CachedTypesCollection AllWithStd = new CachedTypesCollection(8096, ScriptType.Null, type => true, assembly => true);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The all valid types collection for the Visual Script property types (includes basic types like int/float, structures, object references).
|
/// The all valid types collection for the Visual Script property types (includes basic types like int/float, structures, object references).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -574,21 +579,17 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
|||||||
private static bool HasAssemblyValidAnyTypes(Assembly assembly)
|
private static bool HasAssemblyValidAnyTypes(Assembly assembly)
|
||||||
{
|
{
|
||||||
var codeBase = Utils.GetAssemblyLocation(assembly);
|
var codeBase = Utils.GetAssemblyLocation(assembly);
|
||||||
|
if (string.IsNullOrEmpty(codeBase))
|
||||||
|
return true;
|
||||||
#if USE_NETCORE
|
#if USE_NETCORE
|
||||||
if (assembly.ManifestModule.FullyQualifiedName == "<In Memory Module>")
|
if (assembly.ManifestModule.FullyQualifiedName == "<In Memory Module>")
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(codeBase))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Skip runtime related assemblies
|
// Skip runtime related assemblies
|
||||||
string repositoryUrl = assembly.GetCustomAttributes<AssemblyMetadataAttribute>().FirstOrDefault(x => x.Key == "RepositoryUrl")?.Value ?? "";
|
string repositoryUrl = assembly.GetCustomAttributes<AssemblyMetadataAttribute>().FirstOrDefault(x => x.Key == "RepositoryUrl")?.Value ?? "";
|
||||||
if (repositoryUrl != "https://github.com/dotnet/runtime")
|
if (repositoryUrl != "https://github.com/dotnet/runtime")
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
if (string.IsNullOrEmpty(codeBase))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Skip assemblies from in-build Mono directory
|
// Skip assemblies from in-build Mono directory
|
||||||
if (!codeBase.Contains("/Mono/lib/mono/"))
|
if (!codeBase.Contains("/Mono/lib/mono/"))
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -211,10 +211,10 @@ namespace FlaxEditor.Options
|
|||||||
public bool SeparateValueAndUnit { get; set; }
|
public bool SeparateValueAndUnit { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the option to put a space between numbers and units for unit formatting.
|
/// Gets or sets tree line visibility.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DefaultValue(true)]
|
[DefaultValue(true)]
|
||||||
[EditorDisplay("Interface"), EditorOrder(320)]
|
[EditorDisplay("Interface"), EditorOrder(320), Tooltip("Toggles tree line visibility in places like the Scene or Content Panel.")]
|
||||||
public bool ShowTreeLines { get; set; } = true;
|
public bool ShowTreeLines { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -369,7 +369,7 @@ namespace FlaxEditor.Options
|
|||||||
public int NumberOfGameClientsToLaunch = 1;
|
public int NumberOfGameClientsToLaunch = 1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the visject connection curvature.
|
/// Gets or sets the curvature of the line connecting to connected visject nodes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DefaultValue(1.0f), Range(0.0f, 2.0f)]
|
[DefaultValue(1.0f), Range(0.0f, 2.0f)]
|
||||||
[EditorDisplay("Visject"), EditorOrder(550)]
|
[EditorDisplay("Visject"), EditorOrder(550)]
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ namespace FlaxEditor.Surface
|
|||||||
Visible = false,
|
Visible = false,
|
||||||
Parent = this,
|
Parent = this,
|
||||||
EndEditOnClick = false, // We have to handle this ourselves, otherwise the textbox instantly loses focus when double-clicking the header
|
EndEditOnClick = false, // We have to handle this ourselves, otherwise the textbox instantly loses focus when double-clicking the header
|
||||||
|
HorizontalAlignment = TextAlignment.Center,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -448,6 +448,8 @@ namespace FlaxEditor.Surface
|
|||||||
sb.Append("virtual ");
|
sb.Append("virtual ");
|
||||||
sb.Append(valueType.Name);
|
sb.Append(valueType.Name);
|
||||||
sb.Append(' ');
|
sb.Append(' ');
|
||||||
|
if (member.IsMethod)
|
||||||
|
sb.Append(member.DeclaringType.Namespace).Append('.');
|
||||||
sb.Append(declaringType.Name);
|
sb.Append(declaringType.Name);
|
||||||
sb.Append('.');
|
sb.Append('.');
|
||||||
sb.Append(name);
|
sb.Append(name);
|
||||||
|
|||||||
@@ -140,12 +140,12 @@ namespace FlaxEditor.Surface
|
|||||||
var searchStartTime = DateTime.Now;
|
var searchStartTime = DateTime.Now;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
foreach (var scriptType in Editor.Instance.CodeEditing.All.Get())
|
foreach (var scriptType in Editor.Instance.CodeEditing.AllWithStd.Get())
|
||||||
{
|
{
|
||||||
if (!SurfaceUtils.IsValidVisualScriptType(scriptType))
|
if (SurfaceUtils.IsValidVisualScriptType(scriptType))
|
||||||
continue;
|
{
|
||||||
|
_iterator(scriptType, _cache, _version);
|
||||||
_iterator(scriptType, _cache, _version);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add group to context menu (on a main thread)
|
// Add group to context menu (on a main thread)
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ using FlaxEditor.Surface.Elements;
|
|||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
using FlaxEngine.Utilities;
|
using FlaxEngine.Utilities;
|
||||||
using Object = FlaxEngine.Object;
|
|
||||||
|
|
||||||
namespace FlaxEditor.Surface
|
namespace FlaxEditor.Surface
|
||||||
{
|
{
|
||||||
@@ -36,6 +35,14 @@ namespace FlaxEditor.Surface
|
|||||||
Archetypes = new List<NodeArchetype>(),
|
Archetypes = new List<NodeArchetype>(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static readonly string[] _blacklistedTypeNames =
|
||||||
|
{
|
||||||
|
"Newtonsoft.Json.",
|
||||||
|
"System.Array",
|
||||||
|
"System.Linq.Expressions.",
|
||||||
|
"System.Reflection.",
|
||||||
|
};
|
||||||
|
|
||||||
private static NodesCache _nodesCache = new NodesCache(IterateNodesCache);
|
private static NodesCache _nodesCache = new NodesCache(IterateNodesCache);
|
||||||
private DragActors _dragActors;
|
private DragActors _dragActors;
|
||||||
|
|
||||||
@@ -269,8 +276,11 @@ namespace FlaxEditor.Surface
|
|||||||
{
|
{
|
||||||
// Skip Newtonsoft.Json stuff
|
// Skip Newtonsoft.Json stuff
|
||||||
var scriptTypeTypeName = scriptType.TypeName;
|
var scriptTypeTypeName = scriptType.TypeName;
|
||||||
if (scriptTypeTypeName.StartsWith("Newtonsoft.Json."))
|
for (var i = 0; i < _blacklistedTypeNames.Length; i++)
|
||||||
return;
|
{
|
||||||
|
if (scriptTypeTypeName.StartsWith(_blacklistedTypeNames[i]))
|
||||||
|
return;
|
||||||
|
}
|
||||||
var scriptTypeName = scriptType.Name;
|
var scriptTypeName = scriptType.Name;
|
||||||
|
|
||||||
// Enum
|
// Enum
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using FlaxEditor.Gizmo;
|
using FlaxEditor.Gizmo;
|
||||||
using FlaxEditor.GUI.ContextMenu;
|
using FlaxEditor.GUI.ContextMenu;
|
||||||
|
using FlaxEditor.GUI.Input;
|
||||||
using FlaxEditor.SceneGraph;
|
using FlaxEditor.SceneGraph;
|
||||||
using FlaxEditor.Viewport.Cameras;
|
using FlaxEditor.Viewport.Cameras;
|
||||||
using FlaxEditor.Viewport.Widgets;
|
using FlaxEditor.Viewport.Widgets;
|
||||||
@@ -298,9 +299,33 @@ namespace FlaxEditor.Viewport
|
|||||||
}
|
}
|
||||||
var buttonBB = translateSnappingCM.AddButton("Bounding Box").LinkTooltip("Snaps the selection based on it's bounding volume");
|
var buttonBB = translateSnappingCM.AddButton("Bounding Box").LinkTooltip("Snaps the selection based on it's bounding volume");
|
||||||
buttonBB.Tag = -1.0f;
|
buttonBB.Tag = -1.0f;
|
||||||
translateSnappingCM.ButtonClicked += button =>
|
var buttonCustom = translateSnappingCM.AddButton("Custom");
|
||||||
|
buttonCustom.LinkTooltip("Custom grid size");
|
||||||
|
const float defaultCustomTranslateSnappingValue = 250.0f;
|
||||||
|
float customTranslateSnappingValue = transformGizmo.TranslationSnapValue;
|
||||||
|
if (customTranslateSnappingValue < 0.0f)
|
||||||
|
customTranslateSnappingValue = defaultCustomTranslateSnappingValue;
|
||||||
|
foreach (var v in TranslateSnapValues)
|
||||||
{
|
{
|
||||||
var v = (float)button.Tag;
|
if (Mathf.Abs(transformGizmo.TranslationSnapValue - v) < 0.001f)
|
||||||
|
{
|
||||||
|
customTranslateSnappingValue = defaultCustomTranslateSnappingValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buttonCustom.Tag = customTranslateSnappingValue;
|
||||||
|
var customValue = new FloatValueBox(customTranslateSnappingValue, Style.Current.FontMedium.MeasureText(buttonCustom.Text).X + 5, 2, 70.0f, 0.001f, float.MaxValue, 0.1f)
|
||||||
|
{
|
||||||
|
Parent = buttonCustom
|
||||||
|
};
|
||||||
|
customValue.ValueChanged += () =>
|
||||||
|
{
|
||||||
|
buttonCustom.Tag = customValue.Value;
|
||||||
|
buttonCustom.Click();
|
||||||
|
};
|
||||||
|
translateSnappingCM.ButtonClicked += b =>
|
||||||
|
{
|
||||||
|
var v = (float)b.Tag;
|
||||||
transformGizmo.TranslationSnapValue = v;
|
transformGizmo.TranslationSnapValue = v;
|
||||||
if (v < 0.0f)
|
if (v < 0.0f)
|
||||||
translateSnapping.Text = "Bounding Box";
|
translateSnapping.Text = "Bounding Box";
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ namespace FlaxEditor.Viewport
|
|||||||
editor.SceneEditing.SelectionChanged += OnSelectionChanged;
|
editor.SceneEditing.SelectionChanged += OnSelectionChanged;
|
||||||
|
|
||||||
// Gizmo widgets
|
// Gizmo widgets
|
||||||
AddGizmoViewportWidgets(this, TransformGizmo);
|
AddGizmoViewportWidgets(this, TransformGizmo, true);
|
||||||
|
|
||||||
// Show grid widget
|
// Show grid widget
|
||||||
_showGridButton = ViewWidgetShowMenu.AddButton("Grid", () => Grid.Enabled = !Grid.Enabled);
|
_showGridButton = ViewWidgetShowMenu.AddButton("Grid", () => Grid.Enabled = !Grid.Enabled);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
_surface.ContextChanged += OnSurfaceContextChanged;
|
_surface.ContextChanged += OnSurfaceContextChanged;
|
||||||
|
|
||||||
// Toolstrip
|
// Toolstrip
|
||||||
|
SurfaceUtils.PerformCommonSetup(this, _toolstrip, _surface, out _saveButton, out _undoButton, out _redoButton);
|
||||||
_toolstrip.AddSeparator();
|
_toolstrip.AddSeparator();
|
||||||
_toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/anim-graph/index.html")).LinkTooltip("See documentation to learn more");
|
_toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/anim-graph/index.html")).LinkTooltip("See documentation to learn more");
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Toolstrip
|
// Toolstrip
|
||||||
|
SurfaceUtils.PerformCommonSetup(this, _toolstrip, _surface, out _saveButton, out _undoButton, out _redoButton);
|
||||||
_toolstrip.AddSeparator();
|
_toolstrip.AddSeparator();
|
||||||
_toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/materials/index.html")).LinkTooltip("See documentation to learn more");
|
_toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/materials/index.html")).LinkTooltip("See documentation to learn more");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Toolstrip
|
// Toolstrip
|
||||||
|
SurfaceUtils.PerformCommonSetup(this, _toolstrip, _surface, out _saveButton, out _undoButton, out _redoButton);
|
||||||
_toolstrip.AddSeparator();
|
_toolstrip.AddSeparator();
|
||||||
_toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/particles/index.html")).LinkTooltip("See documentation to learn more");
|
_toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/particles/index.html")).LinkTooltip("See documentation to learn more");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,6 +153,14 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
{
|
{
|
||||||
var menu = new ContextMenu();
|
var menu = new ContextMenu();
|
||||||
|
|
||||||
|
var copySprite = menu.AddButton("Copy sprite");
|
||||||
|
copySprite.Tag = groupPanel.Tag;
|
||||||
|
copySprite.ButtonClicked += OnCopySpriteClicked;
|
||||||
|
|
||||||
|
var pasteSprite = menu.AddButton("Paste sprite");
|
||||||
|
pasteSprite.Tag = groupPanel.Tag;
|
||||||
|
pasteSprite.ButtonClicked += OnPasteSpriteClicked;
|
||||||
|
|
||||||
var deleteSprite = menu.AddButton("Delete sprite");
|
var deleteSprite = menu.AddButton("Delete sprite");
|
||||||
deleteSprite.Tag = groupPanel.Tag;
|
deleteSprite.Tag = groupPanel.Tag;
|
||||||
deleteSprite.ButtonClicked += OnDeleteSpriteClicked;
|
deleteSprite.ButtonClicked += OnDeleteSpriteClicked;
|
||||||
@@ -160,6 +168,24 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
menu.Show(groupPanel, location);
|
menu.Show(groupPanel, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnCopySpriteClicked(ContextMenuButton button)
|
||||||
|
{
|
||||||
|
var window = ((PropertiesProxy)ParentEditor.Values[0])._window;
|
||||||
|
var index = (int)button.Tag;
|
||||||
|
var sprite = window.Asset.GetSprite(index);
|
||||||
|
Clipboard.Text = FlaxEngine.Json.JsonSerializer.Serialize(sprite, typeof(Sprite));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPasteSpriteClicked(ContextMenuButton button)
|
||||||
|
{
|
||||||
|
var window = ((PropertiesProxy)ParentEditor.Values[0])._window;
|
||||||
|
var index = (int)button.Tag;
|
||||||
|
var sprite = window.Asset.GetSprite(index);
|
||||||
|
var pasted = FlaxEngine.Json.JsonSerializer.Deserialize<Sprite>(Clipboard.Text);
|
||||||
|
sprite.Area = pasted.Area;
|
||||||
|
window.Asset.SetSprite(index, ref sprite);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnDeleteSpriteClicked(ContextMenuButton button)
|
private void OnDeleteSpriteClicked(ContextMenuButton button)
|
||||||
{
|
{
|
||||||
var window = ((PropertiesProxy)ParentEditor.Values[0])._window;
|
var window = ((PropertiesProxy)ParentEditor.Values[0])._window;
|
||||||
|
|||||||
@@ -27,9 +27,21 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly Panel _panel;
|
protected readonly Panel _panel;
|
||||||
|
|
||||||
private readonly ToolStripButton _saveButton;
|
/// <summary>
|
||||||
private readonly ToolStripButton _undoButton;
|
/// Save button.
|
||||||
private readonly ToolStripButton _redoButton;
|
/// </summary>
|
||||||
|
protected ToolStripButton _saveButton;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Undo button.
|
||||||
|
/// </summary>
|
||||||
|
protected ToolStripButton _undoButton;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Redo button.
|
||||||
|
/// </summary>
|
||||||
|
protected ToolStripButton _redoButton;
|
||||||
|
|
||||||
private bool _showWholeGraphOnLoad = true;
|
private bool _showWholeGraphOnLoad = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -61,17 +73,12 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
protected VisjectFunctionSurfaceWindow(Editor editor, AssetItem item)
|
protected VisjectFunctionSurfaceWindow(Editor editor, AssetItem item)
|
||||||
: base(editor, item)
|
: base(editor, item)
|
||||||
{
|
{
|
||||||
var inputOptions = Editor.Options.Options.Input;
|
|
||||||
|
|
||||||
// Undo
|
// Undo
|
||||||
_undo = new Undo();
|
_undo = new Undo();
|
||||||
_undo.UndoDone += OnUndoRedo;
|
_undo.UndoDone += OnUndoRedo;
|
||||||
_undo.RedoDone += OnUndoRedo;
|
_undo.RedoDone += OnUndoRedo;
|
||||||
_undo.ActionDone += OnUndoRedo;
|
_undo.ActionDone += OnUndoRedo;
|
||||||
|
|
||||||
// Toolstrip
|
|
||||||
SurfaceUtils.PerformCommonSetup(this, _toolstrip, _surface, out _saveButton, out _undoButton, out _redoButton);
|
|
||||||
|
|
||||||
// Panel
|
// Panel
|
||||||
_panel = new Panel(ScrollBars.None)
|
_panel = new Panel(ScrollBars.None)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ const Char* SplashScreenQuotes[] =
|
|||||||
TEXT("Drum roll please"),
|
TEXT("Drum roll please"),
|
||||||
TEXT("Good Luck Have Fun"),
|
TEXT("Good Luck Have Fun"),
|
||||||
TEXT("GG Well Played"),
|
TEXT("GG Well Played"),
|
||||||
|
TEXT("Now with documentation."),
|
||||||
};
|
};
|
||||||
|
|
||||||
SplashScreen::~SplashScreen()
|
SplashScreen::~SplashScreen()
|
||||||
|
|||||||
@@ -396,8 +396,8 @@ void BehaviorTreeMoveToNode::GetAgentSize(Actor* agent, float& outRadius, float&
|
|||||||
// Estimate actor bounds to extract capsule information
|
// Estimate actor bounds to extract capsule information
|
||||||
const BoundingBox box = agent->GetBox();
|
const BoundingBox box = agent->GetBox();
|
||||||
const BoundingSphere sphere = agent->GetSphere();
|
const BoundingSphere sphere = agent->GetSphere();
|
||||||
outRadius = sphere.Radius;
|
outRadius = (float)sphere.Radius;
|
||||||
outHeight = box.GetSize().Y;
|
outHeight = (float)box.GetSize().Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 BehaviorTreeMoveToNode::GetStateSize() const
|
int32 BehaviorTreeMoveToNode::GetStateSize() const
|
||||||
@@ -522,7 +522,7 @@ String BehaviorTreeMoveToNode::GetDebugInfo(const BehaviorUpdateContext& context
|
|||||||
goal = state->GoalLocation.ToString();
|
goal = state->GoalLocation.ToString();
|
||||||
const Vector3 agentLocation = state->Agent->GetPosition();
|
const Vector3 agentLocation = state->Agent->GetPosition();
|
||||||
const Vector3 agentLocationOnPath = agentLocation + state->AgentOffset;
|
const Vector3 agentLocationOnPath = agentLocation + state->AgentOffset;
|
||||||
float distanceLeft = state->Path.Count() > state->TargetPathIndex ? Vector3::Distance(state->Path[state->TargetPathIndex], agentLocationOnPath) : 0;
|
Real distanceLeft = state->Path.Count() > state->TargetPathIndex ? Vector3::Distance(state->Path[state->TargetPathIndex], agentLocationOnPath) : 0;
|
||||||
for (int32 i = state->TargetPathIndex; i < state->Path.Count(); i++)
|
for (int32 i = state->TargetPathIndex; i < state->Path.Count(); i++)
|
||||||
distanceLeft += Vector3::Distance(state->Path[i - 1], state->Path[i]);
|
distanceLeft += Vector3::Distance(state->Path[i - 1], state->Path[i]);
|
||||||
return String::Format(TEXT("Agent: '{}'\nGoal: '{}'\nDistance: {}"), agent, goal, (int32)distanceLeft);
|
return String::Format(TEXT("Agent: '{}'\nGoal: '{}'\nDistance: {}"), agent, goal, (int32)distanceLeft);
|
||||||
@@ -559,7 +559,7 @@ void BehaviorTreeMoveToNode::State::OnUpdate()
|
|||||||
const float acceptableHeightPercentage = 1.05f;
|
const float acceptableHeightPercentage = 1.05f;
|
||||||
const float testHeight = agentHeight * acceptableHeightPercentage;
|
const float testHeight = agentHeight * acceptableHeightPercentage;
|
||||||
const Vector3 toGoal = agentLocationOnPath - pathSegmentEnd;
|
const Vector3 toGoal = agentLocationOnPath - pathSegmentEnd;
|
||||||
const float toGoalHeightDiff = (toGoal * UpVector).SumValues();
|
const Real toGoalHeightDiff = (toGoal * UpVector).SumValues();
|
||||||
if (toGoal.Length() <= testRadius && toGoalHeightDiff <= testHeight)
|
if (toGoal.Length() <= testRadius && toGoalHeightDiff <= testHeight)
|
||||||
{
|
{
|
||||||
TargetPathIndex++;
|
TargetPathIndex++;
|
||||||
|
|||||||
@@ -465,7 +465,7 @@ namespace FlaxEngine
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A single keyframe that can be injected into linear curve.
|
/// A single keyframe that can be injected into linear curve.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
||||||
public struct Keyframe : IComparable, IComparable<Keyframe>
|
public struct Keyframe : IComparable, IComparable<Keyframe>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -720,7 +720,7 @@ namespace FlaxEngine
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A single keyframe that can be injected into Bezier curve.
|
/// A single keyframe that can be injected into Bezier curve.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
||||||
public struct Keyframe : IComparable, IComparable<Keyframe>
|
public struct Keyframe : IComparable, IComparable<Keyframe>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ void InverseKinematics::SolveTwoBoneIK(Transform& rootTransform, Transform& midJ
|
|||||||
newMidJointPos = rootTransform.Translation + projJointDist * toTargetDir + jointLineDist * bendDirection;
|
newMidJointPos = rootTransform.Translation + projJointDist * toTargetDir + jointLineDist * bendDirection;
|
||||||
}
|
}
|
||||||
// TODO: fix the new IK impl (https://github.com/FlaxEngine/FlaxEngine/pull/2421) to properly work for character from https://github.com/PrecisionRender/CharacterControllerPro
|
// TODO: fix the new IK impl (https://github.com/FlaxEngine/FlaxEngine/pull/2421) to properly work for character from https://github.com/PrecisionRender/CharacterControllerPro
|
||||||
#define OLD 0
|
#define OLD 1
|
||||||
// Update root joint orientation
|
// Update root joint orientation
|
||||||
{
|
{
|
||||||
#if OLD
|
#if OLD
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "Loading/ContentLoadingManager.h"
|
#include "Loading/ContentLoadingManager.h"
|
||||||
#include "Loading/Tasks/LoadAssetTask.h"
|
#include "Loading/Tasks/LoadAssetTask.h"
|
||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
|
#include "Engine/Core/LogContext.h"
|
||||||
#include "Engine/Engine/Engine.h"
|
#include "Engine/Engine/Engine.h"
|
||||||
#include "Engine/Threading/Threading.h"
|
#include "Engine/Threading/Threading.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
@@ -596,9 +597,10 @@ bool Asset::IsInternalType() const
|
|||||||
|
|
||||||
bool Asset::onLoad(LoadAssetTask* task)
|
bool Asset::onLoad(LoadAssetTask* task)
|
||||||
{
|
{
|
||||||
if (task->Asset.Get() != this || Platform::AtomicRead(&_loadingTask) == 0)
|
|
||||||
// It may fail when task is cancelled and new one was created later (don't crash but just end with an error)
|
// It may fail when task is cancelled and new one was created later (don't crash but just end with an error)
|
||||||
|
if (task->Asset.Get() != this || Platform::AtomicRead(&_loadingTask) == 0)
|
||||||
return true;
|
return true;
|
||||||
|
LogContextScope logContext(GetID());
|
||||||
|
|
||||||
Locker.Lock();
|
Locker.Lock();
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "Storage/JsonStorageProxy.h"
|
#include "Storage/JsonStorageProxy.h"
|
||||||
#include "Factories/IAssetFactory.h"
|
#include "Factories/IAssetFactory.h"
|
||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
|
#include "Engine/Core/LogContext.h"
|
||||||
#include "Engine/Core/Types/String.h"
|
#include "Engine/Core/Types/String.h"
|
||||||
#include "Engine/Core/ObjectsRemovalService.h"
|
#include "Engine/Core/ObjectsRemovalService.h"
|
||||||
#include "Engine/Engine/EngineService.h"
|
#include "Engine/Engine/EngineService.h"
|
||||||
@@ -970,6 +971,7 @@ Asset* Content::LoadAsync(const Guid& id, const ScriptingTypeHandle& type)
|
|||||||
if (IsAssetTypeIdInvalid(type, result->GetTypeHandle()) && !result->Is(type))
|
if (IsAssetTypeIdInvalid(type, result->GetTypeHandle()) && !result->Is(type))
|
||||||
{
|
{
|
||||||
LOG(Warning, "Different loaded asset type! Asset: \'{0}\'. Expected type: {1}", result->ToString(), type.ToString());
|
LOG(Warning, "Different loaded asset type! Asset: \'{0}\'. Expected type: {1}", result->ToString(), type.ToString());
|
||||||
|
LogContext::Print(LogType::Warning);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -1004,6 +1006,7 @@ Asset* Content::LoadAsync(const Guid& id, const ScriptingTypeHandle& type)
|
|||||||
if (!GetAssetInfo(id, assetInfo))
|
if (!GetAssetInfo(id, assetInfo))
|
||||||
{
|
{
|
||||||
LOG(Warning, "Invalid or missing asset ({0}, {1}).", id, type.ToString());
|
LOG(Warning, "Invalid or missing asset ({0}, {1}).", id, type.ToString());
|
||||||
|
LogContext::Print(LogType::Warning);
|
||||||
LOAD_FAILED();
|
LOAD_FAILED();
|
||||||
}
|
}
|
||||||
#if ASSETS_LOADING_EXTRA_VERIFICATION
|
#if ASSETS_LOADING_EXTRA_VERIFICATION
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#if COMPILE_WITH_ASSETS_IMPORTER
|
#if COMPILE_WITH_ASSETS_IMPORTER
|
||||||
|
|
||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
|
#include "Engine/Core/Cache.h"
|
||||||
#include "Engine/Core/Collections/Sorting.h"
|
#include "Engine/Core/Collections/Sorting.h"
|
||||||
#include "Engine/Core/Collections/ArrayExtensions.h"
|
#include "Engine/Core/Collections/ArrayExtensions.h"
|
||||||
#include "Engine/Serialization/MemoryWriteStream.h"
|
#include "Engine/Serialization/MemoryWriteStream.h"
|
||||||
@@ -766,6 +767,7 @@ CreateAssetResult ImportModel::CreatePrefab(CreateAssetContext& context, ModelDa
|
|||||||
// Link with object from prefab (if reimporting)
|
// Link with object from prefab (if reimporting)
|
||||||
if (prefab)
|
if (prefab)
|
||||||
{
|
{
|
||||||
|
rapidjson_flax::StringBuffer buffer;
|
||||||
for (Actor* a : nodeActors)
|
for (Actor* a : nodeActors)
|
||||||
{
|
{
|
||||||
for (const auto& i : prefab->ObjectsCache)
|
for (const auto& i : prefab->ObjectsCache)
|
||||||
@@ -776,6 +778,32 @@ CreateAssetResult ImportModel::CreatePrefab(CreateAssetContext& context, ModelDa
|
|||||||
if (o->GetName() != a->GetName()) // Name match
|
if (o->GetName() != a->GetName()) // Name match
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Preserve local changes made in the prefab
|
||||||
|
{
|
||||||
|
// Serialize
|
||||||
|
buffer.Clear();
|
||||||
|
CompactJsonWriter writer(buffer);
|
||||||
|
writer.StartObject();
|
||||||
|
const void* defaultInstance = o->GetType().GetDefaultInstance();
|
||||||
|
o->Serialize(writer, defaultInstance);
|
||||||
|
writer.EndObject();
|
||||||
|
|
||||||
|
// Parse json
|
||||||
|
rapidjson_flax::Document document;
|
||||||
|
document.Parse(buffer.GetString(), buffer.GetSize());
|
||||||
|
|
||||||
|
// Strip unwanted data
|
||||||
|
document.RemoveMember("ID");
|
||||||
|
document.RemoveMember("ParentID");
|
||||||
|
document.RemoveMember("PrefabID");
|
||||||
|
document.RemoveMember("PrefabObjectID");
|
||||||
|
document.RemoveMember("Name");
|
||||||
|
|
||||||
|
// Deserialize object
|
||||||
|
auto modifier = Cache::ISerializeModifier.Get();
|
||||||
|
a->Deserialize(document, &*modifier);
|
||||||
|
}
|
||||||
|
|
||||||
// Mark as this object already exists in prefab so will be preserved when updating it
|
// Mark as this object already exists in prefab so will be preserved when updating it
|
||||||
a->LinkPrefab(o->GetPrefabID(), o->GetPrefabObjectID());
|
a->LinkPrefab(o->GetPrefabID(), o->GetPrefabObjectID());
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
#include "LogContext.h"
|
#include "LogContext.h"
|
||||||
|
#include "Engine/Core/Log.h"
|
||||||
#include "Engine/Core/Types/Guid.h"
|
#include "Engine/Core/Types/Guid.h"
|
||||||
#include "Engine/Core/Types/String.h"
|
#include "Engine/Core/Types/String.h"
|
||||||
|
#include "Engine/Core/Types/StringBuilder.h"
|
||||||
#include "Engine/Core/Collections/Array.h"
|
#include "Engine/Core/Collections/Array.h"
|
||||||
|
#include "Engine/Scripting/Scripting.h"
|
||||||
|
#include "Engine/Scripting/Script.h"
|
||||||
|
#include "Engine/Content/Asset.h"
|
||||||
|
#include "Engine/Content/Content.h"
|
||||||
|
#include "Engine/Level/Actor.h"
|
||||||
#include "Engine/Threading/ThreadLocal.h"
|
#include "Engine/Threading/ThreadLocal.h"
|
||||||
|
|
||||||
struct LogContextThreadData
|
struct LogContextThreadData
|
||||||
@@ -30,7 +37,7 @@ struct LogContextThreadData
|
|||||||
Count--;
|
Count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogContextData Peek()
|
LogContextData Peek() const
|
||||||
{
|
{
|
||||||
return Count > 0 ? Ptr[Count - 1] : LogContextData();
|
return Count > 0 ? Ptr[Count - 1] : LogContextData();
|
||||||
}
|
}
|
||||||
@@ -38,12 +45,58 @@ struct LogContextThreadData
|
|||||||
|
|
||||||
ThreadLocal<LogContextThreadData> GlobalLogContexts;
|
ThreadLocal<LogContextThreadData> GlobalLogContexts;
|
||||||
|
|
||||||
String LogContext::GetInfo()
|
void LogContext::Print(LogType verbosity)
|
||||||
{
|
{
|
||||||
LogContextData context = LogContext::Get();
|
auto& stack = GlobalLogContexts.Get();
|
||||||
if (context.ObjectID != Guid::Empty)
|
if (stack.Count == 0)
|
||||||
return String::Format(TEXT("(Loading source was {0})"), context.ObjectID);
|
return;
|
||||||
return String::Empty;
|
const StringView indentation(TEXT(" "));
|
||||||
|
StringBuilder msg;
|
||||||
|
for (int32 index = (int32)stack.Count - 1; index >= 0; index--)
|
||||||
|
{
|
||||||
|
// Build call hierarchy via indentation
|
||||||
|
msg.Clear();
|
||||||
|
for (uint32 i = index; i < stack.Count; i++)
|
||||||
|
msg.Append(indentation);
|
||||||
|
|
||||||
|
LogContextData& context = stack.Ptr[index];
|
||||||
|
if (context.ObjectID != Guid::Empty)
|
||||||
|
{
|
||||||
|
// Object reference context
|
||||||
|
msg.Append(TEXT(" Referenced by "));
|
||||||
|
if (ScriptingObject* object = Scripting::TryFindObject(context.ObjectID))
|
||||||
|
{
|
||||||
|
const StringAnsiView typeName(object->GetType().Fullname);
|
||||||
|
if (Asset* asset = ScriptingObject::Cast<Asset>(object))
|
||||||
|
{
|
||||||
|
msg.AppendFormat(TEXT("asset '{}' ({}, {})"), asset->GetPath(), asset->GetTypeName(), context.ObjectID);
|
||||||
|
}
|
||||||
|
else if (Actor* actor = ScriptingObject::Cast<Actor>(object))
|
||||||
|
{
|
||||||
|
msg.AppendFormat(TEXT("actor '{}' ({}, {})"), actor->GetNamePath(), String(typeName), context.ObjectID);
|
||||||
|
}
|
||||||
|
else if (Script* script = ScriptingObject::Cast<Script>(object))
|
||||||
|
{
|
||||||
|
msg.AppendFormat(TEXT("script '{}' ({}, {})"), script->GetNamePath(), String(typeName), context.ObjectID);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg.AppendFormat(TEXT("object {} ({})"), String(typeName), context.ObjectID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Asset* asset = Content::GetAsset(context.ObjectID))
|
||||||
|
{
|
||||||
|
msg.AppendFormat(TEXT("asset '{}' ({}, {})"), asset->GetPath(), asset->GetTypeName(), context.ObjectID);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msg.AppendFormat(TEXT("object {}"), context.ObjectID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print message
|
||||||
|
Log::Logger::Write(verbosity, msg.ToStringView());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogContext::Push(const Guid& id)
|
void LogContext::Push(const Guid& id)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Engine/Core/Log.h"
|
||||||
#include "Engine/Core/Config.h"
|
#include "Engine/Core/Config.h"
|
||||||
#include "Engine/Scripting/ScriptingType.h"
|
#include "Engine/Scripting/ScriptingType.h"
|
||||||
|
|
||||||
@@ -9,7 +10,7 @@ class String;
|
|||||||
struct Guid;
|
struct Guid;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Log context data structure. Contains different kinds of context data for different situtations.
|
/// Log context data structure. Contains different kinds of context data for different situations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_STRUCT(NoDefault) struct FLAXENGINE_API LogContextData
|
API_STRUCT(NoDefault) struct FLAXENGINE_API LogContextData
|
||||||
{
|
{
|
||||||
@@ -54,10 +55,10 @@ API_CLASS(Static) class FLAXENGINE_API LogContext
|
|||||||
API_FUNCTION() static LogContextData Get();
|
API_FUNCTION() static LogContextData Get();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a string which represents the current log context on the stack.
|
/// Prints the current log context to the log. Does nothing it
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The formatted string representing the current log context.</returns>
|
/// <param name="verbosity">The verbosity of the log.</param>
|
||||||
API_FUNCTION() static String GetInfo();
|
API_FUNCTION() static void Print(LogType verbosity);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -542,10 +542,8 @@ void Quaternion::RotationYawPitchRoll(float yaw, float pitch, float roll, Quater
|
|||||||
Quaternion Quaternion::GetRotationFromNormal(const Vector3& normal, const Transform& reference)
|
Quaternion Quaternion::GetRotationFromNormal(const Vector3& normal, const Transform& reference)
|
||||||
{
|
{
|
||||||
Float3 up = reference.GetUp();
|
Float3 up = reference.GetUp();
|
||||||
const float dot = Vector3::Dot(normal, up);
|
const Real dot = Vector3::Dot(normal, up);
|
||||||
if (Math::NearEqual(Math::Abs(dot), 1))
|
if (Math::NearEqual(Math::Abs(dot), 1))
|
||||||
{
|
|
||||||
up = reference.GetRight();
|
up = reference.GetRight();
|
||||||
}
|
|
||||||
return Quaternion::LookRotation(normal, up);
|
return Quaternion::LookRotation(normal, up);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ namespace FlaxEngine.Interop
|
|||||||
#if FLAX_EDITOR
|
#if FLAX_EDITOR
|
||||||
[HideInEditor]
|
[HideInEditor]
|
||||||
#endif
|
#endif
|
||||||
[CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedHandleMarshaller.ManagedToNative))]
|
[CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedIn, typeof(ManagedHandleMarshaller.ManagedToNativeState))]
|
||||||
[CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedOut, typeof(ManagedHandleMarshaller.ManagedToNative))]
|
[CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedOut, typeof(ManagedHandleMarshaller.ManagedToNativeState))]
|
||||||
[CustomMarshaller(typeof(object), MarshalMode.ElementIn, typeof(ManagedHandleMarshaller.ManagedToNative))]
|
[CustomMarshaller(typeof(object), MarshalMode.ElementIn, typeof(ManagedHandleMarshaller.ManagedToNative))]
|
||||||
[CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedOut, typeof(ManagedHandleMarshaller.NativeToManaged))]
|
[CustomMarshaller(typeof(object), MarshalMode.ManagedToUnmanagedOut, typeof(ManagedHandleMarshaller.NativeToManaged))]
|
||||||
[CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedIn, typeof(ManagedHandleMarshaller.NativeToManaged))]
|
[CustomMarshaller(typeof(object), MarshalMode.UnmanagedToManagedIn, typeof(ManagedHandleMarshaller.NativeToManaged))]
|
||||||
@@ -31,7 +31,20 @@ namespace FlaxEngine.Interop
|
|||||||
#endif
|
#endif
|
||||||
public static class NativeToManaged
|
public static class NativeToManaged
|
||||||
{
|
{
|
||||||
public static object ConvertToManaged(IntPtr unmanaged) => unmanaged == IntPtr.Zero ? null : ManagedHandle.FromIntPtr(unmanaged).Target;
|
public static object ConvertToManaged(IntPtr unmanaged)
|
||||||
|
{
|
||||||
|
if (unmanaged == IntPtr.Zero)
|
||||||
|
return null;
|
||||||
|
object managed = ManagedHandle.FromIntPtr(unmanaged).Target;
|
||||||
|
if (managed is ManagedArray managedArray)
|
||||||
|
{
|
||||||
|
var managedArrayHandle = ManagedHandle.Alloc(managedArray, GCHandleType.Normal);
|
||||||
|
managed = NativeInterop.MarshalToManaged((IntPtr)managedArrayHandle, managedArray.ArrayType);
|
||||||
|
managedArrayHandle.Free();
|
||||||
|
}
|
||||||
|
return managed;
|
||||||
|
}
|
||||||
|
|
||||||
public static IntPtr ConvertToUnmanaged(object managed) => managed != null ? ManagedHandle.ToIntPtr(managed, GCHandleType.Weak) : IntPtr.Zero;
|
public static IntPtr ConvertToUnmanaged(object managed) => managed != null ? ManagedHandle.ToIntPtr(managed, GCHandleType.Weak) : IntPtr.Zero;
|
||||||
|
|
||||||
public static void Free(IntPtr unmanaged)
|
public static void Free(IntPtr unmanaged)
|
||||||
@@ -40,6 +53,52 @@ namespace FlaxEngine.Interop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if FLAX_EDITOR
|
||||||
|
[HideInEditor]
|
||||||
|
#endif
|
||||||
|
public struct ManagedToNativeState
|
||||||
|
{
|
||||||
|
ManagedArray managedArray;
|
||||||
|
IntPtr handle;
|
||||||
|
|
||||||
|
public void FromManaged(object managed)
|
||||||
|
{
|
||||||
|
if (managed == null)
|
||||||
|
return;
|
||||||
|
if (managed is Array arr)
|
||||||
|
{
|
||||||
|
var type = managed.GetType();
|
||||||
|
var elementType = type.GetElementType();
|
||||||
|
if (NativeInterop.ArrayFactory.GetMarshalledType(elementType) == elementType)
|
||||||
|
{
|
||||||
|
// Use pooled managed array wrapper to be passed around as handle to it
|
||||||
|
(ManagedHandle tmp, managedArray) = ManagedArray.WrapPooledArray(arr);
|
||||||
|
handle = ManagedHandle.ToIntPtr(tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Convert array contents to be properly accessed by the native code (as GCHandles array)
|
||||||
|
managedArray = NativeInterop.ManagedArrayToGCHandleWrappedArray(arr);
|
||||||
|
handle = ManagedHandle.ToIntPtr(ManagedHandle.Alloc(managedArray));
|
||||||
|
managedArray = null; // It's not pooled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
handle = ManagedHandle.ToIntPtr(managed, GCHandleType.Weak);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntPtr ToUnmanaged()
|
||||||
|
{
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Free()
|
||||||
|
{
|
||||||
|
managedArray?.FreePooled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if FLAX_EDITOR
|
#if FLAX_EDITOR
|
||||||
[HideInEditor]
|
[HideInEditor]
|
||||||
#endif
|
#endif
|
||||||
@@ -50,12 +109,6 @@ namespace FlaxEngine.Interop
|
|||||||
|
|
||||||
public static void Free(IntPtr unmanaged)
|
public static void Free(IntPtr unmanaged)
|
||||||
{
|
{
|
||||||
// This is a weak handle, no need to free it
|
|
||||||
/*
|
|
||||||
if (unmanaged == IntPtr.Zero)
|
|
||||||
return;
|
|
||||||
ManagedHandle.FromIntPtr(unmanaged).Free();
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,6 +395,7 @@ namespace FlaxEngine.Interop
|
|||||||
{
|
{
|
||||||
public static Dictionary<T, U> ConvertToManaged(IntPtr unmanaged) => DictionaryMarshaller<T, U>.ToManaged(unmanaged);
|
public static Dictionary<T, U> ConvertToManaged(IntPtr unmanaged) => DictionaryMarshaller<T, U>.ToManaged(unmanaged);
|
||||||
public static IntPtr ConvertToUnmanaged(Dictionary<T, U> managed) => DictionaryMarshaller<T, U>.ToNative(managed, GCHandleType.Weak);
|
public static IntPtr ConvertToUnmanaged(Dictionary<T, U> managed) => DictionaryMarshaller<T, U>.ToNative(managed, GCHandleType.Weak);
|
||||||
|
|
||||||
public static void Free(IntPtr unmanaged)
|
public static void Free(IntPtr unmanaged)
|
||||||
{
|
{
|
||||||
//DictionaryMarshaller<T, U>.Free(unmanaged); // No need to free weak handles
|
//DictionaryMarshaller<T, U>.Free(unmanaged); // No need to free weak handles
|
||||||
@@ -614,6 +668,7 @@ namespace FlaxEngine.Interop
|
|||||||
{
|
{
|
||||||
public static string ConvertToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
|
public static string ConvertToManaged(IntPtr unmanaged) => ManagedString.ToManaged(unmanaged);
|
||||||
public static unsafe IntPtr ConvertToUnmanaged(string managed) => managed == null ? IntPtr.Zero : ManagedHandle.ToIntPtr(managed, GCHandleType.Weak);
|
public static unsafe IntPtr ConvertToUnmanaged(string managed) => managed == null ? IntPtr.Zero : ManagedHandle.ToIntPtr(managed, GCHandleType.Weak);
|
||||||
|
|
||||||
public static void Free(IntPtr unmanaged)
|
public static void Free(IntPtr unmanaged)
|
||||||
{
|
{
|
||||||
//ManagedString.Free(unmanaged); // No need to free weak handles
|
//ManagedString.Free(unmanaged); // No need to free weak handles
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "Engine/Core/Collections/CollectionPoolCache.h"
|
#include "Engine/Core/Collections/CollectionPoolCache.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
#include "Engine/Core/Cache.h"
|
#include "Engine/Core/Cache.h"
|
||||||
|
#include "Engine/Core/LogContext.h"
|
||||||
#include "Engine/Debug/Exceptions/ArgumentException.h"
|
#include "Engine/Debug/Exceptions/ArgumentException.h"
|
||||||
#include "Engine/Engine/EngineService.h"
|
#include "Engine/Engine/EngineService.h"
|
||||||
#include "Engine/Scripting/Script.h"
|
#include "Engine/Scripting/Script.h"
|
||||||
@@ -122,6 +123,7 @@ Actor* PrefabManager::SpawnPrefab(Prefab* prefab, const Transform& transform, Ac
|
|||||||
}
|
}
|
||||||
auto& data = *prefab->Data;
|
auto& data = *prefab->Data;
|
||||||
SceneObjectsFactory::Context context(modifier.Value);
|
SceneObjectsFactory::Context context(modifier.Value);
|
||||||
|
LogContextScope logContext(prefabId);
|
||||||
|
|
||||||
// Deserialize prefab objects
|
// Deserialize prefab objects
|
||||||
auto prevIdMapping = Scripting::ObjectsLookupIdMapping.Get();
|
auto prevIdMapping = Scripting::ObjectsLookupIdMapping.Get();
|
||||||
|
|||||||
@@ -1302,6 +1302,11 @@ bool NetworkReplicator::HasObject(const ScriptingObject* obj)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkReplicator::MapObjectId(Guid& objectId)
|
||||||
|
{
|
||||||
|
IdsRemappingTable.TryGet(objectId, objectId);
|
||||||
|
}
|
||||||
|
|
||||||
ScriptingObject* NetworkReplicator::ResolveForeignObject(Guid objectId)
|
ScriptingObject* NetworkReplicator::ResolveForeignObject(Guid objectId)
|
||||||
{
|
{
|
||||||
if (const auto& object = ResolveObject(objectId))
|
if (const auto& object = ResolveObject(objectId))
|
||||||
|
|||||||
@@ -116,6 +116,12 @@ public:
|
|||||||
/// <param name="obj">The network object.</param>
|
/// <param name="obj">The network object.</param>
|
||||||
/// <returns>True if object exists in networking, otherwise false.</returns>
|
/// <returns>True if object exists in networking, otherwise false.</returns>
|
||||||
API_FUNCTION() static bool HasObject(const ScriptingObject* obj);
|
API_FUNCTION() static bool HasObject(const ScriptingObject* obj);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maps object ID into server or client ID (depending on the source ID). Leaves source value unchanged if that specific ID is unused.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectId">The network object identifier to map. Contains result ID once the method completes.</param>
|
||||||
|
API_FUNCTION() static void MapObjectId(API_PARAM(Ref) Guid& objectId);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resolves foreign Guid into a local ScriptingObject
|
/// Resolves foreign Guid into a local ScriptingObject
|
||||||
|
|||||||
@@ -494,28 +494,28 @@ void PhysicsScene::CollectResults()
|
|||||||
bool PhysicsScene::LineCast(const Vector3& start, const Vector3& end, uint32 layerMask, bool hitTriggers)
|
bool PhysicsScene::LineCast(const Vector3& start, const Vector3& end, uint32 layerMask, bool hitTriggers)
|
||||||
{
|
{
|
||||||
Vector3 directionToEnd = end - start;
|
Vector3 directionToEnd = end - start;
|
||||||
const float distanceToEnd = directionToEnd.Length();
|
const Real distanceToEnd = directionToEnd.Length();
|
||||||
if (distanceToEnd >= ZeroTolerance)
|
if (distanceToEnd >= ZeroTolerance)
|
||||||
directionToEnd /= distanceToEnd;
|
directionToEnd /= distanceToEnd;
|
||||||
return PhysicsBackend::RayCast(_scene, start, directionToEnd, distanceToEnd, layerMask, hitTriggers);
|
return PhysicsBackend::RayCast(_scene, start, directionToEnd, (float)distanceToEnd, layerMask, hitTriggers);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicsScene::LineCast(const Vector3& start, const Vector3& end, RayCastHit& hitInfo, uint32 layerMask, bool hitTriggers)
|
bool PhysicsScene::LineCast(const Vector3& start, const Vector3& end, RayCastHit& hitInfo, uint32 layerMask, bool hitTriggers)
|
||||||
{
|
{
|
||||||
Vector3 directionToEnd = end - start;
|
Vector3 directionToEnd = end - start;
|
||||||
const float distanceToEnd = directionToEnd.Length();
|
const Real distanceToEnd = directionToEnd.Length();
|
||||||
if (distanceToEnd >= ZeroTolerance)
|
if (distanceToEnd >= ZeroTolerance)
|
||||||
directionToEnd /= distanceToEnd;
|
directionToEnd /= distanceToEnd;
|
||||||
return PhysicsBackend::RayCast(_scene, start, directionToEnd, hitInfo, distanceToEnd, layerMask, hitTriggers);
|
return PhysicsBackend::RayCast(_scene, start, directionToEnd, hitInfo, (float)distanceToEnd, layerMask, hitTriggers);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicsScene::LineCastAll(const Vector3& start, const Vector3& end, Array<RayCastHit>& results, uint32 layerMask, bool hitTriggers)
|
bool PhysicsScene::LineCastAll(const Vector3& start, const Vector3& end, Array<RayCastHit>& results, uint32 layerMask, bool hitTriggers)
|
||||||
{
|
{
|
||||||
Vector3 directionToEnd = end - start;
|
Vector3 directionToEnd = end - start;
|
||||||
const float distanceToEnd = directionToEnd.Length();
|
const Real distanceToEnd = directionToEnd.Length();
|
||||||
if (distanceToEnd >= ZeroTolerance)
|
if (distanceToEnd >= ZeroTolerance)
|
||||||
directionToEnd /= distanceToEnd;
|
directionToEnd /= distanceToEnd;
|
||||||
return PhysicsBackend::RayCastAll(_scene, start, directionToEnd, results, distanceToEnd, layerMask, hitTriggers);
|
return PhysicsBackend::RayCastAll(_scene, start, directionToEnd, results, (float)distanceToEnd, layerMask, hitTriggers);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicsScene::RayCast(const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
|
bool PhysicsScene::RayCast(const Vector3& origin, const Vector3& direction, const float maxDistance, uint32 layerMask, bool hitTriggers)
|
||||||
|
|||||||
@@ -339,11 +339,10 @@ int32 Font::HitTestText(const StringView& text, const Float2& location, const Te
|
|||||||
float baseLinesDistance = static_cast<float>(_height) * layout.BaseLinesGapScale * scale;
|
float baseLinesDistance = static_cast<float>(_height) * layout.BaseLinesGapScale * scale;
|
||||||
|
|
||||||
// Offset position to match lines origin space
|
// Offset position to match lines origin space
|
||||||
Float2 rootOffset = layout.Bounds.Location + lines.First().Location;
|
Float2 testPoint = location - layout.Bounds.Location;
|
||||||
Float2 testPoint = location - rootOffset;
|
|
||||||
|
|
||||||
// Get line which may intersect with the position (it's possible because lines have fixed height)
|
// Get line which may intersect with the position (it's possible because lines have fixed height)
|
||||||
int32 lineIndex = Math::Clamp(Math::FloorToInt(testPoint.Y / baseLinesDistance), 0, lines.Count() - 1);
|
int32 lineIndex = Math::Clamp(Math::FloorToInt((testPoint.Y - lines.First().Location.Y) / baseLinesDistance), 0, lines.Count() - 1);
|
||||||
const FontLineCache& line = lines[lineIndex];
|
const FontLineCache& line = lines[lineIndex];
|
||||||
float x = line.Location.X;
|
float x = line.Location.X;
|
||||||
|
|
||||||
@@ -411,7 +410,6 @@ Float2 Font::GetCharPosition(const StringView& text, int32 index, const TextLayo
|
|||||||
ASSERT(lines.HasItems());
|
ASSERT(lines.HasItems());
|
||||||
float scale = layout.Scale / FontManager::FontScale;
|
float scale = layout.Scale / FontManager::FontScale;
|
||||||
float baseLinesDistance = static_cast<float>(_height) * layout.BaseLinesGapScale * scale;
|
float baseLinesDistance = static_cast<float>(_height) * layout.BaseLinesGapScale * scale;
|
||||||
Float2 rootOffset = layout.Bounds.Location + lines.First().Location;
|
|
||||||
|
|
||||||
// Find line with that position
|
// Find line with that position
|
||||||
FontCharacterEntry previous;
|
FontCharacterEntry previous;
|
||||||
@@ -423,7 +421,7 @@ Float2 Font::GetCharPosition(const StringView& text, int32 index, const TextLayo
|
|||||||
// Check if desire position is somewhere inside characters in line range
|
// Check if desire position is somewhere inside characters in line range
|
||||||
if (Math::IsInRange(index, line.FirstCharIndex, line.LastCharIndex))
|
if (Math::IsInRange(index, line.FirstCharIndex, line.LastCharIndex))
|
||||||
{
|
{
|
||||||
float x = line.Location.X;
|
Float2 charPos = line.Location;
|
||||||
|
|
||||||
// Check all characters in the line
|
// Check all characters in the line
|
||||||
for (int32 currentIndex = line.FirstCharIndex; currentIndex < index; currentIndex++)
|
for (int32 currentIndex = line.FirstCharIndex; currentIndex < index; currentIndex++)
|
||||||
@@ -436,21 +434,21 @@ Float2 Font::GetCharPosition(const StringView& text, int32 index, const TextLayo
|
|||||||
// Apply kerning
|
// Apply kerning
|
||||||
if (!isWhitespace && previous.IsValid)
|
if (!isWhitespace && previous.IsValid)
|
||||||
{
|
{
|
||||||
x += entry.Font->GetKerning(previous.Character, entry.Character);
|
charPos.X += entry.Font->GetKerning(previous.Character, entry.Character);
|
||||||
}
|
}
|
||||||
previous = entry;
|
previous = entry;
|
||||||
|
|
||||||
// Move
|
// Move
|
||||||
x += entry.AdvanceX * scale;
|
charPos.X += entry.AdvanceX * scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upper left corner of the character
|
// Upper left corner of the character
|
||||||
return rootOffset + Float2(x, static_cast<float>(lineIndex * baseLinesDistance));
|
return layout.Bounds.Location + charPos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Position after last character in the last line
|
// Position after last character in the last line
|
||||||
return rootOffset + Float2(lines.Last().Size.X, static_cast<float>((lines.Count() - 1) * baseLinesDistance));
|
return layout.Bounds.Location + lines.Last().Location + Float2(lines.Last().Size.X, 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Font::FlushFaceSize() const
|
void Font::FlushFaceSize() const
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ namespace FlaxEngine
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The size of the font characters.
|
/// The size of the font characters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorOrder(10), Limit(1, 500, 0.1f), Tooltip("The size of the font characters.")]
|
[EditorOrder(10), Limit(1, 500, 0.5f), Tooltip("The size of the font characters.")]
|
||||||
public float Size
|
public float Size
|
||||||
{
|
{
|
||||||
get => _size;
|
get => _size;
|
||||||
|
|||||||
@@ -841,10 +841,11 @@ void Render2D::PushClip(const Rectangle& clipRect)
|
|||||||
{
|
{
|
||||||
RENDER2D_CHECK_RENDERING_STATE;
|
RENDER2D_CHECK_RENDERING_STATE;
|
||||||
|
|
||||||
|
const auto& mask = ClipLayersStack.Peek();
|
||||||
RotatedRectangle clipRectTransformed;
|
RotatedRectangle clipRectTransformed;
|
||||||
ApplyTransform(clipRect, clipRectTransformed);
|
ApplyTransform(clipRect, clipRectTransformed);
|
||||||
const Rectangle bounds = Rectangle::Shared(clipRectTransformed.ToBoundingRect(), ClipLayersStack.Peek().Bounds);
|
const Rectangle bounds = Rectangle::Shared(clipRectTransformed.ToBoundingRect(), mask.Bounds);
|
||||||
ClipLayersStack.Push({ clipRectTransformed, bounds });
|
ClipLayersStack.Push({ RotatedRectangle::Shared(clipRectTransformed, mask.Bounds), bounds });
|
||||||
|
|
||||||
OnClipScissors();
|
OnClipScissors();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
struct RotatedRectangle
|
struct RotatedRectangle
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The transformed top left corner.
|
/// The transformed top left corner.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -27,7 +26,6 @@ public:
|
|||||||
Float2 ExtentY;
|
Float2 ExtentY;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="RotatedRectangle"/> struct.
|
/// Initializes a new instance of the <see cref="RotatedRectangle"/> struct.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -60,7 +58,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convert rotated rectangle to the axis-aligned rectangle that builds rotated rectangle bounding box.
|
/// Convert rotated rectangle to the axis-aligned rectangle that builds rotated rectangle bounding box.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -95,8 +92,24 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
/// <summary>
|
||||||
|
/// Calculates a rectangle that contains the shared part of both rectangles.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">The first rectangle.</param>
|
||||||
|
/// <param name="b">The second rectangle.</param>
|
||||||
|
/// <returns>Rectangle that contains shared part of a and b rectangles.</returns>
|
||||||
|
static RotatedRectangle Shared(const RotatedRectangle& a, const Rectangle& b)
|
||||||
|
{
|
||||||
|
// Clip the rotated rectangle bounds within the given AABB
|
||||||
|
RotatedRectangle result = a;
|
||||||
|
result.TopLeft = Float2::Max(a.TopLeft, b.GetTopLeft());
|
||||||
|
// TODO: do a little better math below (in case of actually rotated rectangle)
|
||||||
|
result.ExtentX.X = Math::Min(result.TopLeft.X + result.ExtentX.X, b.GetRight()) - result.TopLeft.X;
|
||||||
|
result.ExtentY.Y = Math::Min(result.TopLeft.Y + result.ExtentY.Y, b.GetBottom()) - result.TopLeft.Y;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
bool operator ==(const RotatedRectangle& other) const
|
bool operator ==(const RotatedRectangle& other) const
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace FlaxEngine
|
namespace FlaxEngine
|
||||||
{
|
{
|
||||||
partial struct SpriteHandle
|
partial struct SpriteHandle : IEquatable<SpriteHandle>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invalid sprite handle.
|
/// Invalid sprite handle.
|
||||||
@@ -107,5 +108,53 @@ namespace FlaxEngine
|
|||||||
Atlas.SetSprite(Index, ref sprite);
|
Atlas.SetSprite(Index, ref sprite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests for equality between two objects.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The first value to compare.</param>
|
||||||
|
/// <param name="right">The second value to compare.</param>
|
||||||
|
/// <returns><c>true</c> if <paramref name="left" /> has the same value as <paramref name="right" />; otherwise, <c>false</c>.</returns>
|
||||||
|
public static bool operator ==(SpriteHandle left, SpriteHandle right)
|
||||||
|
{
|
||||||
|
return left.Index == right.Index && left.Atlas == right.Atlas;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests for inequality between two objects.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="left">The first value to compare.</param>
|
||||||
|
/// <param name="right">The second value to compare.</param>
|
||||||
|
/// <returns><c>true</c> if <paramref name="left" /> has a different value than <paramref name="right" />; otherwise, <c>false</c>.</returns>
|
||||||
|
public static bool operator !=(SpriteHandle left, SpriteHandle right)
|
||||||
|
{
|
||||||
|
return left.Index != right.Index || left.Atlas != right.Atlas;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Equals(SpriteHandle other)
|
||||||
|
{
|
||||||
|
return Index == other.Index && Atlas == other.Atlas;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is SpriteHandle other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(Atlas, Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
if (Atlas)
|
||||||
|
return $"{System.IO.Path.GetFileNameWithoutExtension(Atlas.Path)}[{Index}]";
|
||||||
|
return "Invalid";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -318,6 +318,11 @@ void ProbesRendererService::Update()
|
|||||||
// Calculate time delta since last update
|
// Calculate time delta since last update
|
||||||
auto timeNow = Time::Update.UnscaledTime;
|
auto timeNow = Time::Update.UnscaledTime;
|
||||||
auto timeSinceUpdate = timeNow - _lastProbeUpdate;
|
auto timeSinceUpdate = timeNow - _lastProbeUpdate;
|
||||||
|
if (timeSinceUpdate < 0)
|
||||||
|
{
|
||||||
|
_lastProbeUpdate = timeNow;
|
||||||
|
timeSinceUpdate = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if render job is done
|
// Check if render job is done
|
||||||
if (isUpdateSynced())
|
if (isUpdateSynced())
|
||||||
@@ -351,8 +356,9 @@ void ProbesRendererService::Update()
|
|||||||
auto dt = (float)Time::Update.UnscaledDeltaTime.GetTotalSeconds();
|
auto dt = (float)Time::Update.UnscaledDeltaTime.GetTotalSeconds();
|
||||||
for (int32 i = 0; i < _probesToBake.Count(); i++)
|
for (int32 i = 0; i < _probesToBake.Count(); i++)
|
||||||
{
|
{
|
||||||
_probesToBake[i].Timeout -= dt;
|
auto& e = _probesToBake[i];
|
||||||
if (_probesToBake[i].Timeout <= 0)
|
e.Timeout -= dt;
|
||||||
|
if (e.Timeout <= 0)
|
||||||
{
|
{
|
||||||
firstValidEntryIndex = i;
|
firstValidEntryIndex = i;
|
||||||
break;
|
break;
|
||||||
@@ -417,6 +423,9 @@ void ProbesRenderer::OnRender(RenderTask* task, GPUContext* context)
|
|||||||
if (_current.Actor == nullptr)
|
if (_current.Actor == nullptr)
|
||||||
{
|
{
|
||||||
// Probe has been unlinked (or deleted)
|
// Probe has been unlinked (or deleted)
|
||||||
|
_task->Enabled = false;
|
||||||
|
_updateFrameNumber = 0;
|
||||||
|
_current.Type = EntryType::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -28,21 +28,9 @@ public:
|
|||||||
|
|
||||||
struct Entry
|
struct Entry
|
||||||
{
|
{
|
||||||
EntryType Type;
|
EntryType Type = EntryType::Invalid;
|
||||||
ScriptingObjectReference<Actor> Actor;
|
ScriptingObjectReference<Actor> Actor;
|
||||||
float Timeout;
|
float Timeout = 0.0f;
|
||||||
|
|
||||||
Entry()
|
|
||||||
{
|
|
||||||
Type = EntryType::Invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
Entry(const Entry& other)
|
|
||||||
{
|
|
||||||
Type = other.Type;
|
|
||||||
Actor = other.Actor;
|
|
||||||
Timeout = other.Timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UseTextureData() const;
|
bool UseTextureData() const;
|
||||||
int32 GetResolution() const;
|
int32 GetResolution() const;
|
||||||
|
|||||||
@@ -887,7 +887,8 @@ ScriptingObject* Scripting::FindObject(Guid id, const MClass* type)
|
|||||||
// Check type
|
// Check type
|
||||||
if (!type || result->Is(type))
|
if (!type || result->Is(type))
|
||||||
return result;
|
return result;
|
||||||
LOG(Warning, "Found scripting object with ID={0} of type {1} that doesn't match type {2}. {3}", id, String(result->GetType().Fullname), String(type->GetFullName()), LogContext::GetInfo());
|
LOG(Warning, "Found scripting object with ID={0} of type {1} that doesn't match type {2}", id, String(result->GetType().Fullname), String(type->GetFullName()));
|
||||||
|
LogContext::Print(LogType::Warning);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -906,7 +907,8 @@ ScriptingObject* Scripting::FindObject(Guid id, const MClass* type)
|
|||||||
return asset;
|
return asset;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(Warning, "Unable to find scripting object with ID={0}. Required type {1}. {2}", id, String(type->GetFullName()), LogContext::GetInfo());
|
LOG(Warning, "Unable to find scripting object with ID={0}. Required type {1}", id, String(type->GetFullName()));
|
||||||
|
LogContext::Print(LogType::Warning);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -737,7 +737,10 @@ DEFINE_INTERNAL_CALL(MObject*) ObjectInternal_FindObject(Guid* id, MTypeObject*
|
|||||||
if (klass && !obj->Is(klass))
|
if (klass && !obj->Is(klass))
|
||||||
{
|
{
|
||||||
if (!skipLog)
|
if (!skipLog)
|
||||||
LOG(Warning, "Found scripting object with ID={0} of type {1} that doesn't match type {2}. {3}", *id, String(obj->GetType().Fullname), String(klass->GetFullName()), LogContext::GetInfo());
|
{
|
||||||
|
LOG(Warning, "Found scripting object with ID={0} of type {1} that doesn't match type {2}", *id, String(obj->GetType().Fullname), String(klass->GetFullName()));
|
||||||
|
LogContext::Print(LogType::Warning);
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return obj->GetOrCreateManagedInstance();
|
return obj->GetOrCreateManagedInstance();
|
||||||
@@ -746,9 +749,10 @@ DEFINE_INTERNAL_CALL(MObject*) ObjectInternal_FindObject(Guid* id, MTypeObject*
|
|||||||
if (!skipLog)
|
if (!skipLog)
|
||||||
{
|
{
|
||||||
if (klass)
|
if (klass)
|
||||||
LOG(Warning, "Unable to find scripting object with ID={0}. Required type {1}. {2}", *id, String(klass->GetFullName()), LogContext::GetInfo());
|
LOG(Warning, "Unable to find scripting object with ID={0} of type {1}", *id, String(klass->GetFullName()));
|
||||||
else
|
else
|
||||||
LOG(Warning, "Unable to find scripting object with ID={0}", *id);
|
LOG(Warning, "Unable to find scripting object with ID={0}", *id);
|
||||||
|
LogContext::Print(LogType::Warning);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,11 +183,15 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
|
|||||||
break;
|
break;
|
||||||
// Pre-skinned Local Position
|
// Pre-skinned Local Position
|
||||||
case 13:
|
case 13:
|
||||||
value = _treeType == MaterialTreeType::VertexShader ? Value(VariantType::Float3, TEXT("input.PreSkinnedPosition")) : Value::Zero;
|
value = Value(VariantType::Float3, TEXT("input.PreSkinnedPosition"));
|
||||||
|
if (_treeType != MaterialTreeType::VertexShader)
|
||||||
|
value = VsToPs(node, box).AsFloat3();
|
||||||
break;
|
break;
|
||||||
// Pre-skinned Local Normal
|
// Pre-skinned Local Normal
|
||||||
case 14:
|
case 14:
|
||||||
value = _treeType == MaterialTreeType::VertexShader ? Value(VariantType::Float3, TEXT("input.PreSkinnedNormal")) : Value::Zero;
|
value = Value(VariantType::Float3, TEXT("input.PreSkinnedNormal"));
|
||||||
|
if (_treeType != MaterialTreeType::VertexShader)
|
||||||
|
value = VsToPs(node, box).AsFloat3();
|
||||||
break;
|
break;
|
||||||
// Depth
|
// Depth
|
||||||
case 15:
|
case 15:
|
||||||
@@ -211,38 +215,8 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
|
|||||||
break;
|
break;
|
||||||
// Interpolate VS To PS
|
// Interpolate VS To PS
|
||||||
case 20:
|
case 20:
|
||||||
{
|
value = VsToPs(node, node->GetBox(0));
|
||||||
const auto input = node->GetBox(0);
|
|
||||||
|
|
||||||
// If used in VS then pass the value from the input box
|
|
||||||
if (_treeType == MaterialTreeType::VertexShader)
|
|
||||||
{
|
|
||||||
value = tryGetValue(input, Value::Zero).AsFloat4();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if can use more interpolants
|
|
||||||
if (_vsToPsInterpolants.Count() == 16)
|
|
||||||
{
|
|
||||||
OnError(node, box, TEXT("Too many VS to PS interpolants used."));
|
|
||||||
value = Value::Zero;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if can use interpolants
|
|
||||||
const auto layer = GetRootLayer();
|
|
||||||
if (!layer || layer->Domain == MaterialDomain::Decal || layer->Domain == MaterialDomain::PostProcess)
|
|
||||||
{
|
|
||||||
OnError(node, box, TEXT("VS to PS interpolants are not supported in Decal or Post Process materials."));
|
|
||||||
value = Value::Zero;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Indicate the interpolator slot usage
|
|
||||||
value = Value(VariantType::Float4, String::Format(TEXT("input.CustomVSToPS[{0}]"), _vsToPsInterpolants.Count()));
|
|
||||||
_vsToPsInterpolants.Add(input);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
// Terrain Holes Mask
|
// Terrain Holes Mask
|
||||||
case 21:
|
case 21:
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -832,4 +832,32 @@ void MaterialGenerator::WriteCustomGlobalCode(const Array<const MaterialGraph::N
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShaderGenerator::Value MaterialGenerator::VsToPs(Node* node, Box* input)
|
||||||
|
{
|
||||||
|
// If used in VS then pass the value from the input box
|
||||||
|
if (_treeType == MaterialTreeType::VertexShader)
|
||||||
|
{
|
||||||
|
return tryGetValue(input, Value::Zero).AsFloat4();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if can use more interpolants
|
||||||
|
if (_vsToPsInterpolants.Count() == 16)
|
||||||
|
{
|
||||||
|
OnError(node, input, TEXT("Too many VS to PS interpolants used."));
|
||||||
|
return Value::Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if can use interpolants
|
||||||
|
const auto layer = GetRootLayer();
|
||||||
|
if (!layer || layer->Domain == MaterialDomain::Decal || layer->Domain == MaterialDomain::PostProcess)
|
||||||
|
{
|
||||||
|
OnError(node, input, TEXT("VS to PS interpolants are not supported in Decal or Post Process materials."));
|
||||||
|
return Value::Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indicate the interpolator slot usage
|
||||||
|
_vsToPsInterpolants.Add(input);
|
||||||
|
return Value(VariantType::Float4, String::Format(TEXT("input.CustomVSToPS[{0}]"), _vsToPsInterpolants.Count() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -205,6 +205,7 @@ private:
|
|||||||
MaterialValue AccessParticleAttribute(Node* caller, const StringView& name, ParticleAttributeValueTypes valueType, const Char* index = nullptr, ParticleAttributeSpace space = ParticleAttributeSpace::AsIs);
|
MaterialValue AccessParticleAttribute(Node* caller, const StringView& name, ParticleAttributeValueTypes valueType, const Char* index = nullptr, ParticleAttributeSpace space = ParticleAttributeSpace::AsIs);
|
||||||
void prepareLayer(MaterialLayer* layer, bool allowVisibleParams);
|
void prepareLayer(MaterialLayer* layer, bool allowVisibleParams);
|
||||||
void WriteCustomGlobalCode(const Array<const MaterialGraph::Node*, InlinedAllocation<8>>& nodes, int32 templateInputsMapping);
|
void WriteCustomGlobalCode(const Array<const MaterialGraph::Node*, InlinedAllocation<8>>& nodes, int32 templateInputsMapping);
|
||||||
|
Value VsToPs(Node* node, Box* input);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace FlaxEngine.GUI
|
|||||||
/// Button control
|
/// Button control
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ActorToolbox("GUI")]
|
[ActorToolbox("GUI")]
|
||||||
public class Button : ContainerControl
|
public class Button : Label
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default height for the buttons.
|
/// The default height for the buttons.
|
||||||
@@ -20,65 +20,16 @@ namespace FlaxEngine.GUI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected bool _isPressed;
|
protected bool _isPressed;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The font.
|
|
||||||
/// </summary>
|
|
||||||
protected FontReference _font;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The text.
|
|
||||||
/// </summary>
|
|
||||||
protected LocalizedString _text = new LocalizedString();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Button text property.
|
|
||||||
/// </summary>
|
|
||||||
[EditorOrder(10), Tooltip("The button label text.")]
|
|
||||||
public LocalizedString Text
|
|
||||||
{
|
|
||||||
get => _text;
|
|
||||||
set => _text = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the font used to draw button text.
|
|
||||||
/// </summary>
|
|
||||||
[EditorDisplay("Text Style"), EditorOrder(2022), ExpandGroups]
|
|
||||||
public FontReference Font
|
|
||||||
{
|
|
||||||
get => _font;
|
|
||||||
set => _font = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the custom material used to render the text. It must has domain set to GUI and have a public texture parameter named Font used to sample font atlas texture with font characters data.
|
/// Gets or sets the custom material used to render the text. It must has domain set to GUI and have a public texture parameter named Font used to sample font atlas texture with font characters data.
|
||||||
|
/// [Deprecated on 18.09.2024, expires on 18.09.2026]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Text Style"), EditorOrder(2021), Tooltip("Custom material used to render the text. It must has domain set to GUI and have a public texture parameter named Font used to sample font atlas texture with font characters data.")]
|
[Serialize, Obsolete("Use Material property instead."), NoUndo]
|
||||||
public MaterialBase TextMaterial { get; set; }
|
public MaterialBase TextMaterial
|
||||||
|
{
|
||||||
/// <summary>
|
get => Material;
|
||||||
/// Gets or sets the color used to draw button text.
|
set => Material = value;
|
||||||
/// </summary>
|
}
|
||||||
[EditorDisplay("Text Style"), EditorOrder(2020)]
|
|
||||||
public Color TextColor;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the horizontal text alignment within the control bounds.
|
|
||||||
/// </summary>
|
|
||||||
[EditorDisplay("Text Style"), EditorOrder(2027)]
|
|
||||||
public TextAlignment HorizontalAlignment { get; set; } = TextAlignment.Center;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the vertical text alignment within the control bounds.
|
|
||||||
/// </summary>
|
|
||||||
[EditorDisplay("Text Style"), EditorOrder(2028)]
|
|
||||||
public TextAlignment VerticalAlignment { get; set; } = TextAlignment.Center;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the brush used for background drawing.
|
|
||||||
/// </summary>
|
|
||||||
[EditorDisplay("Background Style"), EditorOrder(1999), Tooltip("The brush used for background drawing."), ExpandGroups]
|
|
||||||
public IBrush BackgroundBrush { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the background color when button is highlighted.
|
/// Gets or sets the background color when button is highlighted.
|
||||||
@@ -97,7 +48,7 @@ namespace FlaxEngine.GUI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorDisplay("Border Style"), EditorOrder(2010), ExpandGroups]
|
[EditorDisplay("Border Style"), EditorOrder(2010), ExpandGroups]
|
||||||
public bool HasBorder { get; set; } = true;
|
public bool HasBorder { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the border thickness.
|
/// Gets or sets the border thickness.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -165,6 +116,7 @@ namespace FlaxEngine.GUI
|
|||||||
public Button(float x, float y, float width = 120, float height = DefaultHeight)
|
public Button(float x, float y, float width = 120, float height = DefaultHeight)
|
||||||
: base(x, y, width, height)
|
: base(x, y, width, height)
|
||||||
{
|
{
|
||||||
|
AutoFocus = true;
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
if (style != null)
|
if (style != null)
|
||||||
{
|
{
|
||||||
@@ -242,17 +194,14 @@ namespace FlaxEngine.GUI
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void DrawSelf()
|
public override void DrawSelf()
|
||||||
{
|
{
|
||||||
// Cache data
|
|
||||||
Rectangle clientRect = new Rectangle(Float2.Zero, Size);
|
Rectangle clientRect = new Rectangle(Float2.Zero, Size);
|
||||||
bool enabled = EnabledInHierarchy;
|
bool enabled = EnabledInHierarchy;
|
||||||
Color backgroundColor = BackgroundColor;
|
Color backgroundColor = BackgroundColor;
|
||||||
Color borderColor = BorderColor;
|
Color borderColor = BorderColor;
|
||||||
Color textColor = TextColor;
|
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
{
|
{
|
||||||
backgroundColor *= 0.5f;
|
backgroundColor *= 0.5f;
|
||||||
borderColor *= 0.5f;
|
borderColor *= 0.5f;
|
||||||
textColor *= 0.6f;
|
|
||||||
}
|
}
|
||||||
else if (_isPressed)
|
else if (_isPressed)
|
||||||
{
|
{
|
||||||
@@ -274,7 +223,10 @@ namespace FlaxEngine.GUI
|
|||||||
Render2D.DrawRectangle(clientRect, borderColor, BorderThickness);
|
Render2D.DrawRectangle(clientRect, borderColor, BorderThickness);
|
||||||
|
|
||||||
// Draw text
|
// Draw text
|
||||||
Render2D.DrawText(_font?.GetFont(), TextMaterial, _text, clientRect, textColor, HorizontalAlignment, VerticalAlignment);
|
backgroundColor = BackgroundColor;
|
||||||
|
BackgroundColor = Color.Transparent; // Skip background drawing in Control
|
||||||
|
base.DrawSelf();
|
||||||
|
BackgroundColor = backgroundColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -339,7 +291,7 @@ namespace FlaxEngine.GUI
|
|||||||
OnClick();
|
OnClick();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (button == MouseButton.Left && !_isPressed)
|
if (button == MouseButton.Left && !_isPressed)
|
||||||
{
|
{
|
||||||
OnPressBegin();
|
OnPressBegin();
|
||||||
|
|||||||
@@ -135,5 +135,14 @@ namespace FlaxEngine.GUI
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnSubmit()
|
||||||
|
{
|
||||||
|
base.OnSubmit();
|
||||||
|
|
||||||
|
// Execute default user interaction via mouse click
|
||||||
|
Clicked?.Invoke(this, MouseButton.Left);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ namespace FlaxEngine.GUI
|
|||||||
private bool _autoFitText;
|
private bool _autoFitText;
|
||||||
private Float2 _textSize;
|
private Float2 _textSize;
|
||||||
private Float2 _autoFitTextRange = new Float2(0.1f, 100.0f);
|
private Float2 _autoFitTextRange = new Float2(0.1f, 100.0f);
|
||||||
|
private Margin _margin;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The font.
|
/// The font.
|
||||||
@@ -57,9 +58,9 @@ namespace FlaxEngine.GUI
|
|||||||
get => _text;
|
get => _text;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (_text != value)
|
_text = value;
|
||||||
|
if (_autoWidth || _autoHeight || _autoFitText)
|
||||||
{
|
{
|
||||||
_text = value;
|
|
||||||
_textSize = Float2.Zero;
|
_textSize = Float2.Zero;
|
||||||
PerformLayout();
|
PerformLayout();
|
||||||
}
|
}
|
||||||
@@ -129,15 +130,11 @@ namespace FlaxEngine.GUI
|
|||||||
get => _font;
|
get => _font;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (_font != value)
|
_font = value;
|
||||||
|
if (_autoWidth || _autoHeight || _autoFitText)
|
||||||
{
|
{
|
||||||
_font = value;
|
_textSize = Float2.Zero;
|
||||||
|
PerformLayout();
|
||||||
if (_autoWidth || _autoHeight || _autoFitText)
|
|
||||||
{
|
|
||||||
_textSize = Float2.Zero;
|
|
||||||
PerformLayout();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,7 +149,18 @@ namespace FlaxEngine.GUI
|
|||||||
/// Gets or sets the margin for the text within the control bounds.
|
/// Gets or sets the margin for the text within the control bounds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorOrder(70), Tooltip("The margin for the text within the control bounds.")]
|
[EditorOrder(70), Tooltip("The margin for the text within the control bounds.")]
|
||||||
public Margin Margin { get; set; }
|
public Margin Margin
|
||||||
|
{
|
||||||
|
get => _margin;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_margin = value;
|
||||||
|
if (_autoWidth || _autoHeight)
|
||||||
|
{
|
||||||
|
PerformLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether clip text during rendering.
|
/// Gets or sets a value indicating whether clip text during rendering.
|
||||||
@@ -161,9 +169,9 @@ namespace FlaxEngine.GUI
|
|||||||
public bool ClipText { get; set; }
|
public bool ClipText { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether set automatic width based on text contents.
|
/// Gets or sets a value indicating whether set automatic width based on text contents. Control size is modified relative to the Pivot.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorOrder(85), DefaultValue(false), Tooltip("If checked, the control width will be based on text contents.")]
|
[EditorOrder(85), DefaultValue(false), Tooltip("If checked, the control width will be based on text contents. Control size is modified relative to the Pivot.")]
|
||||||
public bool AutoWidth
|
public bool AutoWidth
|
||||||
{
|
{
|
||||||
get => _autoWidth;
|
get => _autoWidth;
|
||||||
@@ -178,9 +186,9 @@ namespace FlaxEngine.GUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether set automatic height based on text contents.
|
/// Gets or sets a value indicating whether set automatic height based on text contents. Control size is modified relative to the Pivot.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorOrder(90), DefaultValue(false), Tooltip("If checked, the control height will be based on text contents.")]
|
[EditorOrder(90), DefaultValue(false), Tooltip("If checked, the control height will be based on text contents. Control size is modified relative to the Pivot.")]
|
||||||
public bool AutoHeight
|
public bool AutoHeight
|
||||||
{
|
{
|
||||||
get => _autoHeight;
|
get => _autoHeight;
|
||||||
@@ -226,13 +234,8 @@ namespace FlaxEngine.GUI
|
|||||||
/// Initializes a new instance of the <see cref="Label"/> class.
|
/// Initializes a new instance of the <see cref="Label"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Label()
|
public Label()
|
||||||
: base(0, 0, 100, 20)
|
: this(0, 0, 100, 20)
|
||||||
{
|
{
|
||||||
AutoFocus = false;
|
|
||||||
var style = Style.Current;
|
|
||||||
Font = new FontReference(style.FontMedium);
|
|
||||||
TextColor = style.Foreground;
|
|
||||||
TextColorHighlighted = style.Foreground;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -241,9 +244,12 @@ namespace FlaxEngine.GUI
|
|||||||
{
|
{
|
||||||
AutoFocus = false;
|
AutoFocus = false;
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
Font = new FontReference(style.FontMedium);
|
if (style != null)
|
||||||
TextColor = style.Foreground;
|
{
|
||||||
TextColorHighlighted = style.Foreground;
|
Font = new FontReference(style.FontMedium);
|
||||||
|
TextColor = style.Foreground;
|
||||||
|
TextColorHighlighted = style.Foreground;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -251,31 +257,24 @@ namespace FlaxEngine.GUI
|
|||||||
{
|
{
|
||||||
base.DrawSelf();
|
base.DrawSelf();
|
||||||
|
|
||||||
var rect = new Rectangle(new Float2(Margin.Left, Margin.Top), Size - Margin.Size);
|
|
||||||
|
|
||||||
if (ClipText)
|
if (ClipText)
|
||||||
Render2D.PushClip(new Rectangle(Float2.Zero, Size));
|
Render2D.PushClip(new Rectangle(Float2.Zero, Size));
|
||||||
|
|
||||||
|
var rect = new Rectangle(new Float2(Margin.Left, Margin.Top), Size - Margin.Size);
|
||||||
var color = IsMouseOver || IsNavFocused ? TextColorHighlighted : TextColor;
|
var color = IsMouseOver || IsNavFocused ? TextColorHighlighted : TextColor;
|
||||||
|
|
||||||
if (!EnabledInHierarchy)
|
if (!EnabledInHierarchy)
|
||||||
color *= 0.6f;
|
color *= 0.6f;
|
||||||
|
|
||||||
var scale = 1.0f;
|
var scale = 1.0f;
|
||||||
var hAlignment = HorizontalAlignment;
|
var hAlignment = HorizontalAlignment;
|
||||||
var wAlignment = VerticalAlignment;
|
var wAlignment = VerticalAlignment;
|
||||||
if (_autoFitText)
|
if (_autoFitText && !_textSize.IsZero)
|
||||||
{
|
{
|
||||||
if (!_textSize.IsZero)
|
scale = (rect.Size / _textSize).MinValue;
|
||||||
{
|
scale = Mathf.Clamp(scale, _autoFitTextRange.X, _autoFitTextRange.Y);
|
||||||
scale = (rect.Size / _textSize).MinValue;
|
|
||||||
scale = Mathf.Clamp(scale, _autoFitTextRange.X, _autoFitTextRange.Y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Font font = GetFont();
|
Font font = GetFont();
|
||||||
var text = ConvertedText();
|
var text = ConvertedText();
|
||||||
|
|
||||||
Render2D.DrawText(font, Material, text, rect, color, hAlignment, wAlignment, Wrapping, BaseLinesGapScale, scale);
|
Render2D.DrawText(font, Material, text, rect, color, hAlignment, wAlignment, Wrapping, BaseLinesGapScale, scale);
|
||||||
|
|
||||||
if (ClipText)
|
if (ClipText)
|
||||||
@@ -336,7 +335,9 @@ namespace FlaxEngine.GUI
|
|||||||
size.X = _textSize.X + Margin.Width;
|
size.X = _textSize.X + Margin.Width;
|
||||||
if (_autoHeight)
|
if (_autoHeight)
|
||||||
size.Y = _textSize.Y + Margin.Height;
|
size.Y = _textSize.Y + Margin.Height;
|
||||||
|
var pivotRelative = PivotRelative;
|
||||||
Size = size;
|
Size = size;
|
||||||
|
PivotRelative = pivotRelative;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -291,24 +291,7 @@ namespace FlaxEngine.GUI
|
|||||||
{
|
{
|
||||||
float alpha = Mathf.Saturate(Mathf.Cos(_animateTime * CaretFlashSpeed) * 0.5f + 0.7f);
|
float alpha = Mathf.Saturate(Mathf.Cos(_animateTime * CaretFlashSpeed) * 0.5f + 0.7f);
|
||||||
alpha = alpha * alpha * alpha * alpha * alpha * alpha;
|
alpha = alpha * alpha * alpha * alpha * alpha * alpha;
|
||||||
if (CaretPosition == 0)
|
Render2D.FillRectangle(CaretBounds, CaretColor * alpha);
|
||||||
{
|
|
||||||
var bounds = CaretBounds;
|
|
||||||
if (_layout.VerticalAlignment == TextAlignment.Center)
|
|
||||||
bounds.Y = _layout.Bounds.Y + _layout.Bounds.Height * 0.5f - bounds.Height * 0.5f;
|
|
||||||
else if (_layout.VerticalAlignment == TextAlignment.Far)
|
|
||||||
bounds.Y = _layout.Bounds.Y + _layout.Bounds.Height - bounds.Height;
|
|
||||||
|
|
||||||
if (_layout.HorizontalAlignment == TextAlignment.Center)
|
|
||||||
bounds.X = _layout.Bounds.X + _layout.Bounds.Width * 0.5f - bounds.Width * 0.5f;
|
|
||||||
else if (_layout.HorizontalAlignment == TextAlignment.Far)
|
|
||||||
bounds.X = _layout.Bounds.X + _layout.Bounds.Width - bounds.Width;
|
|
||||||
Render2D.FillRectangle(bounds, CaretColor * alpha);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Render2D.FillRectangle(CaretBounds, CaretColor * alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -234,6 +234,11 @@ namespace FlaxEngine.GUI
|
|||||||
if (_bounds.Size.Equals(ref value))
|
if (_bounds.Size.Equals(ref value))
|
||||||
return;
|
return;
|
||||||
var bounds = new Rectangle(_bounds.Location, value);
|
var bounds = new Rectangle(_bounds.Location, value);
|
||||||
|
if (_pivotRelativeSizing)
|
||||||
|
{
|
||||||
|
var delta = _bounds.Size - value;
|
||||||
|
bounds.Location += delta * Pivot;
|
||||||
|
}
|
||||||
SetBounds(ref bounds);
|
SetBounds(ref bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -566,7 +571,7 @@ namespace FlaxEngine.GUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the anchor preset for the control. Can be use to auto-place the control for a given preset or can preserve the current control bounds.
|
/// Sets the anchor preset for the control. Can be used to auto-place the control for a given preset or can preserve the current control bounds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="anchorPreset">The anchor preset to set.</param>
|
/// <param name="anchorPreset">The anchor preset to set.</param>
|
||||||
/// <param name="preserveBounds">True if preserve current control bounds, otherwise will align control position accordingly to the anchor location.</param>
|
/// <param name="preserveBounds">True if preserve current control bounds, otherwise will align control position accordingly to the anchor location.</param>
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ namespace FlaxEngine.GUI
|
|||||||
// Style
|
// Style
|
||||||
|
|
||||||
private Color _backgroundColor = Color.Transparent;
|
private Color _backgroundColor = Color.Transparent;
|
||||||
|
private IBrush _backgroundBrush = null;
|
||||||
|
|
||||||
// Tooltip
|
// Tooltip
|
||||||
|
|
||||||
@@ -174,6 +175,25 @@ namespace FlaxEngine.GUI
|
|||||||
set => _backgroundColor = value;
|
set => _backgroundColor = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets control background brush used to fill the contents. Uses Background Color property as tint color.
|
||||||
|
/// </summary>
|
||||||
|
[EditorDisplay("Background Style"), EditorOrder(2001)]
|
||||||
|
public IBrush BackgroundBrush
|
||||||
|
{
|
||||||
|
get => _backgroundBrush;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_backgroundBrush = value;
|
||||||
|
|
||||||
|
#if FLAX_EDITOR
|
||||||
|
// Auto-reset background color so brush is visible as it uses it for tint
|
||||||
|
if (value != null && _backgroundColor == Color.Transparent && FlaxEditor.CustomEditors.CustomEditor.IsSettingValue)
|
||||||
|
_backgroundColor = Color.White;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the anchor preset used by the control anchors (based on <see cref="AnchorMin"/> and <see cref="AnchorMax"/>).
|
/// Gets or sets the anchor preset used by the control anchors (based on <see cref="AnchorMin"/> and <see cref="AnchorMax"/>).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -416,9 +436,14 @@ namespace FlaxEngine.GUI
|
|||||||
public virtual void Draw()
|
public virtual void Draw()
|
||||||
{
|
{
|
||||||
// Paint Background
|
// Paint Background
|
||||||
if (_backgroundColor.A > 0.0f)
|
var rect = new Rectangle(Float2.Zero, _bounds.Size);
|
||||||
|
if (BackgroundBrush != null)
|
||||||
{
|
{
|
||||||
Render2D.FillRectangle(new Rectangle(Float2.Zero, Size), _backgroundColor);
|
BackgroundBrush.Draw(rect, _backgroundColor);
|
||||||
|
}
|
||||||
|
else if (_backgroundColor.A > 0.0f)
|
||||||
|
{
|
||||||
|
Render2D.FillRectangle(rect, _backgroundColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,6 +639,18 @@ namespace FlaxEngine.GUI
|
|||||||
case NavDirection.Down: return NavTargetDown;
|
case NavDirection.Down: return NavTargetDown;
|
||||||
case NavDirection.Left: return NavTargetLeft;
|
case NavDirection.Left: return NavTargetLeft;
|
||||||
case NavDirection.Right: return NavTargetRight;
|
case NavDirection.Right: return NavTargetRight;
|
||||||
|
case NavDirection.Next:
|
||||||
|
if (NavTargetRight != null)
|
||||||
|
return NavTargetRight;
|
||||||
|
if (NavTargetDown != null)
|
||||||
|
return NavTargetDown;
|
||||||
|
return null;
|
||||||
|
case NavDirection.Previous:
|
||||||
|
if (NavTargetLeft != null)
|
||||||
|
return NavTargetLeft;
|
||||||
|
if (NavTargetUp != null)
|
||||||
|
return NavTargetUp;
|
||||||
|
return null;
|
||||||
default: return null;
|
default: return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ namespace FlaxEngine.GUI
|
|||||||
base.PerformLayoutBeforeChildren();
|
base.PerformLayoutBeforeChildren();
|
||||||
|
|
||||||
// Pre-set height of all controls
|
// Pre-set height of all controls
|
||||||
|
if (!ControlChildSize)
|
||||||
|
return;
|
||||||
float h = Height - _margin.Height;
|
float h = Height - _margin.Height;
|
||||||
for (int i = 0; i < _children.Count; i++)
|
for (int i = 0; i < _children.Count; i++)
|
||||||
{
|
{
|
||||||
@@ -40,6 +42,7 @@ namespace FlaxEngine.GUI
|
|||||||
float left = _margin.Left;
|
float left = _margin.Left;
|
||||||
float right = _margin.Right;
|
float right = _margin.Right;
|
||||||
float h = Height - _margin.Height;
|
float h = Height - _margin.Height;
|
||||||
|
float maxHeight = h;
|
||||||
bool hasAnyLeft = false, hasAnyRight = false;
|
bool hasAnyLeft = false, hasAnyRight = false;
|
||||||
for (int i = 0; i < _children.Count; i++)
|
for (int i = 0; i < _children.Count; i++)
|
||||||
{
|
{
|
||||||
@@ -47,18 +50,20 @@ namespace FlaxEngine.GUI
|
|||||||
if (c.Visible)
|
if (c.Visible)
|
||||||
{
|
{
|
||||||
var w = c.Width;
|
var w = c.Width;
|
||||||
|
var ch = ControlChildSize ? h : c.Height;
|
||||||
if (Mathf.IsZero(c.AnchorMin.X) && Mathf.IsZero(c.AnchorMax.X))
|
if (Mathf.IsZero(c.AnchorMin.X) && Mathf.IsZero(c.AnchorMax.X))
|
||||||
{
|
{
|
||||||
c.Bounds = new Rectangle(left + _offset.X, _margin.Top + _offset.Y, w, h);
|
c.Bounds = new Rectangle(left + _offset.X, _margin.Top + _offset.Y, w, ch);
|
||||||
left = c.Right + _spacing;
|
left = c.Right + _spacing;
|
||||||
hasAnyLeft = true;
|
hasAnyLeft = true;
|
||||||
}
|
}
|
||||||
else if (Mathf.IsOne(c.AnchorMin.X) && Mathf.IsOne(c.AnchorMax.X))
|
else if (Mathf.IsOne(c.AnchorMin.X) && Mathf.IsOne(c.AnchorMax.X))
|
||||||
{
|
{
|
||||||
right += w + _spacing;
|
right += w + _spacing;
|
||||||
c.Bounds = new Rectangle(Width - right + _offset.X, _margin.Top + _offset.Y, w, h);
|
c.Bounds = new Rectangle(Width - right + _offset.X, _margin.Top + _offset.Y, w, ch);
|
||||||
hasAnyRight = true;
|
hasAnyRight = true;
|
||||||
}
|
}
|
||||||
|
maxHeight = Mathf.Max(maxHeight, ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasAnyLeft)
|
if (hasAnyLeft)
|
||||||
@@ -68,7 +73,13 @@ namespace FlaxEngine.GUI
|
|||||||
|
|
||||||
// Update size
|
// Update size
|
||||||
if (_autoSize)
|
if (_autoSize)
|
||||||
Width = left + right;
|
{
|
||||||
|
var size = Size;
|
||||||
|
size.X = left + right;
|
||||||
|
if (!ControlChildSize)
|
||||||
|
size.Y = maxHeight;
|
||||||
|
Size = size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace FlaxEngine.GUI
|
namespace FlaxEngine.GUI
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -133,7 +135,7 @@ namespace FlaxEngine.GUI
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the value indicating whenever the panel size will be based on a children dimensions.
|
/// Gets or sets the value indicating whenever the panel size will be based on a children dimensions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorOrder(30), Tooltip("If checked, the panel size will be based on a children dimensions.")]
|
[EditorOrder(30), DefaultValue(true), Tooltip("If checked, the panel size will be based on a children dimensions.")]
|
||||||
public bool AutoSize
|
public bool AutoSize
|
||||||
{
|
{
|
||||||
get => _autoSize;
|
get => _autoSize;
|
||||||
@@ -147,6 +149,12 @@ namespace FlaxEngine.GUI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the value indicating whenever the panel can resize children controls (eg. auto-fit width/height).
|
||||||
|
/// </summary>
|
||||||
|
[EditorOrder(35), DefaultValue(true), Tooltip("If checked, the panel can resize children controls (eg. auto-fit width/height).")]
|
||||||
|
public bool ControlChildSize { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the panel area margin.
|
/// Gets or sets the panel area margin.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ namespace FlaxEngine.GUI
|
|||||||
base.PerformLayoutBeforeChildren();
|
base.PerformLayoutBeforeChildren();
|
||||||
|
|
||||||
// Pre-set width of all controls
|
// Pre-set width of all controls
|
||||||
|
if (!ControlChildSize)
|
||||||
|
return;
|
||||||
float w = Width - _margin.Width;
|
float w = Width - _margin.Width;
|
||||||
for (int i = 0; i < _children.Count; i++)
|
for (int i = 0; i < _children.Count; i++)
|
||||||
{
|
{
|
||||||
@@ -40,6 +42,7 @@ namespace FlaxEngine.GUI
|
|||||||
float top = _margin.Top;
|
float top = _margin.Top;
|
||||||
float bottom = _margin.Bottom;
|
float bottom = _margin.Bottom;
|
||||||
float w = Width - _margin.Width;
|
float w = Width - _margin.Width;
|
||||||
|
float maxWidth = w;
|
||||||
bool hasAnyTop = false, hasAnyBottom = false;
|
bool hasAnyTop = false, hasAnyBottom = false;
|
||||||
for (int i = 0; i < _children.Count; i++)
|
for (int i = 0; i < _children.Count; i++)
|
||||||
{
|
{
|
||||||
@@ -47,18 +50,20 @@ namespace FlaxEngine.GUI
|
|||||||
if (c.Visible)
|
if (c.Visible)
|
||||||
{
|
{
|
||||||
var h = c.Height;
|
var h = c.Height;
|
||||||
|
var cw = ControlChildSize ? w : c.Width;
|
||||||
if (Mathf.IsZero(c.AnchorMin.Y) && Mathf.IsZero(c.AnchorMax.Y))
|
if (Mathf.IsZero(c.AnchorMin.Y) && Mathf.IsZero(c.AnchorMax.Y))
|
||||||
{
|
{
|
||||||
c.Bounds = new Rectangle(_margin.Left + _offset.X, top + _offset.Y, w, h);
|
c.Bounds = new Rectangle(_margin.Left + _offset.X, top + _offset.Y, cw, h);
|
||||||
top = c.Bottom + _spacing;
|
top = c.Bottom + _spacing;
|
||||||
hasAnyTop = true;
|
hasAnyTop = true;
|
||||||
}
|
}
|
||||||
else if (Mathf.IsOne(c.AnchorMin.Y) && Mathf.IsOne(c.AnchorMax.Y))
|
else if (Mathf.IsOne(c.AnchorMin.Y) && Mathf.IsOne(c.AnchorMax.Y))
|
||||||
{
|
{
|
||||||
bottom += h + _spacing;
|
bottom += h + _spacing;
|
||||||
c.Bounds = new Rectangle(_margin.Left + _offset.X, Height - bottom + _offset.Y, w, h);
|
c.Bounds = new Rectangle(_margin.Left + _offset.X, Height - bottom + _offset.Y, cw, h);
|
||||||
hasAnyBottom = true;
|
hasAnyBottom = true;
|
||||||
}
|
}
|
||||||
|
maxWidth = Mathf.Max(maxWidth, cw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasAnyTop)
|
if (hasAnyTop)
|
||||||
@@ -68,7 +73,13 @@ namespace FlaxEngine.GUI
|
|||||||
|
|
||||||
// Update size
|
// Update size
|
||||||
if (_autoSize)
|
if (_autoSize)
|
||||||
Height = top + bottom;
|
{
|
||||||
|
var size = Size;
|
||||||
|
size.Y = top + bottom;
|
||||||
|
if (!ControlChildSize)
|
||||||
|
size.X = maxWidth;
|
||||||
|
Size = size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,13 +43,9 @@ float4 PointInParallelogram(float2 p, float2 a, float4 bc)
|
|||||||
void PerformClipping(float2 clipOrigin, float2 windowPos, float4 clipExtents)
|
void PerformClipping(float2 clipOrigin, float2 windowPos, float4 clipExtents)
|
||||||
{
|
{
|
||||||
#if CLIPPING_ENABLE
|
#if CLIPPING_ENABLE
|
||||||
|
// Clip pixels which are outside the clipping rect
|
||||||
// Clip pixels which are outside of the clipping rect
|
|
||||||
float4 clipTest = PointInParallelogram(windowPos, clipOrigin, clipExtents);
|
float4 clipTest = PointInParallelogram(windowPos, clipOrigin, clipExtents);
|
||||||
|
|
||||||
// Clip pixels which are outside of the clipping rect
|
|
||||||
clip(clipTest);
|
clip(clipTest);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1478,8 +1478,8 @@ namespace Flax.Build.Bindings
|
|||||||
public static class NativeToManaged
|
public static class NativeToManaged
|
||||||
{
|
{
|
||||||
public static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => Unsafe.As<{{classInfo.Name}}>(ManagedHandleMarshaller.NativeToManaged.ConvertToManaged(unmanaged));
|
public static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => Unsafe.As<{{classInfo.Name}}>(ManagedHandleMarshaller.NativeToManaged.ConvertToManaged(unmanaged));
|
||||||
public static IntPtr ConvertToUnmanaged({{classInfo.Name}} managed) => ManagedHandleMarshaller.ManagedToNative.ConvertToUnmanaged(managed);
|
public static IntPtr ConvertToUnmanaged({{classInfo.Name}} managed) => managed != null ? ManagedHandle.ToIntPtr(managed, GCHandleType.Weak) : IntPtr.Zero;
|
||||||
public static void Free(IntPtr unmanaged) => ManagedHandleMarshaller.NativeToManaged.Free(unmanaged);
|
public static void Free(IntPtr unmanaged) {}
|
||||||
}
|
}
|
||||||
#if FLAX_EDITOR
|
#if FLAX_EDITOR
|
||||||
[HideInEditor]
|
[HideInEditor]
|
||||||
@@ -1487,8 +1487,8 @@ namespace Flax.Build.Bindings
|
|||||||
public static class ManagedToNative
|
public static class ManagedToNative
|
||||||
{
|
{
|
||||||
public static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => Unsafe.As<{{classInfo.Name}}>(ManagedHandleMarshaller.NativeToManaged.ConvertToManaged(unmanaged));
|
public static {{classInfo.Name}} ConvertToManaged(IntPtr unmanaged) => Unsafe.As<{{classInfo.Name}}>(ManagedHandleMarshaller.NativeToManaged.ConvertToManaged(unmanaged));
|
||||||
public static IntPtr ConvertToUnmanaged({{classInfo.Name}} managed) => ManagedHandleMarshaller.ManagedToNative.ConvertToUnmanaged(managed);
|
public static IntPtr ConvertToUnmanaged({{classInfo.Name}} managed) => managed != null ? ManagedHandle.ToIntPtr(managed, GCHandleType.Weak) : IntPtr.Zero;
|
||||||
public static void Free(IntPtr unmanaged) => ManagedHandleMarshaller.ManagedToNative.Free(unmanaged);
|
public static void Free(IntPtr unmanaged) {}
|
||||||
}
|
}
|
||||||
#if FLAX_EDITOR
|
#if FLAX_EDITOR
|
||||||
[HideInEditor]
|
[HideInEditor]
|
||||||
|
|||||||
@@ -242,6 +242,11 @@ namespace Flax.Build.Bindings
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Forward type
|
// Forward type
|
||||||
|
if (token.Value == "enum")
|
||||||
|
{
|
||||||
|
context.Tokenizer.SkipUntil(TokenType.Identifier);
|
||||||
|
token = context.Tokenizer.CurrentToken;
|
||||||
|
}
|
||||||
if (token.Value == "class")
|
if (token.Value == "class")
|
||||||
{
|
{
|
||||||
context.Tokenizer.SkipUntil(TokenType.Identifier);
|
context.Tokenizer.SkipUntil(TokenType.Identifier);
|
||||||
|
|||||||
Reference in New Issue
Block a user