Merge branch 'FlaxEngine:master' into model-prefab-fix
This commit is contained in:
@@ -81,7 +81,7 @@ namespace FlaxEditor.Content.Create
|
|||||||
switch (_options.Template)
|
switch (_options.Template)
|
||||||
{
|
{
|
||||||
case Templates.Empty:
|
case Templates.Empty:
|
||||||
return Editor.CreateAsset(Editor.NewAssetType.ParticleEmitter, ResultUrl);
|
return Editor.CreateAsset("ParticleEmitter", ResultUrl);
|
||||||
case Templates.ConstantBurst:
|
case Templates.ConstantBurst:
|
||||||
templateName = "Constant Burst";
|
templateName = "Constant Burst";
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace FlaxEditor.Content
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Create(string outputPath, object arg)
|
public override void Create(string outputPath, object arg)
|
||||||
{
|
{
|
||||||
if (Editor.CreateAsset(Editor.NewAssetType.AnimationGraphFunction, outputPath))
|
if (Editor.CreateAsset("AnimationGraphFunction", outputPath))
|
||||||
throw new Exception("Failed to create new asset.");
|
throw new Exception("Failed to create new asset.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace FlaxEditor.Content
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Create(string outputPath, object arg)
|
public override void Create(string outputPath, object arg)
|
||||||
{
|
{
|
||||||
if (Editor.CreateAsset(Editor.NewAssetType.AnimationGraph, outputPath))
|
if (Editor.CreateAsset("AnimationGraph", outputPath))
|
||||||
throw new Exception("Failed to create new asset.");
|
throw new Exception("Failed to create new asset.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace FlaxEditor.Content
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Create(string outputPath, object arg)
|
public override void Create(string outputPath, object arg)
|
||||||
{
|
{
|
||||||
if (Editor.CreateAsset(Editor.NewAssetType.Animation, outputPath))
|
if (Editor.CreateAsset("Animation", outputPath))
|
||||||
throw new Exception("Failed to create new asset.");
|
throw new Exception("Failed to create new asset.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace FlaxEditor.Content
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Create(string outputPath, object arg)
|
public override void Create(string outputPath, object arg)
|
||||||
{
|
{
|
||||||
if (Editor.CreateAsset(Editor.NewAssetType.BehaviorTree, outputPath))
|
if (Editor.CreateAsset("BehaviorTree", outputPath))
|
||||||
throw new Exception("Failed to create new asset.");
|
throw new Exception("Failed to create new asset.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ namespace FlaxEditor.Content
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Create(string outputPath, object arg)
|
public override void Create(string outputPath, object arg)
|
||||||
{
|
{
|
||||||
if (Editor.CreateAsset(Editor.NewAssetType.CollisionData, outputPath))
|
if (Editor.CreateAsset("CollisionData", outputPath))
|
||||||
throw new Exception("Failed to create new asset.");
|
throw new Exception("Failed to create new asset.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace FlaxEditor.Content
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Create(string outputPath, object arg)
|
public override void Create(string outputPath, object arg)
|
||||||
{
|
{
|
||||||
if (Editor.CreateAsset(Editor.NewAssetType.MaterialFunction, outputPath))
|
if (Editor.CreateAsset("MaterialFunction", outputPath))
|
||||||
throw new Exception("Failed to create new asset.");
|
throw new Exception("Failed to create new asset.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace FlaxEditor.Content
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Create(string outputPath, object arg)
|
public override void Create(string outputPath, object arg)
|
||||||
{
|
{
|
||||||
if (Editor.CreateAsset(Editor.NewAssetType.MaterialInstance, outputPath))
|
if (Editor.CreateAsset("MaterialInstance", outputPath))
|
||||||
throw new Exception("Failed to create new asset.");
|
throw new Exception("Failed to create new asset.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ namespace FlaxEditor.Content
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Create(string outputPath, object arg)
|
public override void Create(string outputPath, object arg)
|
||||||
{
|
{
|
||||||
if (Editor.CreateAsset(Editor.NewAssetType.Material, outputPath))
|
if (Editor.CreateAsset("Material", outputPath))
|
||||||
throw new Exception("Failed to create new asset.");
|
throw new Exception("Failed to create new asset.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace FlaxEditor.Content
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Create(string outputPath, object arg)
|
public override void Create(string outputPath, object arg)
|
||||||
{
|
{
|
||||||
if (Editor.CreateAsset(Editor.NewAssetType.ParticleEmitterFunction, outputPath))
|
if (Editor.CreateAsset("ParticleEmitterFunction", outputPath))
|
||||||
throw new Exception("Failed to create new asset.");
|
throw new Exception("Failed to create new asset.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ namespace FlaxEditor.Content
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Create(string outputPath, object arg)
|
public override void Create(string outputPath, object arg)
|
||||||
{
|
{
|
||||||
if (Editor.CreateAsset(Editor.NewAssetType.ParticleSystem, outputPath))
|
if (Editor.CreateAsset("ParticleSystem", outputPath))
|
||||||
throw new Exception("Failed to create new asset.");
|
throw new Exception("Failed to create new asset.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ namespace FlaxEditor.Content
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Create(string outputPath, object arg)
|
public override void Create(string outputPath, object arg)
|
||||||
{
|
{
|
||||||
if (Editor.CreateAsset(Editor.NewAssetType.SceneAnimation, outputPath))
|
if (Editor.CreateAsset("SceneAnimation", outputPath))
|
||||||
throw new Exception("Failed to create new asset.");
|
throw new Exception("Failed to create new asset.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace FlaxEditor.Content
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Create(string outputPath, object arg)
|
public override void Create(string outputPath, object arg)
|
||||||
{
|
{
|
||||||
if (Editor.CreateAsset(Editor.NewAssetType.SkeletonMask, outputPath))
|
if (Editor.CreateAsset("SkeletonMask", outputPath))
|
||||||
throw new Exception("Failed to create new asset.");
|
throw new Exception("Failed to create new asset.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -543,10 +543,11 @@ namespace FlaxEditor.CustomEditors
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
string text;
|
string text;
|
||||||
|
var value = Values[0];
|
||||||
if (ParentEditor is Dedicated.ScriptsEditor)
|
if (ParentEditor is Dedicated.ScriptsEditor)
|
||||||
{
|
{
|
||||||
// Script
|
// Script
|
||||||
text = JsonSerializer.Serialize(Values[0]);
|
text = JsonSerializer.Serialize(value);
|
||||||
|
|
||||||
// Remove properties that should be ignored when copy/pasting data
|
// Remove properties that should be ignored when copy/pasting data
|
||||||
if (text == null)
|
if (text == null)
|
||||||
@@ -576,12 +577,12 @@ namespace FlaxEditor.CustomEditors
|
|||||||
else if (ScriptType.FlaxObject.IsAssignableFrom(Values.Type))
|
else if (ScriptType.FlaxObject.IsAssignableFrom(Values.Type))
|
||||||
{
|
{
|
||||||
// Object reference
|
// Object reference
|
||||||
text = JsonSerializer.GetStringID(Values[0] as FlaxEngine.Object);
|
text = JsonSerializer.GetStringID(value as FlaxEngine.Object);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Default
|
// Default
|
||||||
text = JsonSerializer.Serialize(Values[0]);
|
text = JsonSerializer.Serialize(value, TypeUtils.GetType(Values.Type));
|
||||||
}
|
}
|
||||||
Clipboard.Text = text;
|
Clipboard.Text = text;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -591,14 +591,14 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
|||||||
var group = layout.Group(title, editor);
|
var group = layout.Group(title, editor);
|
||||||
if ((Presenter.Features & FeatureFlags.CacheExpandedGroups) != 0)
|
if ((Presenter.Features & FeatureFlags.CacheExpandedGroups) != 0)
|
||||||
{
|
{
|
||||||
if (Editor.Instance.ProjectCache.IsCollapsedGroup(title))
|
if (Editor.Instance.ProjectCache.IsGroupToggled(title))
|
||||||
group.Panel.Close(false);
|
group.Panel.Close();
|
||||||
else
|
else
|
||||||
group.Panel.Open(false);
|
group.Panel.Open();
|
||||||
group.Panel.IsClosedChanged += panel => Editor.Instance.ProjectCache.SetCollapsedGroup(panel.HeaderText, panel.IsClosed);
|
group.Panel.IsClosedChanged += panel => Editor.Instance.ProjectCache.SetGroupToggle(panel.HeaderText, panel.IsClosed);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
group.Panel.Open(false);
|
group.Panel.Open();
|
||||||
|
|
||||||
// Customize
|
// Customize
|
||||||
group.Panel.TooltipText = Editor.Instance.CodeDocs.GetTooltip(scriptType);
|
group.Panel.TooltipText = Editor.Instance.CodeDocs.GetTooltip(scriptType);
|
||||||
|
|||||||
@@ -51,10 +51,13 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
return;
|
return;
|
||||||
Picker = layout.Custom<AssetPicker>().CustomControl;
|
Picker = layout.Custom<AssetPicker>().CustomControl;
|
||||||
|
|
||||||
_valueType = Values.Type.Type != typeof(object) || Values[0] == null ? Values.Type : TypeUtils.GetObjectType(Values[0]);
|
var value = Values[0];
|
||||||
|
_valueType = Values.Type.Type != typeof(object) || value == null ? Values.Type : TypeUtils.GetObjectType(value);
|
||||||
var assetType = _valueType;
|
var assetType = _valueType;
|
||||||
if (assetType == typeof(string))
|
if (assetType == typeof(string))
|
||||||
assetType = new ScriptType(typeof(Asset));
|
assetType = new ScriptType(typeof(Asset));
|
||||||
|
else if (_valueType.Type != null && _valueType.Type.Name == typeof(JsonAssetReference<>).Name)
|
||||||
|
assetType = new ScriptType(_valueType.Type.GenericTypeArguments[0]);
|
||||||
|
|
||||||
float height = 48;
|
float height = 48;
|
||||||
var attributes = Values.GetAttributes();
|
var attributes = Values.GetAttributes();
|
||||||
@@ -102,6 +105,12 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
SetValue(new SceneReference(Picker.Validator.SelectedID));
|
SetValue(new SceneReference(Picker.Validator.SelectedID));
|
||||||
else if (_valueType.Type == typeof(string))
|
else if (_valueType.Type == typeof(string))
|
||||||
SetValue(Picker.Validator.SelectedPath);
|
SetValue(Picker.Validator.SelectedPath);
|
||||||
|
else if (_valueType.Type.Name == typeof(JsonAssetReference<>).Name)
|
||||||
|
{
|
||||||
|
var value = Values[0];
|
||||||
|
value.GetType().GetField("Asset").SetValue(value, Picker.Validator.SelectedAsset as JsonAsset);
|
||||||
|
SetValue(value);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
SetValue(Picker.Validator.SelectedAsset);
|
SetValue(Picker.Validator.SelectedAsset);
|
||||||
}
|
}
|
||||||
@@ -114,16 +123,19 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
if (!HasDifferentValues)
|
if (!HasDifferentValues)
|
||||||
{
|
{
|
||||||
_isRefreshing = true;
|
_isRefreshing = true;
|
||||||
if (Values[0] is AssetItem assetItem)
|
var value = Values[0];
|
||||||
|
if (value is AssetItem assetItem)
|
||||||
Picker.Validator.SelectedItem = assetItem;
|
Picker.Validator.SelectedItem = assetItem;
|
||||||
else if (Values[0] is Guid guid)
|
else if (value is Guid guid)
|
||||||
Picker.Validator.SelectedID = guid;
|
Picker.Validator.SelectedID = guid;
|
||||||
else if (Values[0] is SceneReference sceneAsset)
|
else if (value is SceneReference sceneAsset)
|
||||||
Picker.Validator.SelectedItem = Editor.Instance.ContentDatabase.FindAsset(sceneAsset.ID);
|
Picker.Validator.SelectedItem = Editor.Instance.ContentDatabase.FindAsset(sceneAsset.ID);
|
||||||
else if (Values[0] is string path)
|
else if (value is string path)
|
||||||
Picker.Validator.SelectedPath = path;
|
Picker.Validator.SelectedPath = path;
|
||||||
|
else if (value != null && value.GetType().Name == typeof(JsonAssetReference<>).Name)
|
||||||
|
Picker.Validator.SelectedAsset = value.GetType().GetField("Asset").GetValue(value) as JsonAsset;
|
||||||
else
|
else
|
||||||
Picker.Validator.SelectedAsset = Values[0] as Asset;
|
Picker.Validator.SelectedAsset = value as Asset;
|
||||||
_isRefreshing = false;
|
_isRefreshing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,8 +176,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
|
|
||||||
private IntValueBox _sizeBox;
|
private IntValueBox _sizeBox;
|
||||||
private Color _background;
|
private Color _background;
|
||||||
private int _elementsCount;
|
private int _elementsCount, _minCount, _maxCount;
|
||||||
private bool _readOnly;
|
private bool _canResize;
|
||||||
private bool _canReorderItems;
|
private bool _canReorderItems;
|
||||||
private CollectionAttribute.DisplayType _displayType;
|
private CollectionAttribute.DisplayType _displayType;
|
||||||
|
|
||||||
@@ -209,8 +209,10 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var size = Count;
|
var size = Count;
|
||||||
_readOnly = false;
|
_canResize = true;
|
||||||
_canReorderItems = true;
|
_canReorderItems = true;
|
||||||
|
_minCount = 0;
|
||||||
|
_maxCount = 0;
|
||||||
_background = FlaxEngine.GUI.Style.Current.CollectionBackgroundColor;
|
_background = FlaxEngine.GUI.Style.Current.CollectionBackgroundColor;
|
||||||
_displayType = CollectionAttribute.DisplayType.Header;
|
_displayType = CollectionAttribute.DisplayType.Header;
|
||||||
NotNullItems = false;
|
NotNullItems = false;
|
||||||
@@ -222,7 +224,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
var collection = (CollectionAttribute)attributes?.FirstOrDefault(x => x is CollectionAttribute);
|
var collection = (CollectionAttribute)attributes?.FirstOrDefault(x => x is CollectionAttribute);
|
||||||
if (collection != null)
|
if (collection != null)
|
||||||
{
|
{
|
||||||
_readOnly = collection.ReadOnly;
|
_canResize = !collection.ReadOnly;
|
||||||
|
_minCount = collection.MinCount;
|
||||||
|
_maxCount = collection.MaxCount;
|
||||||
_canReorderItems = collection.CanReorderItems;
|
_canReorderItems = collection.CanReorderItems;
|
||||||
NotNullItems = collection.NotNullItems;
|
NotNullItems = collection.NotNullItems;
|
||||||
if (collection.BackgroundColor.HasValue)
|
if (collection.BackgroundColor.HasValue)
|
||||||
@@ -231,6 +235,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
spacing = collection.Spacing;
|
spacing = collection.Spacing;
|
||||||
_displayType = collection.Display;
|
_displayType = collection.Display;
|
||||||
}
|
}
|
||||||
|
if (_maxCount == 0)
|
||||||
|
_maxCount = ushort.MaxValue;
|
||||||
|
_canResize &= _minCount < _maxCount;
|
||||||
|
|
||||||
var dragArea = layout.CustomContainer<DragAreaControl>();
|
var dragArea = layout.CustomContainer<DragAreaControl>();
|
||||||
dragArea.CustomControl.Editor = this;
|
dragArea.CustomControl.Editor = this;
|
||||||
@@ -268,8 +275,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
var y = -dropPanel.HeaderHeight + dropPanel.HeaderTextMargin.Top;
|
var y = -dropPanel.HeaderHeight + dropPanel.HeaderTextMargin.Top;
|
||||||
_sizeBox = new IntValueBox(size)
|
_sizeBox = new IntValueBox(size)
|
||||||
{
|
{
|
||||||
MinValue = 0,
|
MinValue = _minCount,
|
||||||
MaxValue = ushort.MaxValue,
|
MaxValue = _maxCount,
|
||||||
AnchorPreset = AnchorPresets.TopRight,
|
AnchorPreset = AnchorPresets.TopRight,
|
||||||
Bounds = new Rectangle(-40 - dropPanel.ItemsMargin.Right, y, 40, height),
|
Bounds = new Rectangle(-40 - dropPanel.ItemsMargin.Right, y, 40, height),
|
||||||
Parent = dropPanel,
|
Parent = dropPanel,
|
||||||
@@ -283,7 +290,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
Parent = dropPanel
|
Parent = dropPanel
|
||||||
};
|
};
|
||||||
|
|
||||||
if (_readOnly || (NotNullItems && size == 0))
|
if (!_canResize || (NotNullItems && size == 0))
|
||||||
{
|
{
|
||||||
_sizeBox.IsReadOnly = true;
|
_sizeBox.IsReadOnly = true;
|
||||||
_sizeBox.Enabled = false;
|
_sizeBox.Enabled = false;
|
||||||
@@ -339,7 +346,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
_elementsCount = size;
|
_elementsCount = size;
|
||||||
|
|
||||||
// Add/Remove buttons
|
// Add/Remove buttons
|
||||||
if (!_readOnly)
|
if (_canResize)
|
||||||
{
|
{
|
||||||
var panel = dragArea.HorizontalPanel();
|
var panel = dragArea.HorizontalPanel();
|
||||||
panel.Panel.Size = new Float2(0, 20);
|
panel.Panel.Size = new Float2(0, 20);
|
||||||
@@ -347,25 +354,23 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
|
|
||||||
var removeButton = panel.Button("-", "Remove last item");
|
var removeButton = panel.Button("-", "Remove last item");
|
||||||
removeButton.Button.Size = new Float2(16, 16);
|
removeButton.Button.Size = new Float2(16, 16);
|
||||||
removeButton.Button.Enabled = size > 0;
|
removeButton.Button.Enabled = size > _minCount;
|
||||||
removeButton.Button.AnchorPreset = AnchorPresets.TopRight;
|
removeButton.Button.AnchorPreset = AnchorPresets.TopRight;
|
||||||
removeButton.Button.Clicked += () =>
|
removeButton.Button.Clicked += () =>
|
||||||
{
|
{
|
||||||
if (IsSetBlocked)
|
if (IsSetBlocked)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Resize(Count - 1);
|
Resize(Count - 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
var addButton = panel.Button("+", "Add new item");
|
var addButton = panel.Button("+", "Add new item");
|
||||||
addButton.Button.Size = new Float2(16, 16);
|
addButton.Button.Size = new Float2(16, 16);
|
||||||
addButton.Button.Enabled = !NotNullItems || size > 0;
|
addButton.Button.Enabled = (!NotNullItems || size > 0) && size < _maxCount;
|
||||||
addButton.Button.AnchorPreset = AnchorPresets.TopRight;
|
addButton.Button.AnchorPreset = AnchorPresets.TopRight;
|
||||||
addButton.Button.Clicked += () =>
|
addButton.Button.Clicked += () =>
|
||||||
{
|
{
|
||||||
if (IsSetBlocked)
|
if (IsSetBlocked)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Resize(Count + 1);
|
Resize(Count + 1);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ namespace FlaxEditor.CustomEditors
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal bool isRootGroup = true;
|
internal bool isRootGroup = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parent container who created this one.
|
||||||
|
/// </summary>
|
||||||
|
internal LayoutElementsContainer _parent;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The children.
|
/// The children.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -40,6 +45,24 @@ namespace FlaxEditor.CustomEditors
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract ContainerControl ContainerControl { get; }
|
public abstract ContainerControl ContainerControl { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Custom Editors layout presenter.
|
||||||
|
/// </summary>
|
||||||
|
internal CustomEditorPresenter Presenter
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
CustomEditorPresenter result;
|
||||||
|
var container = this;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
result = container as CustomEditorPresenter;
|
||||||
|
container = container._parent;
|
||||||
|
} while (container != null);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds new group element.
|
/// Adds new group element.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -81,17 +104,31 @@ namespace FlaxEditor.CustomEditors
|
|||||||
public GroupElement Group(string title, bool useTransparentHeader = false)
|
public GroupElement Group(string title, bool useTransparentHeader = false)
|
||||||
{
|
{
|
||||||
var element = new GroupElement();
|
var element = new GroupElement();
|
||||||
if (!isRootGroup)
|
var presenter = Presenter;
|
||||||
|
var isSubGroup = !isRootGroup;
|
||||||
|
if (isSubGroup)
|
||||||
|
element.Panel.Close();
|
||||||
|
if (presenter != null && (presenter.Features & FeatureFlags.CacheExpandedGroups) != 0)
|
||||||
{
|
{
|
||||||
element.Panel.Close(false);
|
// Build group identifier (made of path from group titles)
|
||||||
|
var expandPath = title;
|
||||||
|
var container = this;
|
||||||
|
while (container != null && !(container is CustomEditorPresenter))
|
||||||
|
{
|
||||||
|
if (container.ContainerControl is DropPanel dropPanel)
|
||||||
|
expandPath = dropPanel.HeaderText + "/" + expandPath;
|
||||||
|
container = container._parent;
|
||||||
}
|
}
|
||||||
else if (this is CustomEditorPresenter presenter && (presenter.Features & FeatureFlags.CacheExpandedGroups) != 0)
|
|
||||||
{
|
// Caching/restoring expanded groups (non-root groups cache expanded state so invert boolean expression)
|
||||||
if (Editor.Instance.ProjectCache.IsCollapsedGroup(title))
|
if (Editor.Instance.ProjectCache.IsGroupToggled(expandPath) ^ isSubGroup)
|
||||||
element.Panel.Close(false);
|
element.Panel.Close();
|
||||||
element.Panel.IsClosedChanged += OnPanelIsClosedChanged;
|
else
|
||||||
|
element.Panel.Open();
|
||||||
|
element.Panel.IsClosedChanged += panel => Editor.Instance.ProjectCache.SetGroupToggle(expandPath, panel.IsClosed ^ isSubGroup);
|
||||||
}
|
}
|
||||||
element.isRootGroup = false;
|
element.isRootGroup = false;
|
||||||
|
element._parent = this;
|
||||||
element.Panel.HeaderText = title;
|
element.Panel.HeaderText = title;
|
||||||
if (useTransparentHeader)
|
if (useTransparentHeader)
|
||||||
{
|
{
|
||||||
@@ -103,11 +140,6 @@ namespace FlaxEditor.CustomEditors
|
|||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPanelIsClosedChanged(DropPanel panel)
|
|
||||||
{
|
|
||||||
Editor.Instance.ProjectCache.SetCollapsedGroup(panel.HeaderText, panel.IsClosed);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds new horizontal panel element.
|
/// Adds new horizontal panel element.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -627,7 +659,6 @@ namespace FlaxEditor.CustomEditors
|
|||||||
if (style == DisplayStyle.Group)
|
if (style == DisplayStyle.Group)
|
||||||
{
|
{
|
||||||
var group = Group(name, editor, true);
|
var group = Group(name, editor, true);
|
||||||
group.Panel.Close(false);
|
|
||||||
group.Panel.TooltipText = tooltip;
|
group.Panel.TooltipText = tooltip;
|
||||||
return group.Object(values, editor);
|
return group.Object(values, editor);
|
||||||
}
|
}
|
||||||
@@ -657,7 +688,6 @@ namespace FlaxEditor.CustomEditors
|
|||||||
if (style == DisplayStyle.Group)
|
if (style == DisplayStyle.Group)
|
||||||
{
|
{
|
||||||
var group = Group(label.Text, editor, true);
|
var group = Group(label.Text, editor, true);
|
||||||
group.Panel.Close(false);
|
|
||||||
group.Panel.TooltipText = tooltip;
|
group.Panel.TooltipText = tooltip;
|
||||||
return group.Object(values, editor);
|
return group.Object(values, editor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -869,7 +869,9 @@ namespace FlaxEditor
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// New asset types allowed to create.
|
/// New asset types allowed to create.
|
||||||
|
/// [Deprecated in v1.8]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("Use CreateAsset with named tag.")]
|
||||||
public enum NewAssetType
|
public enum NewAssetType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1046,12 +1048,59 @@ namespace FlaxEditor
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates new asset at the target location.
|
/// Creates new asset at the target location.
|
||||||
|
/// [Deprecated in v1.8]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">New asset type.</param>
|
/// <param name="type">New asset type.</param>
|
||||||
/// <param name="outputPath">Output asset path.</param>
|
/// <param name="outputPath">Output asset path.</param>
|
||||||
|
[Obsolete("Use CreateAsset with named tag.")]
|
||||||
public static bool CreateAsset(NewAssetType type, string outputPath)
|
public static bool CreateAsset(NewAssetType type, string outputPath)
|
||||||
{
|
{
|
||||||
return Internal_CreateAsset(type, outputPath);
|
// [Deprecated on 18.02.2024, expires on 18.02.2025]
|
||||||
|
string tag;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case NewAssetType.Material:
|
||||||
|
tag = "Material";
|
||||||
|
break;
|
||||||
|
case NewAssetType.MaterialInstance:
|
||||||
|
tag = "MaterialInstance";
|
||||||
|
break;
|
||||||
|
case NewAssetType.CollisionData:
|
||||||
|
tag = "CollisionData";
|
||||||
|
break;
|
||||||
|
case NewAssetType.AnimationGraph:
|
||||||
|
tag = "AnimationGraph";
|
||||||
|
break;
|
||||||
|
case NewAssetType.SkeletonMask:
|
||||||
|
tag = "SkeletonMask";
|
||||||
|
break;
|
||||||
|
case NewAssetType.ParticleEmitter:
|
||||||
|
tag = "ParticleEmitter";
|
||||||
|
break;
|
||||||
|
case NewAssetType.ParticleSystem:
|
||||||
|
tag = "ParticleSystem";
|
||||||
|
break;
|
||||||
|
case NewAssetType.SceneAnimation:
|
||||||
|
tag = "SceneAnimation";
|
||||||
|
break;
|
||||||
|
case NewAssetType.MaterialFunction:
|
||||||
|
tag = "MaterialFunction";
|
||||||
|
break;
|
||||||
|
case NewAssetType.ParticleEmitterFunction:
|
||||||
|
tag = "ParticleEmitterFunction";
|
||||||
|
break;
|
||||||
|
case NewAssetType.AnimationGraphFunction:
|
||||||
|
tag = "AnimationGraphFunction";
|
||||||
|
break;
|
||||||
|
case NewAssetType.Animation:
|
||||||
|
tag = "Animation";
|
||||||
|
break;
|
||||||
|
case NewAssetType.BehaviorTree:
|
||||||
|
tag = "BehaviorTree";
|
||||||
|
break;
|
||||||
|
default: return true;
|
||||||
|
}
|
||||||
|
return CreateAsset(tag, outputPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1588,10 +1637,6 @@ namespace FlaxEditor
|
|||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CloseSplashScreen", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CloseSplashScreen", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||||
internal static partial void Internal_CloseSplashScreen();
|
internal static partial void Internal_CloseSplashScreen();
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CreateAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
|
||||||
internal static partial bool Internal_CreateAsset(NewAssetType type, string outputPath);
|
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CreateVisualScript", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CreateVisualScript", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static partial bool Internal_CreateVisualScript(string outputPath, string baseTypename);
|
internal static partial bool Internal_CreateVisualScript(string outputPath, string baseTypename);
|
||||||
|
|||||||
@@ -170,78 +170,6 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CloneAssetFile(MString* dstPathObj, MS
|
|||||||
return Content::CloneAssetFile(dstPath, srcPath, *dstId);
|
return Content::CloneAssetFile(dstPath, srcPath, *dstId);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class NewAssetType
|
|
||||||
{
|
|
||||||
Material = 0,
|
|
||||||
MaterialInstance = 1,
|
|
||||||
CollisionData = 2,
|
|
||||||
AnimationGraph = 3,
|
|
||||||
SkeletonMask = 4,
|
|
||||||
ParticleEmitter = 5,
|
|
||||||
ParticleSystem = 6,
|
|
||||||
SceneAnimation = 7,
|
|
||||||
MaterialFunction = 8,
|
|
||||||
ParticleEmitterFunction = 9,
|
|
||||||
AnimationGraphFunction = 10,
|
|
||||||
Animation = 11,
|
|
||||||
BehaviorTree = 12,
|
|
||||||
};
|
|
||||||
|
|
||||||
DEFINE_INTERNAL_CALL(bool) EditorInternal_CreateAsset(NewAssetType type, MString* outputPathObj)
|
|
||||||
{
|
|
||||||
String tag;
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case NewAssetType::Material:
|
|
||||||
tag = AssetsImportingManager::CreateMaterialTag;
|
|
||||||
break;
|
|
||||||
case NewAssetType::MaterialInstance:
|
|
||||||
tag = AssetsImportingManager::CreateMaterialInstanceTag;
|
|
||||||
break;
|
|
||||||
case NewAssetType::CollisionData:
|
|
||||||
tag = AssetsImportingManager::CreateCollisionDataTag;
|
|
||||||
break;
|
|
||||||
case NewAssetType::AnimationGraph:
|
|
||||||
tag = AssetsImportingManager::CreateAnimationGraphTag;
|
|
||||||
break;
|
|
||||||
case NewAssetType::SkeletonMask:
|
|
||||||
tag = AssetsImportingManager::CreateSkeletonMaskTag;
|
|
||||||
break;
|
|
||||||
case NewAssetType::ParticleEmitter:
|
|
||||||
tag = AssetsImportingManager::CreateParticleEmitterTag;
|
|
||||||
break;
|
|
||||||
case NewAssetType::ParticleSystem:
|
|
||||||
tag = AssetsImportingManager::CreateParticleSystemTag;
|
|
||||||
break;
|
|
||||||
case NewAssetType::SceneAnimation:
|
|
||||||
tag = AssetsImportingManager::CreateSceneAnimationTag;
|
|
||||||
break;
|
|
||||||
case NewAssetType::MaterialFunction:
|
|
||||||
tag = AssetsImportingManager::CreateMaterialFunctionTag;
|
|
||||||
break;
|
|
||||||
case NewAssetType::ParticleEmitterFunction:
|
|
||||||
tag = AssetsImportingManager::CreateParticleEmitterFunctionTag;
|
|
||||||
break;
|
|
||||||
case NewAssetType::AnimationGraphFunction:
|
|
||||||
tag = AssetsImportingManager::CreateAnimationGraphFunctionTag;
|
|
||||||
break;
|
|
||||||
case NewAssetType::Animation:
|
|
||||||
tag = AssetsImportingManager::CreateAnimationTag;
|
|
||||||
break;
|
|
||||||
case NewAssetType::BehaviorTree:
|
|
||||||
tag = AssetsImportingManager::CreateBehaviorTreeTag;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
String outputPath;
|
|
||||||
MUtils::ToString(outputPathObj, outputPath);
|
|
||||||
FileSystem::NormalizePath(outputPath);
|
|
||||||
|
|
||||||
return AssetsImportingManager::Create(tag, outputPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINE_INTERNAL_CALL(bool) EditorInternal_CreateVisualScript(MString* outputPathObj, MString* baseTypenameObj)
|
DEFINE_INTERNAL_CALL(bool) EditorInternal_CreateVisualScript(MString* outputPathObj, MString* baseTypenameObj)
|
||||||
{
|
{
|
||||||
String outputPath;
|
String outputPath;
|
||||||
@@ -639,8 +567,6 @@ bool ManagedEditor::TryRestoreImportOptions(ModelTool::Options& options, String
|
|||||||
{
|
{
|
||||||
options.GenerateSDF = graphicsSettings->GenerateSDFOnModelImport;
|
options.GenerateSDF = graphicsSettings->GenerateSDFOnModelImport;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get options from model
|
|
||||||
FileSystem::NormalizePath(assetPath);
|
FileSystem::NormalizePath(assetPath);
|
||||||
return ImportModel::TryGetImportOptions(assetPath, options);
|
return ImportModel::TryGetImportOptions(assetPath, options);
|
||||||
}
|
}
|
||||||
@@ -652,7 +578,12 @@ bool ManagedEditor::Import(const String& inputPath, const String& outputPath, co
|
|||||||
|
|
||||||
bool ManagedEditor::TryRestoreImportOptions(AudioTool::Options& options, String assetPath)
|
bool ManagedEditor::TryRestoreImportOptions(AudioTool::Options& options, String assetPath)
|
||||||
{
|
{
|
||||||
// Get options from model
|
|
||||||
FileSystem::NormalizePath(assetPath);
|
FileSystem::NormalizePath(assetPath);
|
||||||
return ImportAudio::TryGetImportOptions(assetPath, options);
|
return ImportAudio::TryGetImportOptions(assetPath, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ManagedEditor::CreateAsset(const String& tag, String outputPath)
|
||||||
|
{
|
||||||
|
FileSystem::NormalizePath(outputPath);
|
||||||
|
return AssetsImportingManager::Create(tag, outputPath);
|
||||||
|
}
|
||||||
|
|||||||
@@ -210,6 +210,13 @@ public:
|
|||||||
API_FUNCTION() static bool TryRestoreImportOptions(API_PARAM(Ref) AudioTool::Options& options, String assetPath);
|
API_FUNCTION() static bool TryRestoreImportOptions(API_PARAM(Ref) AudioTool::Options& options, String assetPath);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new asset at the target location.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">New asset type.</param>
|
||||||
|
/// <param name="outputPath">Output asset path.</param>
|
||||||
|
API_FUNCTION() static bool CreateAsset(const String& tag, String outputPath);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
API_STRUCT(Internal, NoDefault) struct VisualScriptStackFrame
|
API_STRUCT(Internal, NoDefault) struct VisualScriptStackFrame
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace FlaxEditor.Modules
|
|||||||
private DateTime _lastSaveTime;
|
private DateTime _lastSaveTime;
|
||||||
|
|
||||||
private readonly HashSet<Guid> _expandedActors = new HashSet<Guid>();
|
private readonly HashSet<Guid> _expandedActors = new HashSet<Guid>();
|
||||||
private readonly HashSet<string> _collapsedGroups = new HashSet<string>();
|
private readonly HashSet<string> _toggledGroups = new HashSet<string>();
|
||||||
private readonly Dictionary<string, string> _customData = new Dictionary<string, string>();
|
private readonly Dictionary<string, string> _customData = new Dictionary<string, string>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -62,26 +62,26 @@ namespace FlaxEditor.Modules
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether group identified by the given title is collapsed in the UI.
|
/// Determines whether group identified by the given title is collapsed/opened in the UI.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The group title.</param>
|
/// <param name="title">The group title.</param>
|
||||||
/// <returns><c>true</c> if group is collapsed; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if group is toggled; otherwise, <c>false</c>.</returns>
|
||||||
public bool IsCollapsedGroup(string title)
|
public bool IsGroupToggled(string title)
|
||||||
{
|
{
|
||||||
return _collapsedGroups.Contains(title);
|
return _toggledGroups.Contains(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the group collapsed cached value.
|
/// Sets the group collapsed/opened cached value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="title">The group title.</param>
|
/// <param name="title">The group title.</param>
|
||||||
/// <param name="isCollapsed">If set to <c>true</c> group will be cached as an collapsed, otherwise false.</param>
|
/// <param name="isToggled">If set to <c>true</c> group will be cached as a toggled, otherwise false.</param>
|
||||||
public void SetCollapsedGroup(string title, bool isCollapsed)
|
public void SetGroupToggle(string title, bool isToggled)
|
||||||
{
|
{
|
||||||
if (isCollapsed)
|
if (isToggled)
|
||||||
_collapsedGroups.Add(title);
|
_toggledGroups.Add(title);
|
||||||
else
|
else
|
||||||
_collapsedGroups.Remove(title);
|
_toggledGroups.Remove(title);
|
||||||
_isDirty = true;
|
_isDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ namespace FlaxEditor.Modules
|
|||||||
_expandedActors.Add(new Guid(bytes16));
|
_expandedActors.Add(new Guid(bytes16));
|
||||||
}
|
}
|
||||||
|
|
||||||
_collapsedGroups.Clear();
|
_toggledGroups.Clear();
|
||||||
_customData.Clear();
|
_customData.Clear();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -176,7 +176,7 @@ namespace FlaxEditor.Modules
|
|||||||
_expandedActors.Add(new Guid(bytes16));
|
_expandedActors.Add(new Guid(bytes16));
|
||||||
}
|
}
|
||||||
|
|
||||||
_collapsedGroups.Clear();
|
_toggledGroups.Clear();
|
||||||
|
|
||||||
_customData.Clear();
|
_customData.Clear();
|
||||||
int customDataCount = reader.ReadInt32();
|
int customDataCount = reader.ReadInt32();
|
||||||
@@ -201,11 +201,9 @@ namespace FlaxEditor.Modules
|
|||||||
}
|
}
|
||||||
|
|
||||||
int collapsedGroupsCount = reader.ReadInt32();
|
int collapsedGroupsCount = reader.ReadInt32();
|
||||||
_collapsedGroups.Clear();
|
_toggledGroups.Clear();
|
||||||
for (int i = 0; i < collapsedGroupsCount; i++)
|
for (int i = 0; i < collapsedGroupsCount; i++)
|
||||||
{
|
_toggledGroups.Add(reader.ReadString());
|
||||||
_collapsedGroups.Add(reader.ReadString());
|
|
||||||
}
|
|
||||||
|
|
||||||
_customData.Clear();
|
_customData.Clear();
|
||||||
int customDataCount = reader.ReadInt32();
|
int customDataCount = reader.ReadInt32();
|
||||||
@@ -259,11 +257,9 @@ namespace FlaxEditor.Modules
|
|||||||
writer.Write(e.ToByteArray());
|
writer.Write(e.ToByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.Write(_collapsedGroups.Count);
|
writer.Write(_toggledGroups.Count);
|
||||||
foreach (var e in _collapsedGroups)
|
foreach (var e in _toggledGroups)
|
||||||
{
|
|
||||||
writer.Write(e);
|
writer.Write(e);
|
||||||
}
|
|
||||||
|
|
||||||
writer.Write(_customData.Count);
|
writer.Write(_customData.Count);
|
||||||
foreach (var e in _customData)
|
foreach (var e in _customData)
|
||||||
@@ -284,7 +280,6 @@ namespace FlaxEditor.Modules
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
SaveGuarded();
|
SaveGuarded();
|
||||||
|
|
||||||
_isDirty = false;
|
_isDirty = false;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -534,6 +534,41 @@ namespace FlaxEditor.Modules
|
|||||||
Delete();
|
Delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create parent for selected actors.
|
||||||
|
/// </summary>
|
||||||
|
public void CreateParentForSelectedActors()
|
||||||
|
{
|
||||||
|
Actor actor = new EmptyActor();
|
||||||
|
Editor.SceneEditing.Spawn(actor, null, false);
|
||||||
|
List<SceneGraphNode> selection = Editor.SceneEditing.Selection;
|
||||||
|
var actors = selection.Where(x => x is ActorNode).Select(x => ((ActorNode)x).Actor);
|
||||||
|
using (new UndoMultiBlock(Undo, actors, "Reparent actors"))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < selection.Count; i++)
|
||||||
|
{
|
||||||
|
if (selection[i] is ActorNode node)
|
||||||
|
{
|
||||||
|
if (node.ParentNode != node.ParentScene) // If parent node is not a scene
|
||||||
|
{
|
||||||
|
if (selection.Contains(node.ParentNode))
|
||||||
|
{
|
||||||
|
continue; // If parent and child nodes selected together, don't touch child nodes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put created node as child of the Parent Node of node
|
||||||
|
int parentOrder = node.Actor.OrderInParent;
|
||||||
|
actor.Parent = node.Actor.Parent;
|
||||||
|
actor.OrderInParent = parentOrder;
|
||||||
|
}
|
||||||
|
node.Actor.Parent = actor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Editor.SceneEditing.Select(actor);
|
||||||
|
Editor.Scene.GetActorNode(actor).TreeNode.StartRenaming(Editor.Windows.SceneWin, Editor.Windows.SceneWin.SceneTreePanel);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Duplicates the selected objects. Supports undo/redo.
|
/// Duplicates the selected objects. Supports undo/redo.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ namespace FlaxEditor.Modules
|
|||||||
private ContextMenuButton _menuEditCut;
|
private ContextMenuButton _menuEditCut;
|
||||||
private ContextMenuButton _menuEditCopy;
|
private ContextMenuButton _menuEditCopy;
|
||||||
private ContextMenuButton _menuEditPaste;
|
private ContextMenuButton _menuEditPaste;
|
||||||
|
private ContextMenuButton _menuCreateParentForSelectedActors;
|
||||||
private ContextMenuButton _menuEditDelete;
|
private ContextMenuButton _menuEditDelete;
|
||||||
private ContextMenuButton _menuEditDuplicate;
|
private ContextMenuButton _menuEditDuplicate;
|
||||||
private ContextMenuButton _menuEditSelectAll;
|
private ContextMenuButton _menuEditSelectAll;
|
||||||
@@ -548,11 +549,11 @@ namespace FlaxEditor.Modules
|
|||||||
_menuEditCut = cm.AddButton("Cut", inputOptions.Cut, Editor.SceneEditing.Cut);
|
_menuEditCut = cm.AddButton("Cut", inputOptions.Cut, Editor.SceneEditing.Cut);
|
||||||
_menuEditCopy = cm.AddButton("Copy", inputOptions.Copy, Editor.SceneEditing.Copy);
|
_menuEditCopy = cm.AddButton("Copy", inputOptions.Copy, Editor.SceneEditing.Copy);
|
||||||
_menuEditPaste = cm.AddButton("Paste", inputOptions.Paste, Editor.SceneEditing.Paste);
|
_menuEditPaste = cm.AddButton("Paste", inputOptions.Paste, Editor.SceneEditing.Paste);
|
||||||
cm.AddSeparator();
|
|
||||||
_menuEditDelete = cm.AddButton("Delete", inputOptions.Delete, Editor.SceneEditing.Delete);
|
_menuEditDelete = cm.AddButton("Delete", inputOptions.Delete, Editor.SceneEditing.Delete);
|
||||||
_menuEditDuplicate = cm.AddButton("Duplicate", inputOptions.Duplicate, Editor.SceneEditing.Duplicate);
|
_menuEditDuplicate = cm.AddButton("Duplicate", inputOptions.Duplicate, Editor.SceneEditing.Duplicate);
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
_menuEditSelectAll = cm.AddButton("Select all", inputOptions.SelectAll, Editor.SceneEditing.SelectAllScenes);
|
_menuEditSelectAll = cm.AddButton("Select all", inputOptions.SelectAll, Editor.SceneEditing.SelectAllScenes);
|
||||||
|
_menuCreateParentForSelectedActors = cm.AddButton("Create parent for selected actors", Editor.SceneEditing.CreateParentForSelectedActors);
|
||||||
_menuEditFind = cm.AddButton("Find", inputOptions.Search, Editor.Windows.SceneWin.Search);
|
_menuEditFind = cm.AddButton("Find", inputOptions.Search, Editor.Windows.SceneWin.Search);
|
||||||
cm.AddSeparator();
|
cm.AddSeparator();
|
||||||
cm.AddButton("Game Settings", () =>
|
cm.AddButton("Game Settings", () =>
|
||||||
@@ -858,6 +859,7 @@ namespace FlaxEditor.Modules
|
|||||||
_menuEditCut.Enabled = hasSthSelected;
|
_menuEditCut.Enabled = hasSthSelected;
|
||||||
_menuEditCopy.Enabled = hasSthSelected;
|
_menuEditCopy.Enabled = hasSthSelected;
|
||||||
_menuEditPaste.Enabled = canEditScene;
|
_menuEditPaste.Enabled = canEditScene;
|
||||||
|
_menuCreateParentForSelectedActors.Enabled = canEditScene && hasSthSelected;
|
||||||
_menuEditDelete.Enabled = hasSthSelected;
|
_menuEditDelete.Enabled = hasSthSelected;
|
||||||
_menuEditDuplicate.Enabled = hasSthSelected;
|
_menuEditDuplicate.Enabled = hasSthSelected;
|
||||||
_menuEditSelectAll.Enabled = Level.IsAnySceneLoaded;
|
_menuEditSelectAll.Enabled = Level.IsAnySceneLoaded;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace FlaxEditor.SceneGraph.Actors
|
|||||||
base.OnDebugDraw(data);
|
base.OnDebugDraw(data);
|
||||||
|
|
||||||
var transform = Actor.Transform;
|
var transform = Actor.Transform;
|
||||||
DebugDraw.DrawWireArrow(transform.Translation, transform.Orientation, 1.0f, Color.Red, 0.0f, false);
|
DebugDraw.DrawWireArrow(transform.Translation, transform.Orientation, 1.0f, 0.5f, Color.Red, 0.0f, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace FlaxEditor.SceneGraph.Actors
|
|||||||
base.OnDebugDraw(data);
|
base.OnDebugDraw(data);
|
||||||
|
|
||||||
var transform = Actor.Transform;
|
var transform = Actor.Transform;
|
||||||
DebugDraw.DrawWireArrow(transform.Translation, transform.Orientation, 0.3f, Color.Red, 0.0f, false);
|
DebugDraw.DrawWireArrow(transform.Translation, transform.Orientation, 0.3f, 0.15f, Color.Red, 0.0f, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -482,7 +482,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
var startPos = PointToParent(ref center);
|
var startPos = PointToParent(ref center);
|
||||||
targetState.GetConnectionEndPoint(ref startPos, out var endPos);
|
targetState.GetConnectionEndPoint(ref startPos, out var endPos);
|
||||||
var color = style.Foreground;
|
var color = style.Foreground;
|
||||||
StateMachineState.DrawConnection(ref startPos, ref endPos, ref color);
|
SurfaceStyle.DrawStraightConnection(startPos, endPos, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,7 +512,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void DrawConnectingLine(ref Float2 startPos, ref Float2 endPos, ref Color color)
|
public void DrawConnectingLine(ref Float2 startPos, ref Float2 endPos, ref Color color)
|
||||||
{
|
{
|
||||||
StateMachineState.DrawConnection(ref startPos, ref endPos, ref color);
|
SurfaceStyle.DrawStraightConnection(startPos, endPos, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -676,38 +676,6 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Draws the connection between two state machine nodes.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="startPos">The start position.</param>
|
|
||||||
/// <param name="endPos">The end position.</param>
|
|
||||||
/// <param name="color">The line color.</param>
|
|
||||||
public static void DrawConnection(ref Float2 startPos, ref Float2 endPos, ref Color color)
|
|
||||||
{
|
|
||||||
var sub = endPos - startPos;
|
|
||||||
var length = sub.Length;
|
|
||||||
if (length > Mathf.Epsilon)
|
|
||||||
{
|
|
||||||
var dir = sub / length;
|
|
||||||
var arrowRect = new Rectangle(0, 0, 16.0f, 16.0f);
|
|
||||||
float rotation = Float2.Dot(dir, Float2.UnitY);
|
|
||||||
if (endPos.X < startPos.X)
|
|
||||||
rotation = 2 - rotation;
|
|
||||||
var sprite = Editor.Instance.Icons.VisjectArrowClosed32;
|
|
||||||
var arrowTransform =
|
|
||||||
Matrix3x3.Translation2D(-6.5f, -8) *
|
|
||||||
Matrix3x3.RotationZ(rotation * Mathf.PiOverTwo) *
|
|
||||||
Matrix3x3.Translation2D(endPos - dir * 8);
|
|
||||||
|
|
||||||
Render2D.PushTransform(ref arrowTransform);
|
|
||||||
Render2D.DrawSprite(sprite, arrowRect, color);
|
|
||||||
Render2D.PopTransform();
|
|
||||||
|
|
||||||
endPos -= dir * 4.0f;
|
|
||||||
}
|
|
||||||
Render2D.DrawLine(startPos, endPos, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the connection end point for the given input position. Puts the end point near the edge of the node bounds.
|
/// Gets the connection end point for the given input position. Puts the end point near the edge of the node bounds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1308,7 +1276,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
isMouseOver = Float2.DistanceSquared(ref mousePosition, ref point) < 25.0f;
|
isMouseOver = Float2.DistanceSquared(ref mousePosition, ref point) < 25.0f;
|
||||||
}
|
}
|
||||||
var color = isMouseOver ? Color.Wheat : t.LineColor;
|
var color = isMouseOver ? Color.Wheat : t.LineColor;
|
||||||
DrawConnection(ref t.StartPos, ref t.EndPos, ref color);
|
SurfaceStyle.DrawStraightConnection(t.StartPos, t.EndPos, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1337,7 +1305,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void DrawConnectingLine(ref Float2 startPos, ref Float2 endPos, ref Color color)
|
public void DrawConnectingLine(ref Float2 startPos, ref Float2 endPos, ref Color color)
|
||||||
{
|
{
|
||||||
DrawConnection(ref startPos, ref endPos, ref color);
|
SurfaceStyle.DrawStraightConnection(startPos, endPos, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace FlaxEditor.Surface
|
|||||||
var editor = Editor.Instance;
|
var editor = Editor.Instance;
|
||||||
var style = SurfaceStyle.CreateStyleHandler(editor);
|
var style = SurfaceStyle.CreateStyleHandler(editor);
|
||||||
style.DrawBox = DrawBox;
|
style.DrawBox = DrawBox;
|
||||||
style.DrawConnection = DrawConnection;
|
style.DrawConnection = SurfaceStyle.DrawStraightConnection;
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,11 +49,6 @@ namespace FlaxEditor.Surface
|
|||||||
Render2D.FillRectangle(rect, color);
|
Render2D.FillRectangle(rect, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DrawConnection(Float2 start, Float2 end, Color color, float thickness)
|
|
||||||
{
|
|
||||||
Archetypes.Animation.StateMachineStateBase.DrawConnection(ref start, ref end, ref color);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnActiveContextMenuVisibleChanged(Control activeCM)
|
private void OnActiveContextMenuVisibleChanged(Control activeCM)
|
||||||
{
|
{
|
||||||
_nodesCache.Wait();
|
_nodesCache.Wait();
|
||||||
|
|||||||
@@ -295,5 +295,38 @@ namespace FlaxEditor.Surface
|
|||||||
Background = editor.UI.VisjectSurfaceBackground,
|
Background = editor.UI.VisjectSurfaceBackground,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draws a simple straight connection between two locations.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="startPos">The start position.</param>
|
||||||
|
/// <param name="endPos">The end position.</param>
|
||||||
|
/// <param name="color">The line color.</param>
|
||||||
|
/// <param name="thickness">The line thickness.</param>
|
||||||
|
public static void DrawStraightConnection(Float2 startPos, Float2 endPos, Color color, float thickness = 1.0f)
|
||||||
|
{
|
||||||
|
var sub = endPos - startPos;
|
||||||
|
var length = sub.Length;
|
||||||
|
if (length > Mathf.Epsilon)
|
||||||
|
{
|
||||||
|
var dir = sub / length;
|
||||||
|
var arrowRect = new Rectangle(0, 0, 16.0f, 16.0f);
|
||||||
|
float rotation = Float2.Dot(dir, Float2.UnitY);
|
||||||
|
if (endPos.X < startPos.X)
|
||||||
|
rotation = 2 - rotation;
|
||||||
|
var sprite = Editor.Instance.Icons.VisjectArrowClosed32;
|
||||||
|
var arrowTransform =
|
||||||
|
Matrix3x3.Translation2D(-6.5f, -8) *
|
||||||
|
Matrix3x3.RotationZ(rotation * Mathf.PiOverTwo) *
|
||||||
|
Matrix3x3.Translation2D(endPos - dir * 8);
|
||||||
|
|
||||||
|
Render2D.PushTransform(ref arrowTransform);
|
||||||
|
Render2D.DrawSprite(sprite, arrowRect, color);
|
||||||
|
Render2D.PopTransform();
|
||||||
|
|
||||||
|
endPos -= dir * 4.0f;
|
||||||
|
}
|
||||||
|
Render2D.DrawLine(startPos, endPos, color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,15 @@ namespace FlaxEditor.Surface
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Utility for easy nodes archetypes generation for Visject Surface based on scripting types.
|
/// Utility for easy nodes archetypes generation for Visject Surface based on scripting types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class NodesCache
|
[HideInEditor]
|
||||||
|
public class NodesCache
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Delegate for scripting types filtering into cache.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="scriptType">The input type to process.</param>
|
||||||
|
/// <param name="cache">Node groups cache that can be used for reusing groups for different nodes.</param>
|
||||||
|
/// <param name="version">The cache version number. Can be used to reject any cached data after <see cref="NodesCache"/> rebuilt.</param>
|
||||||
public delegate void IterateType(ScriptType scriptType, Dictionary<KeyValuePair<string, ushort>, GroupArchetype> cache, int version);
|
public delegate void IterateType(ScriptType scriptType, Dictionary<KeyValuePair<string, ushort>, GroupArchetype> cache, int version);
|
||||||
|
|
||||||
internal static readonly List<NodesCache> Caches = new List<NodesCache>(8);
|
internal static readonly List<NodesCache> Caches = new List<NodesCache>(8);
|
||||||
@@ -33,11 +40,18 @@ namespace FlaxEditor.Surface
|
|||||||
private VisjectCM _taskContextMenu;
|
private VisjectCM _taskContextMenu;
|
||||||
private Dictionary<KeyValuePair<string, ushort>, GroupArchetype> _cache;
|
private Dictionary<KeyValuePair<string, ushort>, GroupArchetype> _cache;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="NodesCache"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="iterator">The iterator callback to build node types from Scripting.</param>
|
||||||
public NodesCache(IterateType iterator)
|
public NodesCache(IterateType iterator)
|
||||||
{
|
{
|
||||||
_iterator = iterator;
|
_iterator = iterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Waits for the async caching job to finish.
|
||||||
|
/// </summary>
|
||||||
public void Wait()
|
public void Wait()
|
||||||
{
|
{
|
||||||
if (_task != null)
|
if (_task != null)
|
||||||
@@ -48,6 +62,9 @@ namespace FlaxEditor.Surface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears cache.
|
||||||
|
/// </summary>
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
Wait();
|
Wait();
|
||||||
@@ -62,6 +79,10 @@ namespace FlaxEditor.Surface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the Visject Context Menu to contain current nodes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="contextMenu">The output context menu to setup.</param>
|
||||||
public void Get(VisjectCM contextMenu)
|
public void Get(VisjectCM contextMenu)
|
||||||
{
|
{
|
||||||
Profiler.BeginEvent("Setup Context Menu");
|
Profiler.BeginEvent("Setup Context Menu");
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace FlaxEditor.Surface
|
|||||||
/// The base interface for editor windows that use <see cref="FlaxEditor.Surface.VisjectSurface"/> for content editing.
|
/// The base interface for editor windows that use <see cref="FlaxEditor.Surface.VisjectSurface"/> for content editing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="FlaxEditor.Surface.IVisjectSurfaceOwner" />
|
/// <seealso cref="FlaxEditor.Surface.IVisjectSurfaceOwner" />
|
||||||
interface IVisjectSurfaceWindow : IVisjectSurfaceOwner
|
public interface IVisjectSurfaceWindow : IVisjectSurfaceOwner
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the asset edited by the window.
|
/// Gets the asset edited by the window.
|
||||||
|
|||||||
@@ -43,6 +43,19 @@ namespace FlaxEngine.Tools
|
|||||||
/// Enables continuous painting, otherwise single paint on click.
|
/// Enables continuous painting, otherwise single paint on click.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ContinuousPaint;
|
public bool ContinuousPaint;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables drawing cloth paint debugging with Depth Test enabled (skips occluded vertices).
|
||||||
|
/// </summary>
|
||||||
|
public bool DebugDrawDepthTest
|
||||||
|
{
|
||||||
|
get => Gizmo.Cloth?.DebugDrawDepthTest ?? true;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (Gizmo.Cloth != null)
|
||||||
|
Gizmo.Cloth.DebugDrawDepthTest = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
#pragma warning restore CS0649
|
#pragma warning restore CS0649
|
||||||
|
|
||||||
public override void Init(IGizmoOwner owner)
|
public override void Init(IGizmoOwner owner)
|
||||||
@@ -62,6 +75,7 @@ namespace FlaxEngine.Tools
|
|||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
Owner.Gizmos.Remove(Gizmo);
|
Owner.Gizmos.Remove(Gizmo);
|
||||||
|
Gizmo = null;
|
||||||
|
|
||||||
base.Dispose();
|
base.Dispose();
|
||||||
}
|
}
|
||||||
@@ -83,6 +97,7 @@ namespace FlaxEngine.Tools
|
|||||||
private EditClothPaintAction _undoAction;
|
private EditClothPaintAction _undoAction;
|
||||||
|
|
||||||
public bool IsPainting => _isPainting;
|
public bool IsPainting => _isPainting;
|
||||||
|
public Cloth Cloth => _cloth;
|
||||||
|
|
||||||
public ClothPaintingGizmo(IGizmoOwner owner, ClothPaintingGizmoMode mode)
|
public ClothPaintingGizmo(IGizmoOwner owner, ClothPaintingGizmoMode mode)
|
||||||
: base(owner)
|
: base(owner)
|
||||||
|
|||||||
@@ -45,9 +45,6 @@ namespace FlaxEditor.Tools.Terrain
|
|||||||
[EditorOrder(130), EditorDisplay("Layout"), DefaultValue(null), Tooltip("The default material used for terrain rendering (chunks can override this). It must have Domain set to terrain.")]
|
[EditorOrder(130), EditorDisplay("Layout"), DefaultValue(null), Tooltip("The default material used for terrain rendering (chunks can override this). It must have Domain set to terrain.")]
|
||||||
public MaterialBase Material;
|
public MaterialBase Material;
|
||||||
|
|
||||||
[EditorOrder(200), EditorDisplay("Collision"), DefaultValue(null), AssetReference(typeof(PhysicalMaterial), true), Tooltip("Terrain default physical material used to define the collider physical properties.")]
|
|
||||||
public JsonAsset PhysicalMaterial;
|
|
||||||
|
|
||||||
[EditorOrder(210), EditorDisplay("Collision", "Collision LOD"), DefaultValue(-1), Limit(-1, 100, 0.1f), Tooltip("Terrain geometry LOD index used for collision.")]
|
[EditorOrder(210), EditorDisplay("Collision", "Collision LOD"), DefaultValue(-1), Limit(-1, 100, 0.1f), Tooltip("Terrain geometry LOD index used for collision.")]
|
||||||
public int CollisionLOD = -1;
|
public int CollisionLOD = -1;
|
||||||
|
|
||||||
@@ -152,7 +149,6 @@ namespace FlaxEditor.Tools.Terrain
|
|||||||
terrain.Setup(_options.LODCount, (int)_options.ChunkSize);
|
terrain.Setup(_options.LODCount, (int)_options.ChunkSize);
|
||||||
terrain.Transform = new Transform(_options.Position, _options.Orientation, _options.Scale);
|
terrain.Transform = new Transform(_options.Position, _options.Orientation, _options.Scale);
|
||||||
terrain.Material = _options.Material;
|
terrain.Material = _options.Material;
|
||||||
terrain.PhysicalMaterial = _options.PhysicalMaterial;
|
|
||||||
terrain.CollisionLOD = _options.CollisionLOD;
|
terrain.CollisionLOD = _options.CollisionLOD;
|
||||||
if (_options.Heightmap)
|
if (_options.Heightmap)
|
||||||
terrain.Position -= new Vector3(0, _options.HeightmapScale * 0.5f, 0);
|
terrain.Position -= new Vector3(0, _options.HeightmapScale * 0.5f, 0);
|
||||||
|
|||||||
@@ -67,11 +67,13 @@ namespace FlaxEditor.Tools.Terrain.Paint
|
|||||||
|
|
||||||
// Prepare
|
// Prepare
|
||||||
var splatmapIndex = ActiveSplatmapIndex;
|
var splatmapIndex = ActiveSplatmapIndex;
|
||||||
|
var splatmapIndexOther = (splatmapIndex + 1) % 2;
|
||||||
var chunkSize = terrain.ChunkSize;
|
var chunkSize = terrain.ChunkSize;
|
||||||
var heightmapSize = chunkSize * FlaxEngine.Terrain.PatchEdgeChunksCount + 1;
|
var heightmapSize = chunkSize * FlaxEngine.Terrain.PatchEdgeChunksCount + 1;
|
||||||
var heightmapLength = heightmapSize * heightmapSize;
|
var heightmapLength = heightmapSize * heightmapSize;
|
||||||
var patchSize = chunkSize * FlaxEngine.Terrain.UnitsPerVertex * FlaxEngine.Terrain.PatchEdgeChunksCount;
|
var patchSize = chunkSize * FlaxEngine.Terrain.UnitsPerVertex * FlaxEngine.Terrain.PatchEdgeChunksCount;
|
||||||
var tempBuffer = (Color32*)gizmo.GetSplatmapTempBuffer(heightmapLength * Color32.SizeInBytes).ToPointer();
|
var tempBuffer = (Color32*)gizmo.GetSplatmapTempBuffer(heightmapLength * Color32.SizeInBytes, splatmapIndex).ToPointer();
|
||||||
|
var tempBufferOther = (Color32*)gizmo.GetSplatmapTempBuffer(heightmapLength * Color32.SizeInBytes, (splatmapIndex + 1) % 2).ToPointer();
|
||||||
var unitsPerVertexInv = 1.0f / FlaxEngine.Terrain.UnitsPerVertex;
|
var unitsPerVertexInv = 1.0f / FlaxEngine.Terrain.UnitsPerVertex;
|
||||||
ApplyParams p = new ApplyParams
|
ApplyParams p = new ApplyParams
|
||||||
{
|
{
|
||||||
@@ -81,8 +83,10 @@ namespace FlaxEditor.Tools.Terrain.Paint
|
|||||||
Options = options,
|
Options = options,
|
||||||
Strength = strength,
|
Strength = strength,
|
||||||
SplatmapIndex = splatmapIndex,
|
SplatmapIndex = splatmapIndex,
|
||||||
|
SplatmapIndexOther = splatmapIndexOther,
|
||||||
HeightmapSize = heightmapSize,
|
HeightmapSize = heightmapSize,
|
||||||
TempBuffer = tempBuffer,
|
TempBuffer = tempBuffer,
|
||||||
|
TempBufferOther = tempBufferOther,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get brush bounds in terrain local space
|
// Get brush bounds in terrain local space
|
||||||
@@ -132,10 +136,15 @@ namespace FlaxEditor.Tools.Terrain.Paint
|
|||||||
if (sourceData == null)
|
if (sourceData == null)
|
||||||
throw new Exception("Cannot modify terrain. Loading splatmap failed. See log for more info.");
|
throw new Exception("Cannot modify terrain. Loading splatmap failed. See log for more info.");
|
||||||
|
|
||||||
|
var sourceDataOther = TerrainTools.GetSplatMapData(terrain, ref patch.PatchCoord, splatmapIndexOther);
|
||||||
|
if (sourceDataOther == null)
|
||||||
|
throw new Exception("Cannot modify terrain. Loading splatmap failed. See log for more info.");
|
||||||
|
|
||||||
// Record patch data before editing it
|
// Record patch data before editing it
|
||||||
if (!gizmo.CurrentEditUndoAction.HashPatch(ref patch.PatchCoord))
|
if (!gizmo.CurrentEditUndoAction.HashPatch(ref patch.PatchCoord))
|
||||||
{
|
{
|
||||||
gizmo.CurrentEditUndoAction.AddPatch(ref patch.PatchCoord, splatmapIndex);
|
gizmo.CurrentEditUndoAction.AddPatch(ref patch.PatchCoord, splatmapIndex);
|
||||||
|
gizmo.CurrentEditUndoAction.AddPatch(ref patch.PatchCoord, splatmapIndexOther);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply modification
|
// Apply modification
|
||||||
@@ -144,6 +153,7 @@ namespace FlaxEditor.Tools.Terrain.Paint
|
|||||||
p.PatchCoord = patch.PatchCoord;
|
p.PatchCoord = patch.PatchCoord;
|
||||||
p.PatchPositionLocal = patchPositionLocal;
|
p.PatchPositionLocal = patchPositionLocal;
|
||||||
p.SourceData = sourceData;
|
p.SourceData = sourceData;
|
||||||
|
p.SourceDataOther = sourceDataOther;
|
||||||
Apply(ref p);
|
Apply(ref p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,16 +208,32 @@ namespace FlaxEditor.Tools.Terrain.Paint
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int SplatmapIndex;
|
public int SplatmapIndex;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The splatmap texture index. If <see cref="SplatmapIndex"/> is 0, this will be 1. If <see cref="SplatmapIndex"/> is 1, this will be 0.
|
||||||
|
/// </summary>
|
||||||
|
public int SplatmapIndexOther;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The temporary data buffer (for modified data).
|
/// The temporary data buffer (for modified data).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Color32* TempBuffer;
|
public Color32* TempBuffer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The 'other' temporary data buffer (for modified data). If <see cref="TempBuffer"/> refersto the splatmap with index 0, this one will refer to the one with index 1.
|
||||||
|
/// </summary>
|
||||||
|
public Color32* TempBufferOther;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The source data buffer.
|
/// The source data buffer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Color32* SourceData;
|
public Color32* SourceData;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The 'other' source data buffer. If <see cref="SourceData"/> refers
|
||||||
|
/// to the splatmap with index 0, this one will refer to the one with index 1.
|
||||||
|
/// </summary>
|
||||||
|
public Color32* SourceDataOther;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The heightmap size (edge).
|
/// The heightmap size (edge).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using System;
|
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
|
|
||||||
namespace FlaxEditor.Tools.Terrain.Paint
|
namespace FlaxEditor.Tools.Terrain.Paint
|
||||||
@@ -73,53 +72,53 @@ namespace FlaxEditor.Tools.Terrain.Paint
|
|||||||
var strength = p.Strength;
|
var strength = p.Strength;
|
||||||
var layer = (int)Layer;
|
var layer = (int)Layer;
|
||||||
var brushPosition = p.Gizmo.CursorPosition;
|
var brushPosition = p.Gizmo.CursorPosition;
|
||||||
var layerComponent = layer % 4;
|
var c = layer % 4;
|
||||||
|
|
||||||
// Apply brush modification
|
// Apply brush modification
|
||||||
Profiler.BeginEvent("Apply Brush");
|
Profiler.BeginEvent("Apply Brush");
|
||||||
|
bool otherModified = false;
|
||||||
for (int z = 0; z < p.ModifiedSize.Y; z++)
|
for (int z = 0; z < p.ModifiedSize.Y; z++)
|
||||||
{
|
{
|
||||||
var zz = z + p.ModifiedOffset.Y;
|
var zz = z + p.ModifiedOffset.Y;
|
||||||
for (int x = 0; x < p.ModifiedSize.X; x++)
|
for (int x = 0; x < p.ModifiedSize.X; x++)
|
||||||
{
|
{
|
||||||
var xx = x + p.ModifiedOffset.X;
|
var xx = x + p.ModifiedOffset.X;
|
||||||
var src = p.SourceData[zz * p.HeightmapSize + xx];
|
var src = (Color)p.SourceData[zz * p.HeightmapSize + xx];
|
||||||
|
|
||||||
var samplePositionLocal = p.PatchPositionLocal + new Vector3(xx * FlaxEngine.Terrain.UnitsPerVertex, 0, zz * FlaxEngine.Terrain.UnitsPerVertex);
|
var samplePositionLocal = p.PatchPositionLocal + new Vector3(xx * FlaxEngine.Terrain.UnitsPerVertex, 0, zz * FlaxEngine.Terrain.UnitsPerVertex);
|
||||||
Vector3.Transform(ref samplePositionLocal, ref p.TerrainWorld, out Vector3 samplePositionWorld);
|
Vector3.Transform(ref samplePositionLocal, ref p.TerrainWorld, out Vector3 samplePositionWorld);
|
||||||
|
var sample = Mathf.Saturate(p.Brush.Sample(ref brushPosition, ref samplePositionWorld));
|
||||||
|
|
||||||
var paintAmount = p.Brush.Sample(ref brushPosition, ref samplePositionWorld) * strength;
|
var paintAmount = sample * strength;
|
||||||
|
if (paintAmount < 0.0f)
|
||||||
|
continue; // Skip when pixel won't be affected
|
||||||
|
|
||||||
// Extract layer weight
|
// Paint on the active splatmap texture
|
||||||
byte* srcPtr = &src.R;
|
src[c] = Mathf.Saturate(src[c] + paintAmount);
|
||||||
var srcWeight = *(srcPtr + layerComponent) / 255.0f;
|
src[(c + 1) % 4] = Mathf.Saturate(src[(c + 1) % 4] - paintAmount);
|
||||||
|
src[(c + 2) % 4] = Mathf.Saturate(src[(c + 2) % 4] - paintAmount);
|
||||||
// Accumulate weight
|
src[(c + 3) % 4] = Mathf.Saturate(src[(c + 3) % 4] - paintAmount);
|
||||||
float dstWeight = srcWeight + paintAmount;
|
|
||||||
|
|
||||||
// Check for solid layer case
|
|
||||||
if (dstWeight >= 1.0f)
|
|
||||||
{
|
|
||||||
// Erase other layers
|
|
||||||
// TODO: maybe erase only the higher layers?
|
|
||||||
// TODO: need to erase also weights form the other splatmaps
|
|
||||||
src = Color32.Transparent;
|
|
||||||
|
|
||||||
// Use limit value
|
|
||||||
dstWeight = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Modify packed weight
|
|
||||||
*(srcPtr + layerComponent) = (byte)(dstWeight * 255.0f);
|
|
||||||
|
|
||||||
// Write back
|
|
||||||
p.TempBuffer[z * p.ModifiedSize.X + x] = src;
|
p.TempBuffer[z * p.ModifiedSize.X + x] = src;
|
||||||
|
|
||||||
|
var other = (Color)p.SourceDataOther[zz * p.HeightmapSize + xx];
|
||||||
|
//if (other.ValuesSum > 0.0f) // Skip editing the other splatmap if it's empty
|
||||||
|
{
|
||||||
|
// Remove 'paint' from the other splatmap texture
|
||||||
|
other[c] = Mathf.Saturate(other[c] - paintAmount);
|
||||||
|
other[(c + 1) % 4] = Mathf.Saturate(other[(c + 1) % 4] - paintAmount);
|
||||||
|
other[(c + 2) % 4] = Mathf.Saturate(other[(c + 2) % 4] - paintAmount);
|
||||||
|
other[(c + 3) % 4] = Mathf.Saturate(other[(c + 3) % 4] - paintAmount);
|
||||||
|
p.TempBufferOther[z * p.ModifiedSize.X + x] = other;
|
||||||
|
otherModified = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Profiler.EndEvent();
|
Profiler.EndEvent();
|
||||||
|
|
||||||
// Update terrain patch
|
// Update terrain patch
|
||||||
TerrainTools.ModifySplatMap(p.Terrain, ref p.PatchCoord, p.SplatmapIndex, p.TempBuffer, ref p.ModifiedOffset, ref p.ModifiedSize);
|
TerrainTools.ModifySplatMap(p.Terrain, ref p.PatchCoord, p.SplatmapIndex, p.TempBuffer, ref p.ModifiedOffset, ref p.ModifiedSize);
|
||||||
|
if (otherModified)
|
||||||
|
TerrainTools.ModifySplatMap(p.Terrain, ref p.PatchCoord, p.SplatmapIndexOther, p.TempBufferOther, ref p.ModifiedOffset, ref p.ModifiedSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,9 +36,34 @@ namespace FlaxEditor.Tools.Terrain
|
|||||||
"Layer 7",
|
"Layer 7",
|
||||||
};
|
};
|
||||||
|
|
||||||
private IntPtr _cachedSplatmapData;
|
private struct SplatmapData
|
||||||
private int _cachedSplatmapDataSize;
|
{
|
||||||
|
public IntPtr DataPtr;
|
||||||
|
public int Size;
|
||||||
|
|
||||||
|
public void EnsureCapacity(int size)
|
||||||
|
{
|
||||||
|
if (Size < size)
|
||||||
|
{
|
||||||
|
if (DataPtr != IntPtr.Zero)
|
||||||
|
Marshal.FreeHGlobal(DataPtr);
|
||||||
|
DataPtr = Marshal.AllocHGlobal(size);
|
||||||
|
Size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Free()
|
||||||
|
{
|
||||||
|
if (DataPtr == IntPtr.Zero)
|
||||||
|
return;
|
||||||
|
Marshal.FreeHGlobal(DataPtr);
|
||||||
|
DataPtr = IntPtr.Zero;
|
||||||
|
Size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private EditTerrainMapAction _activeAction;
|
private EditTerrainMapAction _activeAction;
|
||||||
|
private SplatmapData[] _cachedSplatmapData = new SplatmapData[2];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The terrain painting gizmo.
|
/// The terrain painting gizmo.
|
||||||
@@ -230,20 +255,13 @@ namespace FlaxEditor.Tools.Terrain
|
|||||||
/// Gets the splatmap temporary scratch memory buffer used to modify terrain samples. Allocated memory is unmanaged by GC.
|
/// Gets the splatmap temporary scratch memory buffer used to modify terrain samples. Allocated memory is unmanaged by GC.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="size">The minimum buffer size (in bytes).</param>
|
/// <param name="size">The minimum buffer size (in bytes).</param>
|
||||||
|
/// <param name="splatmapIndex">The splatmap index for which to return/create the temp buffer.</param>
|
||||||
/// <returns>The allocated memory using <see cref="Marshal"/> interface.</returns>
|
/// <returns>The allocated memory using <see cref="Marshal"/> interface.</returns>
|
||||||
public IntPtr GetSplatmapTempBuffer(int size)
|
public IntPtr GetSplatmapTempBuffer(int size, int splatmapIndex)
|
||||||
{
|
{
|
||||||
if (_cachedSplatmapDataSize < size)
|
ref var splatmapData = ref _cachedSplatmapData[splatmapIndex];
|
||||||
{
|
splatmapData.EnsureCapacity(size);
|
||||||
if (_cachedSplatmapData != IntPtr.Zero)
|
return splatmapData.DataPtr;
|
||||||
{
|
|
||||||
Marshal.FreeHGlobal(_cachedSplatmapData);
|
|
||||||
}
|
|
||||||
_cachedSplatmapData = Marshal.AllocHGlobal(size);
|
|
||||||
_cachedSplatmapDataSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _cachedSplatmapData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -276,12 +294,8 @@ namespace FlaxEditor.Tools.Terrain
|
|||||||
base.OnDeactivated();
|
base.OnDeactivated();
|
||||||
|
|
||||||
// Free temporary memory buffer
|
// Free temporary memory buffer
|
||||||
if (_cachedSplatmapData != IntPtr.Zero)
|
foreach (var splatmapData in _cachedSplatmapData)
|
||||||
{
|
splatmapData.Free();
|
||||||
Marshal.FreeHGlobal(_cachedSplatmapData);
|
|
||||||
_cachedSplatmapData = IntPtr.Zero;
|
|
||||||
_cachedSplatmapDataSize = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ bool TerrainTools::TryGetPatchCoordToAdd(Terrain* terrain, const Ray& ray, Int2&
|
|||||||
{
|
{
|
||||||
CHECK_RETURN(terrain, true);
|
CHECK_RETURN(terrain, true);
|
||||||
result = Int2::Zero;
|
result = Int2::Zero;
|
||||||
const float patchSize = terrain->GetChunkSize() * TERRAIN_UNITS_PER_VERTEX * TerrainPatch::CHUNKS_COUNT_EDGE;
|
const float patchSize = terrain->GetChunkSize() * TERRAIN_UNITS_PER_VERTEX * Terrain::ChunksCountEdge;
|
||||||
|
|
||||||
// Try to pick any of the patch edges
|
// Try to pick any of the patch edges
|
||||||
for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++)
|
for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++)
|
||||||
@@ -179,7 +179,7 @@ bool TerrainTools::GenerateTerrain(Terrain* terrain, const Int2& numberOfPatches
|
|||||||
terrain->AddPatches(numberOfPatches);
|
terrain->AddPatches(numberOfPatches);
|
||||||
|
|
||||||
// Prepare data
|
// Prepare data
|
||||||
const auto heightmapSize = terrain->GetChunkSize() * TerrainPatch::CHUNKS_COUNT_EDGE + 1;
|
const auto heightmapSize = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1;
|
||||||
Array<float> heightmapData;
|
Array<float> heightmapData;
|
||||||
heightmapData.Resize(heightmapSize * heightmapSize);
|
heightmapData.Resize(heightmapSize * heightmapSize);
|
||||||
|
|
||||||
@@ -380,7 +380,7 @@ bool TerrainTools::ExportTerrain(Terrain* terrain, String outputFolder)
|
|||||||
const auto firstPatch = terrain->GetPatch(0);
|
const auto firstPatch = terrain->GetPatch(0);
|
||||||
|
|
||||||
// Calculate texture size
|
// Calculate texture size
|
||||||
const int32 patchEdgeVertexCount = terrain->GetChunkSize() * TerrainPatch::CHUNKS_COUNT_EDGE + 1;
|
const int32 patchEdgeVertexCount = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1;
|
||||||
const int32 patchVertexCount = patchEdgeVertexCount * patchEdgeVertexCount;
|
const int32 patchVertexCount = patchEdgeVertexCount * patchEdgeVertexCount;
|
||||||
|
|
||||||
// Find size of heightmap in patches
|
// Find size of heightmap in patches
|
||||||
|
|||||||
@@ -234,7 +234,6 @@ namespace FlaxEditor.Viewport
|
|||||||
LocalOrientation = RootNode.RaycastNormalRotation(ref hitNormal),
|
LocalOrientation = RootNode.RaycastNormalRotation(ref hitNormal),
|
||||||
Name = item.ShortName
|
Name = item.ShortName
|
||||||
};
|
};
|
||||||
DebugDraw.DrawWireArrow(PostProcessSpawnedActorLocation(actor, ref hitNormal), actor.LocalOrientation, 1.0f, Color.Red, 1000000);
|
|
||||||
Spawn(actor, ref hitLocation, ref hitNormal);
|
Spawn(actor, ref hitLocation, ref hitNormal);
|
||||||
}
|
}
|
||||||
else if (hit is StaticModelNode staticModelNode)
|
else if (hit is StaticModelNode staticModelNode)
|
||||||
|
|||||||
@@ -132,10 +132,13 @@ namespace FlaxEditor.Windows
|
|||||||
b = contextMenu.AddButton("Cut", inputOptions.Cut, Editor.SceneEditing.Cut);
|
b = contextMenu.AddButton("Cut", inputOptions.Cut, Editor.SceneEditing.Cut);
|
||||||
b.Enabled = canEditScene;
|
b.Enabled = canEditScene;
|
||||||
|
|
||||||
// Prefab options
|
// Create option
|
||||||
|
|
||||||
contextMenu.AddSeparator();
|
contextMenu.AddSeparator();
|
||||||
|
|
||||||
|
b = contextMenu.AddButton("Create parent for selected actors", Editor.SceneEditing.CreateParentForSelectedActors);
|
||||||
|
b.Enabled = canEditScene && hasSthSelected;
|
||||||
|
|
||||||
b = contextMenu.AddButton("Create Prefab", Editor.Prefabs.CreatePrefab);
|
b = contextMenu.AddButton("Create Prefab", Editor.Prefabs.CreatePrefab);
|
||||||
b.Enabled = isSingleActorSelected &&
|
b.Enabled = isSingleActorSelected &&
|
||||||
((ActorNode)Editor.SceneEditing.Selection[0]).CanCreatePrefab &&
|
((ActorNode)Editor.SceneEditing.Selection[0]).CanCreatePrefab &&
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using FlaxEditor.Gizmo;
|
using FlaxEditor.Gizmo;
|
||||||
using FlaxEditor.Content;
|
using FlaxEditor.Content;
|
||||||
using FlaxEditor.GUI.Tree;
|
using FlaxEditor.GUI.Tree;
|
||||||
@@ -14,7 +13,6 @@ using FlaxEditor.Scripting;
|
|||||||
using FlaxEditor.States;
|
using FlaxEditor.States;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
using static FlaxEditor.GUI.ItemsListContextMenu;
|
|
||||||
|
|
||||||
namespace FlaxEditor.Windows
|
namespace FlaxEditor.Windows
|
||||||
{
|
{
|
||||||
@@ -35,6 +33,11 @@ namespace FlaxEditor.Windows
|
|||||||
private DragScriptItems _dragScriptItems;
|
private DragScriptItems _dragScriptItems;
|
||||||
private DragHandlers _dragHandlers;
|
private DragHandlers _dragHandlers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Scene tree panel.
|
||||||
|
/// </summary>
|
||||||
|
public Panel SceneTreePanel => _sceneTreePanel;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="SceneTreeWindow"/> class.
|
/// Initializes a new instance of the <see cref="SceneTreeWindow"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ namespace FlaxEngine
|
|||||||
public string Path;
|
public string Path;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="BehaviorKnowledgeSelectorAny"/> structure.
|
/// Initializes a new instance of the <see cref="BehaviorKnowledgeSelector{T}"/> structure.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The selector path.</param>
|
/// <param name="path">The selector path.</param>
|
||||||
public BehaviorKnowledgeSelector(string path)
|
public BehaviorKnowledgeSelector(string path)
|
||||||
@@ -155,7 +155,7 @@ namespace FlaxEngine
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="BehaviorKnowledgeSelectorAny"/> structure.
|
/// Initializes a new instance of the <see cref="BehaviorKnowledgeSelector{T}"/> structure.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="other">The other selector.</param>
|
/// <param name="other">The other selector.</param>
|
||||||
public BehaviorKnowledgeSelector(BehaviorKnowledgeSelectorAny other)
|
public BehaviorKnowledgeSelector(BehaviorKnowledgeSelectorAny other)
|
||||||
|
|||||||
@@ -91,6 +91,13 @@ API_STRUCT(InBuild, Template, MarshalAs=StringAnsi) struct FLAXENGINE_API Behavi
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BehaviorKnowledgeSelector() = default;
|
||||||
|
|
||||||
|
BehaviorKnowledgeSelector(const StringAnsi& other)
|
||||||
|
{
|
||||||
|
Path = other;
|
||||||
|
}
|
||||||
|
|
||||||
BehaviorKnowledgeSelector& operator=(const StringAnsiView& other) noexcept
|
BehaviorKnowledgeSelector& operator=(const StringAnsiView& other) noexcept
|
||||||
{
|
{
|
||||||
Path = other;
|
Path = other;
|
||||||
|
|||||||
@@ -221,6 +221,7 @@ void AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt)
|
|||||||
context.NodePath.Clear();
|
context.NodePath.Clear();
|
||||||
context.Data = &data;
|
context.Data = &data;
|
||||||
context.DeltaTime = dt;
|
context.DeltaTime = dt;
|
||||||
|
context.StackOverFlow = false;
|
||||||
context.CurrentFrameIndex = ++data.CurrentFrame;
|
context.CurrentFrameIndex = ++data.CurrentFrame;
|
||||||
context.CallStack.Clear();
|
context.CallStack.Clear();
|
||||||
context.Functions.Clear();
|
context.Functions.Clear();
|
||||||
@@ -411,9 +412,12 @@ VisjectExecutor::Value AnimGraphExecutor::eatBox(Node* caller, Box* box)
|
|||||||
auto& context = *Context.Get();
|
auto& context = *Context.Get();
|
||||||
|
|
||||||
// Check if graph is looped or is too deep
|
// Check if graph is looped or is too deep
|
||||||
|
if (context.StackOverFlow)
|
||||||
|
return Value::Zero;
|
||||||
if (context.CallStack.Count() >= ANIM_GRAPH_MAX_CALL_STACK)
|
if (context.CallStack.Count() >= ANIM_GRAPH_MAX_CALL_STACK)
|
||||||
{
|
{
|
||||||
OnError(caller, box, TEXT("Graph is looped or too deep!"));
|
OnError(caller, box, TEXT("Graph is looped or too deep!"));
|
||||||
|
context.StackOverFlow = true;
|
||||||
return Value::Zero;
|
return Value::Zero;
|
||||||
}
|
}
|
||||||
#if !BUILD_RELEASE
|
#if !BUILD_RELEASE
|
||||||
|
|||||||
@@ -796,6 +796,7 @@ struct AnimGraphContext
|
|||||||
AnimGraphInstanceData* Data;
|
AnimGraphInstanceData* Data;
|
||||||
AnimGraphImpulse EmptyNodes;
|
AnimGraphImpulse EmptyNodes;
|
||||||
AnimGraphTransitionData TransitionData;
|
AnimGraphTransitionData TransitionData;
|
||||||
|
bool StackOverFlow;
|
||||||
Array<VisjectExecutor::Node*, FixedAllocation<ANIM_GRAPH_MAX_CALL_STACK>> CallStack;
|
Array<VisjectExecutor::Node*, FixedAllocation<ANIM_GRAPH_MAX_CALL_STACK>> CallStack;
|
||||||
Array<VisjectExecutor::Graph*, FixedAllocation<32>> GraphStack;
|
Array<VisjectExecutor::Graph*, FixedAllocation<32>> GraphStack;
|
||||||
Array<uint32, FixedAllocation<ANIM_GRAPH_MAX_CALL_STACK> > NodePath;
|
Array<uint32, FixedAllocation<ANIM_GRAPH_MAX_CALL_STACK> > NodePath;
|
||||||
|
|||||||
@@ -277,6 +277,8 @@ bool Content::GetAssetInfo(const StringView& path, AssetInfo& info)
|
|||||||
// Find asset in registry
|
// Find asset in registry
|
||||||
if (Cache.FindAsset(path, info))
|
if (Cache.FindAsset(path, info))
|
||||||
return true;
|
return true;
|
||||||
|
if (!FileSystem::FileExists(path))
|
||||||
|
return false;
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
|
|
||||||
const auto extension = FileSystem::GetExtension(path).ToLower();
|
const auto extension = FileSystem::GetExtension(path).ToLower();
|
||||||
|
|||||||
@@ -393,35 +393,58 @@ bool JsonAsset::CreateInstance()
|
|||||||
if (typeHandle)
|
if (typeHandle)
|
||||||
{
|
{
|
||||||
auto& type = typeHandle.GetType();
|
auto& type = typeHandle.GetType();
|
||||||
switch (type.Type)
|
|
||||||
{
|
|
||||||
case ScriptingTypes::Class:
|
|
||||||
{
|
|
||||||
// Ensure that object can deserialized
|
// Ensure that object can deserialized
|
||||||
const ScriptingType::InterfaceImplementation* interface = type.GetInterface(ISerializable::TypeInitializer);
|
const ScriptingType::InterfaceImplementation* interface = type.GetInterface(ISerializable::TypeInitializer);
|
||||||
if (!interface)
|
if (!interface)
|
||||||
{
|
{
|
||||||
LOG(Warning, "Cannot deserialize {0} from Json Asset because it doesn't implement ISerializable interface.", type.ToString());
|
LOG(Warning, "Cannot deserialize {0} from Json Asset because it doesn't implement ISerializable interface.", type.ToString());
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
|
auto modifier = Cache::ISerializeModifier.Get();
|
||||||
|
modifier->EngineBuild = DataEngineBuild;
|
||||||
|
|
||||||
// Allocate object
|
// Create object
|
||||||
|
switch (type.Type)
|
||||||
|
{
|
||||||
|
case ScriptingTypes::Class:
|
||||||
|
case ScriptingTypes::Structure:
|
||||||
|
{
|
||||||
const auto instance = Allocator::Allocate(type.Size);
|
const auto instance = Allocator::Allocate(type.Size);
|
||||||
if (!instance)
|
if (!instance)
|
||||||
return true;
|
return true;
|
||||||
Instance = instance;
|
Instance = instance;
|
||||||
InstanceType = typeHandle;
|
if (type.Type == ScriptingTypes::Class)
|
||||||
|
{
|
||||||
_dtor = type.Class.Dtor;
|
_dtor = type.Class.Dtor;
|
||||||
type.Class.Ctor(instance);
|
type.Class.Ctor(instance);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_dtor = type.Struct.Dtor;
|
||||||
|
type.Struct.Ctor(instance);
|
||||||
|
}
|
||||||
|
|
||||||
// Deserialize object
|
// Deserialize object
|
||||||
auto modifier = Cache::ISerializeModifier.Get();
|
|
||||||
modifier->EngineBuild = DataEngineBuild;
|
|
||||||
((ISerializable*)((byte*)instance + interface->VTableOffset))->Deserialize(*Data, modifier.Value);
|
((ISerializable*)((byte*)instance + interface->VTableOffset))->Deserialize(*Data, modifier.Value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ScriptingTypes::Script:
|
||||||
|
{
|
||||||
|
const ScriptingObjectSpawnParams params(Guid::New(), typeHandle);
|
||||||
|
const auto instance = type.Script.Spawn(params);
|
||||||
|
if (!instance)
|
||||||
|
return true;
|
||||||
|
Instance = instance;
|
||||||
|
_dtor = nullptr;
|
||||||
|
|
||||||
|
// Deserialize object
|
||||||
|
ToInterface<ISerializable>(instance)->Deserialize(*Data, modifier.Value);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
InstanceType = typeHandle;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -441,13 +464,20 @@ void JsonAsset::DeleteInstance()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// C++ instance
|
// C++ instance
|
||||||
if (!Instance || !_dtor)
|
if (!Instance)
|
||||||
return;
|
return;
|
||||||
|
if (_dtor)
|
||||||
|
{
|
||||||
_dtor(Instance);
|
_dtor(Instance);
|
||||||
InstanceType = ScriptingTypeHandle();
|
|
||||||
Allocator::Free(Instance);
|
|
||||||
Instance = nullptr;
|
|
||||||
_dtor = nullptr;
|
_dtor = nullptr;
|
||||||
|
Allocator::Free(Instance);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Delete((ScriptingObject*)Instance);
|
||||||
|
}
|
||||||
|
InstanceType = ScriptingTypeHandle();
|
||||||
|
Instance = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
|
|||||||
@@ -139,7 +139,8 @@ public:
|
|||||||
T* GetInstance() const
|
T* GetInstance() const
|
||||||
{
|
{
|
||||||
const_cast<JsonAsset*>(this)->CreateInstance();
|
const_cast<JsonAsset*>(this)->CreateInstance();
|
||||||
return Instance && InstanceType.IsAssignableFrom(T::TypeInitializer) ? (T*)Instance : nullptr;
|
const ScriptingTypeHandle& type = T::TypeInitializer;
|
||||||
|
return Instance && type.IsAssignableFrom(InstanceType) ? (T*)Instance : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
133
Source/Engine/Content/JsonAssetReference.cs
Normal file
133
Source/Engine/Content/JsonAssetReference.cs
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace FlaxEngine
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Json asset reference utility. References resource with a typed data type.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Type of the asset instance type.</typeparam>
|
||||||
|
#if FLAX_EDITOR
|
||||||
|
[CustomEditor(typeof(FlaxEditor.CustomEditors.Editors.AssetRefEditor))]
|
||||||
|
#endif
|
||||||
|
public struct JsonAssetReference<T> : IComparable, IComparable<JsonAssetReference<T>>, IEquatable<JsonAssetReference<T>>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the referenced asset.
|
||||||
|
/// </summary>
|
||||||
|
public JsonAsset Asset;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the instance of the serialized object from the json asset data. Cached internally.
|
||||||
|
/// </summary>
|
||||||
|
public T Instance => (T)Asset?.Instance;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JsonAssetReference{T}"/> structure.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="asset">The Json Asset.</param>
|
||||||
|
public JsonAssetReference(JsonAsset asset)
|
||||||
|
{
|
||||||
|
Asset = asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implicit cast operator.
|
||||||
|
/// </summary>
|
||||||
|
public static implicit operator JsonAsset(JsonAssetReference<T> value)
|
||||||
|
{
|
||||||
|
return value.Asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implicit cast operator.
|
||||||
|
/// </summary>
|
||||||
|
public static implicit operator IntPtr(JsonAssetReference<T> value)
|
||||||
|
{
|
||||||
|
return Object.GetUnmanagedPtr(value.Asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implicit cast operator.
|
||||||
|
/// </summary>
|
||||||
|
public static implicit operator JsonAssetReference<T>(JsonAsset value)
|
||||||
|
{
|
||||||
|
return new JsonAssetReference<T>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implicit cast operator.
|
||||||
|
/// </summary>
|
||||||
|
public static implicit operator JsonAssetReference<T>(IntPtr valuePtr)
|
||||||
|
{
|
||||||
|
return new JsonAssetReference<T>(Object.FromUnmanagedPtr(valuePtr) as JsonAsset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the object exists (reference is not null and the unmanaged object pointer is valid).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object to check.</param>
|
||||||
|
/// <returns>True if object is valid, otherwise false.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static implicit operator bool(JsonAssetReference<T> obj)
|
||||||
|
{
|
||||||
|
return obj.Asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether the two objects are equal.
|
||||||
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool operator ==(JsonAssetReference<T> left, JsonAssetReference<T> right)
|
||||||
|
{
|
||||||
|
return left.Asset == right.Asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether the two objects are not equal.
|
||||||
|
/// </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool operator !=(JsonAssetReference<T> left, JsonAssetReference<T> right)
|
||||||
|
{
|
||||||
|
return left.Asset != right.Asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Equals(JsonAssetReference<T> other)
|
||||||
|
{
|
||||||
|
return Asset == other.Asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int CompareTo(JsonAssetReference<T> other)
|
||||||
|
{
|
||||||
|
return Object.GetUnmanagedPtr(Asset).CompareTo(Object.GetUnmanagedPtr(other.Asset));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is JsonAssetReference<T> other && Asset == other.Asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Asset?.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int CompareTo(object obj)
|
||||||
|
{
|
||||||
|
return obj is JsonAssetReference<T> other ? CompareTo(other) : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return (Asset != null ? Asset.GetHashCode() : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
Source/Engine/Content/JsonAssetReference.h
Normal file
41
Source/Engine/Content/JsonAssetReference.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Engine/Content/JsonAsset.h"
|
||||||
|
#include "Engine/Content/AssetReference.h"
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Json asset reference utility. References resource with a typed data type.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Type of the asset instance type.</typeparam>
|
||||||
|
template<typename T>
|
||||||
|
API_STRUCT(NoDefault, Template, MarshalAs=JsonAsset*) struct JsonAssetReference : AssetReference<JsonAsset>
|
||||||
|
{
|
||||||
|
JsonAssetReference() = default;
|
||||||
|
|
||||||
|
JsonAssetReference(JsonAsset* asset)
|
||||||
|
{
|
||||||
|
OnSet(asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the deserialized native object instance of the given type. Returns null if asset is not loaded or loaded object has different type.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The asset instance object or null.</returns>
|
||||||
|
FORCE_INLINE T* GetInstance() const
|
||||||
|
{
|
||||||
|
return _asset ? Get()->template GetInstance<T>() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonAssetReference& operator=(JsonAsset* asset) noexcept
|
||||||
|
{
|
||||||
|
OnSet(asset);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator JsonAsset*() const
|
||||||
|
{
|
||||||
|
return Get();
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -234,7 +234,6 @@ bool AssetsImportingManager::Create(const String& tag, const StringView& outputP
|
|||||||
LOG(Warning, "Cannot find asset creator object for tag \'{0}\'.", tag);
|
LOG(Warning, "Cannot find asset creator object for tag \'{0}\'.", tag);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Create(creator->Callback, outputPath, assetId, arg);
|
return Create(creator->Callback, outputPath, assetId, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ private:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Asset importer entry
|
/// Asset importer entry
|
||||||
/// </summary>
|
/// </summary>
|
||||||
struct AssetImporter
|
struct FLAXENGINE_API AssetImporter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -135,7 +135,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Asset creator entry
|
/// Asset creator entry
|
||||||
/// </summary>
|
/// </summary>
|
||||||
struct AssetCreator
|
struct FLAXENGINE_API AssetCreator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -92,6 +92,21 @@ namespace FlaxEngine
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public float MaxColorComponent => Mathf.Max(Mathf.Max(R, G), B);
|
public float MaxColorComponent => Mathf.Max(Mathf.Max(R, G), B);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a minimum component value (max of r,g,b,a).
|
||||||
|
/// </summary>
|
||||||
|
public float MinValue => Math.Min(R, Math.Min(G, Math.Min(B, A)));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a maximum component value (min of r,g,b,a).
|
||||||
|
/// </summary>
|
||||||
|
public float MaxValue => Math.Max(R, Math.Max(G, Math.Max(B, A)));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a sum of the component values.
|
||||||
|
/// </summary>
|
||||||
|
public float ValuesSum => R + G + B + A;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a new Color with given r,g,b,a component.
|
/// Constructs a new Color with given r,g,b,a component.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1940,15 +1940,15 @@ void DebugDraw::DrawWireArc(const Vector3& position, const Quaternion& orientati
|
|||||||
DrawLine(prevPos, world.GetTranslation(), color, duration, depthTest);
|
DrawLine(prevPos, world.GetTranslation(), color, duration, depthTest);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugDraw::DrawWireArrow(const Vector3& position, const Quaternion& orientation, float scale, const Color& color, float duration, bool depthTest)
|
void DebugDraw::DrawWireArrow(const Vector3& position, const Quaternion& orientation, float scale, float capScale, const Color& color, float duration, bool depthTest)
|
||||||
{
|
{
|
||||||
Float3 direction, up, right;
|
Float3 direction, up, right;
|
||||||
Float3::Transform(Float3::Forward, orientation, direction);
|
Float3::Transform(Float3::Forward, orientation, direction);
|
||||||
Float3::Transform(Float3::Up, orientation, up);
|
Float3::Transform(Float3::Up, orientation, up);
|
||||||
Float3::Transform(Float3::Right, orientation, right);
|
Float3::Transform(Float3::Right, orientation, right);
|
||||||
const Vector3 end = position + direction * (100.0f * scale);
|
const Vector3 end = position + direction * (100.0f * scale);
|
||||||
const Vector3 capEnd = position + direction * (70.0f * scale);
|
const Vector3 capEnd = end - (direction * (100 * Math::Min(capScale, scale * 0.5f)));
|
||||||
const float arrowSidesRatio = scale * 30.0f;
|
const float arrowSidesRatio = Math::Min(capScale, scale * 0.5f) * 30.0f;
|
||||||
|
|
||||||
DrawLine(position, end, color, duration, depthTest);
|
DrawLine(position, end, color, duration, depthTest);
|
||||||
DrawLine(end, capEnd + up * arrowSidesRatio, color, duration, depthTest);
|
DrawLine(end, capEnd + up * arrowSidesRatio, color, duration, depthTest);
|
||||||
|
|||||||
@@ -218,10 +218,11 @@ namespace FlaxEngine
|
|||||||
/// <param name="position">The arrow origin position.</param>
|
/// <param name="position">The arrow origin position.</param>
|
||||||
/// <param name="orientation">The orientation (defines the arrow direction).</param>
|
/// <param name="orientation">The orientation (defines the arrow direction).</param>
|
||||||
/// <param name="scale">The arrow scale (used to adjust the arrow size).</param>
|
/// <param name="scale">The arrow scale (used to adjust the arrow size).</param>
|
||||||
|
/// <param name="capScale">The arrow cap scale.</param>
|
||||||
/// <param name="color">The color.</param>
|
/// <param name="color">The color.</param>
|
||||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||||
public static void DrawWireArrow(Vector3 position, Quaternion orientation, float scale, Color color, float duration = 0.0f, bool depthTest = true)
|
public static void DrawWireArrow(Vector3 position, Quaternion orientation, float scale, float capScale, Color color, float duration = 0.0f, bool depthTest = true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -570,10 +570,11 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
|||||||
/// <param name="position">The arrow origin position.</param>
|
/// <param name="position">The arrow origin position.</param>
|
||||||
/// <param name="orientation">The orientation (defines the arrow direction).</param>
|
/// <param name="orientation">The orientation (defines the arrow direction).</param>
|
||||||
/// <param name="scale">The arrow scale (used to adjust the arrow size).</param>
|
/// <param name="scale">The arrow scale (used to adjust the arrow size).</param>
|
||||||
|
/// <param name="capScale">The arrow cap scale.</param>
|
||||||
/// <param name="color">The color.</param>
|
/// <param name="color">The color.</param>
|
||||||
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
/// <param name="duration">The duration (in seconds). Use 0 to draw it only once.</param>
|
||||||
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
/// <param name="depthTest">If set to <c>true</c> depth test will be performed, otherwise depth will be ignored.</param>
|
||||||
API_FUNCTION() static void DrawWireArrow(const Vector3& position, const Quaternion& orientation, float scale, const Color& color, float duration = 0.0f, bool depthTest = true);
|
API_FUNCTION() static void DrawWireArrow(const Vector3& position, const Quaternion& orientation, float scale, float capScale, const Color& color, float duration = 0.0f, bool depthTest = true);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Draws the box.
|
/// Draws the box.
|
||||||
@@ -650,7 +651,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
|||||||
#define DEBUG_DRAW_WIRE_CYLINDER(position, orientation, radius, height, color, duration, depthTest) DebugDraw::DrawWireCylinder(position, orientation, radius, height, color, duration, depthTest)
|
#define DEBUG_DRAW_WIRE_CYLINDER(position, orientation, radius, height, color, duration, depthTest) DebugDraw::DrawWireCylinder(position, orientation, radius, height, color, duration, depthTest)
|
||||||
#define DEBUG_DRAW_WIRE_CONE(position, orientation, radius, angleXY, angleXZ, color, duration, depthTest) DebugDraw::DrawWireCone(position, orientation, radius, angleXY, angleXZ, color, duration, depthTest)
|
#define DEBUG_DRAW_WIRE_CONE(position, orientation, radius, angleXY, angleXZ, color, duration, depthTest) DebugDraw::DrawWireCone(position, orientation, radius, angleXY, angleXZ, color, duration, depthTest)
|
||||||
#define DEBUG_DRAW_WIRE_ARC(position, orientation, radius, angle, color, duration, depthTest) DebugDraw::DrawWireArc(position, orientation, radius, angle, color, duration, depthTest)
|
#define DEBUG_DRAW_WIRE_ARC(position, orientation, radius, angle, color, duration, depthTest) DebugDraw::DrawWireArc(position, orientation, radius, angle, color, duration, depthTest)
|
||||||
#define DEBUG_DRAW_WIRE_ARROW(position, orientation, scale, color, duration, depthTest) DebugDraw::DrawWireArrow(position, orientation, scale, color, duration, depthTest)
|
#define DEBUG_DRAW_WIRE_ARROW(position, orientation, scale, capScale, color, duration, depthTest) DebugDraw::DrawWireArrow(position, orientation, scale, capScale, color, duration, depthTest)
|
||||||
#define DEBUG_DRAW_TEXT(text, position, color, size, duration) DebugDraw::DrawText(text, position, color, size, duration)
|
#define DEBUG_DRAW_TEXT(text, position, color, size, duration) DebugDraw::DrawText(text, position, color, size, duration)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@@ -679,7 +680,7 @@ API_CLASS(Static) class FLAXENGINE_API DebugDraw
|
|||||||
#define DEBUG_DRAW_WIRE_CYLINDER(position, orientation, radius, height, color, duration, depthTest)
|
#define DEBUG_DRAW_WIRE_CYLINDER(position, orientation, radius, height, color, duration, depthTest)
|
||||||
#define DEBUG_DRAW_WIRE_CONE(position, orientation, radius, angleXY, angleXZ, color, duration, depthTest)
|
#define DEBUG_DRAW_WIRE_CONE(position, orientation, radius, angleXY, angleXZ, color, duration, depthTest)
|
||||||
#define DEBUG_DRAW_WIRE_ARC(position, orientation, radius, angle, color, duration, depthTest)
|
#define DEBUG_DRAW_WIRE_ARC(position, orientation, radius, angle, color, duration, depthTest)
|
||||||
#define DEBUG_DRAW_WIRE_ARROW(position, orientation, scale, color, duration, depthTest)
|
#define DEBUG_DRAW_WIRE_ARROW(position, orientation, scale, capScale, color, duration, depthTest)
|
||||||
#define DEBUG_DRAW_TEXT(text, position, color, size, duration)
|
#define DEBUG_DRAW_TEXT(text, position, color, size, duration)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -214,9 +214,6 @@ int32 Engine::Main(const Char* cmdLine)
|
|||||||
Time::OnEndDraw();
|
Time::OnEndDraw();
|
||||||
FrameMark;
|
FrameMark;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect physics simulation results (does nothing if Simulate hasn't been called in the previous loop step)
|
|
||||||
Physics::CollectResults();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call on exit event
|
// Call on exit event
|
||||||
@@ -288,6 +285,9 @@ void Engine::OnLateFixedUpdate()
|
|||||||
|
|
||||||
// Update services
|
// Update services
|
||||||
EngineService::OnLateFixedUpdate();
|
EngineService::OnLateFixedUpdate();
|
||||||
|
|
||||||
|
// Collect physics simulation results (does nothing if Simulate hasn't been called in the previous loop step)
|
||||||
|
Physics::CollectResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::OnUpdate()
|
void Engine::OnUpdate()
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ namespace FlaxEngine.Interop
|
|||||||
/// <param name="src">The input array.</param>
|
/// <param name="src">The input array.</param>
|
||||||
/// <param name="convertFunc">Converter callback.</param>
|
/// <param name="convertFunc">Converter callback.</param>
|
||||||
/// <returns>The output array.</returns>
|
/// <returns>The output array.</returns>
|
||||||
public static TDst[] ConvertArray<TSrc, TDst>(Span<TSrc> src, Func<TSrc, TDst> convertFunc)
|
public static TDst[] ConvertArray<TSrc, TDst>(this Span<TSrc> src, Func<TSrc, TDst> convertFunc)
|
||||||
{
|
{
|
||||||
TDst[] dst = new TDst[src.Length];
|
TDst[] dst = new TDst[src.Length];
|
||||||
for (int i = 0; i < src.Length; i++)
|
for (int i = 0; i < src.Length; i++)
|
||||||
@@ -265,7 +265,7 @@ namespace FlaxEngine.Interop
|
|||||||
/// <param name="src">The input array.</param>
|
/// <param name="src">The input array.</param>
|
||||||
/// <param name="convertFunc">Converter callback.</param>
|
/// <param name="convertFunc">Converter callback.</param>
|
||||||
/// <returns>The output array.</returns>
|
/// <returns>The output array.</returns>
|
||||||
public static TDst[] ConvertArray<TSrc, TDst>(TSrc[] src, Func<TSrc, TDst> convertFunc)
|
public static TDst[] ConvertArray<TSrc, TDst>(this TSrc[] src, Func<TSrc, TDst> convertFunc)
|
||||||
{
|
{
|
||||||
TDst[] dst = new TDst[src.Length];
|
TDst[] dst = new TDst[src.Length];
|
||||||
for (int i = 0; i < src.Length; i++)
|
for (int i = 0; i < src.Length; i++)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "Engine/Debug/Exceptions/InvalidOperationException.h"
|
#include "Engine/Debug/Exceptions/InvalidOperationException.h"
|
||||||
#include "Engine/Debug/Exceptions/ArgumentNullException.h"
|
#include "Engine/Debug/Exceptions/ArgumentNullException.h"
|
||||||
#include "Engine/Debug/Exceptions/ArgumentOutOfRangeException.h"
|
#include "Engine/Debug/Exceptions/ArgumentOutOfRangeException.h"
|
||||||
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
#include "Engine/Scripting/Enums.h"
|
#include "Engine/Scripting/Enums.h"
|
||||||
#include "Engine/Threading/ThreadPoolTask.h"
|
#include "Engine/Threading/ThreadPoolTask.h"
|
||||||
#include "Engine/Threading/Threading.h"
|
#include "Engine/Threading/Threading.h"
|
||||||
@@ -81,33 +82,10 @@ bool GPUBufferDescription::Equals(const GPUBufferDescription& other) const
|
|||||||
|
|
||||||
String GPUBufferDescription::ToString() const
|
String GPUBufferDescription::ToString() const
|
||||||
{
|
{
|
||||||
// TODO: add tool to Format to string
|
|
||||||
|
|
||||||
String flags;
|
|
||||||
if (Flags == GPUBufferFlags::None)
|
|
||||||
{
|
|
||||||
flags = TEXT("None");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO: create tool to auto convert flag enums to string
|
|
||||||
|
|
||||||
#define CONVERT_FLAGS_FLAGS_2_STR(value) if (EnumHasAnyFlags(Flags, GPUBufferFlags::value)) { if (flags.HasChars()) flags += TEXT('|'); flags += TEXT(#value); }
|
|
||||||
CONVERT_FLAGS_FLAGS_2_STR(ShaderResource);
|
|
||||||
CONVERT_FLAGS_FLAGS_2_STR(VertexBuffer);
|
|
||||||
CONVERT_FLAGS_FLAGS_2_STR(IndexBuffer);
|
|
||||||
CONVERT_FLAGS_FLAGS_2_STR(UnorderedAccess);
|
|
||||||
CONVERT_FLAGS_FLAGS_2_STR(Append);
|
|
||||||
CONVERT_FLAGS_FLAGS_2_STR(Counter);
|
|
||||||
CONVERT_FLAGS_FLAGS_2_STR(Argument);
|
|
||||||
CONVERT_FLAGS_FLAGS_2_STR(Structured);
|
|
||||||
#undef CONVERT_FLAGS_FLAGS_2_STR
|
|
||||||
}
|
|
||||||
|
|
||||||
return String::Format(TEXT("Size: {0}, Stride: {1}, Flags: {2}, Format: {3}, Usage: {4}"),
|
return String::Format(TEXT("Size: {0}, Stride: {1}, Flags: {2}, Format: {3}, Usage: {4}"),
|
||||||
Size,
|
Size,
|
||||||
Stride,
|
Stride,
|
||||||
flags,
|
ScriptingEnum::ToStringFlags(Flags),
|
||||||
ScriptingEnum::ToString(Format),
|
ScriptingEnum::ToString(Format),
|
||||||
(int32)Usage);
|
(int32)Usage);
|
||||||
}
|
}
|
||||||
@@ -212,7 +190,7 @@ GPUBuffer* GPUBuffer::ToStagingUpload() const
|
|||||||
|
|
||||||
bool GPUBuffer::Resize(uint32 newSize)
|
bool GPUBuffer::Resize(uint32 newSize)
|
||||||
{
|
{
|
||||||
// Validate input
|
PROFILE_CPU();
|
||||||
if (!IsAllocated())
|
if (!IsAllocated())
|
||||||
{
|
{
|
||||||
Log::InvalidOperationException(TEXT("Buffer.Resize"));
|
Log::InvalidOperationException(TEXT("Buffer.Resize"));
|
||||||
@@ -236,12 +214,12 @@ bool GPUBuffer::DownloadData(BytesContainer& result)
|
|||||||
LOG(Warning, "Cannot download GPU buffer data from an empty buffer.");
|
LOG(Warning, "Cannot download GPU buffer data from an empty buffer.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_desc.Usage == GPUResourceUsage::StagingReadback || _desc.Usage == GPUResourceUsage::Dynamic)
|
if (_desc.Usage == GPUResourceUsage::StagingReadback || _desc.Usage == GPUResourceUsage::Dynamic)
|
||||||
{
|
{
|
||||||
// Use faster path for staging resources
|
// Use faster path for staging resources
|
||||||
return GetData(result);
|
return GetData(result);
|
||||||
}
|
}
|
||||||
|
PROFILE_CPU();
|
||||||
|
|
||||||
// Ensure not running on main thread
|
// Ensure not running on main thread
|
||||||
if (IsInMainThread())
|
if (IsInMainThread())
|
||||||
@@ -358,6 +336,7 @@ Task* GPUBuffer::DownloadDataAsync(BytesContainer& result)
|
|||||||
|
|
||||||
bool GPUBuffer::GetData(BytesContainer& output)
|
bool GPUBuffer::GetData(BytesContainer& output)
|
||||||
{
|
{
|
||||||
|
PROFILE_CPU();
|
||||||
void* mapped = Map(GPUResourceMapMode::Read);
|
void* mapped = Map(GPUResourceMapMode::Read);
|
||||||
if (!mapped)
|
if (!mapped)
|
||||||
return true;
|
return true;
|
||||||
@@ -368,6 +347,7 @@ bool GPUBuffer::GetData(BytesContainer& output)
|
|||||||
|
|
||||||
void GPUBuffer::SetData(const void* data, uint32 size)
|
void GPUBuffer::SetData(const void* data, uint32 size)
|
||||||
{
|
{
|
||||||
|
PROFILE_CPU();
|
||||||
if (size == 0 || data == nullptr)
|
if (size == 0 || data == nullptr)
|
||||||
{
|
{
|
||||||
Log::ArgumentNullException(TEXT("Buffer.SetData"));
|
Log::ArgumentNullException(TEXT("Buffer.SetData"));
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "Engine/Graphics/GPULimits.h"
|
#include "Engine/Graphics/GPULimits.h"
|
||||||
#include "Engine/Threading/ThreadPoolTask.h"
|
#include "Engine/Threading/ThreadPoolTask.h"
|
||||||
#include "Engine/Graphics/GPUDevice.h"
|
#include "Engine/Graphics/GPUDevice.h"
|
||||||
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
#include "Engine/Scripting/Enums.h"
|
#include "Engine/Scripting/Enums.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@@ -158,29 +159,6 @@ bool GPUTextureDescription::Equals(const GPUTextureDescription& other) const
|
|||||||
|
|
||||||
String GPUTextureDescription::ToString() const
|
String GPUTextureDescription::ToString() const
|
||||||
{
|
{
|
||||||
// TODO: add tool to Format to string
|
|
||||||
|
|
||||||
String flags;
|
|
||||||
if (Flags == GPUTextureFlags::None)
|
|
||||||
{
|
|
||||||
flags = TEXT("None");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO: create tool to auto convert flag enums to string
|
|
||||||
|
|
||||||
#define CONVERT_FLAGS_FLAGS_2_STR(value) if (EnumHasAnyFlags(Flags, GPUTextureFlags::value)) { if (flags.HasChars()) flags += TEXT('|'); flags += TEXT(#value); }
|
|
||||||
CONVERT_FLAGS_FLAGS_2_STR(ShaderResource);
|
|
||||||
CONVERT_FLAGS_FLAGS_2_STR(RenderTarget);
|
|
||||||
CONVERT_FLAGS_FLAGS_2_STR(UnorderedAccess);
|
|
||||||
CONVERT_FLAGS_FLAGS_2_STR(DepthStencil);
|
|
||||||
CONVERT_FLAGS_FLAGS_2_STR(PerMipViews);
|
|
||||||
CONVERT_FLAGS_FLAGS_2_STR(PerSliceViews);
|
|
||||||
CONVERT_FLAGS_FLAGS_2_STR(ReadOnlyDepthView);
|
|
||||||
CONVERT_FLAGS_FLAGS_2_STR(BackBuffer);
|
|
||||||
#undef CONVERT_FLAGS_FLAGS_2_STR
|
|
||||||
}
|
|
||||||
|
|
||||||
return String::Format(TEXT("Size: {0}x{1}x{2}[{3}], Type: {4}, Mips: {5}, Format: {6}, MSAA: {7}, Flags: {8}, Usage: {9}"),
|
return String::Format(TEXT("Size: {0}x{1}x{2}[{3}], Type: {4}, Mips: {5}, Format: {6}, MSAA: {7}, Flags: {8}, Usage: {9}"),
|
||||||
Width,
|
Width,
|
||||||
Height,
|
Height,
|
||||||
@@ -190,7 +168,7 @@ String GPUTextureDescription::ToString() const
|
|||||||
MipLevels,
|
MipLevels,
|
||||||
ScriptingEnum::ToString(Format),
|
ScriptingEnum::ToString(Format),
|
||||||
::ToString(MultiSampleLevel),
|
::ToString(MultiSampleLevel),
|
||||||
flags,
|
ScriptingEnum::ToStringFlags(Flags),
|
||||||
(int32)Usage);
|
(int32)Usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,7 +522,7 @@ GPUTexture* GPUTexture::ToStagingUpload() const
|
|||||||
|
|
||||||
bool GPUTexture::Resize(int32 width, int32 height, int32 depth, PixelFormat format)
|
bool GPUTexture::Resize(int32 width, int32 height, int32 depth, PixelFormat format)
|
||||||
{
|
{
|
||||||
// Validate texture is created
|
PROFILE_CPU();
|
||||||
if (!IsAllocated())
|
if (!IsAllocated())
|
||||||
{
|
{
|
||||||
LOG(Warning, "Cannot resize not created textures.");
|
LOG(Warning, "Cannot resize not created textures.");
|
||||||
@@ -608,6 +586,7 @@ GPUTask* GPUTexture::UploadMipMapAsync(const BytesContainer& data, int32 mipInde
|
|||||||
|
|
||||||
GPUTask* GPUTexture::UploadMipMapAsync(const BytesContainer& data, int32 mipIndex, int32 rowPitch, int32 slicePitch, bool copyData)
|
GPUTask* GPUTexture::UploadMipMapAsync(const BytesContainer& data, int32 mipIndex, int32 rowPitch, int32 slicePitch, bool copyData)
|
||||||
{
|
{
|
||||||
|
PROFILE_CPU();
|
||||||
ASSERT(IsAllocated());
|
ASSERT(IsAllocated());
|
||||||
ASSERT(mipIndex < MipLevels() && data.IsValid());
|
ASSERT(mipIndex < MipLevels() && data.IsValid());
|
||||||
ASSERT(data.Length() >= slicePitch);
|
ASSERT(data.Length() >= slicePitch);
|
||||||
@@ -699,6 +678,7 @@ bool GPUTexture::DownloadData(TextureData& result)
|
|||||||
{
|
{
|
||||||
MISSING_CODE("support volume texture data downloading.");
|
MISSING_CODE("support volume texture data downloading.");
|
||||||
}
|
}
|
||||||
|
PROFILE_CPU();
|
||||||
|
|
||||||
// Use faster path for staging resources
|
// Use faster path for staging resources
|
||||||
if (IsStaging())
|
if (IsStaging())
|
||||||
@@ -780,6 +760,7 @@ Task* GPUTexture::DownloadDataAsync(TextureData& result)
|
|||||||
{
|
{
|
||||||
MISSING_CODE("support volume texture data downloading.");
|
MISSING_CODE("support volume texture data downloading.");
|
||||||
}
|
}
|
||||||
|
PROFILE_CPU();
|
||||||
|
|
||||||
// Use faster path for staging resources
|
// Use faster path for staging resources
|
||||||
if (IsStaging())
|
if (IsStaging())
|
||||||
|
|||||||
@@ -386,5 +386,9 @@ namespace FlaxEngine
|
|||||||
{
|
{
|
||||||
return $"{Name} ({GetType().Name})";
|
return $"{Name} ({GetType().Name})";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FLAX_EDITOR
|
||||||
|
internal bool ShowTransform => !(this is UIControl);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -534,9 +534,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets actor direction vector (forward vector).
|
/// Gets actor direction vector (forward vector).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The result value.</returns>
|
API_PROPERTY(Attributes="HideInEditor, NoSerialize") FORCE_INLINE Float3 GetDirection() const
|
||||||
API_PROPERTY(Attributes="HideInEditor, NoSerialize")
|
|
||||||
FORCE_INLINE Float3 GetDirection() const
|
|
||||||
{
|
{
|
||||||
return Float3::Transform(Float3::Forward, GetOrientation());
|
return Float3::Transform(Float3::Forward, GetOrientation());
|
||||||
}
|
}
|
||||||
@@ -571,7 +569,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets local position of the actor in parent actor space.
|
/// Gets local position of the actor in parent actor space.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_PROPERTY(Attributes="EditorDisplay(\"Transform\", \"Position\"), DefaultValue(typeof(Vector3), \"0,0,0\"), EditorOrder(-30), NoSerialize, CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ActorTransformEditor+PositionEditor\")")
|
API_PROPERTY(Attributes="EditorDisplay(\"Transform\", \"Position\"), VisibleIf(\"ShowTransform\"), DefaultValue(typeof(Vector3), \"0,0,0\"), EditorOrder(-30), NoSerialize, CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ActorTransformEditor+PositionEditor\")")
|
||||||
FORCE_INLINE Vector3 GetLocalPosition() const
|
FORCE_INLINE Vector3 GetLocalPosition() const
|
||||||
{
|
{
|
||||||
return _localTransform.Translation;
|
return _localTransform.Translation;
|
||||||
@@ -587,7 +585,7 @@ public:
|
|||||||
/// Gets local rotation of the actor in parent actor space.
|
/// Gets local rotation of the actor in parent actor space.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <code>Actor.LocalOrientation *= Quaternion.Euler(0, 10 * Time.DeltaTime, 0)</code>
|
/// <code>Actor.LocalOrientation *= Quaternion.Euler(0, 10 * Time.DeltaTime, 0)</code>
|
||||||
API_PROPERTY(Attributes="EditorDisplay(\"Transform\", \"Rotation\"), DefaultValue(typeof(Quaternion), \"0,0,0,1\"), EditorOrder(-20), NoSerialize, CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ActorTransformEditor+OrientationEditor\")")
|
API_PROPERTY(Attributes="EditorDisplay(\"Transform\", \"Rotation\"), VisibleIf(\"ShowTransform\"), DefaultValue(typeof(Quaternion), \"0,0,0,1\"), EditorOrder(-20), NoSerialize, CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ActorTransformEditor+OrientationEditor\")")
|
||||||
FORCE_INLINE Quaternion GetLocalOrientation() const
|
FORCE_INLINE Quaternion GetLocalOrientation() const
|
||||||
{
|
{
|
||||||
return _localTransform.Orientation;
|
return _localTransform.Orientation;
|
||||||
@@ -602,7 +600,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets local scale vector of the actor in parent actor space.
|
/// Gets local scale vector of the actor in parent actor space.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_PROPERTY(Attributes="EditorDisplay(\"Transform\", \"Scale\"), DefaultValue(typeof(Float3), \"1,1,1\"), Limit(float.MinValue, float.MaxValue, 0.01f), EditorOrder(-10), NoSerialize, CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ActorTransformEditor+ScaleEditor\")")
|
API_PROPERTY(Attributes="EditorDisplay(\"Transform\", \"Scale\"), VisibleIf(\"ShowTransform\"), DefaultValue(typeof(Float3), \"1,1,1\"), Limit(float.MinValue, float.MaxValue, 0.01f), EditorOrder(-10), NoSerialize, CustomEditorAlias(\"FlaxEditor.CustomEditors.Editors.ActorTransformEditor+ScaleEditor\")")
|
||||||
FORCE_INLINE Float3 GetLocalScale() const
|
FORCE_INLINE Float3 GetLocalScale() const
|
||||||
{
|
{
|
||||||
return _localTransform.Scale;
|
return _localTransform.Scale;
|
||||||
|
|||||||
@@ -415,9 +415,9 @@ void Cloth::OnDebugDrawSelected()
|
|||||||
c1 = Color::Lerp(Color::Red, Color::White, _paint[i1]);
|
c1 = Color::Lerp(Color::Red, Color::White, _paint[i1]);
|
||||||
c2 = Color::Lerp(Color::Red, Color::White, _paint[i2]);
|
c2 = Color::Lerp(Color::Red, Color::White, _paint[i2]);
|
||||||
}
|
}
|
||||||
DebugDraw::DrawLine(v0, v1, c0, c1, 0, false);
|
DebugDraw::DrawLine(v0, v1, c0, c1, 0, DebugDrawDepthTest);
|
||||||
DebugDraw::DrawLine(v1, v2, c1, c2, 0, false);
|
DebugDraw::DrawLine(v1, v2, c1, c2, 0, DebugDrawDepthTest);
|
||||||
DebugDraw::DrawLine(v2, v0, c2, c0, 0, false);
|
DebugDraw::DrawLine(v2, v0, c2, c0, 0, DebugDrawDepthTest);
|
||||||
}
|
}
|
||||||
PhysicsBackend::UnlockClothParticles(_cloth);
|
PhysicsBackend::UnlockClothParticles(_cloth);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -332,6 +332,11 @@ public:
|
|||||||
bool OnPreUpdate();
|
bool OnPreUpdate();
|
||||||
void OnPostUpdate();
|
void OnPostUpdate();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if USE_EDITOR
|
||||||
|
API_FIELD(Internal) bool DebugDrawDepthTest = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// [Actor]
|
// [Actor]
|
||||||
void Draw(RenderContext& renderContext) override;
|
void Draw(RenderContext& renderContext) override;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "Engine/Level/Actor.h"
|
#include "Engine/Level/Actor.h"
|
||||||
#include "Engine/Physics/Collisions.h"
|
#include "Engine/Physics/Collisions.h"
|
||||||
|
|
||||||
|
struct RayCastHit;
|
||||||
struct Collision;
|
struct Collision;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -42,6 +43,40 @@ public:
|
|||||||
/// <returns>The rigid body or null.</returns>
|
/// <returns>The rigid body or null.</returns>
|
||||||
API_PROPERTY() virtual RigidBody* GetAttachedRigidBody() const = 0;
|
API_PROPERTY() virtual RigidBody* GetAttachedRigidBody() const = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs a raycast against this collider shape.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="origin">The origin of the ray.</param>
|
||||||
|
/// <param name="direction">The normalized direction of the ray.</param>
|
||||||
|
/// <param name="resultHitDistance">The raycast result hit position distance from the ray origin. Valid only if raycast hits anything.</param>
|
||||||
|
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
||||||
|
/// <returns>True if ray hits an object, otherwise false.</returns>
|
||||||
|
API_FUNCTION(Sealed) virtual bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) float& resultHitDistance, float maxDistance = MAX_float) const = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs a raycast against this collider, returns results in a RaycastHit structure.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="origin">The origin of the ray.</param>
|
||||||
|
/// <param name="direction">The normalized direction of the ray.</param>
|
||||||
|
/// <param name="hitInfo">The result hit information. Valid only when method returns true.</param>
|
||||||
|
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
||||||
|
/// <returns>True if ray hits an object, otherwise false.</returns>
|
||||||
|
API_FUNCTION(Sealed) virtual bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) RayCastHit& hitInfo, float maxDistance = MAX_float) const = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a point on the collider that is closest to a given location. Can be used to find a hit location or position to apply explosion force or any other special effects.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="point">The position to find the closest point to it.</param>
|
||||||
|
/// <param name="result">The result point on the collider that is closest to the specified location.</param>
|
||||||
|
API_FUNCTION(Sealed) virtual void ClosestPoint(const Vector3& point, API_PARAM(Out) Vector3& result) const = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if a point is inside the collider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="point">The point to check if is contained by the collider shape (in world-space).</param>
|
||||||
|
/// <returns>True if collider shape contains a given point, otherwise false.</returns>
|
||||||
|
API_FUNCTION(Sealed) virtual bool ContainsPoint(const Vector3& point) const = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when a collision start gets registered for this collider (it collides with something).
|
/// Called when a collision start gets registered for this collider (it collides with something).
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ void CharacterController::CreateController()
|
|||||||
_cachedScale = GetScale();
|
_cachedScale = GetScale();
|
||||||
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
||||||
const Vector3 position = _transform.LocalToWorld(_center);
|
const Vector3 position = _transform.LocalToWorld(_center);
|
||||||
_controller = PhysicsBackend::CreateController(GetPhysicsScene()->GetPhysicsScene(), this, this, _contactOffset, position, _slopeLimit, (int32)_nonWalkableMode, Material.Get(), Math::Abs(_radius) * scaling, Math::Abs(_height) * scaling, _stepOffset, _shape);
|
_controller = PhysicsBackend::CreateController(GetPhysicsScene()->GetPhysicsScene(), this, this, _contactOffset, position, _slopeLimit, (int32)_nonWalkableMode, Material, Math::Abs(_radius) * scaling, Math::Abs(_height) * scaling, _stepOffset, _shape);
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
PhysicsBackend::SetControllerUpDirection(_controller, _upDirection);
|
PhysicsBackend::SetControllerUpDirection(_controller, _upDirection);
|
||||||
@@ -280,12 +280,8 @@ void CharacterController::OnActiveTransformChanged()
|
|||||||
// Change actor transform (but with locking)
|
// Change actor transform (but with locking)
|
||||||
ASSERT(!_isUpdatingTransform);
|
ASSERT(!_isUpdatingTransform);
|
||||||
_isUpdatingTransform = true;
|
_isUpdatingTransform = true;
|
||||||
Transform transform;
|
const Vector3 position = PhysicsBackend::GetControllerPosition(_controller) - _center;
|
||||||
PhysicsBackend::GetRigidActorPose(PhysicsBackend::GetShapeActor(_shape), transform.Translation, transform.Orientation);
|
SetPosition(position);
|
||||||
transform.Translation -= _center;
|
|
||||||
transform.Orientation = _transform.Orientation;
|
|
||||||
transform.Scale = _transform.Scale;
|
|
||||||
SetTransform(transform);
|
|
||||||
_isUpdatingTransform = false;
|
_isUpdatingTransform = false;
|
||||||
|
|
||||||
UpdateBounds();
|
UpdateBounds();
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ void Collider::CreateShape()
|
|||||||
|
|
||||||
// Create shape
|
// Create shape
|
||||||
const bool isTrigger = _isTrigger && CanBeTrigger();
|
const bool isTrigger = _isTrigger && CanBeTrigger();
|
||||||
_shape = PhysicsBackend::CreateShape(this, shape, Material.Get(), IsActiveInHierarchy(), isTrigger);
|
_shape = PhysicsBackend::CreateShape(this, shape, Material, IsActiveInHierarchy(), isTrigger);
|
||||||
PhysicsBackend::SetShapeContactOffset(_shape, _contactOffset);
|
PhysicsBackend::SetShapeContactOffset(_shape, _contactOffset);
|
||||||
UpdateLayerBits();
|
UpdateLayerBits();
|
||||||
}
|
}
|
||||||
@@ -288,7 +288,7 @@ void Collider::OnMaterialChanged()
|
|||||||
{
|
{
|
||||||
// Update the shape material
|
// Update the shape material
|
||||||
if (_shape)
|
if (_shape)
|
||||||
PhysicsBackend::SetShapeMaterial(_shape, Material.Get());
|
PhysicsBackend::SetShapeMaterial(_shape, Material);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Collider::BeginPlay(SceneBeginData* data)
|
void Collider::BeginPlay(SceneBeginData* data)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include "Engine/Physics/Types.h"
|
#include "Engine/Physics/Types.h"
|
||||||
#include "Engine/Content/JsonAsset.h"
|
#include "Engine/Content/JsonAsset.h"
|
||||||
#include "Engine/Content/AssetReference.h"
|
#include "Engine/Content/JsonAssetReference.h"
|
||||||
#include "Engine/Physics/Actors/PhysicsColliderActor.h"
|
#include "Engine/Physics/Actors/PhysicsColliderActor.h"
|
||||||
|
|
||||||
struct RayCastHit;
|
struct RayCastHit;
|
||||||
@@ -80,44 +80,10 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The physical material used to define the collider physical properties.
|
/// The physical material used to define the collider physical properties.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD(Attributes="EditorOrder(2), DefaultValue(null), AssetReference(typeof(PhysicalMaterial), true), EditorDisplay(\"Collider\")")
|
API_FIELD(Attributes="EditorOrder(2), DefaultValue(null), EditorDisplay(\"Collider\")")
|
||||||
AssetReference<JsonAsset> Material;
|
JsonAssetReference<PhysicalMaterial> Material;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
|
||||||
/// Performs a raycast against this collider shape.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="origin">The origin of the ray.</param>
|
|
||||||
/// <param name="direction">The normalized direction of the ray.</param>
|
|
||||||
/// <param name="resultHitDistance">The raycast result hit position distance from the ray origin. Valid only if raycast hits anything.</param>
|
|
||||||
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
|
||||||
/// <returns>True if ray hits an object, otherwise false.</returns>
|
|
||||||
API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) float& resultHitDistance, float maxDistance = MAX_float) const;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Performs a raycast against this collider, returns results in a RaycastHit structure.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="origin">The origin of the ray.</param>
|
|
||||||
/// <param name="direction">The normalized direction of the ray.</param>
|
|
||||||
/// <param name="hitInfo">The result hit information. Valid only when method returns true.</param>
|
|
||||||
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
|
||||||
/// <returns>True if ray hits an object, otherwise false.</returns>
|
|
||||||
API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) RayCastHit& hitInfo, float maxDistance = MAX_float) const;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a point on the collider that is closest to a given location. Can be used to find a hit location or position to apply explosion force or any other special effects.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="point">The position to find the closest point to it.</param>
|
|
||||||
/// <param name="result">The result point on the collider that is closest to the specified location.</param>
|
|
||||||
API_FUNCTION() void ClosestPoint(const Vector3& point, API_PARAM(Out) Vector3& result) const;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if a point is inside the collider.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="point">The point to check if is contained by the collider shape (in world-space).</param>
|
|
||||||
/// <returns>True if collider shape contains a given point, otherwise false.</returns>
|
|
||||||
API_FUNCTION() bool ContainsPoint(const Vector3& point) const;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Computes minimum translational distance between two geometry objects.
|
/// Computes minimum translational distance between two geometry objects.
|
||||||
/// Translating the first collider by direction * distance will separate the colliders apart if the function returned true. Otherwise, direction and distance are not defined.
|
/// Translating the first collider by direction * distance will separate the colliders apart if the function returned true. Otherwise, direction and distance are not defined.
|
||||||
@@ -198,6 +164,10 @@ private:
|
|||||||
public:
|
public:
|
||||||
// [PhysicsColliderActor]
|
// [PhysicsColliderActor]
|
||||||
RigidBody* GetAttachedRigidBody() const override;
|
RigidBody* GetAttachedRigidBody() const override;
|
||||||
|
bool RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, float maxDistance = MAX_float) const final;
|
||||||
|
bool RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, float maxDistance = MAX_float) const final;
|
||||||
|
void ClosestPoint(const Vector3& point, Vector3& result) const final;
|
||||||
|
bool ContainsPoint(const Vector3& point) const final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// [PhysicsColliderActor]
|
// [PhysicsColliderActor]
|
||||||
|
|||||||
@@ -58,9 +58,7 @@ API_STRUCT(NoDefault) struct FLAXENGINE_API Collision
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The total impulse applied to this contact pair to resolve the collision.
|
/// The total impulse applied to this contact pair to resolve the collision.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>The total impulse is obtained by summing up impulses applied at all contact points in this collision pair.</remarks>
|
||||||
/// The total impulse is obtained by summing up impulses applied at all contact points in this collision pair.
|
|
||||||
/// </remarks>
|
|
||||||
API_FIELD() Vector3 Impulse;
|
API_FIELD() Vector3 Impulse;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -87,9 +85,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the relative linear velocity of the two colliding objects.
|
/// Gets the relative linear velocity of the two colliding objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>Can be used to detect stronger collisions. </remarks>
|
||||||
/// Can be used to detect stronger collisions.
|
|
||||||
/// </remarks>
|
|
||||||
Vector3 GetRelativeVelocity() const
|
Vector3 GetRelativeVelocity() const
|
||||||
{
|
{
|
||||||
return ThisVelocity - OtherVelocity;
|
return ThisVelocity - OtherVelocity;
|
||||||
|
|||||||
@@ -159,7 +159,8 @@ void D6Joint::OnDebugDrawSelected()
|
|||||||
const float twistSize = 9.0f;
|
const float twistSize = 9.0f;
|
||||||
const Color swingColor = Color::Green.AlphaMultiplied(0.6f);
|
const Color swingColor = Color::Green.AlphaMultiplied(0.6f);
|
||||||
const Color twistColor = Color::Yellow.AlphaMultiplied(0.5f);
|
const Color twistColor = Color::Yellow.AlphaMultiplied(0.5f);
|
||||||
DEBUG_DRAW_WIRE_ARROW(target, targetRotation, swingSize / 100.0f * 0.5f, Color::Red, 0, false);
|
const float arrowSize = swingSize / 100.0f * 0.5f;
|
||||||
|
DEBUG_DRAW_WIRE_ARROW(target, targetRotation, arrowSize, arrowSize * 0.5f, Color::Red, 0, false);
|
||||||
if (_motion[(int32)D6JointAxis::SwingY] == D6JointMotion::Locked && _motion[(int32)D6JointAxis::SwingZ] == D6JointMotion::Locked)
|
if (_motion[(int32)D6JointAxis::SwingY] == D6JointMotion::Locked && _motion[(int32)D6JointAxis::SwingZ] == D6JointMotion::Locked)
|
||||||
{
|
{
|
||||||
// Swing is locked
|
// Swing is locked
|
||||||
|
|||||||
@@ -63,8 +63,9 @@ void HingeJoint::OnDebugDrawSelected()
|
|||||||
const Quaternion targetRotation = GetTargetOrientation() * xRotation;
|
const Quaternion targetRotation = GetTargetOrientation() * xRotation;
|
||||||
const float size = 15.0f;
|
const float size = 15.0f;
|
||||||
const Color color = Color::Green.AlphaMultiplied(0.6f);
|
const Color color = Color::Green.AlphaMultiplied(0.6f);
|
||||||
DEBUG_DRAW_WIRE_ARROW(source, sourceRotation, size / 100.0f * 0.5f, Color::Red, 0, false);
|
const float arrowSize = size / 100.0f * 0.5f;
|
||||||
DEBUG_DRAW_WIRE_ARROW(target, targetRotation, size / 100.0f * 0.5f, Color::Blue, 0, false);
|
DEBUG_DRAW_WIRE_ARROW(source, sourceRotation, arrowSize, arrowSize * 0.5f, Color::Red, 0, false);
|
||||||
|
DEBUG_DRAW_WIRE_ARROW(target, targetRotation, arrowSize, arrowSize * 0.5f, Color::Blue, 0, false);
|
||||||
if (EnumHasAnyFlags(_flags, HingeJointFlag::Limit))
|
if (EnumHasAnyFlags(_flags, HingeJointFlag::Limit))
|
||||||
{
|
{
|
||||||
const float upper = Math::Max(_limit.Upper, _limit.Lower);
|
const float upper = Math::Max(_limit.Upper, _limit.Lower);
|
||||||
|
|||||||
@@ -38,8 +38,9 @@ void SphericalJoint::OnDebugDrawSelected()
|
|||||||
const Vector3 source = GetPosition();
|
const Vector3 source = GetPosition();
|
||||||
const Vector3 target = GetTargetPosition();
|
const Vector3 target = GetTargetPosition();
|
||||||
const float size = 15.0f;
|
const float size = 15.0f;
|
||||||
|
const float arrowSize = size / 100.0f * 0.5f;
|
||||||
const Color color = Color::Green.AlphaMultiplied(0.6f);
|
const Color color = Color::Green.AlphaMultiplied(0.6f);
|
||||||
DEBUG_DRAW_WIRE_ARROW(source, GetOrientation(), size / 100.0f * 0.5f, Color::Red, 0, false);
|
DEBUG_DRAW_WIRE_ARROW(source, GetOrientation(), arrowSize, arrowSize * 0.5f, Color::Red, 0, false);
|
||||||
if (EnumHasAnyFlags(_flags, SphericalJointFlag::Limit))
|
if (EnumHasAnyFlags(_flags, SphericalJointFlag::Limit))
|
||||||
{
|
{
|
||||||
DEBUG_DRAW_CONE(source, GetOrientation(), size, _limit.YLimitAngle * DegreesToRadians, _limit.ZLimitAngle * DegreesToRadians, color, 0, false);
|
DEBUG_DRAW_CONE(source, GetOrientation(), size, _limit.YLimitAngle * DegreesToRadians, _limit.ZLimitAngle * DegreesToRadians, color, 0, false);
|
||||||
|
|||||||
@@ -228,9 +228,7 @@ class QueryFilterPhysX : public PxQueryFilterCallback
|
|||||||
// Check mask
|
// Check mask
|
||||||
const PxFilterData shapeFilter = shape->getQueryFilterData();
|
const PxFilterData shapeFilter = shape->getQueryFilterData();
|
||||||
if ((filterData.word0 & shapeFilter.word0) == 0)
|
if ((filterData.word0 & shapeFilter.word0) == 0)
|
||||||
{
|
|
||||||
return PxQueryHitType::eNONE;
|
return PxQueryHitType::eNONE;
|
||||||
}
|
|
||||||
|
|
||||||
// Check if skip triggers
|
// Check if skip triggers
|
||||||
const bool hitTriggers = filterData.word2 != 0;
|
const bool hitTriggers = filterData.word2 != 0;
|
||||||
@@ -483,8 +481,10 @@ protected:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define PxHitFlagEmpty (PxHitFlags)0
|
||||||
|
#define SCENE_QUERY_FLAGS (PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eFACE_INDEX | PxHitFlag::eUV)
|
||||||
|
|
||||||
#define SCENE_QUERY_SETUP(blockSingle) auto scenePhysX = (ScenePhysX*)scene; if (scene == nullptr) return false; \
|
#define SCENE_QUERY_SETUP(blockSingle) auto scenePhysX = (ScenePhysX*)scene; if (scene == nullptr) return false; \
|
||||||
const PxHitFlags hitFlags = PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eUV; \
|
|
||||||
PxQueryFilterData filterData; \
|
PxQueryFilterData filterData; \
|
||||||
filterData.flags |= PxQueryFlag::ePREFILTER; \
|
filterData.flags |= PxQueryFlag::ePREFILTER; \
|
||||||
filterData.data.word0 = layerMask; \
|
filterData.data.word0 = layerMask; \
|
||||||
@@ -644,6 +644,19 @@ void GetShapeGeometry(const CollisionShape& shape, PxGeometryHolder& geometry)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetShapeMaterials(Array<PxMaterial*, InlinedAllocation<1>>& materialsPhysX, Span<JsonAsset*> materials)
|
||||||
|
{
|
||||||
|
materialsPhysX.Resize(materials.Length());
|
||||||
|
for (int32 i = 0; i < materials.Length(); i++)
|
||||||
|
{
|
||||||
|
PxMaterial* materialPhysX = DefaultMaterial;
|
||||||
|
const JsonAsset* material = materials.Get()[i];
|
||||||
|
if (material && !material->WaitForLoaded() && material->Instance)
|
||||||
|
materialPhysX = (PxMaterial*)((PhysicalMaterial*)material->Instance)->GetPhysicsMaterial();
|
||||||
|
materialsPhysX.Get()[i] = materialPhysX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PxFilterFlags FilterShader(
|
PxFilterFlags FilterShader(
|
||||||
PxFilterObjectAttributes attributes0, PxFilterData filterData0,
|
PxFilterObjectAttributes attributes0, PxFilterData filterData0,
|
||||||
PxFilterObjectAttributes attributes1, PxFilterData filterData1,
|
PxFilterObjectAttributes attributes1, PxFilterData filterData1,
|
||||||
@@ -1735,8 +1748,6 @@ void PhysicsBackend::EndSimulateScene(void* scene)
|
|||||||
|
|
||||||
{
|
{
|
||||||
PROFILE_CPU_NAMED("Physics.SendEvents");
|
PROFILE_CPU_NAMED("Physics.SendEvents");
|
||||||
|
|
||||||
scenePhysX->EventsCallback.CollectResults();
|
|
||||||
scenePhysX->EventsCallback.SendTriggerEvents();
|
scenePhysX->EventsCallback.SendTriggerEvents();
|
||||||
scenePhysX->EventsCallback.SendCollisionEvents();
|
scenePhysX->EventsCallback.SendCollisionEvents();
|
||||||
scenePhysX->EventsCallback.SendJointEvents();
|
scenePhysX->EventsCallback.SendJointEvents();
|
||||||
@@ -1880,14 +1891,14 @@ bool PhysicsBackend::RayCast(void* scene, const Vector3& origin, const Vector3&
|
|||||||
{
|
{
|
||||||
SCENE_QUERY_SETUP(true);
|
SCENE_QUERY_SETUP(true);
|
||||||
PxRaycastBuffer buffer;
|
PxRaycastBuffer buffer;
|
||||||
return scenePhysX->Scene->raycast(C2P(origin - scenePhysX->Origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter);
|
return scenePhysX->Scene->raycast(C2P(origin - scenePhysX->Origin), C2P(direction), maxDistance, buffer, PxHitFlagEmpty, filterData, &QueryFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicsBackend::RayCast(void* scene, const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
|
bool PhysicsBackend::RayCast(void* scene, const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
|
||||||
{
|
{
|
||||||
SCENE_QUERY_SETUP(true);
|
SCENE_QUERY_SETUP(true);
|
||||||
PxRaycastBuffer buffer;
|
PxRaycastBuffer buffer;
|
||||||
if (!scenePhysX->Scene->raycast(C2P(origin - scenePhysX->Origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
|
if (!scenePhysX->Scene->raycast(C2P(origin - scenePhysX->Origin), C2P(direction), maxDistance, buffer, SCENE_QUERY_FLAGS, filterData, &QueryFilter))
|
||||||
return false;
|
return false;
|
||||||
SCENE_QUERY_COLLECT_SINGLE();
|
SCENE_QUERY_COLLECT_SINGLE();
|
||||||
return true;
|
return true;
|
||||||
@@ -1897,7 +1908,7 @@ bool PhysicsBackend::RayCastAll(void* scene, const Vector3& origin, const Vector
|
|||||||
{
|
{
|
||||||
SCENE_QUERY_SETUP(false);
|
SCENE_QUERY_SETUP(false);
|
||||||
DynamicHitBuffer<PxRaycastHit> buffer;
|
DynamicHitBuffer<PxRaycastHit> buffer;
|
||||||
if (!scenePhysX->Scene->raycast(C2P(origin - scenePhysX->Origin), C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
|
if (!scenePhysX->Scene->raycast(C2P(origin - scenePhysX->Origin), C2P(direction), maxDistance, buffer, SCENE_QUERY_FLAGS, filterData, &QueryFilter))
|
||||||
return false;
|
return false;
|
||||||
SCENE_QUERY_COLLECT_ALL();
|
SCENE_QUERY_COLLECT_ALL();
|
||||||
return true;
|
return true;
|
||||||
@@ -1908,7 +1919,7 @@ bool PhysicsBackend::BoxCast(void* scene, const Vector3& center, const Vector3&
|
|||||||
SCENE_QUERY_SETUP_SWEEP_1();
|
SCENE_QUERY_SETUP_SWEEP_1();
|
||||||
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
||||||
const PxBoxGeometry geometry(C2P(halfExtents));
|
const PxBoxGeometry geometry(C2P(halfExtents));
|
||||||
return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter);
|
return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, PxHitFlagEmpty, filterData, &QueryFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicsBackend::BoxCast(void* scene, const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
|
bool PhysicsBackend::BoxCast(void* scene, const Vector3& center, const Vector3& halfExtents, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
|
||||||
@@ -1916,7 +1927,7 @@ bool PhysicsBackend::BoxCast(void* scene, const Vector3& center, const Vector3&
|
|||||||
SCENE_QUERY_SETUP_SWEEP_1();
|
SCENE_QUERY_SETUP_SWEEP_1();
|
||||||
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
||||||
const PxBoxGeometry geometry(C2P(halfExtents));
|
const PxBoxGeometry geometry(C2P(halfExtents));
|
||||||
if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
|
if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, SCENE_QUERY_FLAGS, filterData, &QueryFilter))
|
||||||
return false;
|
return false;
|
||||||
SCENE_QUERY_COLLECT_SINGLE();
|
SCENE_QUERY_COLLECT_SINGLE();
|
||||||
return true;
|
return true;
|
||||||
@@ -1927,7 +1938,7 @@ bool PhysicsBackend::BoxCastAll(void* scene, const Vector3& center, const Vector
|
|||||||
SCENE_QUERY_SETUP_SWEEP();
|
SCENE_QUERY_SETUP_SWEEP();
|
||||||
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
||||||
const PxBoxGeometry geometry(C2P(halfExtents));
|
const PxBoxGeometry geometry(C2P(halfExtents));
|
||||||
if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
|
if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, SCENE_QUERY_FLAGS, filterData, &QueryFilter))
|
||||||
return false;
|
return false;
|
||||||
SCENE_QUERY_COLLECT_ALL();
|
SCENE_QUERY_COLLECT_ALL();
|
||||||
return true;
|
return true;
|
||||||
@@ -1938,7 +1949,7 @@ bool PhysicsBackend::SphereCast(void* scene, const Vector3& center, const float
|
|||||||
SCENE_QUERY_SETUP_SWEEP_1();
|
SCENE_QUERY_SETUP_SWEEP_1();
|
||||||
const PxTransform pose(C2P(center - scenePhysX->Origin));
|
const PxTransform pose(C2P(center - scenePhysX->Origin));
|
||||||
const PxSphereGeometry geometry(radius);
|
const PxSphereGeometry geometry(radius);
|
||||||
return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter);
|
return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, PxHitFlagEmpty, filterData, &QueryFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicsBackend::SphereCast(void* scene, const Vector3& center, const float radius, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
|
bool PhysicsBackend::SphereCast(void* scene, const Vector3& center, const float radius, const Vector3& direction, RayCastHit& hitInfo, const float maxDistance, uint32 layerMask, bool hitTriggers)
|
||||||
@@ -1946,7 +1957,7 @@ bool PhysicsBackend::SphereCast(void* scene, const Vector3& center, const float
|
|||||||
SCENE_QUERY_SETUP_SWEEP_1();
|
SCENE_QUERY_SETUP_SWEEP_1();
|
||||||
const PxTransform pose(C2P(center - scenePhysX->Origin));
|
const PxTransform pose(C2P(center - scenePhysX->Origin));
|
||||||
const PxSphereGeometry geometry(radius);
|
const PxSphereGeometry geometry(radius);
|
||||||
if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
|
if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, SCENE_QUERY_FLAGS, filterData, &QueryFilter))
|
||||||
return false;
|
return false;
|
||||||
SCENE_QUERY_COLLECT_SINGLE();
|
SCENE_QUERY_COLLECT_SINGLE();
|
||||||
return true;
|
return true;
|
||||||
@@ -1957,7 +1968,7 @@ bool PhysicsBackend::SphereCastAll(void* scene, const Vector3& center, const flo
|
|||||||
SCENE_QUERY_SETUP_SWEEP();
|
SCENE_QUERY_SETUP_SWEEP();
|
||||||
const PxTransform pose(C2P(center - scenePhysX->Origin));
|
const PxTransform pose(C2P(center - scenePhysX->Origin));
|
||||||
const PxSphereGeometry geometry(radius);
|
const PxSphereGeometry geometry(radius);
|
||||||
if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
|
if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, SCENE_QUERY_FLAGS, filterData, &QueryFilter))
|
||||||
return false;
|
return false;
|
||||||
SCENE_QUERY_COLLECT_ALL();
|
SCENE_QUERY_COLLECT_ALL();
|
||||||
return true;
|
return true;
|
||||||
@@ -1968,7 +1979,7 @@ bool PhysicsBackend::CapsuleCast(void* scene, const Vector3& center, const float
|
|||||||
SCENE_QUERY_SETUP_SWEEP_1();
|
SCENE_QUERY_SETUP_SWEEP_1();
|
||||||
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
||||||
const PxCapsuleGeometry geometry(radius, height * 0.5f);
|
const PxCapsuleGeometry geometry(radius, height * 0.5f);
|
||||||
return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter);
|
return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, PxHitFlagEmpty, filterData, &QueryFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicsBackend::CapsuleCast(void* scene, const Vector3& center, const float radius, const float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
|
bool PhysicsBackend::CapsuleCast(void* scene, const Vector3& center, const float radius, const float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
|
||||||
@@ -1976,7 +1987,7 @@ bool PhysicsBackend::CapsuleCast(void* scene, const Vector3& center, const float
|
|||||||
SCENE_QUERY_SETUP_SWEEP_1();
|
SCENE_QUERY_SETUP_SWEEP_1();
|
||||||
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
||||||
const PxCapsuleGeometry geometry(radius, height * 0.5f);
|
const PxCapsuleGeometry geometry(radius, height * 0.5f);
|
||||||
if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
|
if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, SCENE_QUERY_FLAGS, filterData, &QueryFilter))
|
||||||
return false;
|
return false;
|
||||||
SCENE_QUERY_COLLECT_SINGLE();
|
SCENE_QUERY_COLLECT_SINGLE();
|
||||||
return true;
|
return true;
|
||||||
@@ -1987,7 +1998,7 @@ bool PhysicsBackend::CapsuleCastAll(void* scene, const Vector3& center, const fl
|
|||||||
SCENE_QUERY_SETUP_SWEEP();
|
SCENE_QUERY_SETUP_SWEEP();
|
||||||
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
||||||
const PxCapsuleGeometry geometry(radius, height * 0.5f);
|
const PxCapsuleGeometry geometry(radius, height * 0.5f);
|
||||||
if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
|
if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, SCENE_QUERY_FLAGS, filterData, &QueryFilter))
|
||||||
return false;
|
return false;
|
||||||
SCENE_QUERY_COLLECT_ALL();
|
SCENE_QUERY_COLLECT_ALL();
|
||||||
return true;
|
return true;
|
||||||
@@ -1999,7 +2010,7 @@ bool PhysicsBackend::ConvexCast(void* scene, const Vector3& center, const Collis
|
|||||||
SCENE_QUERY_SETUP_SWEEP_1();
|
SCENE_QUERY_SETUP_SWEEP_1();
|
||||||
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
||||||
const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
|
const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
|
||||||
return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter);
|
return scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, PxHitFlagEmpty, filterData, &QueryFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicsBackend::ConvexCast(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
|
bool PhysicsBackend::ConvexCast(void* scene, const Vector3& center, const CollisionData* convexMesh, const Vector3& scale, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
|
||||||
@@ -2008,7 +2019,7 @@ bool PhysicsBackend::ConvexCast(void* scene, const Vector3& center, const Collis
|
|||||||
SCENE_QUERY_SETUP_SWEEP_1();
|
SCENE_QUERY_SETUP_SWEEP_1();
|
||||||
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
||||||
const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
|
const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
|
||||||
if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
|
if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, SCENE_QUERY_FLAGS, filterData, &QueryFilter))
|
||||||
return false;
|
return false;
|
||||||
SCENE_QUERY_COLLECT_SINGLE();
|
SCENE_QUERY_COLLECT_SINGLE();
|
||||||
return true;
|
return true;
|
||||||
@@ -2020,7 +2031,7 @@ bool PhysicsBackend::ConvexCastAll(void* scene, const Vector3& center, const Col
|
|||||||
SCENE_QUERY_SETUP_SWEEP();
|
SCENE_QUERY_SETUP_SWEEP();
|
||||||
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
const PxTransform pose(C2P(center - scenePhysX->Origin), C2P(rotation));
|
||||||
const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
|
const PxConvexMeshGeometry geometry((PxConvexMesh*)convexMesh->GetConvex(), PxMeshScale(C2P(scale)));
|
||||||
if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, &QueryFilter))
|
if (!scenePhysX->Scene->sweep(geometry, pose, C2P(direction), maxDistance, buffer, SCENE_QUERY_FLAGS, filterData, &QueryFilter))
|
||||||
return false;
|
return false;
|
||||||
SCENE_QUERY_COLLECT_ALL();
|
SCENE_QUERY_COLLECT_ALL();
|
||||||
return true;
|
return true;
|
||||||
@@ -2451,17 +2462,14 @@ void PhysicsBackend::AddRigidDynamicActorTorque(void* actor, const Vector3& torq
|
|||||||
actorPhysX->addTorque(C2P(torque), static_cast<PxForceMode::Enum>(mode));
|
actorPhysX->addTorque(C2P(torque), static_cast<PxForceMode::Enum>(mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
void* PhysicsBackend::CreateShape(PhysicsColliderActor* collider, const CollisionShape& geometry, JsonAsset* material, bool enabled, bool trigger)
|
void* PhysicsBackend::CreateShape(PhysicsColliderActor* collider, const CollisionShape& geometry, Span<JsonAsset*> materials, bool enabled, bool trigger)
|
||||||
{
|
{
|
||||||
const PxShapeFlags shapeFlags = GetShapeFlags(trigger, enabled);
|
const PxShapeFlags shapeFlags = GetShapeFlags(trigger, enabled);
|
||||||
PxMaterial* materialPhysX = DefaultMaterial;
|
Array<PxMaterial*, InlinedAllocation<1>> materialsPhysX;
|
||||||
if (material && !material->WaitForLoaded() && material->Instance)
|
GetShapeMaterials(materialsPhysX, materials);
|
||||||
{
|
|
||||||
materialPhysX = (PxMaterial*)((PhysicalMaterial*)material->Instance)->GetPhysicsMaterial();
|
|
||||||
}
|
|
||||||
PxGeometryHolder geometryPhysX;
|
PxGeometryHolder geometryPhysX;
|
||||||
GetShapeGeometry(geometry, geometryPhysX);
|
GetShapeGeometry(geometry, geometryPhysX);
|
||||||
PxShape* shapePhysX = PhysX->createShape(geometryPhysX.any(), *materialPhysX, true, shapeFlags);
|
PxShape* shapePhysX = PhysX->createShape(geometryPhysX.any(), materialsPhysX.Get(), materialsPhysX.Count(), true, shapeFlags);
|
||||||
shapePhysX->userData = collider;
|
shapePhysX->userData = collider;
|
||||||
#if PHYSX_DEBUG_NAMING
|
#if PHYSX_DEBUG_NAMING
|
||||||
shapePhysX->setName("Shape");
|
shapePhysX->setName("Shape");
|
||||||
@@ -2551,15 +2559,12 @@ void PhysicsBackend::SetShapeContactOffset(void* shape, float value)
|
|||||||
shapePhysX->setContactOffset(Math::Max(shapePhysX->getRestOffset() + ZeroTolerance, value));
|
shapePhysX->setContactOffset(Math::Max(shapePhysX->getRestOffset() + ZeroTolerance, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsBackend::SetShapeMaterial(void* shape, JsonAsset* material)
|
void PhysicsBackend::SetShapeMaterials(void* shape, Span<JsonAsset*> materials)
|
||||||
{
|
{
|
||||||
auto shapePhysX = (PxShape*)shape;
|
auto shapePhysX = (PxShape*)shape;
|
||||||
PxMaterial* materialPhysX = DefaultMaterial;
|
Array<PxMaterial*, InlinedAllocation<1>> materialsPhysX;
|
||||||
if (material && !material->WaitForLoaded() && material->Instance)
|
GetShapeMaterials(materialsPhysX, materials);
|
||||||
{
|
shapePhysX->setMaterials(materialsPhysX.Get(), materialsPhysX.Count());
|
||||||
materialPhysX = (PxMaterial*)((PhysicalMaterial*)material->Instance)->GetPhysicsMaterial();
|
|
||||||
}
|
|
||||||
shapePhysX->setMaterials(&materialPhysX, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsBackend::SetShapeGeometry(void* shape, const CollisionShape& geometry)
|
void PhysicsBackend::SetShapeGeometry(void* shape, const CollisionShape& geometry)
|
||||||
@@ -2608,9 +2613,8 @@ bool PhysicsBackend::RayCastShape(void* shape, const Vector3& position, const Qu
|
|||||||
auto shapePhysX = (PxShape*)shape;
|
auto shapePhysX = (PxShape*)shape;
|
||||||
const Vector3 sceneOrigin = SceneOrigins[shapePhysX->getActor() ? shapePhysX->getActor()->getScene() : nullptr];
|
const Vector3 sceneOrigin = SceneOrigins[shapePhysX->getActor() ? shapePhysX->getActor()->getScene() : nullptr];
|
||||||
const PxTransform trans(C2P(position - sceneOrigin), C2P(orientation));
|
const PxTransform trans(C2P(position - sceneOrigin), C2P(orientation));
|
||||||
const PxHitFlags hitFlags = (PxHitFlags)0;
|
|
||||||
PxRaycastHit hit;
|
PxRaycastHit hit;
|
||||||
if (PxGeometryQuery::raycast(C2P(origin - sceneOrigin), C2P(direction), shapePhysX->getGeometry(), trans, maxDistance, hitFlags, 1, &hit) != 0)
|
if (PxGeometryQuery::raycast(C2P(origin - sceneOrigin), C2P(direction), shapePhysX->getGeometry(), trans, maxDistance, PxHitFlagEmpty, 1, &hit) != 0)
|
||||||
{
|
{
|
||||||
resultHitDistance = hit.distance;
|
resultHitDistance = hit.distance;
|
||||||
return true;
|
return true;
|
||||||
@@ -2623,10 +2627,10 @@ bool PhysicsBackend::RayCastShape(void* shape, const Vector3& position, const Qu
|
|||||||
auto shapePhysX = (PxShape*)shape;
|
auto shapePhysX = (PxShape*)shape;
|
||||||
const Vector3 sceneOrigin = SceneOrigins[shapePhysX->getActor() ? shapePhysX->getActor()->getScene() : nullptr];
|
const Vector3 sceneOrigin = SceneOrigins[shapePhysX->getActor() ? shapePhysX->getActor()->getScene() : nullptr];
|
||||||
const PxTransform trans(C2P(position - sceneOrigin), C2P(orientation));
|
const PxTransform trans(C2P(position - sceneOrigin), C2P(orientation));
|
||||||
const PxHitFlags hitFlags = PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eFACE_INDEX | PxHitFlag::eUV;
|
|
||||||
PxRaycastHit hit;
|
PxRaycastHit hit;
|
||||||
if (PxGeometryQuery::raycast(C2P(origin - sceneOrigin), C2P(direction), shapePhysX->getGeometry(), trans, maxDistance, hitFlags, 1, &hit) == 0)
|
if (PxGeometryQuery::raycast(C2P(origin - sceneOrigin), C2P(direction), shapePhysX->getGeometry(), trans, maxDistance, SCENE_QUERY_FLAGS, 1, &hit) == 0)
|
||||||
return false;
|
return false;
|
||||||
|
hit.shape = shapePhysX;
|
||||||
P2C(hit, hitInfo);
|
P2C(hit, hitInfo);
|
||||||
hitInfo.Point += sceneOrigin;
|
hitInfo.Point += sceneOrigin;
|
||||||
return true;
|
return true;
|
||||||
@@ -3004,7 +3008,7 @@ void* PhysicsBackend::CreateController(void* scene, IPhysicsActor* actor, Physic
|
|||||||
desc.material = DefaultMaterial;
|
desc.material = DefaultMaterial;
|
||||||
const float minSize = 0.001f;
|
const float minSize = 0.001f;
|
||||||
desc.height = Math::Max(height, minSize);
|
desc.height = Math::Max(height, minSize);
|
||||||
desc.radius = Math::Max(radius - desc.contactOffset, minSize);
|
desc.radius = Math::Max(radius - Math::Max(contactOffset, 0.0f), minSize);
|
||||||
desc.stepOffset = Math::Min(stepOffset, desc.height + desc.radius * 2.0f - minSize);
|
desc.stepOffset = Math::Min(stepOffset, desc.height + desc.radius * 2.0f - minSize);
|
||||||
auto controllerPhysX = (PxCapsuleController*)scenePhysX->ControllerManager->createController(desc);
|
auto controllerPhysX = (PxCapsuleController*)scenePhysX->ControllerManager->createController(desc);
|
||||||
PxRigidActor* actorPhysX = controllerPhysX->getActor();
|
PxRigidActor* actorPhysX = controllerPhysX->getActor();
|
||||||
@@ -4081,10 +4085,17 @@ void PhysicsBackend::GetHeightFieldSize(void* heightField, int32& rows, int32& c
|
|||||||
columns = (int32)heightFieldPhysX->getNbColumns();
|
columns = (int32)heightFieldPhysX->getNbColumns();
|
||||||
}
|
}
|
||||||
|
|
||||||
float PhysicsBackend::GetHeightFieldHeight(void* heightField, float x, float z)
|
float PhysicsBackend::GetHeightFieldHeight(void* heightField, int32 x, int32 z)
|
||||||
{
|
{
|
||||||
auto heightFieldPhysX = (PxHeightField*)heightField;
|
auto heightFieldPhysX = (PxHeightField*)heightField;
|
||||||
return heightFieldPhysX->getHeight(x, z);
|
return heightFieldPhysX->getHeight((float)x, (float)z);
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsBackend::HeightFieldSample PhysicsBackend::GetHeightFieldSample(void* heightField, int32 x, int32 z)
|
||||||
|
{
|
||||||
|
auto heightFieldPhysX = (PxHeightField*)heightField;
|
||||||
|
auto sample = heightFieldPhysX->getSample(x, z);
|
||||||
|
return { sample.height, sample.materialIndex0, sample.materialIndex1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicsBackend::ModifyHeightField(void* heightField, int32 startCol, int32 startRow, int32 cols, int32 rows, const HeightFieldSample* data)
|
bool PhysicsBackend::ModifyHeightField(void* heightField, int32 startCol, int32 startRow, int32 cols, int32 rows, const HeightFieldSample* data)
|
||||||
|
|||||||
@@ -38,10 +38,6 @@ void SimulationEventCallback::Clear()
|
|||||||
BrokenJoints.Clear();
|
BrokenJoints.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulationEventCallback::CollectResults()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimulationEventCallback::SendCollisionEvents()
|
void SimulationEventCallback::SendCollisionEvents()
|
||||||
{
|
{
|
||||||
for (auto& c : RemovedCollisions)
|
for (auto& c : RemovedCollisions)
|
||||||
@@ -132,7 +128,6 @@ void SimulationEventCallback::onContact(const PxContactPairHeader& pairHeader, c
|
|||||||
//const PxU32 flippedContacts = (pair.flags & PxContactPairFlag::eINTERNAL_CONTACTS_ARE_FLIPPED);
|
//const PxU32 flippedContacts = (pair.flags & PxContactPairFlag::eINTERNAL_CONTACTS_ARE_FLIPPED);
|
||||||
const bool hasImpulses = pair.flags.isSet(PxContactPairFlag::eINTERNAL_HAS_IMPULSES);
|
const bool hasImpulses = pair.flags.isSet(PxContactPairFlag::eINTERNAL_HAS_IMPULSES);
|
||||||
const bool hasPostVelocities = !pair.flags.isSet(PxContactPairFlag::eACTOR_PAIR_LOST_TOUCH);
|
const bool hasPostVelocities = !pair.flags.isSet(PxContactPairFlag::eACTOR_PAIR_LOST_TOUCH);
|
||||||
PxU32 nbContacts = 0;
|
|
||||||
PxVec3 totalImpulse(0.0f);
|
PxVec3 totalImpulse(0.0f);
|
||||||
|
|
||||||
c.ThisActor = static_cast<PhysicsColliderActor*>(pair.shapes[0]->userData);
|
c.ThisActor = static_cast<PhysicsColliderActor*>(pair.shapes[0]->userData);
|
||||||
@@ -144,48 +139,38 @@ void SimulationEventCallback::onContact(const PxContactPairHeader& pairHeader, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Extract contact points
|
// Extract contact points
|
||||||
|
c.ContactsCount = 0;
|
||||||
while (i.hasNextPatch())
|
while (i.hasNextPatch())
|
||||||
{
|
{
|
||||||
i.nextPatch();
|
i.nextPatch();
|
||||||
while (i.hasNextContact() && nbContacts < COLLISION_NAX_CONTACT_POINTS)
|
while (i.hasNextContact() && c.ContactsCount < COLLISION_NAX_CONTACT_POINTS)
|
||||||
{
|
{
|
||||||
i.nextContact();
|
i.nextContact();
|
||||||
|
|
||||||
const PxVec3 point = i.getContactPoint();
|
const PxVec3 point = i.getContactPoint();
|
||||||
const PxVec3 normal = i.getContactNormal();
|
const PxVec3 normal = i.getContactNormal();
|
||||||
if (hasImpulses)
|
if (hasImpulses)
|
||||||
totalImpulse += normal * impulses[nbContacts];
|
totalImpulse += normal * impulses[c.ContactsCount];
|
||||||
|
|
||||||
//PxU32 internalFaceIndex0 = flippedContacts ? iter.getFaceIndex1() : iter.getFaceIndex0();
|
ContactPoint& contact = c.Contacts[c.ContactsCount++];
|
||||||
//PxU32 internalFaceIndex1 = flippedContacts ? iter.getFaceIndex0() : iter.getFaceIndex1();
|
|
||||||
|
|
||||||
ContactPoint& contact = c.Contacts[nbContacts];
|
|
||||||
contact.Point = P2C(point);
|
contact.Point = P2C(point);
|
||||||
contact.Normal = P2C(normal);
|
contact.Normal = P2C(normal);
|
||||||
contact.Separation = i.getSeparation();
|
contact.Separation = i.getSeparation();
|
||||||
|
|
||||||
nbContacts++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
c.Impulse = P2C(totalImpulse);
|
||||||
|
|
||||||
// Extract velocities
|
// Extract velocities
|
||||||
c.ThisVelocity = c.OtherVelocity = Vector3::Zero;
|
c.ThisVelocity = c.OtherVelocity = Vector3::Zero;
|
||||||
if (hasPostVelocities && j.nextItemSet())
|
if (hasPostVelocities && j.nextItemSet())
|
||||||
{
|
{
|
||||||
ASSERT(j.contactPairIndex == pairIndex);
|
ASSERT_LOW_LAYER(j.contactPairIndex == pairIndex);
|
||||||
if (j.postSolverVelocity)
|
if (j.postSolverVelocity)
|
||||||
{
|
{
|
||||||
const PxVec3 linearVelocityActor0 = j.postSolverVelocity->linearVelocity[0];
|
c.ThisVelocity = P2C(j.postSolverVelocity->linearVelocity[0]);
|
||||||
const PxVec3 linearVelocityActor1 = j.postSolverVelocity->linearVelocity[1];
|
c.OtherVelocity = P2C(j.postSolverVelocity->linearVelocity[1]);
|
||||||
|
|
||||||
c.ThisVelocity = P2C(linearVelocityActor0);
|
|
||||||
c.OtherVelocity = P2C(linearVelocityActor1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ContactsCount = nbContacts;
|
|
||||||
c.Impulse = P2C(totalImpulse);
|
|
||||||
|
|
||||||
if (pair.flags & PxContactPairFlag::eACTOR_PAIR_HAS_FIRST_TOUCH)
|
if (pair.flags & PxContactPairFlag::eACTOR_PAIR_HAS_FIRST_TOUCH)
|
||||||
{
|
{
|
||||||
NewCollisions.Add(c);
|
NewCollisions.Add(c);
|
||||||
|
|||||||
@@ -49,11 +49,6 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the new/old/removed collisions and a valid trigger pairs.
|
|
||||||
/// </summary>
|
|
||||||
void CollectResults();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends the collision events to the managed objects.
|
/// Sends the collision events to the managed objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <ThirdParty/PhysX/foundation/PxBounds3.h>
|
#include <ThirdParty/PhysX/foundation/PxBounds3.h>
|
||||||
#include <ThirdParty/PhysX/characterkinematic/PxExtended.h>
|
#include <ThirdParty/PhysX/characterkinematic/PxExtended.h>
|
||||||
#include <ThirdParty/PhysX/PxShape.h>
|
#include <ThirdParty/PhysX/PxShape.h>
|
||||||
|
#include <ThirdParty/PhysX/PxMaterial.h>
|
||||||
#include <ThirdParty/PhysX/PxQueryReport.h>
|
#include <ThirdParty/PhysX/PxQueryReport.h>
|
||||||
|
|
||||||
namespace physx
|
namespace physx
|
||||||
@@ -233,12 +234,28 @@ inline float RadPerSToRpm(float v)
|
|||||||
return v * (30.0f / PI);
|
return v * (30.0f / PI);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline PhysicalMaterial* GetMaterial(const PxShape* shape, PxU32 faceIndex)
|
||||||
|
{
|
||||||
|
if (faceIndex != 0xFFFFffff)
|
||||||
|
{
|
||||||
|
PxBaseMaterial* mat = shape->getMaterialFromInternalFaceIndex(faceIndex);
|
||||||
|
return mat ? (PhysicalMaterial*)mat->userData : nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PxMaterial* mat;
|
||||||
|
shape->getMaterials(&mat, 1);
|
||||||
|
return mat ? (PhysicalMaterial*)mat->userData : nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline void P2C(const PxRaycastHit& hit, RayCastHit& result)
|
inline void P2C(const PxRaycastHit& hit, RayCastHit& result)
|
||||||
{
|
{
|
||||||
result.Point = P2C(hit.position);
|
result.Point = P2C(hit.position);
|
||||||
result.Normal = P2C(hit.normal);
|
result.Normal = P2C(hit.normal);
|
||||||
result.Distance = hit.distance;
|
result.Distance = hit.distance;
|
||||||
result.Collider = hit.shape ? static_cast<PhysicsColliderActor*>(hit.shape->userData) : nullptr;
|
result.Collider = hit.shape ? static_cast<PhysicsColliderActor*>(hit.shape->userData) : nullptr;
|
||||||
|
result.Material = hit.shape ? GetMaterial(hit.shape, hit.faceIndex) : nullptr;
|
||||||
result.FaceIndex = hit.faceIndex;
|
result.FaceIndex = hit.faceIndex;
|
||||||
result.UV.X = hit.u;
|
result.UV.X = hit.u;
|
||||||
result.UV.Y = hit.v;
|
result.UV.Y = hit.v;
|
||||||
@@ -250,6 +267,7 @@ inline void P2C(const PxSweepHit& hit, RayCastHit& result)
|
|||||||
result.Normal = P2C(hit.normal);
|
result.Normal = P2C(hit.normal);
|
||||||
result.Distance = hit.distance;
|
result.Distance = hit.distance;
|
||||||
result.Collider = hit.shape ? static_cast<PhysicsColliderActor*>(hit.shape->userData) : nullptr;
|
result.Collider = hit.shape ? static_cast<PhysicsColliderActor*>(hit.shape->userData) : nullptr;
|
||||||
|
result.Material = hit.shape ? GetMaterial(hit.shape, hit.faceIndex) : nullptr;
|
||||||
result.FaceIndex = hit.faceIndex;
|
result.FaceIndex = hit.faceIndex;
|
||||||
result.UV = Vector2::Zero;
|
result.UV = Vector2::Zero;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,27 +4,21 @@
|
|||||||
|
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
#include "Engine/Core/ISerializable.h"
|
#include "Engine/Core/ISerializable.h"
|
||||||
|
#include "Engine/Scripting/ScriptingObject.h"
|
||||||
#include "Engine/Level/Tags.h"
|
#include "Engine/Level/Tags.h"
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Physical materials are used to define the response of a physical object when interacting dynamically with the world.
|
/// Physical materials are used to define the response of a physical object when interacting dynamically with the world.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_CLASS(Attributes = "ContentContextMenu(\"New/Physics/Physical Material\")") class FLAXENGINE_API PhysicalMaterial final : public ISerializable
|
API_CLASS(Attributes = "ContentContextMenu(\"New/Physics/Physical Material\")")
|
||||||
|
class FLAXENGINE_API PhysicalMaterial final : public ScriptingObject, public ISerializable
|
||||||
{
|
{
|
||||||
API_AUTO_SERIALIZATION();
|
API_AUTO_SERIALIZATION();
|
||||||
DECLARE_SCRIPTING_TYPE_MINIMAL(PhysicalMaterial);
|
DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(PhysicalMaterial, ScriptingObject);
|
||||||
private:
|
private:
|
||||||
void* _material;
|
void* _material = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="PhysicalMaterial"/> class.
|
|
||||||
/// </summary>
|
|
||||||
PhysicalMaterial();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Finalizes an instance of the <see cref="PhysicalMaterial"/> class.
|
|
||||||
/// </summary>
|
|
||||||
~PhysicalMaterial();
|
~PhysicalMaterial();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -78,11 +78,6 @@ void PhysicsSettings::Deserialize(DeserializeStream& stream, ISerializeModifier*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PhysicalMaterial::PhysicalMaterial()
|
|
||||||
: _material(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysicalMaterial::~PhysicalMaterial()
|
PhysicalMaterial::~PhysicalMaterial()
|
||||||
{
|
{
|
||||||
if (_material)
|
if (_material)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "Physics.h"
|
#include "Physics.h"
|
||||||
#include "PhysicsSettings.h"
|
#include "PhysicsSettings.h"
|
||||||
|
#include "Engine/Core/Types/Span.h"
|
||||||
|
|
||||||
struct HingeJointDrive;
|
struct HingeJointDrive;
|
||||||
struct SpringParameters;
|
struct SpringParameters;
|
||||||
@@ -182,7 +183,7 @@ public:
|
|||||||
static void AddRigidDynamicActorTorque(void* actor, const Vector3& torque, ForceMode mode);
|
static void AddRigidDynamicActorTorque(void* actor, const Vector3& torque, ForceMode mode);
|
||||||
|
|
||||||
// Shapes
|
// Shapes
|
||||||
static void* CreateShape(PhysicsColliderActor* collider, const CollisionShape& geometry, JsonAsset* material, bool enabled, bool trigger);
|
static void* CreateShape(PhysicsColliderActor* collider, const CollisionShape& geometry, Span<JsonAsset*> materials, bool enabled, bool trigger);
|
||||||
static void SetShapeState(void* shape, bool enabled, bool trigger);
|
static void SetShapeState(void* shape, bool enabled, bool trigger);
|
||||||
static void SetShapeFilterMask(void* shape, uint32 mask0, uint32 mask1);
|
static void SetShapeFilterMask(void* shape, uint32 mask0, uint32 mask1);
|
||||||
static void* GetShapeActor(void* shape);
|
static void* GetShapeActor(void* shape);
|
||||||
@@ -191,7 +192,7 @@ public:
|
|||||||
static void GetShapeLocalPose(void* shape, Vector3& position, Quaternion& orientation);
|
static void GetShapeLocalPose(void* shape, Vector3& position, Quaternion& orientation);
|
||||||
static void SetShapeLocalPose(void* shape, const Vector3& position, const Quaternion& orientation);
|
static void SetShapeLocalPose(void* shape, const Vector3& position, const Quaternion& orientation);
|
||||||
static void SetShapeContactOffset(void* shape, float value);
|
static void SetShapeContactOffset(void* shape, float value);
|
||||||
static void SetShapeMaterial(void* shape, JsonAsset* material);
|
static void SetShapeMaterials(void* shape, Span<JsonAsset*> materials);
|
||||||
static void SetShapeGeometry(void* shape, const CollisionShape& geometry);
|
static void SetShapeGeometry(void* shape, const CollisionShape& geometry);
|
||||||
static void AttachShape(void* shape, void* actor);
|
static void AttachShape(void* shape, void* actor);
|
||||||
static void DetachShape(void* shape, void* actor);
|
static void DetachShape(void* shape, void* actor);
|
||||||
@@ -303,7 +304,8 @@ public:
|
|||||||
static void GetTriangleMeshTriangles(void* triangleMesh, Array<Float3, HeapAllocation>& vertexBuffer, Array<int32, HeapAllocation>& indexBuffer);
|
static void GetTriangleMeshTriangles(void* triangleMesh, Array<Float3, HeapAllocation>& vertexBuffer, Array<int32, HeapAllocation>& indexBuffer);
|
||||||
static const uint32* GetTriangleMeshRemap(void* triangleMesh, uint32& count);
|
static const uint32* GetTriangleMeshRemap(void* triangleMesh, uint32& count);
|
||||||
static void GetHeightFieldSize(void* heightField, int32& rows, int32& columns);
|
static void GetHeightFieldSize(void* heightField, int32& rows, int32& columns);
|
||||||
static float GetHeightFieldHeight(void* heightField, float x, float z);
|
static float GetHeightFieldHeight(void* heightField, int32 x, int32 z);
|
||||||
|
static HeightFieldSample GetHeightFieldSample(void* heightField, int32 x, int32 z);
|
||||||
static bool ModifyHeightField(void* heightField, int32 startCol, int32 startRow, int32 cols, int32 rows, const HeightFieldSample* data);
|
static bool ModifyHeightField(void* heightField, int32 startCol, int32 startRow, int32 cols, int32 rows, const HeightFieldSample* data);
|
||||||
static void FlushRequests();
|
static void FlushRequests();
|
||||||
static void FlushRequests(void* scene);
|
static void FlushRequests(void* scene);
|
||||||
@@ -330,6 +332,14 @@ public:
|
|||||||
flags = (RigidDynamicFlags)(((uint32)flags & ~(uint32)flag) | (value ? (uint32)flag : 0));
|
flags = (RigidDynamicFlags)(((uint32)flags & ~(uint32)flag) | (value ? (uint32)flag : 0));
|
||||||
SetRigidDynamicActorFlags(actor, flags);
|
SetRigidDynamicActorFlags(actor, flags);
|
||||||
}
|
}
|
||||||
|
FORCE_INLINE static void* CreateShape(PhysicsColliderActor* collider, const CollisionShape& geometry, JsonAsset* material, bool enabled, bool trigger)
|
||||||
|
{
|
||||||
|
return CreateShape(collider, geometry, Span<JsonAsset*>(&material, 1), enabled, trigger);
|
||||||
|
}
|
||||||
|
FORCE_INLINE static void SetShapeMaterial(void* shape, JsonAsset* material)
|
||||||
|
{
|
||||||
|
SetShapeMaterials(shape, Span<JsonAsset*>(&material, 1));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_ENUM_OPERATORS(PhysicsBackend::ActorFlags);
|
DECLARE_ENUM_OPERATORS(PhysicsBackend::ActorFlags);
|
||||||
|
|||||||
@@ -408,7 +408,7 @@ void PhysicsBackend::AddRigidDynamicActorTorque(void* actor, const Vector3& torq
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void* PhysicsBackend::CreateShape(PhysicsColliderActor* collider, const CollisionShape& geometry, JsonAsset* material, bool enabled, bool trigger)
|
void* PhysicsBackend::CreateShape(PhysicsColliderActor* collider, const CollisionShape& geometry, Span<JsonAsset*> materials, bool enabled, bool trigger)
|
||||||
{
|
{
|
||||||
return DUMY_HANDLE;
|
return DUMY_HANDLE;
|
||||||
}
|
}
|
||||||
@@ -447,7 +447,7 @@ void PhysicsBackend::SetShapeContactOffset(void* shape, float value)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsBackend::SetShapeMaterial(void* shape, JsonAsset* material)
|
void PhysicsBackend::SetShapeMaterials(void* shape, Span<JsonAsset*> materials)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -826,11 +826,16 @@ void PhysicsBackend::GetHeightFieldSize(void* heightField, int32& rows, int32& c
|
|||||||
columns = 0;
|
columns = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
float PhysicsBackend::GetHeightFieldHeight(void* heightField, float x, float z)
|
float PhysicsBackend::GetHeightFieldHeight(void* heightField, int32 x, int32 z)
|
||||||
{
|
{
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PhysicsBackend::HeightFieldSample PhysicsBackend::GetHeightFieldSample(void* heightField, int32 x, int32 z)
|
||||||
|
{
|
||||||
|
return HeightFieldSample();
|
||||||
|
}
|
||||||
|
|
||||||
bool PhysicsBackend::ModifyHeightField(void* heightField, int32 startCol, int32 startRow, int32 cols, int32 rows, const HeightFieldSample* data)
|
bool PhysicsBackend::ModifyHeightField(void* heightField, int32 startCol, int32 startRow, int32 cols, int32 rows, const HeightFieldSample* data)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
struct PhysicsStatistics;
|
struct PhysicsStatistics;
|
||||||
class PhysicsColliderActor;
|
class PhysicsColliderActor;
|
||||||
class PhysicsScene;
|
class PhysicsScene;
|
||||||
|
class PhysicalMaterial;
|
||||||
class Joint;
|
class Joint;
|
||||||
class Collider;
|
class Collider;
|
||||||
class CollisionData;
|
class CollisionData;
|
||||||
@@ -132,7 +133,7 @@ DECLARE_ENUM_OPERATORS(RigidbodyConstraints);
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raycast hit result data.
|
/// Raycast hit result data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_STRUCT() struct RayCastHit
|
API_STRUCT(NoDefault) struct RayCastHit
|
||||||
{
|
{
|
||||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(RayCastHit);
|
DECLARE_SCRIPTING_TYPE_NO_SPAWN(RayCastHit);
|
||||||
|
|
||||||
@@ -141,6 +142,11 @@ API_STRUCT() struct RayCastHit
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() PhysicsColliderActor* Collider = nullptr;
|
API_FIELD() PhysicsColliderActor* Collider = nullptr;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The physical material of the surface that was hit.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD() PhysicalMaterial* Material = nullptr;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The normal of the surface the ray hit.
|
/// The normal of the surface the ray hit.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -151,17 +157,17 @@ API_STRUCT() struct RayCastHit
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() float Distance;
|
API_FIELD() float Distance;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The point in the world space where ray hit the collider.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD() Vector3 Point;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The index of the face that was hit. Valid only for convex mesh (polygon index), triangle mesh (triangle index) and height field (triangle index).
|
/// The index of the face that was hit. Valid only for convex mesh (polygon index), triangle mesh (triangle index) and height field (triangle index).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="CollisionData.GetModelTriangle" />
|
/// <seealso cref="CollisionData.GetModelTriangle" />
|
||||||
API_FIELD() uint32 FaceIndex;
|
API_FIELD() uint32 FaceIndex;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The point in the world space where ray hit the collider.
|
|
||||||
/// </summary>
|
|
||||||
API_FIELD() Vector3 Point;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The barycentric coordinates of hit triangle. Valid only for triangle mesh and height field.
|
/// The barycentric coordinates of hit triangle. Valid only for triangle mesh and height field.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -61,6 +61,16 @@ namespace FlaxEngine
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public float Spacing;
|
public float Spacing;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The minimum size of the collection.
|
||||||
|
/// </summary>
|
||||||
|
public int MinCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum size of the collection. Zero if unlimited.
|
||||||
|
/// </summary>
|
||||||
|
public int MaxCount;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The collection background color.
|
/// The collection background color.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -68,4 +68,30 @@ public:
|
|||||||
{
|
{
|
||||||
return FromString<EnumType>(StringAnsi(name));
|
return FromString<EnumType>(StringAnsi(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gets the name of the enum value as separated flags
|
||||||
|
template<class EnumType>
|
||||||
|
static String ToStringFlags(EnumType value, Char separator = '|')
|
||||||
|
{
|
||||||
|
String result;
|
||||||
|
if (const auto items = GetItems<EnumType>())
|
||||||
|
{
|
||||||
|
for (int32 i = 0; items[i].Name; i++)
|
||||||
|
{
|
||||||
|
const uint64 itemValue = items[i].Value;
|
||||||
|
if ((uint64)value == 0 && itemValue == 0)
|
||||||
|
{
|
||||||
|
result = items[i].Name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (itemValue != 0 && EnumHasAllFlags<EnumType>(value, (EnumType)itemValue))
|
||||||
|
{
|
||||||
|
if (result.HasChars())
|
||||||
|
result += separator;
|
||||||
|
result += items[i].Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ bool cacheStaticGeometryTree(Actor* actor, ShadowsOfMordor::Builder::SceneBuildC
|
|||||||
{
|
{
|
||||||
auto patch = terrain->GetPatch(patchIndex);
|
auto patch = terrain->GetPatch(patchIndex);
|
||||||
entry.AsTerrain.PatchIndex = patchIndex;
|
entry.AsTerrain.PatchIndex = patchIndex;
|
||||||
for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++)
|
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||||
{
|
{
|
||||||
auto chunk = patch->Chunks[chunkIndex];
|
auto chunk = patch->Chunks[chunkIndex];
|
||||||
entry.AsTerrain.ChunkIndex = chunkIndex;
|
entry.AsTerrain.ChunkIndex = chunkIndex;
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ void ShadowsOfMordor::Builder::onJobRender(GPUContext* context)
|
|||||||
Matrix::Transpose(world, shaderData.WorldMatrix);
|
Matrix::Transpose(world, shaderData.WorldMatrix);
|
||||||
shaderData.LightmapArea = chunk->Lightmap.UVsArea;
|
shaderData.LightmapArea = chunk->Lightmap.UVsArea;
|
||||||
shaderData.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize;
|
shaderData.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize;
|
||||||
chunk->GetHeightmapUVScaleBias(&shaderData.HeightmapUVScaleBias);
|
shaderData.HeightmapUVScaleBias = chunk->GetHeightmapUVScaleBias();
|
||||||
|
|
||||||
// Extract per axis scales from LocalToWorld transform
|
// Extract per axis scales from LocalToWorld transform
|
||||||
const float scaleX = Float3(world.M11, world.M12, world.M13).Length();
|
const float scaleX = Float3(world.M11, world.M12, world.M13).Length();
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ Terrain::Terrain(const SpawnParams& params)
|
|||||||
, _cachedScale(1.0f)
|
, _cachedScale(1.0f)
|
||||||
{
|
{
|
||||||
_drawCategory = SceneRendering::SceneDrawAsync;
|
_drawCategory = SceneRendering::SceneDrawAsync;
|
||||||
PhysicalMaterial.Changed.Bind<Terrain, &Terrain::OnPhysicalMaterialChanged>(this);
|
_physicalMaterials.Resize(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
Terrain::~Terrain()
|
Terrain::~Terrain()
|
||||||
@@ -59,7 +59,7 @@ void Terrain::CacheNeighbors()
|
|||||||
for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++)
|
for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++)
|
||||||
{
|
{
|
||||||
const auto patch = _patches[pathIndex];
|
const auto patch = _patches[pathIndex];
|
||||||
for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++)
|
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||||
{
|
{
|
||||||
patch->Chunks[chunkIndex].CacheNeighbors();
|
patch->Chunks[chunkIndex].CacheNeighbors();
|
||||||
}
|
}
|
||||||
@@ -185,7 +185,7 @@ bool Terrain::RayCast(const Vector3& origin, const Vector3& direction, RayCastHi
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terrain::ClosestPoint(const Vector3& position, Vector3& result) const
|
void Terrain::ClosestPoint(const Vector3& point, Vector3& result) const
|
||||||
{
|
{
|
||||||
Real minDistance = MAX_Real;
|
Real minDistance = MAX_Real;
|
||||||
Vector3 tmp;
|
Vector3 tmp;
|
||||||
@@ -194,8 +194,8 @@ void Terrain::ClosestPoint(const Vector3& position, Vector3& result) const
|
|||||||
const auto patch = _patches[pathIndex];
|
const auto patch = _patches[pathIndex];
|
||||||
if (patch->HasCollision())
|
if (patch->HasCollision())
|
||||||
{
|
{
|
||||||
patch->ClosestPoint(position, tmp);
|
patch->ClosestPoint(point, tmp);
|
||||||
const auto distance = Vector3::DistanceSquared(position, tmp);
|
const auto distance = Vector3::DistanceSquared(point, tmp);
|
||||||
if (distance < minDistance)
|
if (distance < minDistance)
|
||||||
{
|
{
|
||||||
minDistance = distance;
|
minDistance = distance;
|
||||||
@@ -205,12 +205,17 @@ void Terrain::ClosestPoint(const Vector3& position, Vector3& result) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Terrain::ContainsPoint(const Vector3& point) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Terrain::DrawPatch(const RenderContext& renderContext, const Int2& patchCoord, MaterialBase* material, int32 lodIndex) const
|
void Terrain::DrawPatch(const RenderContext& renderContext, const Int2& patchCoord, MaterialBase* material, int32 lodIndex) const
|
||||||
{
|
{
|
||||||
auto patch = GetPatch(patchCoord);
|
auto patch = GetPatch(patchCoord);
|
||||||
if (patch)
|
if (patch)
|
||||||
{
|
{
|
||||||
for (int32 i = 0; i < TerrainPatch::CHUNKS_COUNT; i++)
|
for (int32 i = 0; i < Terrain::ChunksCount; i++)
|
||||||
patch->Chunks[i].Draw(renderContext, material, lodIndex);
|
patch->Chunks[i].Draw(renderContext, material, lodIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,22 +233,6 @@ void Terrain::DrawChunk(const RenderContext& renderContext, const Int2& patchCoo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terrain::OnPhysicalMaterialChanged()
|
|
||||||
{
|
|
||||||
if (_patches.IsEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Update the shapes material
|
|
||||||
for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++)
|
|
||||||
{
|
|
||||||
const auto patch = _patches[pathIndex];
|
|
||||||
if (patch->HasCollision())
|
|
||||||
{
|
|
||||||
PhysicsBackend::SetShapeMaterial(patch->_physicsShape, PhysicalMaterial.Get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||||
|
|
||||||
void Terrain::DrawPhysicsDebug(RenderView& view)
|
void Terrain::DrawPhysicsDebug(RenderView& view)
|
||||||
@@ -295,6 +284,21 @@ void Terrain::SetCollisionLOD(int32 value)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Terrain::SetPhysicalMaterials(const Array<JsonAssetReference<PhysicalMaterial>, FixedAllocation<8>>& value)
|
||||||
|
{
|
||||||
|
_physicalMaterials = value;
|
||||||
|
_physicalMaterials.Resize(8);
|
||||||
|
JsonAsset* materials[8];
|
||||||
|
for (int32 i = 0;i<8;i++)
|
||||||
|
materials[i] = _physicalMaterials[i];
|
||||||
|
for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++)
|
||||||
|
{
|
||||||
|
const auto patch = _patches.Get()[pathIndex];
|
||||||
|
if (patch->HasCollision())
|
||||||
|
PhysicsBackend::SetShapeMaterials(patch->_physicsShape, ToSpan(materials, 8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TerrainPatch* Terrain::GetPatch(const Int2& patchCoord) const
|
TerrainPatch* Terrain::GetPatch(const Int2& patchCoord) const
|
||||||
{
|
{
|
||||||
return GetPatch(patchCoord.X, patchCoord.Y);
|
return GetPatch(patchCoord.X, patchCoord.Y);
|
||||||
@@ -540,7 +544,7 @@ void Terrain::Draw(RenderContext& renderContext)
|
|||||||
Matrix localToWorld, worldToLocal;
|
Matrix localToWorld, worldToLocal;
|
||||||
BoundingSphere chunkSphere;
|
BoundingSphere chunkSphere;
|
||||||
BoundingBox localBounds;
|
BoundingBox localBounds;
|
||||||
for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++)
|
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||||
{
|
{
|
||||||
TerrainChunk* chunk = &patch->Chunks[chunkIndex];
|
TerrainChunk* chunk = &patch->Chunks[chunkIndex];
|
||||||
chunk->GetTransform().GetWorld(localToWorld); // TODO: large-worlds
|
chunk->GetTransform().GetWorld(localToWorld); // TODO: large-worlds
|
||||||
@@ -570,7 +574,7 @@ void Terrain::Draw(RenderContext& renderContext)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Frustum vs Box culling for chunks
|
// Frustum vs Box culling for chunks
|
||||||
for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++)
|
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||||
{
|
{
|
||||||
auto chunk = &patch->Chunks[chunkIndex];
|
auto chunk = &patch->Chunks[chunkIndex];
|
||||||
chunk->_cachedDrawLOD = 0;
|
chunk->_cachedDrawLOD = 0;
|
||||||
@@ -588,7 +592,7 @@ void Terrain::Draw(RenderContext& renderContext)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Reset cached LOD for chunks (prevent LOD transition from invisible chunks)
|
// Reset cached LOD for chunks (prevent LOD transition from invisible chunks)
|
||||||
for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++)
|
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||||
{
|
{
|
||||||
auto chunk = &patch->Chunks[chunkIndex];
|
auto chunk = &patch->Chunks[chunkIndex];
|
||||||
chunk->_cachedDrawLOD = 0;
|
chunk->_cachedDrawLOD = 0;
|
||||||
@@ -616,10 +620,10 @@ void Terrain::OnDebugDrawSelected()
|
|||||||
for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++)
|
for (int32 pathIndex = 0; pathIndex < _patches.Count(); pathIndex++)
|
||||||
{
|
{
|
||||||
const auto patch = _patches[pathIndex];
|
const auto patch = _patches[pathIndex];
|
||||||
for (int32 chunkIndex = 0; chunkIndex < TerrainPatch::CHUNKS_COUNT; chunkIndex++)
|
for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++)
|
||||||
{
|
{
|
||||||
auto chunk = &patch->Chunks[chunkIndex];
|
auto chunk = &patch->Chunks[chunkIndex];
|
||||||
DebugDraw::DrawBox(chunk->_bounds, Color(chunk->_x / (float)TerrainPatch::CHUNKS_COUNT_EDGE, 1.0f, chunk->_z / (float)TerrainPatch::CHUNKS_COUNT_EDGE));
|
DebugDraw::DrawBox(chunk->_bounds, Color(chunk->_x / (float)Terrain::ChunksCountEdge, 1.0f, chunk->_z / (float)Terrain::ChunksCountEdge));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@@ -667,8 +671,8 @@ void Terrain::Serialize(SerializeStream& stream, const void* otherObj)
|
|||||||
SERIALIZE_MEMBER(ScaleInLightmap, _scaleInLightmap);
|
SERIALIZE_MEMBER(ScaleInLightmap, _scaleInLightmap);
|
||||||
SERIALIZE_MEMBER(BoundsExtent, _boundsExtent);
|
SERIALIZE_MEMBER(BoundsExtent, _boundsExtent);
|
||||||
SERIALIZE_MEMBER(CollisionLOD, _collisionLod);
|
SERIALIZE_MEMBER(CollisionLOD, _collisionLod);
|
||||||
|
SERIALIZE_MEMBER(PhysicalMaterials, _physicalMaterials);
|
||||||
SERIALIZE(Material);
|
SERIALIZE(Material);
|
||||||
SERIALIZE(PhysicalMaterial);
|
|
||||||
SERIALIZE(DrawModes);
|
SERIALIZE(DrawModes);
|
||||||
|
|
||||||
SERIALIZE_MEMBER(LODCount, _lodCount);
|
SERIALIZE_MEMBER(LODCount, _lodCount);
|
||||||
@@ -714,8 +718,8 @@ void Terrain::Deserialize(DeserializeStream& stream, ISerializeModifier* modifie
|
|||||||
DESERIALIZE_MEMBER(LODDistribution, _lodDistribution);
|
DESERIALIZE_MEMBER(LODDistribution, _lodDistribution);
|
||||||
DESERIALIZE_MEMBER(ScaleInLightmap, _scaleInLightmap);
|
DESERIALIZE_MEMBER(ScaleInLightmap, _scaleInLightmap);
|
||||||
DESERIALIZE_MEMBER(BoundsExtent, _boundsExtent);
|
DESERIALIZE_MEMBER(BoundsExtent, _boundsExtent);
|
||||||
|
DESERIALIZE_MEMBER(PhysicalMaterials, _physicalMaterials);
|
||||||
DESERIALIZE(Material);
|
DESERIALIZE(Material);
|
||||||
DESERIALIZE(PhysicalMaterial);
|
|
||||||
DESERIALIZE(DrawModes);
|
DESERIALIZE(DrawModes);
|
||||||
|
|
||||||
member = stream.FindMember("LODCount");
|
member = stream.FindMember("LODCount");
|
||||||
@@ -780,6 +784,15 @@ void Terrain::Deserialize(DeserializeStream& stream, ISerializeModifier* modifie
|
|||||||
// [Deprecated on 27.04.2022, expires on 27.04.2024]
|
// [Deprecated on 27.04.2022, expires on 27.04.2024]
|
||||||
if (modifier->EngineBuild <= 6331)
|
if (modifier->EngineBuild <= 6331)
|
||||||
DrawModes |= DrawPass::GlobalSurfaceAtlas;
|
DrawModes |= DrawPass::GlobalSurfaceAtlas;
|
||||||
|
|
||||||
|
// [Deprecated on 15.02.2024, expires on 15.02.2026]
|
||||||
|
JsonAssetReference<PhysicalMaterial> PhysicalMaterial;
|
||||||
|
DESERIALIZE(PhysicalMaterial);
|
||||||
|
if (PhysicalMaterial)
|
||||||
|
{
|
||||||
|
for (auto& e : _physicalMaterials)
|
||||||
|
e = PhysicalMaterial;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RigidBody* Terrain::GetAttachedRigidBody() const
|
RigidBody* Terrain::GetAttachedRigidBody() const
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Engine/Content/JsonAsset.h"
|
#include "Engine/Content/JsonAssetReference.h"
|
||||||
#include "Engine/Content/Assets/MaterialBase.h"
|
#include "Engine/Content/Assets/MaterialBase.h"
|
||||||
#include "Engine/Physics/Actors/PhysicsColliderActor.h"
|
#include "Engine/Physics/Actors/PhysicsColliderActor.h"
|
||||||
|
|
||||||
@@ -10,6 +10,7 @@ class Terrain;
|
|||||||
class TerrainChunk;
|
class TerrainChunk;
|
||||||
class TerrainPatch;
|
class TerrainPatch;
|
||||||
class TerrainManager;
|
class TerrainManager;
|
||||||
|
class PhysicalMaterial;
|
||||||
struct RayCastHit;
|
struct RayCastHit;
|
||||||
struct RenderView;
|
struct RenderView;
|
||||||
|
|
||||||
@@ -23,10 +24,7 @@ struct RenderView;
|
|||||||
#define TERRAIN_EDITING 1
|
#define TERRAIN_EDITING 1
|
||||||
|
|
||||||
// Enable/disable terrain heightmap samples modification and gather. Used by the editor to modify the terrain with the brushes.
|
// Enable/disable terrain heightmap samples modification and gather. Used by the editor to modify the terrain with the brushes.
|
||||||
#define TERRAIN_UPDATING (USE_EDITOR)
|
#define TERRAIN_UPDATING 1
|
||||||
|
|
||||||
// Enable/disable precise terrain geometry collision testing (with in-build vertex buffer caching, this will increase memory usage)
|
|
||||||
#define USE_PRECISE_TERRAIN_INTERSECTS (USE_EDITOR)
|
|
||||||
|
|
||||||
// Enable/disable terrain physics collision drawing
|
// Enable/disable terrain physics collision drawing
|
||||||
#define TERRAIN_USE_PHYSICS_DEBUG (USE_EDITOR && 1)
|
#define TERRAIN_USE_PHYSICS_DEBUG (USE_EDITOR && 1)
|
||||||
@@ -41,13 +39,28 @@ struct RenderView;
|
|||||||
/// <seealso cref="PhysicsColliderActor" />
|
/// <seealso cref="PhysicsColliderActor" />
|
||||||
API_CLASS(Sealed) class FLAXENGINE_API Terrain : public PhysicsColliderActor
|
API_CLASS(Sealed) class FLAXENGINE_API Terrain : public PhysicsColliderActor
|
||||||
{
|
{
|
||||||
DECLARE_SCENE_OBJECT(Terrain);
|
DECLARE_SCENE_OBJECT(Terrain);
|
||||||
friend Terrain;
|
friend Terrain;
|
||||||
friend TerrainPatch;
|
friend TerrainPatch;
|
||||||
friend TerrainChunk;
|
friend TerrainChunk;
|
||||||
|
|
||||||
private:
|
/// <summary>
|
||||||
|
/// Various defines regarding terrain configuration.
|
||||||
|
/// </summary>
|
||||||
|
API_ENUM() enum Config
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum allowed amount of chunks per patch.
|
||||||
|
/// </summary>
|
||||||
|
ChunksCount = 16,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum allowed amount of chunks per chunk.
|
||||||
|
/// </summary>
|
||||||
|
ChunksCountEdge = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
char _lodBias;
|
char _lodBias;
|
||||||
char _forcedLod;
|
char _forcedLod;
|
||||||
char _collisionLod;
|
char _collisionLod;
|
||||||
@@ -60,28 +73,21 @@ private:
|
|||||||
Float3 _cachedScale;
|
Float3 _cachedScale;
|
||||||
Array<TerrainPatch*, InlinedAllocation<64>> _patches;
|
Array<TerrainPatch*, InlinedAllocation<64>> _patches;
|
||||||
Array<TerrainChunk*> _drawChunks;
|
Array<TerrainChunk*> _drawChunks;
|
||||||
|
Array<JsonAssetReference<PhysicalMaterial>, FixedAllocation<8>> _physicalMaterials;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finalizes an instance of the <see cref="Terrain"/> class.
|
/// Finalizes an instance of the <see cref="Terrain"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
~Terrain();
|
~Terrain();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default material used for terrain rendering (chunks can override this).
|
/// The default material used for terrain rendering (chunks can override this).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD(Attributes="EditorOrder(100), DefaultValue(null), EditorDisplay(\"Terrain\")")
|
API_FIELD(Attributes="EditorOrder(100), DefaultValue(null), EditorDisplay(\"Terrain\")")
|
||||||
AssetReference<MaterialBase> Material;
|
AssetReference<MaterialBase> Material;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The physical material used to define the terrain collider physical properties.
|
|
||||||
/// </summary>
|
|
||||||
API_FIELD(Attributes="EditorOrder(520), DefaultValue(null), Limit(-1, 100, 0.1f), EditorDisplay(\"Collision\"), AssetReference(typeof(PhysicalMaterial), true)")
|
|
||||||
AssetReference<JsonAsset> PhysicalMaterial;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The draw passes to use for rendering this object.
|
/// The draw passes to use for rendering this object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -89,7 +95,6 @@ public:
|
|||||||
DrawPass DrawModes = DrawPass::Default;
|
DrawPass DrawModes = DrawPass::Default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the terrain Level Of Detail bias value. Allows to increase or decrease rendered terrain quality.
|
/// Gets the terrain Level Of Detail bias value. Allows to increase or decrease rendered terrain quality.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -180,6 +185,21 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
API_PROPERTY() void SetCollisionLOD(int32 value);
|
API_PROPERTY() void SetCollisionLOD(int32 value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the list with physical materials used to define the terrain collider physical properties - each for terrain layer (layer index matches index in this array).
|
||||||
|
/// </summary>
|
||||||
|
API_PROPERTY(Attributes="EditorOrder(520), EditorDisplay(\"Collision\"), Collection(MinCount = 8, MaxCount = 8)")
|
||||||
|
FORCE_INLINE const Array<JsonAssetReference<PhysicalMaterial>, FixedAllocation<8>>& GetPhysicalMaterials() const
|
||||||
|
{
|
||||||
|
return _physicalMaterials;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the list with physical materials used to define the terrain collider physical properties - each for terrain layer (layer index matches index in this array).
|
||||||
|
/// </summary>
|
||||||
|
API_PROPERTY()
|
||||||
|
void SetPhysicalMaterials(const Array<JsonAssetReference<PhysicalMaterial>, FixedAllocation<8>>& value);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the terrain Level Of Detail count.
|
/// Gets the terrain Level Of Detail count.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -219,7 +239,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="patchCoord">The patch location (x and z).</param>
|
/// <param name="patchCoord">The patch location (x and z).</param>
|
||||||
/// <returns>The patch.</returns>
|
/// <returns>The patch.</returns>
|
||||||
TerrainPatch* GetPatch(const Int2& patchCoord) const;
|
API_FUNCTION() TerrainPatch* GetPatch(API_PARAM(Ref) const Int2& patchCoord) const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the patch at the given location.
|
/// Gets the patch at the given location.
|
||||||
@@ -227,7 +247,7 @@ public:
|
|||||||
/// <param name="x">The patch location x.</param>
|
/// <param name="x">The patch location x.</param>
|
||||||
/// <param name="z">The patch location z.</param>
|
/// <param name="z">The patch location z.</param>
|
||||||
/// <returns>The patch.</returns>
|
/// <returns>The patch.</returns>
|
||||||
TerrainPatch* GetPatch(int32 x, int32 z) const;
|
API_FUNCTION() TerrainPatch* GetPatch(int32 x, int32 z) const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the zero-based index of the terrain patch in the terrain patches collection.
|
/// Gets the zero-based index of the terrain patch in the terrain patches collection.
|
||||||
@@ -241,7 +261,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index">The index.</param>
|
/// <param name="index">The index.</param>
|
||||||
/// <returns>The patch.</returns>
|
/// <returns>The patch.</returns>
|
||||||
FORCE_INLINE TerrainPatch* GetPatch(int32 index) const
|
API_FUNCTION() FORCE_INLINE TerrainPatch* GetPatch(int32 index) const
|
||||||
{
|
{
|
||||||
return _patches[index];
|
return _patches[index];
|
||||||
}
|
}
|
||||||
@@ -311,9 +331,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
#if TERRAIN_EDITING
|
#if TERRAIN_EDITING
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Setups the terrain. Clears the existing data.
|
/// Setups the terrain. Clears the existing data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -338,7 +356,6 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="patchCoord">The patch location (x and z).</param>
|
/// <param name="patchCoord">The patch location (x and z).</param>
|
||||||
API_FUNCTION() void RemovePatch(API_PARAM(Ref) const Int2& patchCoord);
|
API_FUNCTION() void RemovePatch(API_PARAM(Ref) const Int2& patchCoord);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -362,17 +379,6 @@ public:
|
|||||||
void RemoveLightmap();
|
void RemoveLightmap();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Performs a raycast against this terrain collision shape.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="origin">The origin of the ray.</param>
|
|
||||||
/// <param name="direction">The normalized direction of the ray.</param>
|
|
||||||
/// <param name="resultHitDistance">The raycast result hit position distance from the ray origin. Valid only if raycast hits anything.</param>
|
|
||||||
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
|
||||||
/// <returns>True if ray hits an object, otherwise false.</returns>
|
|
||||||
API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, float maxDistance = MAX_float) const;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs a raycast against this terrain collision shape. Returns the hit chunk.
|
/// Performs a raycast against this terrain collision shape. Returns the hit chunk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -382,7 +388,7 @@ public:
|
|||||||
/// <param name="resultChunk">The raycast result hit chunk. Valid only if raycast hits anything.</param>
|
/// <param name="resultChunk">The raycast result hit chunk. Valid only if raycast hits anything.</param>
|
||||||
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
||||||
/// <returns>True if ray hits an object, otherwise false.</returns>
|
/// <returns>True if ray hits an object, otherwise false.</returns>
|
||||||
bool RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, TerrainChunk*& resultChunk, float maxDistance = MAX_float) const;
|
API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) float& resultHitDistance, API_PARAM(Out) TerrainChunk*& resultChunk, float maxDistance = MAX_float) const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs a raycast against this terrain collision shape. Returns the hit chunk.
|
/// Performs a raycast against this terrain collision shape. Returns the hit chunk.
|
||||||
@@ -395,23 +401,6 @@ public:
|
|||||||
/// <returns>True if ray hits an object, otherwise false.</returns>
|
/// <returns>True if ray hits an object, otherwise false.</returns>
|
||||||
API_FUNCTION() bool RayCast(const Ray& ray, API_PARAM(Out) float& resultHitDistance, API_PARAM(Out) Int2& resultPatchCoord, API_PARAM(Out) Int2& resultChunkCoord, float maxDistance = MAX_float) const;
|
API_FUNCTION() bool RayCast(const Ray& ray, API_PARAM(Out) float& resultHitDistance, API_PARAM(Out) Int2& resultPatchCoord, API_PARAM(Out) Int2& resultChunkCoord, float maxDistance = MAX_float) const;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Performs a raycast against terrain collision, returns results in a RayCastHit structure.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="origin">The origin of the ray.</param>
|
|
||||||
/// <param name="direction">The normalized direction of the ray.</param>
|
|
||||||
/// <param name="hitInfo">The result hit information. Valid only when method returns true.</param>
|
|
||||||
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
|
||||||
/// <returns>True if ray hits an object, otherwise false.</returns>
|
|
||||||
API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) RayCastHit& hitInfo, float maxDistance = MAX_float) const;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a point on the terrain collider that is closest to a given location. Can be used to find a hit location or position to apply explosion force or any other special effects.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="position">The position to find the closest point to it.</param>
|
|
||||||
/// <param name="result">The result point on the collider that is closest to the specified location.</param>
|
|
||||||
API_FUNCTION() void ClosestPoint(const Vector3& position, API_PARAM(Out) Vector3& result) const;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Draws the terrain patch.
|
/// Draws the terrain patch.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -432,14 +421,11 @@ public:
|
|||||||
API_FUNCTION() void DrawChunk(API_PARAM(Ref) const RenderContext& renderContext, API_PARAM(Ref) const Int2& patchCoord, API_PARAM(Ref) const Int2& chunkCoord, MaterialBase* material, int32 lodIndex = 0) const;
|
API_FUNCTION() void DrawChunk(API_PARAM(Ref) const RenderContext& renderContext, API_PARAM(Ref) const Int2& patchCoord, API_PARAM(Ref) const Int2& chunkCoord, MaterialBase* material, int32 lodIndex = 0) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void OnPhysicalMaterialChanged();
|
|
||||||
#if TERRAIN_USE_PHYSICS_DEBUG
|
#if TERRAIN_USE_PHYSICS_DEBUG
|
||||||
void DrawPhysicsDebug(RenderView& view);
|
void DrawPhysicsDebug(RenderView& view);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// [PhysicsColliderActor]
|
// [PhysicsColliderActor]
|
||||||
void Draw(RenderContext& renderContext) override;
|
void Draw(RenderContext& renderContext) override;
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
@@ -450,9 +436,12 @@ public:
|
|||||||
void Serialize(SerializeStream& stream, const void* otherObj) override;
|
void Serialize(SerializeStream& stream, const void* otherObj) override;
|
||||||
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
|
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
|
||||||
RigidBody* GetAttachedRigidBody() const override;
|
RigidBody* GetAttachedRigidBody() const override;
|
||||||
|
bool RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, float maxDistance = MAX_float) const final;
|
||||||
|
bool RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, float maxDistance = MAX_float) const final;
|
||||||
|
void ClosestPoint(const Vector3& point, Vector3& result) const final;
|
||||||
|
bool ContainsPoint(const Vector3& point) const final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// [PhysicsColliderActor]
|
// [PhysicsColliderActor]
|
||||||
void OnEnable() override;
|
void OnEnable() override;
|
||||||
void OnDisable() override;
|
void OnDisable() override;
|
||||||
|
|||||||
@@ -11,7 +11,14 @@
|
|||||||
#include "Engine/Renderer/RenderList.h"
|
#include "Engine/Renderer/RenderList.h"
|
||||||
#include "Engine/Core/Math/OrientedBoundingBox.h"
|
#include "Engine/Core/Math/OrientedBoundingBox.h"
|
||||||
#include "Engine/Level/Scene/Scene.h"
|
#include "Engine/Level/Scene/Scene.h"
|
||||||
|
#if USE_EDITOR
|
||||||
#include "Engine/Level/Prefabs/PrefabManager.h"
|
#include "Engine/Level/Prefabs/PrefabManager.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TerrainChunk::TerrainChunk(const SpawnParams& params)
|
||||||
|
: ScriptingObject(params)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void TerrainChunk::Init(TerrainPatch* patch, uint16 x, uint16 z)
|
void TerrainChunk::Init(TerrainPatch* patch, uint16 x, uint16 z)
|
||||||
{
|
{
|
||||||
@@ -21,7 +28,7 @@ void TerrainChunk::Init(TerrainPatch* patch, uint16 x, uint16 z)
|
|||||||
_z = z;
|
_z = z;
|
||||||
_yOffset = 0;
|
_yOffset = 0;
|
||||||
_yHeight = 1;
|
_yHeight = 1;
|
||||||
_heightmapUVScaleBias = Float4(1.0f, 1.0f, _x, _z) * (1.0f / TerrainPatch::CHUNKS_COUNT_EDGE);
|
_heightmapUVScaleBias = Float4(1.0f, 1.0f, _x, _z) * (1.0f / Terrain::ChunksCountEdge);
|
||||||
_perInstanceRandom = (_patch->_terrain->_id.C ^ _x ^ _z) * (1.0f / (float)MAX_uint32);
|
_perInstanceRandom = (_patch->_terrain->_id.C ^ _x ^ _z) * (1.0f / (float)MAX_uint32);
|
||||||
OverrideMaterial = nullptr;
|
OverrideMaterial = nullptr;
|
||||||
}
|
}
|
||||||
@@ -51,8 +58,8 @@ bool TerrainChunk::PrepareDraw(const RenderContext& renderContext)
|
|||||||
|
|
||||||
//lod = 0;
|
//lod = 0;
|
||||||
//lod = 10;
|
//lod = 10;
|
||||||
//lod = (_x + _z + TerrainPatch::CHUNKS_COUNT_EDGE * (_patch->_x + _patch->_z));
|
//lod = (_x + _z + Terrain::ChunksCountEdge * (_patch->_x + _patch->_z));
|
||||||
//lod = (int32)Vector2::Distance(Vector2(2, 2), Vector2(_patch->_x, _patch->_z) * TerrainPatch::CHUNKS_COUNT_EDGE + Vector2(_x, _z));
|
//lod = (int32)Vector2::Distance(Vector2(2, 2), Vector2(_patch->_x, _patch->_z) * Terrain::ChunksCountEdge + Vector2(_x, _z));
|
||||||
//lod = (int32)(Vector3::Distance(_bounds.GetCenter(), view.Position) / 10000.0f);
|
//lod = (int32)(Vector3::Distance(_bounds.GetCenter(), view.Position) / 10000.0f);
|
||||||
}
|
}
|
||||||
lod = Math::Clamp(lod, minStreamedLod, lodCount - 1);
|
lod = Math::Clamp(lod, minStreamedLod, lodCount - 1);
|
||||||
@@ -93,7 +100,7 @@ void TerrainChunk::Draw(const RenderContext& renderContext) const
|
|||||||
drawCall.ObjectRadius = _sphere.Radius;
|
drawCall.ObjectRadius = _sphere.Radius;
|
||||||
drawCall.Terrain.Patch = _patch;
|
drawCall.Terrain.Patch = _patch;
|
||||||
drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias;
|
drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias;
|
||||||
drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z));
|
drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * Terrain::ChunksCountEdge + _x), (float)(_patch->_z * Terrain::ChunksCountEdge + _z));
|
||||||
drawCall.Terrain.CurrentLOD = (float)lod;
|
drawCall.Terrain.CurrentLOD = (float)lod;
|
||||||
drawCall.Terrain.ChunkSizeNextLOD = (float)(((chunkSize + 1) >> (lod + 1)) - 1);
|
drawCall.Terrain.ChunkSizeNextLOD = (float)(((chunkSize + 1) >> (lod + 1)) - 1);
|
||||||
drawCall.Terrain.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize;
|
drawCall.Terrain.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize;
|
||||||
@@ -151,7 +158,7 @@ void TerrainChunk::Draw(const RenderContext& renderContext, MaterialBase* materi
|
|||||||
drawCall.ObjectRadius = _sphere.Radius;
|
drawCall.ObjectRadius = _sphere.Radius;
|
||||||
drawCall.Terrain.Patch = _patch;
|
drawCall.Terrain.Patch = _patch;
|
||||||
drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias;
|
drawCall.Terrain.HeightmapUVScaleBias = _heightmapUVScaleBias;
|
||||||
drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * TerrainPatch::CHUNKS_COUNT_EDGE + _x), (float)(_patch->_z * TerrainPatch::CHUNKS_COUNT_EDGE + _z));
|
drawCall.Terrain.OffsetUV = Vector2((float)(_patch->_x * Terrain::ChunksCountEdge + _x), (float)(_patch->_z * Terrain::ChunksCountEdge + _z));
|
||||||
drawCall.Terrain.CurrentLOD = (float)lod;
|
drawCall.Terrain.CurrentLOD = (float)lod;
|
||||||
drawCall.Terrain.ChunkSizeNextLOD = (float)(((chunkSize + 1) >> (lod + 1)) - 1);
|
drawCall.Terrain.ChunkSizeNextLOD = (float)(((chunkSize + 1) >> (lod + 1)) - 1);
|
||||||
drawCall.Terrain.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize;
|
drawCall.Terrain.TerrainChunkSizeLOD0 = TERRAIN_UNITS_PER_VERTEX * chunkSize;
|
||||||
@@ -232,46 +239,46 @@ void TerrainChunk::CacheNeighbors()
|
|||||||
_neighbors[0] = this;
|
_neighbors[0] = this;
|
||||||
if (_z > 0)
|
if (_z > 0)
|
||||||
{
|
{
|
||||||
_neighbors[0] = &_patch->Chunks[(_z - 1) * TerrainPatch::CHUNKS_COUNT_EDGE + _x];
|
_neighbors[0] = &_patch->Chunks[(_z - 1) * Terrain::ChunksCountEdge + _x];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const auto patch = _patch->_terrain->GetPatch(_patch->_x, _patch->_z - 1);
|
const auto patch = _patch->_terrain->GetPatch(_patch->_x, _patch->_z - 1);
|
||||||
if (patch)
|
if (patch)
|
||||||
_neighbors[0] = &patch->Chunks[(TerrainPatch::CHUNKS_COUNT_EDGE - 1) * TerrainPatch::CHUNKS_COUNT_EDGE + _x];
|
_neighbors[0] = &patch->Chunks[(Terrain::ChunksCountEdge - 1) * Terrain::ChunksCountEdge + _x];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1: left
|
// 1: left
|
||||||
_neighbors[1] = this;
|
_neighbors[1] = this;
|
||||||
if (_x > 0)
|
if (_x > 0)
|
||||||
{
|
{
|
||||||
_neighbors[1] = &_patch->Chunks[_z * TerrainPatch::CHUNKS_COUNT_EDGE + (_x - 1)];
|
_neighbors[1] = &_patch->Chunks[_z * Terrain::ChunksCountEdge + (_x - 1)];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const auto patch = _patch->_terrain->GetPatch(_patch->_x - 1, _patch->_z);
|
const auto patch = _patch->_terrain->GetPatch(_patch->_x - 1, _patch->_z);
|
||||||
if (patch)
|
if (patch)
|
||||||
_neighbors[1] = &patch->Chunks[_z * TerrainPatch::CHUNKS_COUNT_EDGE + (TerrainPatch::CHUNKS_COUNT_EDGE - 1)];
|
_neighbors[1] = &patch->Chunks[_z * Terrain::ChunksCountEdge + (Terrain::ChunksCountEdge - 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2: right
|
// 2: right
|
||||||
_neighbors[2] = this;
|
_neighbors[2] = this;
|
||||||
if (_x < TerrainPatch::CHUNKS_COUNT_EDGE - 1)
|
if (_x < Terrain::ChunksCountEdge - 1)
|
||||||
{
|
{
|
||||||
_neighbors[2] = &_patch->Chunks[_z * TerrainPatch::CHUNKS_COUNT_EDGE + (_x + 1)];
|
_neighbors[2] = &_patch->Chunks[_z * Terrain::ChunksCountEdge + (_x + 1)];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const auto patch = _patch->_terrain->GetPatch(_patch->_x + 1, _patch->_z);
|
const auto patch = _patch->_terrain->GetPatch(_patch->_x + 1, _patch->_z);
|
||||||
if (patch)
|
if (patch)
|
||||||
_neighbors[2] = &patch->Chunks[_z * TerrainPatch::CHUNKS_COUNT_EDGE];
|
_neighbors[2] = &patch->Chunks[_z * Terrain::ChunksCountEdge];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3: top
|
// 3: top
|
||||||
_neighbors[3] = this;
|
_neighbors[3] = this;
|
||||||
if (_z < TerrainPatch::CHUNKS_COUNT_EDGE - 1)
|
if (_z < Terrain::ChunksCountEdge - 1)
|
||||||
{
|
{
|
||||||
_neighbors[3] = &_patch->Chunks[(_z + 1) * TerrainPatch::CHUNKS_COUNT_EDGE + _x];
|
_neighbors[3] = &_patch->Chunks[(_z + 1) * Terrain::ChunksCountEdge + _x];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,14 +17,14 @@ struct RenderContext;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a single terrain chunk.
|
/// Represents a single terrain chunk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class FLAXENGINE_API TerrainChunk : public ISerializable
|
API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API TerrainChunk : public ScriptingObject, public ISerializable
|
||||||
{
|
{
|
||||||
|
DECLARE_SCRIPTING_TYPE(TerrainChunk);
|
||||||
friend Terrain;
|
friend Terrain;
|
||||||
friend TerrainPatch;
|
friend TerrainPatch;
|
||||||
friend TerrainChunk;
|
friend TerrainChunk;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
TerrainPatch* _patch;
|
TerrainPatch* _patch;
|
||||||
uint16 _x, _z;
|
uint16 _x, _z;
|
||||||
Float4 _heightmapUVScaleBias;
|
Float4 _heightmapUVScaleBias;
|
||||||
@@ -41,11 +41,10 @@ private:
|
|||||||
void Init(TerrainPatch* patch, uint16 x, uint16 z);
|
void Init(TerrainPatch* patch, uint16 x, uint16 z);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The material to override the terrain default one for this chunk.
|
/// The material to override the terrain default one for this chunk.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
AssetReference<MaterialBase> OverrideMaterial;
|
API_FIELD() AssetReference<MaterialBase> OverrideMaterial;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The baked lightmap entry info for this chunk.
|
/// The baked lightmap entry info for this chunk.
|
||||||
@@ -53,11 +52,10 @@ public:
|
|||||||
LightmapEntry Lightmap;
|
LightmapEntry Lightmap;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the x coordinate.
|
/// Gets the x coordinate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE int32 GetX() const
|
API_FUNCTION() FORCE_INLINE int32 GetX() const
|
||||||
{
|
{
|
||||||
return _x;
|
return _x;
|
||||||
}
|
}
|
||||||
@@ -65,7 +63,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the z coordinate.
|
/// Gets the z coordinate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE int32 GetZ() const
|
API_FUNCTION() FORCE_INLINE int32 GetZ() const
|
||||||
{
|
{
|
||||||
return _z;
|
return _z;
|
||||||
}
|
}
|
||||||
@@ -73,7 +71,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the patch.
|
/// Gets the patch.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE TerrainPatch* GetPatch() const
|
API_FUNCTION() FORCE_INLINE TerrainPatch* GetPatch() const
|
||||||
{
|
{
|
||||||
return _patch;
|
return _patch;
|
||||||
}
|
}
|
||||||
@@ -81,7 +79,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the chunk world bounds.
|
/// Gets the chunk world bounds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE const BoundingBox& GetBounds() const
|
API_FUNCTION() FORCE_INLINE const BoundingBox& GetBounds() const
|
||||||
{
|
{
|
||||||
return _bounds;
|
return _bounds;
|
||||||
}
|
}
|
||||||
@@ -89,7 +87,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the chunk transformation (world to local).
|
/// Gets the chunk transformation (world to local).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FORCE_INLINE const Transform& GetTransform() const
|
API_FUNCTION() FORCE_INLINE const Transform& GetTransform() const
|
||||||
{
|
{
|
||||||
return _transform;
|
return _transform;
|
||||||
}
|
}
|
||||||
@@ -97,10 +95,9 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the scale (in XY) and bias (in ZW) applied to the vertex UVs to get the chunk coordinates.
|
/// Gets the scale (in XY) and bias (in ZW) applied to the vertex UVs to get the chunk coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="result">The result.</param>
|
API_FUNCTION() FORCE_INLINE const Float4& GetHeightmapUVScaleBias() const
|
||||||
FORCE_INLINE void GetHeightmapUVScaleBias(Float4* result) const
|
|
||||||
{
|
{
|
||||||
*result = _heightmapUVScaleBias;
|
return _heightmapUVScaleBias;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -120,7 +117,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prepares for drawing chunk. Cached LOD and material.
|
/// Prepares for drawing chunk. Cached LOD and material.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -140,7 +136,7 @@ public:
|
|||||||
/// <param name="renderContext">The rendering context.</param>
|
/// <param name="renderContext">The rendering context.</param>
|
||||||
/// <param name="material">The material to use for rendering.</param>
|
/// <param name="material">The material to use for rendering.</param>
|
||||||
/// <param name="lodIndex">The LOD index.</param>
|
/// <param name="lodIndex">The LOD index.</param>
|
||||||
void Draw(const RenderContext& renderContext, MaterialBase* material, int32 lodIndex = 0) const;
|
API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, int32 lodIndex = 0) const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines if there is an intersection between the terrain chunk and a point
|
/// Determines if there is an intersection between the terrain chunk and a point
|
||||||
@@ -148,7 +144,7 @@ public:
|
|||||||
/// <param name="ray">The ray.</param>
|
/// <param name="ray">The ray.</param>
|
||||||
/// <param name="distance">The output distance.</param>
|
/// <param name="distance">The output distance.</param>
|
||||||
/// <returns>True if chunk intersects with the ray, otherwise false.</returns>
|
/// <returns>True if chunk intersects with the ray, otherwise false.</returns>
|
||||||
bool Intersects(const Ray& ray, Real& distance);
|
API_FUNCTION() bool Intersects(const Ray& ray, API_PARAM(Out) Real& distance);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the cached bounds of the chunk.
|
/// Updates the cached bounds of the chunk.
|
||||||
@@ -166,7 +162,6 @@ public:
|
|||||||
void CacheNeighbors();
|
void CacheNeighbors();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// [ISerializable]
|
// [ISerializable]
|
||||||
void Serialize(SerializeStream& stream, const void* otherObj) override;
|
void Serialize(SerializeStream& stream, const void* otherObj) override;
|
||||||
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
|
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -15,22 +15,14 @@ class TerrainMaterialShader;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents single terrain patch made of 16 terrain chunks.
|
/// Represents single terrain patch made of 16 terrain chunks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class FLAXENGINE_API TerrainPatch : public ISerializable
|
API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API TerrainPatch : public ScriptingObject, public ISerializable
|
||||||
{
|
{
|
||||||
|
DECLARE_SCRIPTING_TYPE(TerrainPatch);
|
||||||
friend Terrain;
|
friend Terrain;
|
||||||
friend TerrainPatch;
|
friend TerrainPatch;
|
||||||
friend TerrainChunk;
|
friend TerrainChunk;
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
CHUNKS_COUNT = 16,
|
|
||||||
CHUNKS_COUNT_EDGE = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Terrain* _terrain;
|
Terrain* _terrain;
|
||||||
int16 _x, _z;
|
int16 _x, _z;
|
||||||
float _yOffset, _yHeight;
|
float _yOffset, _yHeight;
|
||||||
@@ -62,23 +54,21 @@ private:
|
|||||||
void Init(Terrain* terrain, int16 x, int16 z);
|
void Init(Terrain* terrain, int16 x, int16 z);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finalizes an instance of the <see cref="TerrainPatch"/> class.
|
/// Finalizes an instance of the <see cref="TerrainPatch"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
~TerrainPatch();
|
~TerrainPatch();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The chunks contained within the patch. Organized in 4x4 square.
|
/// The chunks contained within the patch. Organized in 4x4 square.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
TerrainChunk Chunks[CHUNKS_COUNT];
|
TerrainChunk Chunks[Terrain::ChunksCount];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The heightmap texture.
|
/// The heightmap texture.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
AssetReference<Texture> Heightmap;
|
API_FIELD() AssetReference<Texture> Heightmap;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The splatmap textures.
|
/// The splatmap textures.
|
||||||
@@ -86,12 +76,10 @@ public:
|
|||||||
AssetReference<Texture> Splatmap[TERRAIN_MAX_SPLATMAPS_COUNT];
|
AssetReference<Texture> Splatmap[TERRAIN_MAX_SPLATMAPS_COUNT];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Y axis heightmap offset from terrain origin.
|
/// Gets the Y axis heightmap offset from terrain origin.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The offset.</returns>
|
API_FUNCTION() FORCE_INLINE float GetOffsetY() const
|
||||||
FORCE_INLINE float GetOffsetY() const
|
|
||||||
{
|
{
|
||||||
return _yOffset;
|
return _yOffset;
|
||||||
}
|
}
|
||||||
@@ -99,8 +87,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Y axis heightmap height.
|
/// Gets the Y axis heightmap height.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The height.</returns>
|
API_FUNCTION() FORCE_INLINE float GetHeightY() const
|
||||||
FORCE_INLINE float GetHeightY() const
|
|
||||||
{
|
{
|
||||||
return _yHeight;
|
return _yHeight;
|
||||||
}
|
}
|
||||||
@@ -108,8 +95,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the x coordinate.
|
/// Gets the x coordinate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The x position.</returns>
|
API_FUNCTION() FORCE_INLINE int32 GetX() const
|
||||||
FORCE_INLINE int32 GetX() const
|
|
||||||
{
|
{
|
||||||
return _x;
|
return _x;
|
||||||
}
|
}
|
||||||
@@ -117,8 +103,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the z coordinate.
|
/// Gets the z coordinate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The z position.</returns>
|
API_FUNCTION() FORCE_INLINE int32 GetZ() const
|
||||||
FORCE_INLINE int32 GetZ() const
|
|
||||||
{
|
{
|
||||||
return _z;
|
return _z;
|
||||||
}
|
}
|
||||||
@@ -126,8 +111,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the terrain.
|
/// Gets the terrain.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The terrain,</returns>
|
API_FUNCTION() FORCE_INLINE Terrain* GetTerrain() const
|
||||||
FORCE_INLINE Terrain* GetTerrain() const
|
|
||||||
{
|
{
|
||||||
return _terrain;
|
return _terrain;
|
||||||
}
|
}
|
||||||
@@ -137,9 +121,9 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index">The chunk zero-based index.</param>
|
/// <param name="index">The chunk zero-based index.</param>
|
||||||
/// <returns>The chunk.</returns>
|
/// <returns>The chunk.</returns>
|
||||||
TerrainChunk* GetChunk(int32 index)
|
API_FUNCTION() TerrainChunk* GetChunk(int32 index)
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= CHUNKS_COUNT)
|
if (index < 0 || index >= Terrain::ChunksCount)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return &Chunks[index];
|
return &Chunks[index];
|
||||||
}
|
}
|
||||||
@@ -149,9 +133,9 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="chunkCoord">The chunk location (x and z).</param>
|
/// <param name="chunkCoord">The chunk location (x and z).</param>
|
||||||
/// <returns>The chunk.</returns>
|
/// <returns>The chunk.</returns>
|
||||||
TerrainChunk* GetChunk(const Int2& chunkCoord)
|
API_FUNCTION() TerrainChunk* GetChunk(API_PARAM(Ref) const Int2& chunkCoord)
|
||||||
{
|
{
|
||||||
return GetChunk(chunkCoord.Y * CHUNKS_COUNT_EDGE + chunkCoord.X);
|
return GetChunk(chunkCoord.Y * Terrain::ChunksCountEdge + chunkCoord.X);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -160,22 +144,43 @@ public:
|
|||||||
/// <param name="x">The chunk location x.</param>
|
/// <param name="x">The chunk location x.</param>
|
||||||
/// <param name="z">The chunk location z.</param>
|
/// <param name="z">The chunk location z.</param>
|
||||||
/// <returns>The chunk.</returns>
|
/// <returns>The chunk.</returns>
|
||||||
TerrainChunk* GetChunk(int32 x, int32 z)
|
API_FUNCTION() TerrainChunk* GetChunk(int32 x, int32 z)
|
||||||
{
|
{
|
||||||
return GetChunk(z * CHUNKS_COUNT_EDGE + x);
|
return GetChunk(z * Terrain::ChunksCountEdge + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the splatmap assigned to this patch.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The zero-based index of the splatmap.</param>
|
||||||
|
/// <returns>The splatmap texture.</returns>
|
||||||
|
API_FUNCTION() AssetReference<Texture> GetSplatmap(int32 index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= TERRAIN_MAX_SPLATMAPS_COUNT)
|
||||||
|
return nullptr;
|
||||||
|
return Splatmap[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets a splatmap to this patch.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The zero-based index of the splatmap.</param>
|
||||||
|
/// <param name="splatMap">Splatmap texture.</param>
|
||||||
|
API_FUNCTION() void SetSplatmap(int32 index, const AssetReference<Texture>& splatMap)
|
||||||
|
{
|
||||||
|
if (index >= 0 && index < TERRAIN_MAX_SPLATMAPS_COUNT)
|
||||||
|
Splatmap[index] = splatMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the patch world bounds.
|
/// Gets the patch world bounds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The bounding box.</returns>
|
API_FUNCTION() FORCE_INLINE const BoundingBox& GetBounds() const
|
||||||
FORCE_INLINE const BoundingBox& GetBounds() const
|
|
||||||
{
|
{
|
||||||
return _bounds;
|
return _bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes the lightmap data from the terrain patch.
|
/// Removes the lightmap data from the terrain patch.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -192,12 +197,11 @@ public:
|
|||||||
void UpdateTransform();
|
void UpdateTransform();
|
||||||
|
|
||||||
#if TERRAIN_EDITING
|
#if TERRAIN_EDITING
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes the patch heightmap and collision to the default flat level.
|
/// Initializes the patch heightmap and collision to the default flat level.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if failed, otherwise false.</returns>
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
bool InitializeHeightMap();
|
API_FUNCTION() bool InitializeHeightMap();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Setups the terrain patch using the specified heightmap data.
|
/// Setups the terrain patch using the specified heightmap data.
|
||||||
@@ -207,7 +211,7 @@ public:
|
|||||||
/// <param name="holesMask">The holes mask (optional). Normalized to 0-1 range values with holes mask per-vertex. Must match the heightmap dimensions.</param>
|
/// <param name="holesMask">The holes mask (optional). Normalized to 0-1 range values with holes mask per-vertex. Must match the heightmap dimensions.</param>
|
||||||
/// <param name="forceUseVirtualStorage">If set to <c>true</c> patch will use virtual storage by force. Otherwise it can use normal texture asset storage on drive (valid only during Editor). Runtime-created terrain can only use virtual storage (in RAM).</param>
|
/// <param name="forceUseVirtualStorage">If set to <c>true</c> patch will use virtual storage by force. Otherwise it can use normal texture asset storage on drive (valid only during Editor). Runtime-created terrain can only use virtual storage (in RAM).</param>
|
||||||
/// <returns>True if failed, otherwise false.</returns>
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
bool SetupHeightMap(int32 heightMapLength, const float* heightMap, const byte* holesMask = nullptr, bool forceUseVirtualStorage = false);
|
API_FUNCTION() bool SetupHeightMap(int32 heightMapLength, API_PARAM(Ref) const float* heightMap, API_PARAM(Ref) const byte* holesMask = nullptr, bool forceUseVirtualStorage = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Setups the terrain patch layer weights using the specified splatmaps data.
|
/// Setups the terrain patch layer weights using the specified splatmaps data.
|
||||||
@@ -217,50 +221,48 @@ public:
|
|||||||
/// <param name="splatMap">The splat map. Each array item contains 4 layer weights.</param>
|
/// <param name="splatMap">The splat map. Each array item contains 4 layer weights.</param>
|
||||||
/// <param name="forceUseVirtualStorage">If set to <c>true</c> patch will use virtual storage by force. Otherwise it can use normal texture asset storage on drive (valid only during Editor). Runtime-created terrain can only use virtual storage (in RAM).</param>
|
/// <param name="forceUseVirtualStorage">If set to <c>true</c> patch will use virtual storage by force. Otherwise it can use normal texture asset storage on drive (valid only during Editor). Runtime-created terrain can only use virtual storage (in RAM).</param>
|
||||||
/// <returns>True if failed, otherwise false.</returns>
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
bool SetupSplatMap(int32 index, int32 splatMapLength, const Color32* splatMap, bool forceUseVirtualStorage = false);
|
API_FUNCTION() bool SetupSplatMap(int32 index, int32 splatMapLength, API_PARAM(Ref) const Color32* splatMap, bool forceUseVirtualStorage = false);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if TERRAIN_UPDATING
|
#if TERRAIN_UPDATING
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the raw pointer to the heightmap data.
|
/// Gets the raw pointer to the heightmap data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The heightmap data.</returns>
|
/// <returns>The heightmap data.</returns>
|
||||||
float* GetHeightmapData();
|
API_FUNCTION() float* GetHeightmapData();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears cache of the heightmap data.
|
/// Clears cache of the heightmap data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void ClearHeightmapCache();
|
API_FUNCTION() void ClearHeightmapCache();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the raw pointer to the holes mask data.
|
/// Gets the raw pointer to the holes mask data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The holes mask data.</returns>
|
/// <returns>The holes mask data.</returns>
|
||||||
byte* GetHolesMaskData();
|
API_FUNCTION() byte* GetHolesMaskData();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears cache of the holes mask data.
|
/// Clears cache of the holes mask data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void ClearHolesMaskCache();
|
API_FUNCTION() void ClearHolesMaskCache();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the raw pointer to the splat map data.
|
/// Gets the raw pointer to the splat map data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index">The zero-based index of the splatmap texture.</param>
|
/// <param name="index">The zero-based index of the splatmap texture.</param>
|
||||||
/// <returns>The splat map data.</returns>
|
/// <returns>The splat map data.</returns>
|
||||||
Color32* GetSplatMapData(int32 index);
|
API_FUNCTION() Color32* GetSplatMapData(int32 index);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears cache of the splat map data.
|
/// Clears cache of the splat map data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void ClearSplatMapCache();
|
API_FUNCTION() void ClearSplatMapCache();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears all caches.
|
/// Clears all caches.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void ClearCache();
|
API_FUNCTION() void ClearCache();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Modifies the terrain patch heightmap with the given samples.
|
/// Modifies the terrain patch heightmap with the given samples.
|
||||||
@@ -269,7 +271,7 @@ public:
|
|||||||
/// <param name="modifiedOffset">The offset from the first row and column of the heightmap data (offset destination x and z start position).</param>
|
/// <param name="modifiedOffset">The offset from the first row and column of the heightmap data (offset destination x and z start position).</param>
|
||||||
/// <param name="modifiedSize">The size of the heightmap to modify (x and z). Amount of samples in each direction.</param>
|
/// <param name="modifiedSize">The size of the heightmap to modify (x and z). Amount of samples in each direction.</param>
|
||||||
/// <returns>True if failed, otherwise false.</returns>
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
bool ModifyHeightMap(const float* samples, const Int2& modifiedOffset, const Int2& modifiedSize);
|
API_FUNCTION() bool ModifyHeightMap(API_PARAM(Ref) const float* samples, API_PARAM(Ref) const Int2& modifiedOffset, API_PARAM(Ref) const Int2& modifiedSize);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Modifies the terrain patch holes mask with the given samples.
|
/// Modifies the terrain patch holes mask with the given samples.
|
||||||
@@ -278,7 +280,7 @@ public:
|
|||||||
/// <param name="modifiedOffset">The offset from the first row and column of the holes map data (offset destination x and z start position).</param>
|
/// <param name="modifiedOffset">The offset from the first row and column of the holes map data (offset destination x and z start position).</param>
|
||||||
/// <param name="modifiedSize">The size of the holes map to modify (x and z). Amount of samples in each direction.</param>
|
/// <param name="modifiedSize">The size of the holes map to modify (x and z). Amount of samples in each direction.</param>
|
||||||
/// <returns>True if failed, otherwise false.</returns>
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
bool ModifyHolesMask(const byte* samples, const Int2& modifiedOffset, const Int2& modifiedSize);
|
API_FUNCTION() bool ModifyHolesMask(API_PARAM(Ref) const byte* samples, API_PARAM(Ref) const Int2& modifiedOffset, API_PARAM(Ref) const Int2& modifiedSize);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Modifies the terrain patch splat map (layers mask) with the given samples.
|
/// Modifies the terrain patch splat map (layers mask) with the given samples.
|
||||||
@@ -288,21 +290,18 @@ public:
|
|||||||
/// <param name="modifiedOffset">The offset from the first row and column of the splat map data (offset destination x and z start position).</param>
|
/// <param name="modifiedOffset">The offset from the first row and column of the splat map data (offset destination x and z start position).</param>
|
||||||
/// <param name="modifiedSize">The size of the splat map to modify (x and z). Amount of samples in each direction.</param>
|
/// <param name="modifiedSize">The size of the splat map to modify (x and z). Amount of samples in each direction.</param>
|
||||||
/// <returns>True if failed, otherwise false.</returns>
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
bool ModifySplatMap(int32 index, const Color32* samples, const Int2& modifiedOffset, const Int2& modifiedSize);
|
API_FUNCTION() bool ModifySplatMap(int32 index, API_PARAM(Ref) const Color32* samples, API_PARAM(Ref) const Int2& modifiedOffset, API_PARAM(Ref) const Int2& modifiedSize);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool UpdateHeightData(struct TerrainDataUpdateInfo& info, const Int2& modifiedOffset, const Int2& modifiedSize, bool wasHeightRangeChanged, bool wasHeightChanged);
|
||||||
bool UpdateHeightData(const struct TerrainDataUpdateInfo& info, const Int2& modifiedOffset, const Int2& modifiedSize, bool wasHeightRangeChanged);
|
|
||||||
void SaveHeightData();
|
void SaveHeightData();
|
||||||
void CacheHeightData();
|
void CacheHeightData();
|
||||||
void SaveSplatData();
|
void SaveSplatData();
|
||||||
void SaveSplatData(int32 index);
|
void SaveSplatData(int32 index);
|
||||||
void CacheSplatData();
|
void CacheSplatData();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs a raycast against this terrain collision shape.
|
/// Performs a raycast against this terrain collision shape.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -311,7 +310,7 @@ public:
|
|||||||
/// <param name="resultHitDistance">The raycast result hit position distance from the ray origin. Valid only if raycast hits anything.</param>
|
/// <param name="resultHitDistance">The raycast result hit position distance from the ray origin. Valid only if raycast hits anything.</param>
|
||||||
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
||||||
/// <returns>True if ray hits an object, otherwise false.</returns>
|
/// <returns>True if ray hits an object, otherwise false.</returns>
|
||||||
bool RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, float maxDistance = MAX_float) const;
|
API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) float& resultHitDistance, float maxDistance = MAX_float) const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs a raycast against this terrain collision shape.
|
/// Performs a raycast against this terrain collision shape.
|
||||||
@@ -322,7 +321,7 @@ public:
|
|||||||
/// <param name="resultHitNormal">The raycast result hit position normal vector. Valid only if raycast hits anything.</param>
|
/// <param name="resultHitNormal">The raycast result hit position normal vector. Valid only if raycast hits anything.</param>
|
||||||
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
||||||
/// <returns>True if ray hits an object, otherwise false.</returns>
|
/// <returns>True if ray hits an object, otherwise false.</returns>
|
||||||
bool RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, Vector3& resultHitNormal, float maxDistance = MAX_float) const;
|
API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) float& resultHitDistance, API_PARAM(Out) Vector3& resultHitNormal, float maxDistance = MAX_float) const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs a raycast against this terrain collision shape. Returns the hit chunk.
|
/// Performs a raycast against this terrain collision shape. Returns the hit chunk.
|
||||||
@@ -333,7 +332,7 @@ public:
|
|||||||
/// <param name="resultChunk">The raycast result hit chunk. Valid only if raycast hits anything.</param>
|
/// <param name="resultChunk">The raycast result hit chunk. Valid only if raycast hits anything.</param>
|
||||||
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
||||||
/// <returns>True if ray hits an object, otherwise false.</returns>
|
/// <returns>True if ray hits an object, otherwise false.</returns>
|
||||||
bool RayCast(const Vector3& origin, const Vector3& direction, float& resultHitDistance, TerrainChunk*& resultChunk, float maxDistance = MAX_float) const;
|
API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) float& resultHitDistance, API_PARAM(Out) TerrainChunk*& resultChunk, float maxDistance = MAX_float) const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs a raycast against terrain collision, returns results in a RaycastHit structure.
|
/// Performs a raycast against terrain collision, returns results in a RaycastHit structure.
|
||||||
@@ -343,28 +342,24 @@ public:
|
|||||||
/// <param name="hitInfo">The result hit information. Valid only when method returns true.</param>
|
/// <param name="hitInfo">The result hit information. Valid only when method returns true.</param>
|
||||||
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
||||||
/// <returns>True if ray hits an object, otherwise false.</returns>
|
/// <returns>True if ray hits an object, otherwise false.</returns>
|
||||||
bool RayCast(const Vector3& origin, const Vector3& direction, RayCastHit& hitInfo, float maxDistance = MAX_float) const;
|
API_FUNCTION() bool RayCast(const Vector3& origin, const Vector3& direction, API_PARAM(Out) RayCastHit& hitInfo, float maxDistance = MAX_float) const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a point on the terrain collider that is closest to a given location. Can be used to find a hit location or position to apply explosion force or any other special effects.
|
/// Gets a point on the terrain collider that is closest to a given location. Can be used to find a hit location or position to apply explosion force or any other special effects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="position">The position to find the closest point to it.</param>
|
/// <param name="position">The position to find the closest point to it.</param>
|
||||||
/// <param name="result">The result point on the collider that is closest to the specified location.</param>
|
/// <param name="result">The result point on the collider that is closest to the specified location.</param>
|
||||||
void ClosestPoint(const Vector3& position, Vector3& result) const;
|
API_FUNCTION() void ClosestPoint(API_PARAM(Ref) const Vector3& position, API_PARAM(Out) Vector3& result) const;
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the patch data after manual deserialization called at runtime (eg. by editor undo).
|
/// Updates the patch data after manual deserialization called at runtime (eg. by editor undo).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void UpdatePostManualDeserialization();
|
void UpdatePostManualDeserialization();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the collision mesh triangles array (3 vertices per triangle in linear list). Cached internally to reuse data.
|
/// Gets the collision mesh triangles array (3 vertices per triangle in linear list). Cached internally to reuse data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -376,8 +371,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bounds">The world-space bounds to find terrain triangles that intersect with it.</param>
|
/// <param name="bounds">The world-space bounds to find terrain triangles that intersect with it.</param>
|
||||||
/// <param name="result">The result triangles that intersect with the given bounds (in world-space).</param>
|
/// <param name="result">The result triangles that intersect with the given bounds (in world-space).</param>
|
||||||
void GetCollisionTriangles(const BoundingSphere& bounds, Array<Vector3>& result);
|
void GetCollisionTriangles(API_PARAM(Ref) const BoundingSphere& bounds, API_PARAM(Out) Array<Vector3>& result);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -385,10 +379,9 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="vertexBuffer">The output vertex buffer.</param>
|
/// <param name="vertexBuffer">The output vertex buffer.</param>
|
||||||
/// <param name="indexBuffer">The output index buffer.</param>
|
/// <param name="indexBuffer">The output index buffer.</param>
|
||||||
void ExtractCollisionGeometry(Array<Float3>& vertexBuffer, Array<int32>& indexBuffer);
|
API_FUNCTION() void ExtractCollisionGeometry(API_PARAM(Out) Array<Float3>& vertexBuffer, API_PARAM(Out) Array<int32>& indexBuffer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether this patch has created collision representation.
|
/// Determines whether this patch has created collision representation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -430,8 +423,8 @@ private:
|
|||||||
bool UpdateCollision();
|
bool UpdateCollision();
|
||||||
|
|
||||||
void OnPhysicsSceneChanged(PhysicsScene* previous);
|
void OnPhysicsSceneChanged(PhysicsScene* previous);
|
||||||
public:
|
|
||||||
|
|
||||||
|
public:
|
||||||
// [ISerializable]
|
// [ISerializable]
|
||||||
void Serialize(SerializeStream& stream, const void* otherObj) override;
|
void Serialize(SerializeStream& stream, const void* otherObj) override;
|
||||||
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
|
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
|
||||||
|
|||||||
@@ -1468,7 +1468,7 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option
|
|||||||
Transform srcNode = data.Skeleton.Nodes[nodeIndex].LocalTransform;
|
Transform srcNode = data.Skeleton.Nodes[nodeIndex].LocalTransform;
|
||||||
auto& node = data.Skeleton.Nodes[nodeIndex];
|
auto& node = data.Skeleton.Nodes[nodeIndex];
|
||||||
if (auto* channel = animation.GetChannel(node.Name))
|
if (auto* channel = animation.GetChannel(node.Name))
|
||||||
channel->Evaluate(frame, &srcNode, false);
|
channel->Evaluate((float)frame, &srcNode, false);
|
||||||
pose.Nodes[nodeIndex] = srcNode;
|
pose.Nodes[nodeIndex] = srcNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1476,7 +1476,7 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option
|
|||||||
key = Float3::Zero;
|
key = Float3::Zero;
|
||||||
for (int32 nodeIndex = 0; nodeIndex < nodes; nodeIndex++)
|
for (int32 nodeIndex = 0; nodeIndex < nodes; nodeIndex++)
|
||||||
key += pose.GetNodeModelTransformation(data.Skeleton, nodeIndex).Translation;
|
key += pose.GetNodeModelTransformation(data.Skeleton, nodeIndex).Translation;
|
||||||
key /= nodes;
|
key /= (float)nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate skeleton center of mass movement over the animation frames
|
// Calculate skeleton center of mass movement over the animation frames
|
||||||
@@ -1485,7 +1485,7 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option
|
|||||||
for (int32 frame = 0; frame < frames; frame++)
|
for (int32 frame = 0; frame < frames; frame++)
|
||||||
{
|
{
|
||||||
auto& key = rootChannel.Position[frame];
|
auto& key = rootChannel.Position[frame];
|
||||||
key.Time = frame;
|
key.Time = (float)frame;
|
||||||
key.Value = centerOfMass[frame] - centerOfMassRefPose;
|
key.Value = centerOfMass[frame] - centerOfMassRefPose;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1531,7 +1531,7 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option
|
|||||||
Transform srcNode = data.Skeleton.Nodes[nodeIndex].LocalTransform;
|
Transform srcNode = data.Skeleton.Nodes[nodeIndex].LocalTransform;
|
||||||
auto& node = data.Skeleton.Nodes[nodeIndex];
|
auto& node = data.Skeleton.Nodes[nodeIndex];
|
||||||
if (auto* channel = animation.GetChannel(node.Name))
|
if (auto* channel = animation.GetChannel(node.Name))
|
||||||
channel->Evaluate(frame, &srcNode, false);
|
channel->Evaluate((float)frame, &srcNode, false);
|
||||||
pose.Nodes[nodeIndex] = srcNode;
|
pose.Nodes[nodeIndex] = srcNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using System;
|
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace FlaxEngine.GUI;
|
namespace FlaxEngine.GUI;
|
||||||
|
|
||||||
@@ -7,6 +9,32 @@ namespace FlaxEngine.GUI;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Slider : ContainerControl
|
public class Slider : ContainerControl
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The slider direction
|
||||||
|
/// </summary>
|
||||||
|
public enum SliderDirection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Slider direction, horizontal right
|
||||||
|
/// </summary>
|
||||||
|
HorizontalRight,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Slider direction, horizontal left
|
||||||
|
/// </summary>
|
||||||
|
HorizontalLeft,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Slider direction, vertical up
|
||||||
|
/// </summary>
|
||||||
|
VerticalUp,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Slider direction, vertical down
|
||||||
|
/// </summary>
|
||||||
|
VerticalDown,
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The minimum value.
|
/// The minimum value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -15,26 +43,7 @@ public class Slider : ContainerControl
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum value.
|
/// The maximum value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected float _maximum = 100f;
|
protected float _maximum = 100;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the minimum value.
|
|
||||||
/// </summary>
|
|
||||||
[EditorOrder(20), Tooltip("The minimum value.")]
|
|
||||||
public float Minimum
|
|
||||||
{
|
|
||||||
get => _minimum;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value > _maximum)
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
if (WholeNumbers)
|
|
||||||
value = Mathf.RoundToInt(value);
|
|
||||||
_minimum = value;
|
|
||||||
if (Value < _minimum)
|
|
||||||
Value = _minimum;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the maximum value.
|
/// Gets or sets the maximum value.
|
||||||
@@ -45,8 +54,6 @@ public class Slider : ContainerControl
|
|||||||
get => _maximum;
|
get => _maximum;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value < _minimum || Mathf.IsZero(value))
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
if (WholeNumbers)
|
if (WholeNumbers)
|
||||||
value = Mathf.RoundToInt(value);
|
value = Mathf.RoundToInt(value);
|
||||||
_maximum = value;
|
_maximum = value;
|
||||||
@@ -55,6 +62,38 @@ public class Slider : ContainerControl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the minimum value.
|
||||||
|
/// </summary>
|
||||||
|
[EditorOrder(20), Tooltip("The minimum value.")]
|
||||||
|
public float Minimum
|
||||||
|
{
|
||||||
|
get => _minimum;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (WholeNumbers)
|
||||||
|
value = Mathf.RoundToInt(value);
|
||||||
|
_minimum = value;
|
||||||
|
if (Value < _minimum)
|
||||||
|
Value = _minimum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the slider direction.
|
||||||
|
/// </summary>
|
||||||
|
[EditorOrder(40), Tooltip("Slider Direction.")]
|
||||||
|
public SliderDirection Direction
|
||||||
|
{
|
||||||
|
get => _direction;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_direction = value;
|
||||||
|
UpdateThumb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SliderDirection _direction = SliderDirection.HorizontalRight;
|
||||||
private float _value = 100f;
|
private float _value = 100f;
|
||||||
private Rectangle _thumbRect;
|
private Rectangle _thumbRect;
|
||||||
private float _thumbCenter;
|
private float _thumbCenter;
|
||||||
@@ -89,31 +128,60 @@ public class Slider : ContainerControl
|
|||||||
/// The local position of the thumb center
|
/// The local position of the thumb center
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HideInEditor]
|
[HideInEditor]
|
||||||
public Float2 ThumbCenter => new(_thumbCenter, Height / 2);
|
public Float2 ThumbCenter => (Direction is SliderDirection.HorizontalLeft or SliderDirection.HorizontalRight) ? new Float2(_thumbCenter, Height / 2) : new Float2(Width / 2, _thumbCenter);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The local position of the beginning of the track.
|
/// The local position of the beginning of the track.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HideInEditor]
|
[HideInEditor]
|
||||||
public Float2 TrackBeginning => new(_thumbSize.X / 2, Height / 2);
|
public Float2 TrackBeginning
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (Direction)
|
||||||
|
{
|
||||||
|
case SliderDirection.HorizontalRight: return new Float2(_thumbSize.X / 2, Height / 2);
|
||||||
|
case SliderDirection.HorizontalLeft: return new Float2(Width - _thumbSize.X / 2, Height / 2);
|
||||||
|
case SliderDirection.VerticalUp: return new Float2(Width / 2, Height - _thumbSize.Y / 2);
|
||||||
|
case SliderDirection.VerticalDown: return new Float2(Width / 2, _thumbSize.Y / 2);
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return Float2.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The local position of the end of the track.
|
/// The local position of the end of the track.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HideInEditor]
|
[HideInEditor]
|
||||||
public Float2 TrackEnd => new(Width - _thumbSize.X / 2, Height / 2);
|
public Float2 TrackEnd
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
switch (Direction)
|
||||||
|
{
|
||||||
|
case SliderDirection.HorizontalRight: return new Float2(Width - _thumbSize.X / 2, Height / 2);
|
||||||
|
case SliderDirection.HorizontalLeft: return new Float2(_thumbSize.X / 2, Height / 2);
|
||||||
|
case SliderDirection.VerticalUp: return new Float2(Width / 2, _thumbSize.Y / 2);
|
||||||
|
case SliderDirection.VerticalDown: return new Float2(Width / 2, Height - _thumbSize.Y / 2);
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return Float2.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The height of the track.
|
/// The height of the track.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorOrder(40), Tooltip("The track height.")]
|
[EditorOrder(40), Tooltip("The track height.")]
|
||||||
public int TrackHeight { get; set; } = 2;
|
public int TrackThickness { get; set; } = 2;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The thumb size.
|
/// The thumb size.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditorOrder(41), Tooltip("The size of the thumb.")]
|
[EditorOrder(41), Tooltip("The size of the thumb.")]
|
||||||
public Float2 ThumbSize {
|
public Float2 ThumbSize
|
||||||
|
{
|
||||||
get => _thumbSize;
|
get => _thumbSize;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
@@ -147,9 +215,14 @@ public class Slider : ContainerControl
|
|||||||
public Color TrackFillLineColor { get; set; }
|
public Color TrackFillLineColor { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the size of the track.
|
/// Gets the width of the track.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private float TrackWidth => Width;
|
private float TrackWidth => (Direction is SliderDirection.HorizontalLeft or SliderDirection.HorizontalRight) ? Width - _thumbSize.X : TrackThickness;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the height of the track.
|
||||||
|
/// </summary>
|
||||||
|
private float TrackHeight => (Direction is SliderDirection.HorizontalLeft or SliderDirection.HorizontalRight) ? TrackThickness : Height - _thumbSize.Y;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the brush used for slider track drawing.
|
/// Gets or sets the brush used for slider track drawing.
|
||||||
@@ -236,13 +309,32 @@ public class Slider : ContainerControl
|
|||||||
private void UpdateThumb()
|
private void UpdateThumb()
|
||||||
{
|
{
|
||||||
// Cache data
|
// Cache data
|
||||||
float trackSize = TrackWidth;
|
var isHorizontal = Direction is SliderDirection.HorizontalRight or SliderDirection.HorizontalLeft;
|
||||||
|
float trackSize = isHorizontal ? Width : Height;
|
||||||
float range = Maximum - Minimum;
|
float range = Maximum - Minimum;
|
||||||
float pixelRange = trackSize - _thumbSize.X;
|
float pixelRange = trackSize - (isHorizontal ? _thumbSize.X : _thumbSize.Y);
|
||||||
float perc = (_value - Minimum) / range;
|
float perc = (_value - Minimum) / range;
|
||||||
float thumbPosition = (int)(perc * pixelRange);
|
float thumbPosition = (int)(perc * pixelRange);
|
||||||
|
switch (Direction)
|
||||||
|
{
|
||||||
|
case SliderDirection.HorizontalRight:
|
||||||
_thumbCenter = thumbPosition + _thumbSize.X / 2;
|
_thumbCenter = thumbPosition + _thumbSize.X / 2;
|
||||||
_thumbRect = new Rectangle(thumbPosition, (Height - _thumbSize.Y) / 2, _thumbSize.X, _thumbSize.Y);
|
_thumbRect = new Rectangle(thumbPosition, (Height - _thumbSize.Y) / 2, _thumbSize.X, _thumbSize.Y);
|
||||||
|
break;
|
||||||
|
case SliderDirection.VerticalDown:
|
||||||
|
_thumbCenter = thumbPosition + _thumbSize.Y / 2;
|
||||||
|
_thumbRect = new Rectangle((Width - _thumbSize.X) / 2, thumbPosition, _thumbSize.X, _thumbSize.Y);
|
||||||
|
break;
|
||||||
|
case SliderDirection.HorizontalLeft:
|
||||||
|
_thumbCenter = Width - thumbPosition - _thumbSize.X / 2;
|
||||||
|
_thumbRect = new Rectangle(Width - thumbPosition - _thumbSize.X, (Height - _thumbSize.Y) / 2, _thumbSize.X, _thumbSize.Y);
|
||||||
|
break;
|
||||||
|
case SliderDirection.VerticalUp:
|
||||||
|
_thumbCenter = Height - thumbPosition - _thumbSize.Y / 2;
|
||||||
|
_thumbRect = new Rectangle((Width - _thumbSize.X) / 2, Height - thumbPosition - _thumbSize.Y, _thumbSize.X, _thumbSize.Y);
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EndSliding()
|
private void EndSliding()
|
||||||
@@ -257,9 +349,27 @@ public class Slider : ContainerControl
|
|||||||
{
|
{
|
||||||
base.Draw();
|
base.Draw();
|
||||||
|
|
||||||
|
// Set rectangles
|
||||||
|
var lineRect = new Rectangle(_thumbSize.X / 2, (Height - TrackThickness) / 2, Width - _thumbSize.X, TrackThickness);
|
||||||
|
var fillLineRect = new Rectangle(_thumbSize.X / 2 - 1, (Height - TrackThickness - 2) / 2, Width - (Width - _thumbCenter) - _thumbSize.X / 2 + 1, TrackThickness + 2);
|
||||||
|
switch (Direction)
|
||||||
|
{
|
||||||
|
case SliderDirection.HorizontalRight: break;
|
||||||
|
case SliderDirection.VerticalDown:
|
||||||
|
lineRect = new Rectangle((Width - TrackThickness) / 2, _thumbSize.Y / 2, TrackThickness, Height - _thumbSize.Y);
|
||||||
|
fillLineRect = new Rectangle((Width - TrackThickness - 2) / 2, _thumbSize.Y / 2 - 1, TrackThickness + 2, Height - (Height - _thumbCenter) - _thumbSize.Y / 2 + 1);
|
||||||
|
break;
|
||||||
|
case SliderDirection.HorizontalLeft:
|
||||||
|
fillLineRect = new Rectangle(Width - (Width - _thumbCenter) - 1, (Height - TrackThickness - 2) / 2, Width - _thumbCenter + 1, TrackThickness + 2);
|
||||||
|
break;
|
||||||
|
case SliderDirection.VerticalUp:
|
||||||
|
lineRect = new Rectangle((Width - TrackThickness) / 2, _thumbSize.Y / 2, TrackThickness, Height - _thumbSize.Y);
|
||||||
|
fillLineRect = new Rectangle((Width - TrackThickness - 2) / 2, Height - (Height - _thumbCenter) - 1, TrackThickness + 2, Height - _thumbCenter + 1);
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
// Draw track line
|
// Draw track line
|
||||||
//var lineRect = new Rectangle(4, (Height - TrackHeight) / 2, Width - 8, TrackHeight);
|
|
||||||
var lineRect = new Rectangle(_thumbSize.X / 2, (Height - TrackHeight) / 2, Width - _thumbSize.X, TrackHeight);
|
|
||||||
if (TrackBrush != null)
|
if (TrackBrush != null)
|
||||||
TrackBrush.Draw(lineRect, TrackLineColor);
|
TrackBrush.Draw(lineRect, TrackLineColor);
|
||||||
else
|
else
|
||||||
@@ -268,7 +378,6 @@ public class Slider : ContainerControl
|
|||||||
// Draw track fill
|
// Draw track fill
|
||||||
if (FillTrack)
|
if (FillTrack)
|
||||||
{
|
{
|
||||||
var fillLineRect = new Rectangle(_thumbSize.X / 2 - 1, (Height - TrackHeight - 2) / 2, Width - (Width - _thumbCenter) - _thumbSize.X / 2, TrackHeight + 2);
|
|
||||||
Render2D.PushClip(ref fillLineRect);
|
Render2D.PushClip(ref fillLineRect);
|
||||||
if (FillTrackBrush != null)
|
if (FillTrackBrush != null)
|
||||||
FillTrackBrush.Draw(lineRect, TrackFillLineColor);
|
FillTrackBrush.Draw(lineRect, TrackFillLineColor);
|
||||||
@@ -278,11 +387,11 @@ public class Slider : ContainerControl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw thumb
|
// Draw thumb
|
||||||
var thumbColor = _isSliding ? ThumbColorSelected : (_mouseOverThumb ? ThumbColorHighlighted : ThumbColor);
|
var thumbColorV = _isSliding ? ThumbColorSelected : (_mouseOverThumb ? ThumbColorHighlighted : ThumbColor);
|
||||||
if (ThumbBrush != null)
|
if (ThumbBrush != null)
|
||||||
ThumbBrush.Draw(_thumbRect, thumbColor);
|
ThumbBrush.Draw(_thumbRect, thumbColorV);
|
||||||
else
|
else
|
||||||
Render2D.FillRectangle(_thumbRect, thumbColor);
|
Render2D.FillRectangle(_thumbRect, thumbColorV);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -302,7 +411,7 @@ public class Slider : ContainerControl
|
|||||||
if (button == MouseButton.Left)
|
if (button == MouseButton.Left)
|
||||||
{
|
{
|
||||||
Focus();
|
Focus();
|
||||||
float mousePosition = location.X;
|
float mousePosition = Direction is SliderDirection.HorizontalRight or SliderDirection.HorizontalLeft ? location.X : location.Y;
|
||||||
|
|
||||||
if (_thumbRect.Contains(ref location))
|
if (_thumbRect.Contains(ref location))
|
||||||
{
|
{
|
||||||
@@ -315,7 +424,16 @@ public class Slider : ContainerControl
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Click change
|
// Click change
|
||||||
|
switch (Direction)
|
||||||
|
{
|
||||||
|
case SliderDirection.HorizontalRight or SliderDirection.VerticalDown:
|
||||||
Value += (mousePosition < _thumbCenter ? -1 : 1) * 10;
|
Value += (mousePosition < _thumbCenter ? -1 : 1) * 10;
|
||||||
|
break;
|
||||||
|
case SliderDirection.HorizontalLeft or SliderDirection.VerticalUp:
|
||||||
|
Value -= (mousePosition < _thumbCenter ? -1 : 1) * 10;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,7 +448,22 @@ public class Slider : ContainerControl
|
|||||||
{
|
{
|
||||||
// Update sliding
|
// Update sliding
|
||||||
var slidePosition = location + Root.TrackingMouseOffset;
|
var slidePosition = location + Root.TrackingMouseOffset;
|
||||||
Value = Mathf.Remap(slidePosition.X, 4, TrackWidth - 4, Minimum, Maximum);
|
switch (Direction)
|
||||||
|
{
|
||||||
|
case SliderDirection.HorizontalRight:
|
||||||
|
Value = Mathf.Remap(slidePosition.X, 4, Width - 4, Minimum, Maximum);
|
||||||
|
break;
|
||||||
|
case SliderDirection.VerticalDown:
|
||||||
|
Value = Mathf.Remap(slidePosition.Y, 4, Height - 4, Minimum, Maximum);
|
||||||
|
break;
|
||||||
|
case SliderDirection.HorizontalLeft:
|
||||||
|
Value = Mathf.Remap(slidePosition.X, Width - 4, 4, Minimum, Maximum);
|
||||||
|
break;
|
||||||
|
case SliderDirection.VerticalUp:
|
||||||
|
Value = Mathf.Remap(slidePosition.Y, Height - 4, 4, Minimum, Maximum);
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ public:
|
|||||||
/// Visject graph parameter.
|
/// Visject graph parameter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="GraphParameter" />
|
/// <seealso cref="GraphParameter" />
|
||||||
API_CLASS() class VisjectGraphParameter : public GraphParameter
|
API_CLASS() class FLAXENGINE_API VisjectGraphParameter : public GraphParameter
|
||||||
{
|
{
|
||||||
DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(VisjectGraphParameter, GraphParameter);
|
DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(VisjectGraphParameter, GraphParameter);
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -5,10 +5,6 @@
|
|||||||
#include "Engine/Serialization/ReadStream.h"
|
#include "Engine/Serialization/ReadStream.h"
|
||||||
#include "Engine/Serialization/WriteStream.h"
|
#include "Engine/Serialization/WriteStream.h"
|
||||||
|
|
||||||
VisjectMeta::VisjectMeta()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VisjectMeta::Load(ReadStream* stream, bool loadData)
|
bool VisjectMeta::Load(ReadStream* stream, bool loadData)
|
||||||
{
|
{
|
||||||
Release();
|
Release();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Visject metadata container
|
/// Visject metadata container
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class VisjectMeta
|
class FLAXENGINE_API VisjectMeta
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -27,19 +27,6 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Array<Entry, FixedAllocation<8>> Entries;
|
Array<Entry, FixedAllocation<8>> Entries;
|
||||||
|
|
||||||
public:
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="VisjectMeta"/> class.
|
|
||||||
/// </summary>
|
|
||||||
VisjectMeta();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Finalizes an instance of the <see cref="VisjectMeta"/> class.
|
|
||||||
/// </summary>
|
|
||||||
~VisjectMeta()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Load from the stream
|
/// Load from the stream
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace Flax.Build.Bindings
|
|||||||
public string[] Comment;
|
public string[] Comment;
|
||||||
public bool IsInBuild;
|
public bool IsInBuild;
|
||||||
public bool IsDeprecated;
|
public bool IsDeprecated;
|
||||||
public string MarshalAs;
|
public TypeInfo MarshalAs;
|
||||||
internal bool IsInited;
|
internal bool IsInited;
|
||||||
internal TypedefInfo Instigator;
|
internal TypedefInfo Instigator;
|
||||||
|
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ namespace Flax.Build.Bindings
|
|||||||
if (apiType != null)
|
if (apiType != null)
|
||||||
{
|
{
|
||||||
if (apiType.MarshalAs != null)
|
if (apiType.MarshalAs != null)
|
||||||
return UsePassByReference(buildData, new TypeInfo(apiType.MarshalAs), caller);
|
return UsePassByReference(buildData, apiType.MarshalAs, caller);
|
||||||
|
|
||||||
// Skip for scripting objects
|
// Skip for scripting objects
|
||||||
if (apiType.IsScriptingObject)
|
if (apiType.IsScriptingObject)
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ namespace Flax.Build.Bindings
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GenerateCSharpNativeToManaged(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller)
|
private static string GenerateCSharpNativeToManaged(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller, bool marshalling = false)
|
||||||
{
|
{
|
||||||
string result;
|
string result;
|
||||||
if (typeInfo?.Type == null)
|
if (typeInfo?.Type == null)
|
||||||
@@ -280,7 +280,7 @@ namespace Flax.Build.Bindings
|
|||||||
if (typeInfo.IsArray)
|
if (typeInfo.IsArray)
|
||||||
{
|
{
|
||||||
typeInfo.IsArray = false;
|
typeInfo.IsArray = false;
|
||||||
result = GenerateCSharpNativeToManaged(buildData, typeInfo, caller);
|
result = GenerateCSharpNativeToManaged(buildData, typeInfo, caller, marshalling);
|
||||||
typeInfo.IsArray = true;
|
typeInfo.IsArray = true;
|
||||||
return result + "[]";
|
return result + "[]";
|
||||||
}
|
}
|
||||||
@@ -307,7 +307,7 @@ namespace Flax.Build.Bindings
|
|||||||
|
|
||||||
// Object reference property
|
// Object reference property
|
||||||
if (typeInfo.IsObjectRef)
|
if (typeInfo.IsObjectRef)
|
||||||
return GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller);
|
return GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller, marshalling);
|
||||||
if (typeInfo.Type == "SoftTypeReference" || typeInfo.Type == "SoftObjectReference")
|
if (typeInfo.Type == "SoftTypeReference" || typeInfo.Type == "SoftObjectReference")
|
||||||
return typeInfo.Type;
|
return typeInfo.Type;
|
||||||
|
|
||||||
@@ -317,15 +317,25 @@ namespace Flax.Build.Bindings
|
|||||||
#else
|
#else
|
||||||
if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer") && typeInfo.GenericArgs != null)
|
if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer") && typeInfo.GenericArgs != null)
|
||||||
#endif
|
#endif
|
||||||
return GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller) + "[]";
|
{
|
||||||
|
var arrayTypeInfo = typeInfo.GenericArgs[0];
|
||||||
|
if (marshalling)
|
||||||
|
{
|
||||||
|
// Convert array that uses different type for marshalling
|
||||||
|
var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller);
|
||||||
|
if (arrayApiType != null && arrayApiType.MarshalAs != null)
|
||||||
|
arrayTypeInfo = arrayApiType.MarshalAs;
|
||||||
|
}
|
||||||
|
return GenerateCSharpNativeToManaged(buildData, arrayTypeInfo, caller) + "[]";
|
||||||
|
}
|
||||||
|
|
||||||
// Dictionary
|
// Dictionary
|
||||||
if (typeInfo.Type == "Dictionary" && typeInfo.GenericArgs != null)
|
if (typeInfo.Type == "Dictionary" && typeInfo.GenericArgs != null)
|
||||||
return string.Format("System.Collections.Generic.Dictionary<{0}, {1}>", GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller), GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[1], caller));
|
return string.Format("System.Collections.Generic.Dictionary<{0}, {1}>", GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller, marshalling), GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[1], caller, marshalling));
|
||||||
|
|
||||||
// HashSet
|
// HashSet
|
||||||
if (typeInfo.Type == "HashSet" && typeInfo.GenericArgs != null)
|
if (typeInfo.Type == "HashSet" && typeInfo.GenericArgs != null)
|
||||||
return string.Format("System.Collections.Generic.HashSet<{0}>", GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller));
|
return string.Format("System.Collections.Generic.HashSet<{0}>", GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller, marshalling));
|
||||||
|
|
||||||
// BitArray
|
// BitArray
|
||||||
if (typeInfo.Type == "BitArray" && typeInfo.GenericArgs != null)
|
if (typeInfo.Type == "BitArray" && typeInfo.GenericArgs != null)
|
||||||
@@ -348,16 +358,16 @@ namespace Flax.Build.Bindings
|
|||||||
// TODO: generate delegates globally in the module namespace to share more code (smaller binary size)
|
// TODO: generate delegates globally in the module namespace to share more code (smaller binary size)
|
||||||
var key = string.Empty;
|
var key = string.Empty;
|
||||||
for (int i = 0; i < typeInfo.GenericArgs.Count; i++)
|
for (int i = 0; i < typeInfo.GenericArgs.Count; i++)
|
||||||
key += GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[i], caller);
|
key += GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[i], caller, marshalling);
|
||||||
if (!CSharpAdditionalCodeCache.TryGetValue(key, out var delegateName))
|
if (!CSharpAdditionalCodeCache.TryGetValue(key, out var delegateName))
|
||||||
{
|
{
|
||||||
delegateName = "Delegate" + CSharpAdditionalCodeCache.Count;
|
delegateName = "Delegate" + CSharpAdditionalCodeCache.Count;
|
||||||
var signature = $"public delegate {GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller)} {delegateName}(";
|
var signature = $"public delegate {GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[0], caller, marshalling)} {delegateName}(";
|
||||||
for (int i = 1; i < typeInfo.GenericArgs.Count; i++)
|
for (int i = 1; i < typeInfo.GenericArgs.Count; i++)
|
||||||
{
|
{
|
||||||
if (i != 1)
|
if (i != 1)
|
||||||
signature += ", ";
|
signature += ", ";
|
||||||
signature += GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[i], caller);
|
signature += GenerateCSharpNativeToManaged(buildData, typeInfo.GenericArgs[i], caller, marshalling);
|
||||||
signature += $" arg{(i - 1)}";
|
signature += $" arg{(i - 1)}";
|
||||||
}
|
}
|
||||||
signature += ");";
|
signature += ");";
|
||||||
@@ -390,11 +400,14 @@ namespace Flax.Build.Bindings
|
|||||||
{
|
{
|
||||||
typeName += '<';
|
typeName += '<';
|
||||||
foreach (var arg in typeInfo.GenericArgs)
|
foreach (var arg in typeInfo.GenericArgs)
|
||||||
typeName += GenerateCSharpNativeToManaged(buildData, arg, caller);
|
typeName += GenerateCSharpNativeToManaged(buildData, arg, caller, marshalling);
|
||||||
typeName += '>';
|
typeName += '>';
|
||||||
}
|
}
|
||||||
if (apiType != null)
|
if (apiType != null)
|
||||||
{
|
{
|
||||||
|
if (marshalling && apiType.MarshalAs != null)
|
||||||
|
return GenerateCSharpNativeToManaged(buildData, apiType.MarshalAs, caller);
|
||||||
|
|
||||||
// Add reference to the namespace
|
// Add reference to the namespace
|
||||||
CSharpUsedNamespaces.Add(apiType.Namespace);
|
CSharpUsedNamespaces.Add(apiType.Namespace);
|
||||||
var apiTypeParent = apiType.Parent;
|
var apiTypeParent = apiType.Parent;
|
||||||
@@ -419,11 +432,11 @@ namespace Flax.Build.Bindings
|
|||||||
return typeName;
|
return typeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GenerateCSharpManagedToNativeType(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller)
|
private static string GenerateCSharpManagedToNativeType(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller, bool marshalling = false)
|
||||||
{
|
{
|
||||||
// Fixed-size array
|
// Fixed-size array
|
||||||
if (typeInfo.IsArray)
|
if (typeInfo.IsArray)
|
||||||
return GenerateCSharpNativeToManaged(buildData, typeInfo, caller);
|
return GenerateCSharpNativeToManaged(buildData, typeInfo, caller, marshalling);
|
||||||
|
|
||||||
// Find API type info
|
// Find API type info
|
||||||
var apiType = FindApiTypeInfo(buildData, typeInfo, caller);
|
var apiType = FindApiTypeInfo(buildData, typeInfo, caller);
|
||||||
@@ -439,7 +452,7 @@ namespace Flax.Build.Bindings
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (apiType.MarshalAs != null)
|
if (apiType.MarshalAs != null)
|
||||||
return GenerateCSharpManagedToNativeType(buildData, new TypeInfo(apiType.MarshalAs), caller);
|
return GenerateCSharpManagedToNativeType(buildData, apiType.MarshalAs, caller, marshalling);
|
||||||
if (apiType.IsScriptingObject || apiType.IsInterface)
|
if (apiType.IsScriptingObject || apiType.IsInterface)
|
||||||
return "IntPtr";
|
return "IntPtr";
|
||||||
}
|
}
|
||||||
@@ -452,7 +465,7 @@ namespace Flax.Build.Bindings
|
|||||||
if (typeInfo.Type == "Function" && typeInfo.GenericArgs != null)
|
if (typeInfo.Type == "Function" && typeInfo.GenericArgs != null)
|
||||||
return "IntPtr";
|
return "IntPtr";
|
||||||
|
|
||||||
return GenerateCSharpNativeToManaged(buildData, typeInfo, caller);
|
return GenerateCSharpNativeToManaged(buildData, typeInfo, caller, marshalling);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GenerateCSharpManagedToNativeConverter(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller)
|
private static string GenerateCSharpManagedToNativeConverter(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller)
|
||||||
@@ -485,6 +498,18 @@ namespace Flax.Build.Bindings
|
|||||||
case "Function":
|
case "Function":
|
||||||
// delegate
|
// delegate
|
||||||
return "NativeInterop.GetFunctionPointerForDelegate({0})";
|
return "NativeInterop.GetFunctionPointerForDelegate({0})";
|
||||||
|
case "Array":
|
||||||
|
case "Span":
|
||||||
|
case "DataContainer":
|
||||||
|
if (typeInfo.GenericArgs != null)
|
||||||
|
{
|
||||||
|
// Convert array that uses different type for marshalling
|
||||||
|
var arrayTypeInfo = typeInfo.GenericArgs[0];
|
||||||
|
var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller);
|
||||||
|
if (arrayApiType != null && arrayApiType.MarshalAs != null)
|
||||||
|
return $"{{0}}.ConvertArray(x => ({GenerateCSharpNativeToManaged(buildData, arrayApiType.MarshalAs, caller)})x)";
|
||||||
|
}
|
||||||
|
return string.Empty;
|
||||||
default:
|
default:
|
||||||
var apiType = FindApiTypeInfo(buildData, typeInfo, caller);
|
var apiType = FindApiTypeInfo(buildData, typeInfo, caller);
|
||||||
if (apiType != null)
|
if (apiType != null)
|
||||||
@@ -531,9 +556,9 @@ namespace Flax.Build.Bindings
|
|||||||
{
|
{
|
||||||
var apiType = FindApiTypeInfo(buildData, functionInfo.ReturnType, caller);
|
var apiType = FindApiTypeInfo(buildData, functionInfo.ReturnType, caller);
|
||||||
if (apiType != null && apiType.MarshalAs != null)
|
if (apiType != null && apiType.MarshalAs != null)
|
||||||
returnValueType = GenerateCSharpNativeToManaged(buildData, new TypeInfo(apiType.MarshalAs), caller);
|
returnValueType = GenerateCSharpNativeToManaged(buildData, apiType.MarshalAs, caller, true);
|
||||||
else
|
else
|
||||||
returnValueType = GenerateCSharpNativeToManaged(buildData, functionInfo.ReturnType, caller);
|
returnValueType = GenerateCSharpNativeToManaged(buildData, functionInfo.ReturnType, caller, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USE_NETCORE
|
#if USE_NETCORE
|
||||||
@@ -594,7 +619,7 @@ namespace Flax.Build.Bindings
|
|||||||
contents.Append(", ");
|
contents.Append(", ");
|
||||||
separator = true;
|
separator = true;
|
||||||
|
|
||||||
var nativeType = GenerateCSharpManagedToNativeType(buildData, parameterInfo.Type, caller);
|
var nativeType = GenerateCSharpManagedToNativeType(buildData, parameterInfo.Type, caller, true);
|
||||||
#if USE_NETCORE
|
#if USE_NETCORE
|
||||||
string parameterMarshalType = "";
|
string parameterMarshalType = "";
|
||||||
if (nativeType == "System.Type")
|
if (nativeType == "System.Type")
|
||||||
@@ -643,7 +668,7 @@ namespace Flax.Build.Bindings
|
|||||||
contents.Append(", ");
|
contents.Append(", ");
|
||||||
separator = true;
|
separator = true;
|
||||||
|
|
||||||
var nativeType = GenerateCSharpManagedToNativeType(buildData, parameterInfo.Type, caller);
|
var nativeType = GenerateCSharpManagedToNativeType(buildData, parameterInfo.Type, caller, true);
|
||||||
#if USE_NETCORE
|
#if USE_NETCORE
|
||||||
string parameterMarshalType = "";
|
string parameterMarshalType = "";
|
||||||
if (parameterInfo.IsOut && parameterInfo.DefaultValue == "var __resultAsRef")
|
if (parameterInfo.IsOut && parameterInfo.DefaultValue == "var __resultAsRef")
|
||||||
@@ -756,7 +781,16 @@ namespace Flax.Build.Bindings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contents.Append(");");
|
contents.Append(')');
|
||||||
|
if ((functionInfo.ReturnType.Type == "Array" || functionInfo.ReturnType.Type == "Span" || functionInfo.ReturnType.Type == "DataContainer") && functionInfo.ReturnType.GenericArgs != null)
|
||||||
|
{
|
||||||
|
// Convert array that uses different type for marshalling
|
||||||
|
var arrayTypeInfo = functionInfo.ReturnType.GenericArgs[0];
|
||||||
|
var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller);
|
||||||
|
if (arrayApiType != null && arrayApiType.MarshalAs != null)
|
||||||
|
contents.Append($".ConvertArray(x => ({GenerateCSharpNativeToManaged(buildData, arrayTypeInfo, caller)})x)");
|
||||||
|
}
|
||||||
|
contents.Append(';');
|
||||||
|
|
||||||
// Return result
|
// Return result
|
||||||
if (functionInfo.Glue.UseReferenceForResult)
|
if (functionInfo.Glue.UseReferenceForResult)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace Flax.Build.Bindings
|
|||||||
partial class BindingsGenerator
|
partial class BindingsGenerator
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<string, Type> TypeCache = new Dictionary<string, Type>();
|
private static readonly Dictionary<string, Type> TypeCache = new Dictionary<string, Type>();
|
||||||
private const int CacheVersion = 21;
|
private const int CacheVersion = 22;
|
||||||
|
|
||||||
internal static void Write(BinaryWriter writer, string e)
|
internal static void Write(BinaryWriter writer, string e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -167,11 +167,7 @@ namespace Flax.Build.Bindings
|
|||||||
return $"Variant(StringView({value}))";
|
return $"Variant(StringView({value}))";
|
||||||
if (typeInfo.Type == "StringAnsi")
|
if (typeInfo.Type == "StringAnsi")
|
||||||
return $"Variant(StringAnsiView({value}))";
|
return $"Variant(StringAnsiView({value}))";
|
||||||
if (typeInfo.Type == "AssetReference" ||
|
if (typeInfo.IsObjectRef)
|
||||||
typeInfo.Type == "WeakAssetReference" ||
|
|
||||||
typeInfo.Type == "SoftAssetReference" ||
|
|
||||||
typeInfo.Type == "ScriptingObjectReference" ||
|
|
||||||
typeInfo.Type == "SoftObjectReference")
|
|
||||||
return $"Variant({value}.Get())";
|
return $"Variant({value}.Get())";
|
||||||
if (typeInfo.IsArray)
|
if (typeInfo.IsArray)
|
||||||
{
|
{
|
||||||
@@ -227,10 +223,10 @@ namespace Flax.Build.Bindings
|
|||||||
return $"(StringAnsiView){value}";
|
return $"(StringAnsiView){value}";
|
||||||
if (typeInfo.IsPtr && typeInfo.IsConst && typeInfo.Type == "Char")
|
if (typeInfo.IsPtr && typeInfo.IsConst && typeInfo.Type == "Char")
|
||||||
return $"((StringView){value}).GetText()"; // (StringView)Variant, if not empty, is guaranteed to point to a null-terminated buffer.
|
return $"((StringView){value}).GetText()"; // (StringView)Variant, if not empty, is guaranteed to point to a null-terminated buffer.
|
||||||
if (typeInfo.Type == "AssetReference" || typeInfo.Type == "WeakAssetReference" || typeInfo.Type == "SoftAssetReference")
|
|
||||||
return $"ScriptingObject::Cast<{typeInfo.GenericArgs[0].Type}>((Asset*){value})";
|
|
||||||
if (typeInfo.Type == "ScriptingObjectReference" || typeInfo.Type == "SoftObjectReference")
|
if (typeInfo.Type == "ScriptingObjectReference" || typeInfo.Type == "SoftObjectReference")
|
||||||
return $"ScriptingObject::Cast<{typeInfo.GenericArgs[0].Type}>((ScriptingObject*){value})";
|
return $"ScriptingObject::Cast<{typeInfo.GenericArgs[0].Type}>((ScriptingObject*){value})";
|
||||||
|
if (typeInfo.IsObjectRef)
|
||||||
|
return $"ScriptingObject::Cast<{typeInfo.GenericArgs[0].Type}>((Asset*){value})";
|
||||||
if (typeInfo.IsArray)
|
if (typeInfo.IsArray)
|
||||||
throw new Exception($"Not supported type to convert from the Variant to fixed-size array '{typeInfo}[{typeInfo.ArraySize}]'.");
|
throw new Exception($"Not supported type to convert from the Variant to fixed-size array '{typeInfo}[{typeInfo.ArraySize}]'.");
|
||||||
if (typeInfo.Type == "Array" && typeInfo.GenericArgs != null)
|
if (typeInfo.Type == "Array" && typeInfo.GenericArgs != null)
|
||||||
@@ -309,7 +305,7 @@ namespace Flax.Build.Bindings
|
|||||||
private static string GenerateCppGetMClass(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller, FunctionInfo functionInfo)
|
private static string GenerateCppGetMClass(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller, FunctionInfo functionInfo)
|
||||||
{
|
{
|
||||||
// Optimal path for in-build types
|
// Optimal path for in-build types
|
||||||
var managedType = GenerateCSharpNativeToManaged(buildData, typeInfo, caller);
|
var managedType = GenerateCSharpNativeToManaged(buildData, typeInfo, caller, true);
|
||||||
switch (managedType)
|
switch (managedType)
|
||||||
{
|
{
|
||||||
// In-built types (cached by the engine on startup)
|
// In-built types (cached by the engine on startup)
|
||||||
@@ -392,7 +388,7 @@ namespace Flax.Build.Bindings
|
|||||||
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h");
|
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MClass.h");
|
||||||
|
|
||||||
// Optimal path for in-build types
|
// Optimal path for in-build types
|
||||||
var managedType = GenerateCSharpNativeToManaged(buildData, typeInfo, caller);
|
var managedType = GenerateCSharpNativeToManaged(buildData, typeInfo, caller, true);
|
||||||
switch (managedType)
|
switch (managedType)
|
||||||
{
|
{
|
||||||
case "bool":
|
case "bool":
|
||||||
@@ -514,11 +510,7 @@ namespace Flax.Build.Bindings
|
|||||||
return "MUtils::ToManaged({0})";
|
return "MUtils::ToManaged({0})";
|
||||||
default:
|
default:
|
||||||
// Object reference property
|
// Object reference property
|
||||||
if ((typeInfo.Type == "ScriptingObjectReference" ||
|
if (typeInfo.IsObjectRef)
|
||||||
typeInfo.Type == "AssetReference" ||
|
|
||||||
typeInfo.Type == "WeakAssetReference" ||
|
|
||||||
typeInfo.Type == "SoftAssetReference" ||
|
|
||||||
typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null)
|
|
||||||
{
|
{
|
||||||
type = "MObject*";
|
type = "MObject*";
|
||||||
return "{0}.GetManagedInstance()";
|
return "{0}.GetManagedInstance()";
|
||||||
@@ -527,16 +519,28 @@ namespace Flax.Build.Bindings
|
|||||||
// Array or DataContainer
|
// Array or DataContainer
|
||||||
if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer") && typeInfo.GenericArgs != null)
|
if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer") && typeInfo.GenericArgs != null)
|
||||||
{
|
{
|
||||||
|
var arrayTypeInfo = typeInfo.GenericArgs[0];
|
||||||
#if USE_NETCORE
|
#if USE_NETCORE
|
||||||
// Boolean arrays does not support custom marshalling for some unknown reason
|
// Boolean arrays does not support custom marshalling for some unknown reason
|
||||||
if (typeInfo.GenericArgs[0].Type == "bool")
|
if (arrayTypeInfo.Type == "bool")
|
||||||
{
|
{
|
||||||
type = "bool*";
|
type = "bool*";
|
||||||
return "MUtils::ToBoolArray({0})";
|
return "MUtils::ToBoolArray({0})";
|
||||||
}
|
}
|
||||||
|
var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller);
|
||||||
#endif
|
#endif
|
||||||
type = "MArray*";
|
type = "MArray*";
|
||||||
return "MUtils::ToArray({0}, " + GenerateCppGetMClass(buildData, typeInfo.GenericArgs[0], caller, functionInfo) + ")";
|
if (arrayApiType != null && arrayApiType.MarshalAs != null)
|
||||||
|
{
|
||||||
|
// Convert array that uses different type for marshalling
|
||||||
|
if (arrayApiType != null && arrayApiType.MarshalAs != null)
|
||||||
|
arrayTypeInfo = arrayApiType.MarshalAs; // Convert array that uses different type for marshalling
|
||||||
|
var genericArgs = arrayApiType.MarshalAs.GetFullNameNative(buildData, caller);
|
||||||
|
if (typeInfo.GenericArgs.Count != 1)
|
||||||
|
genericArgs += ", " + typeInfo.GenericArgs[1];
|
||||||
|
return "MUtils::ToArray(Array<" + genericArgs + ">({0}), " + GenerateCppGetMClass(buildData, arrayTypeInfo, caller, functionInfo) + ")";
|
||||||
|
}
|
||||||
|
return "MUtils::ToArray({0}, " + GenerateCppGetMClass(buildData, arrayTypeInfo, caller, functionInfo) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Span
|
// Span
|
||||||
@@ -597,7 +601,7 @@ namespace Flax.Build.Bindings
|
|||||||
CppReferencesFiles.Add(apiType.File);
|
CppReferencesFiles.Add(apiType.File);
|
||||||
|
|
||||||
if (apiType.MarshalAs != null)
|
if (apiType.MarshalAs != null)
|
||||||
return GenerateCppWrapperNativeToManaged(buildData, new TypeInfo(apiType.MarshalAs), caller, out type, functionInfo);
|
return GenerateCppWrapperNativeToManaged(buildData, apiType.MarshalAs, caller, out type, functionInfo);
|
||||||
|
|
||||||
// Scripting Object
|
// Scripting Object
|
||||||
if (apiType.IsScriptingObject)
|
if (apiType.IsScriptingObject)
|
||||||
@@ -704,11 +708,7 @@ namespace Flax.Build.Bindings
|
|||||||
return "MUtils::ToNative({0})";
|
return "MUtils::ToNative({0})";
|
||||||
default:
|
default:
|
||||||
// Object reference property
|
// Object reference property
|
||||||
if ((typeInfo.Type == "ScriptingObjectReference" ||
|
if (typeInfo.IsObjectRef)
|
||||||
typeInfo.Type == "AssetReference" ||
|
|
||||||
typeInfo.Type == "WeakAssetReference" ||
|
|
||||||
typeInfo.Type == "SoftAssetReference" ||
|
|
||||||
typeInfo.Type == "SoftObjectReference") && typeInfo.GenericArgs != null)
|
|
||||||
{
|
{
|
||||||
// For non-pod types converting only, other API converts managed to unmanaged object in C# wrapper code)
|
// For non-pod types converting only, other API converts managed to unmanaged object in C# wrapper code)
|
||||||
if (CppNonPodTypesConvertingGeneration)
|
if (CppNonPodTypesConvertingGeneration)
|
||||||
@@ -731,11 +731,26 @@ namespace Flax.Build.Bindings
|
|||||||
// Array
|
// Array
|
||||||
if (typeInfo.Type == "Array" && typeInfo.GenericArgs != null)
|
if (typeInfo.Type == "Array" && typeInfo.GenericArgs != null)
|
||||||
{
|
{
|
||||||
var T = typeInfo.GenericArgs[0].GetFullNameNative(buildData, caller);
|
var arrayTypeInfo = typeInfo.GenericArgs[0];
|
||||||
type = "MArray*";
|
var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller);
|
||||||
|
if (arrayApiType != null && arrayApiType.MarshalAs != null)
|
||||||
|
arrayTypeInfo = arrayApiType.MarshalAs;
|
||||||
|
var genericArgs = arrayTypeInfo.GetFullNameNative(buildData, caller);
|
||||||
if (typeInfo.GenericArgs.Count != 1)
|
if (typeInfo.GenericArgs.Count != 1)
|
||||||
return "MUtils::ToArray<" + T + ", " + typeInfo.GenericArgs[1] + ">({0})";
|
genericArgs += ", " + typeInfo.GenericArgs[1];
|
||||||
return "MUtils::ToArray<" + T + ">({0})";
|
|
||||||
|
type = "MArray*";
|
||||||
|
var result = "MUtils::ToArray<" + genericArgs + ">({0})";
|
||||||
|
|
||||||
|
if (arrayApiType != null && arrayApiType.MarshalAs != null)
|
||||||
|
{
|
||||||
|
// Convert array that uses different type for marshalling
|
||||||
|
genericArgs = typeInfo.GenericArgs[0].GetFullNameNative(buildData, caller);
|
||||||
|
if (typeInfo.GenericArgs.Count != 1)
|
||||||
|
genericArgs += ", " + typeInfo.GenericArgs[1];
|
||||||
|
result = $"Array<{genericArgs}>({result})";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Span or DataContainer
|
// Span or DataContainer
|
||||||
@@ -801,7 +816,7 @@ namespace Flax.Build.Bindings
|
|||||||
if (apiType != null)
|
if (apiType != null)
|
||||||
{
|
{
|
||||||
if (apiType.MarshalAs != null)
|
if (apiType.MarshalAs != null)
|
||||||
return GenerateCppWrapperManagedToNative(buildData, new TypeInfo(apiType.MarshalAs), caller, out type, out apiType, functionInfo, out needLocalVariable);
|
return GenerateCppWrapperManagedToNative(buildData, apiType.MarshalAs, caller, out type, out apiType, functionInfo, out needLocalVariable);
|
||||||
|
|
||||||
// Scripting Object (for non-pod types converting only, other API converts managed to unmanaged object in C# wrapper code)
|
// Scripting Object (for non-pod types converting only, other API converts managed to unmanaged object in C# wrapper code)
|
||||||
if (CppNonPodTypesConvertingGeneration && apiType.IsScriptingObject && typeInfo.IsPtr)
|
if (CppNonPodTypesConvertingGeneration && apiType.IsScriptingObject && typeInfo.IsPtr)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user