Merge remote-tracking branch 'origin/master' into 1.1
# Conflicts: # Source/Editor/Surface/SurfaceNode.cs
This commit is contained in:
32
CONTRIBUTING.md
Normal file
32
CONTRIBUTING.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# How to contribute to the FlaxEngine
|
||||||
|
|
||||||
|
For any questions, suggestions or help join our discord!
|
||||||
|
|
||||||
|
<a href="https://flaxengine.com/discord"><img src="https://discordapp.com/api/guilds/437989205315158016/widget.png"/></a>
|
||||||
|
|
||||||
|
Want to see whats planned for Flax?
|
||||||
|
|
||||||
|
Go check out our [Trello](https://trello.com/b/NQjLXRCP/flax-roadmap).
|
||||||
|
|
||||||
|
## **Found a bug?**
|
||||||
|
|
||||||
|
* Avoid opening any new issues without having checked if your problem has already been reported. If there are no currently open issues that fit your problem's description, feel free to [add it](https://github.com/FlaxEngine/FlaxEngine/issues/new).
|
||||||
|
|
||||||
|
* When writing an issue make sure to include a clear title and description as well as having filled out all the necessary information, depending on the severity of the issue also include the necessary log files and minidump.
|
||||||
|
|
||||||
|
* Try to following the given template when writing a new issue if possible.
|
||||||
|
|
||||||
|
## **Want to contribute?**
|
||||||
|
|
||||||
|
* When creating a PR for fixing an issue/bug make sure to describe as to what led to the fix for better understanding, for small and obvious fixes this is not really needed.
|
||||||
|
However make sure to mention the relevant issue where it was first reported if possible.
|
||||||
|
|
||||||
|
* For feature PR's the first thing you should evaluate is the value of your contribution, as in, what would it bring to this engine? Is it really required?
|
||||||
|
If its a small change you could preferably suggest it to us on our discord, else feel free to open up a PR for it.
|
||||||
|
|
||||||
|
* Ensure when creating a PR that your contribution is well explained with a adequate description and title.
|
||||||
|
|
||||||
|
* Generally, good code quality is expected, make sure your contribution works as intended and is appropriately commented where necessary.
|
||||||
|
|
||||||
|
|
||||||
|
Thank you for taking interest in contributing to Flax!
|
||||||
@@ -23,7 +23,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnValueChanged()
|
protected override void OnValueChanged()
|
||||||
{
|
{
|
||||||
var value = (StaticFlags)element.EnumComboBox.EnumTypeValue;
|
var value = (StaticFlags)element.ComboBox.EnumTypeValue;
|
||||||
|
|
||||||
// If selected is single actor that has children, ask if apply flags to the sub objects as well
|
// If selected is single actor that has children, ask if apply flags to the sub objects as well
|
||||||
if (Values.IsSingleObject && (StaticFlags)Values[0] != value && ParentEditor.Values[0] is Actor actor && actor.HasChildren)
|
if (Values.IsSingleObject && (StaticFlags)Values[0] != value && ParentEditor.Values[0] is Actor actor && actor.HasChildren)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
{
|
{
|
||||||
var enumType = Values.Type.Type != typeof(object) || Values[0] == null ? TypeUtils.GetType(Values.Type) : Values[0].GetType();
|
var enumType = Values.Type.Type != typeof(object) || Values[0] == null ? TypeUtils.GetType(Values.Type) : Values[0].GetType();
|
||||||
element = layout.Enum(enumType, null, mode);
|
element = layout.Enum(enumType, null, mode);
|
||||||
element.EnumComboBox.ValueChanged += OnValueChanged;
|
element.ComboBox.ValueChanged += OnValueChanged;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnValueChanged()
|
protected virtual void OnValueChanged()
|
||||||
{
|
{
|
||||||
SetValue(element.EnumComboBox.EnumTypeValue);
|
SetValue(element.ComboBox.EnumTypeValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -63,7 +63,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
element.EnumComboBox.EnumTypeValue = Values[0];
|
element.ComboBox.EnumTypeValue = Values[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace FlaxEditor.CustomEditors.Elements
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The combo box used to show enum values.
|
/// The combo box used to show enum values.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public EnumComboBox EnumComboBox;
|
public EnumComboBox ComboBox;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="EnumElement"/> class.
|
/// Initializes a new instance of the <see cref="EnumElement"/> class.
|
||||||
@@ -26,10 +26,10 @@ namespace FlaxEditor.CustomEditors.Elements
|
|||||||
/// <param name="formatMode">The formatting mode.</param>
|
/// <param name="formatMode">The formatting mode.</param>
|
||||||
public EnumElement(Type type, EnumComboBox.BuildEntriesDelegate customBuildEntriesDelegate = null, EnumDisplayAttribute.FormatMode formatMode = EnumDisplayAttribute.FormatMode.Default)
|
public EnumElement(Type type, EnumComboBox.BuildEntriesDelegate customBuildEntriesDelegate = null, EnumDisplayAttribute.FormatMode formatMode = EnumDisplayAttribute.FormatMode.Default)
|
||||||
{
|
{
|
||||||
EnumComboBox = new EnumComboBox(type, customBuildEntriesDelegate, formatMode);
|
ComboBox = new EnumComboBox(type, customBuildEntriesDelegate, formatMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override Control Control => EnumComboBox;
|
public override Control Control => ComboBox;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,6 +143,8 @@ namespace FlaxEditor.GUI.Input
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var value = ShuntingYard.Parse(Text);
|
var value = ShuntingYard.Parse(Text);
|
||||||
|
if (value < 0)
|
||||||
|
value = 0;
|
||||||
Value = (uint)value;
|
Value = (uint)value;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -45,5 +45,12 @@ namespace FlaxEditor.Options
|
|||||||
[DefaultValue(60.0f), Limit(35.0f, 160.0f, 0.1f)]
|
[DefaultValue(60.0f), Limit(35.0f, 160.0f, 0.1f)]
|
||||||
[EditorDisplay("Defaults", "Default Field Of View"), EditorOrder(140), Tooltip("The default field of view angle (in degrees) for the viewport camera.")]
|
[EditorDisplay("Defaults", "Default Field Of View"), EditorOrder(140), Tooltip("The default field of view angle (in degrees) for the viewport camera.")]
|
||||||
public float DefaultFieldOfView { get; set; } = 60.0f;
|
public float DefaultFieldOfView { get; set; } = 60.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets if the panning direction is inverted for the viewport camera.
|
||||||
|
/// </summary>
|
||||||
|
[DefaultValue(false)]
|
||||||
|
[EditorDisplay("Defaults"), EditorOrder(150), Tooltip( "Invert the panning direction for the viewport camera." )]
|
||||||
|
public bool DefaultInvertPanning { get; set; } = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -791,7 +791,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
Title = "Transform Node (local space)",
|
Title = "Transform Node (local space)",
|
||||||
Description = "Transforms the skeleton node",
|
Description = "Transforms the skeleton node",
|
||||||
Flags = NodeFlags.AnimGraph,
|
Flags = NodeFlags.AnimGraph,
|
||||||
Size = new Vector2(270, 130),
|
Size = new Vector2(280, 130),
|
||||||
DefaultValues = new object[]
|
DefaultValues = new object[]
|
||||||
{
|
{
|
||||||
string.Empty,
|
string.Empty,
|
||||||
@@ -816,7 +816,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
Title = "Transform Node (model space)",
|
Title = "Transform Node (model space)",
|
||||||
Description = "Transforms the skeleton node",
|
Description = "Transforms the skeleton node",
|
||||||
Flags = NodeFlags.AnimGraph,
|
Flags = NodeFlags.AnimGraph,
|
||||||
Size = new Vector2(270, 130),
|
Size = new Vector2(280, 130),
|
||||||
DefaultValues = new object[]
|
DefaultValues = new object[]
|
||||||
{
|
{
|
||||||
string.Empty,
|
string.Empty,
|
||||||
@@ -872,7 +872,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
Title = "Get Node Transform (model space)",
|
Title = "Get Node Transform (model space)",
|
||||||
Description = "Samples the skeleton node transformation (in model space)",
|
Description = "Samples the skeleton node transformation (in model space)",
|
||||||
Flags = NodeFlags.AnimGraph,
|
Flags = NodeFlags.AnimGraph,
|
||||||
Size = new Vector2(250, 40),
|
Size = new Vector2(324, 40),
|
||||||
DefaultValues = new object[]
|
DefaultValues = new object[]
|
||||||
{
|
{
|
||||||
string.Empty,
|
string.Empty,
|
||||||
@@ -880,9 +880,10 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
Elements = new[]
|
Elements = new[]
|
||||||
{
|
{
|
||||||
NodeElementArchetype.Factory.Input(0, string.Empty, true, typeof(void), 0),
|
NodeElementArchetype.Factory.Input(0, string.Empty, true, typeof(void), 0),
|
||||||
NodeElementArchetype.Factory.SkeletonNodeNameSelect(40, Surface.Constants.LayoutOffsetY * 1, 120, 0),
|
NodeElementArchetype.Factory.SkeletonNodeNameSelect(40, Surface.Constants.LayoutOffsetY * 1, 160, 0),
|
||||||
NodeElementArchetype.Factory.Text(0, Surface.Constants.LayoutOffsetY * 1, "Node:"),
|
NodeElementArchetype.Factory.Text(0, Surface.Constants.LayoutOffsetY * 1, "Node:"),
|
||||||
NodeElementArchetype.Factory.Output(0, "Transform", typeof(Transform), 1),
|
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(void), 0),
|
||||||
|
NodeElementArchetype.Factory.Output(1, "Transform", typeof(Transform), 1),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new NodeArchetype
|
new NodeArchetype
|
||||||
@@ -903,7 +904,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
NodeElementArchetype.Factory.Input(0, string.Empty, true, typeof(void), 1),
|
NodeElementArchetype.Factory.Input(0, string.Empty, true, typeof(void), 1),
|
||||||
NodeElementArchetype.Factory.Input(1, "Target", true, typeof(Vector3), 2),
|
NodeElementArchetype.Factory.Input(1, "Target", true, typeof(Vector3), 2),
|
||||||
NodeElementArchetype.Factory.Input(2, "Weight", true, typeof(float), 3, 1),
|
NodeElementArchetype.Factory.Input(2, "Weight", true, typeof(float), 3, 1),
|
||||||
NodeElementArchetype.Factory.SkeletonNodeNameSelect(40, Surface.Constants.LayoutOffsetY * 3, 120, 0),
|
NodeElementArchetype.Factory.SkeletonNodeNameSelect(40, Surface.Constants.LayoutOffsetY * 3, 160, 0),
|
||||||
NodeElementArchetype.Factory.Text(0, Surface.Constants.LayoutOffsetY * 3, "Node:"),
|
NodeElementArchetype.Factory.Text(0, Surface.Constants.LayoutOffsetY * 3, "Node:"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -913,7 +914,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
Title = "Get Node Transform (local space)",
|
Title = "Get Node Transform (local space)",
|
||||||
Description = "Samples the skeleton node transformation (in local space)",
|
Description = "Samples the skeleton node transformation (in local space)",
|
||||||
Flags = NodeFlags.AnimGraph,
|
Flags = NodeFlags.AnimGraph,
|
||||||
Size = new Vector2(250, 40),
|
Size = new Vector2(316, 40),
|
||||||
DefaultValues = new object[]
|
DefaultValues = new object[]
|
||||||
{
|
{
|
||||||
string.Empty,
|
string.Empty,
|
||||||
@@ -923,7 +924,8 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
NodeElementArchetype.Factory.Input(0, string.Empty, true, typeof(void), 0),
|
NodeElementArchetype.Factory.Input(0, string.Empty, true, typeof(void), 0),
|
||||||
NodeElementArchetype.Factory.SkeletonNodeNameSelect(40, Surface.Constants.LayoutOffsetY * 1, 120, 0),
|
NodeElementArchetype.Factory.SkeletonNodeNameSelect(40, Surface.Constants.LayoutOffsetY * 1, 120, 0),
|
||||||
NodeElementArchetype.Factory.Text(0, Surface.Constants.LayoutOffsetY * 1, "Node:"),
|
NodeElementArchetype.Factory.Text(0, Surface.Constants.LayoutOffsetY * 1, "Node:"),
|
||||||
NodeElementArchetype.Factory.Output(0, "Transform", typeof(Transform), 1),
|
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(void), 0),
|
||||||
|
NodeElementArchetype.Factory.Output(1, "Transform", typeof(Transform), 1),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new NodeArchetype
|
new NodeArchetype
|
||||||
|
|||||||
@@ -379,7 +379,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
Elements = new[]
|
Elements = new[]
|
||||||
{
|
{
|
||||||
NodeElementArchetype.Factory.Output(0, "Value", typeof(uint), 0),
|
NodeElementArchetype.Factory.Output(0, "Value", typeof(uint), 0),
|
||||||
NodeElementArchetype.Factory.Integer(0, 0, 0)
|
NodeElementArchetype.Factory.UnsignedInteger(0, 0, 0, -1, 0, int.MaxValue)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -868,8 +868,15 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
for (int i = 0; i < signature.Params.Length; i++)
|
for (int i = 0; i < signature.Params.Length; i++)
|
||||||
{
|
{
|
||||||
ref var param = ref signature.Params[i];
|
ref var param = ref signature.Params[i];
|
||||||
if (param.Type != memberParameters[i].Type || param.IsOut != memberParameters[i].IsOut)
|
ref var paramMember = ref memberParameters[i];
|
||||||
|
if (param.Type != paramMember.Type || param.IsOut != paramMember.IsOut)
|
||||||
{
|
{
|
||||||
|
// Special case: param.Type is serialized as just a type while paramMember.Type might be a reference for output parameters (eg. `out Int32` vs `out Int32&`)
|
||||||
|
var paramMemberTypeName = paramMember.Type.TypeName;
|
||||||
|
if (param.IsOut && param.IsOut == paramMember.IsOut && paramMember.Type.IsReference && !param.Type.IsReference &&
|
||||||
|
paramMemberTypeName.Substring(0, paramMemberTypeName.Length - 1) == param.Type.TypeName)
|
||||||
|
continue;
|
||||||
|
|
||||||
isInvalid = true;
|
isInvalid = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -642,6 +642,85 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
NodeElementArchetype.Factory.Output(0, "XYZ", typeof(Vector3), 0),
|
NodeElementArchetype.Factory.Output(0, "XYZ", typeof(Vector3), 0),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
new NodeArchetype
|
||||||
|
{
|
||||||
|
TypeID = 26,
|
||||||
|
Title = "Blend Normals",
|
||||||
|
Description = "Blend two normal maps to create a single normal map",
|
||||||
|
Flags = NodeFlags.MaterialGraph,
|
||||||
|
Size = new Vector2(170, 40),
|
||||||
|
ConnectionsHints = ConnectionsHint.Vector,
|
||||||
|
Elements = new[]
|
||||||
|
{
|
||||||
|
NodeElementArchetype.Factory.Input(0, "Base Normal", true, typeof(Vector3), 0),
|
||||||
|
NodeElementArchetype.Factory.Input(1, "Additional Normal", true, typeof(Vector3), 1),
|
||||||
|
NodeElementArchetype.Factory.Output(0, "Result", typeof(Vector3), 2)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new NodeArchetype
|
||||||
|
{
|
||||||
|
TypeID = 27,
|
||||||
|
Title = "Rotator",
|
||||||
|
Description = "Rotates UV coordinates according to a scalar angle (0-1)",
|
||||||
|
Flags = NodeFlags.MaterialGraph,
|
||||||
|
Size = new Vector2(150, 55),
|
||||||
|
Elements = new[]
|
||||||
|
{
|
||||||
|
NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Vector2), 0),
|
||||||
|
NodeElementArchetype.Factory.Input(1, "Center", true, typeof(Vector2), 1),
|
||||||
|
NodeElementArchetype.Factory.Input(2, "Rotation Angle", true, typeof(float), 2),
|
||||||
|
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Vector2), 3),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new NodeArchetype
|
||||||
|
{
|
||||||
|
TypeID = 28,
|
||||||
|
Title = "Sphere Mask",
|
||||||
|
Description = "Creates a sphere mask",
|
||||||
|
Flags = NodeFlags.MaterialGraph,
|
||||||
|
Size = new Vector2(150, 100),
|
||||||
|
ConnectionsHints = ConnectionsHint.Vector,
|
||||||
|
IndependentBoxes = new[]
|
||||||
|
{
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
},
|
||||||
|
DefaultValues = new object[]
|
||||||
|
{
|
||||||
|
0.3f,
|
||||||
|
0.5f,
|
||||||
|
false
|
||||||
|
},
|
||||||
|
Elements = new[]
|
||||||
|
{
|
||||||
|
NodeElementArchetype.Factory.Input(0, "A", true, null, 0),
|
||||||
|
NodeElementArchetype.Factory.Input(1, "B", true, null, 1),
|
||||||
|
NodeElementArchetype.Factory.Input(2, "Radius", true, typeof(float), 2, 0),
|
||||||
|
NodeElementArchetype.Factory.Input(3, "Hardness", true, typeof(float), 3, 1),
|
||||||
|
NodeElementArchetype.Factory.Input(4, "Invert", true, typeof(bool), 4, 2),
|
||||||
|
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 5),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new NodeArchetype
|
||||||
|
{
|
||||||
|
TypeID = 29,
|
||||||
|
Title = "UV Tiling & Offset",
|
||||||
|
Description = "Takes UVs and applies tiling and offset",
|
||||||
|
Flags = NodeFlags.MaterialGraph,
|
||||||
|
Size = new Vector2(175, 60),
|
||||||
|
DefaultValues = new object[]
|
||||||
|
{
|
||||||
|
Vector2.One,
|
||||||
|
Vector2.Zero
|
||||||
|
},
|
||||||
|
Elements = new[]
|
||||||
|
{
|
||||||
|
NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Vector2), 0),
|
||||||
|
NodeElementArchetype.Factory.Input(1, "Tiling", true, typeof(Vector2), 1, 0),
|
||||||
|
NodeElementArchetype.Factory.Input(2, "Offset", true, typeof(Vector2), 2, 1),
|
||||||
|
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Vector2), 3),
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -404,6 +404,29 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
NodeElementArchetype.Factory.Output(0, "A | B", null, 2),
|
NodeElementArchetype.Factory.Output(0, "A | B", null, 2),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
new NodeArchetype
|
||||||
|
{
|
||||||
|
TypeID = 48,
|
||||||
|
Title = "Remap",
|
||||||
|
Description = "Remaps a value from one range to another, so for example having 25 in a range of 0 to 100 being remapped to 0 to 1 would return 0.25",
|
||||||
|
Flags = NodeFlags.AllGraphs,
|
||||||
|
Size = new Vector2(175, 75),
|
||||||
|
DefaultValues = new object[]
|
||||||
|
{
|
||||||
|
25.0f,
|
||||||
|
new Vector2(0.0f, 100.0f),
|
||||||
|
new Vector2(0.0f, 1.0f),
|
||||||
|
false
|
||||||
|
},
|
||||||
|
Elements = new[]
|
||||||
|
{
|
||||||
|
NodeElementArchetype.Factory.Input(0, "Value", true, typeof(float), 0, 0),
|
||||||
|
NodeElementArchetype.Factory.Input(1, "In Range", true, typeof(Vector2), 1, 1),
|
||||||
|
NodeElementArchetype.Factory.Input(2, "Out Range", true, typeof(Vector2), 2, 2),
|
||||||
|
NodeElementArchetype.Factory.Input(3, "Clamp", true, typeof(bool), 3, 3),
|
||||||
|
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 4),
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -486,7 +486,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
Description = "Unpack X component from Vector",
|
Description = "Unpack X component from Vector",
|
||||||
Flags = NodeFlags.AllGraphs,
|
Flags = NodeFlags.AllGraphs,
|
||||||
ConnectionsHints = ConnectionsHint.Vector,
|
ConnectionsHints = ConnectionsHint.Vector,
|
||||||
Size = new Vector2(160, 30),
|
Size = new Vector2(110, 30),
|
||||||
Elements = new[]
|
Elements = new[]
|
||||||
{
|
{
|
||||||
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
|
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
|
||||||
@@ -500,7 +500,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
Description = "Unpack Y component from Vector",
|
Description = "Unpack Y component from Vector",
|
||||||
Flags = NodeFlags.AllGraphs,
|
Flags = NodeFlags.AllGraphs,
|
||||||
ConnectionsHints = ConnectionsHint.Vector,
|
ConnectionsHints = ConnectionsHint.Vector,
|
||||||
Size = new Vector2(160, 30),
|
Size = new Vector2(110, 30),
|
||||||
Elements = new[]
|
Elements = new[]
|
||||||
{
|
{
|
||||||
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
|
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
|
||||||
@@ -514,7 +514,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
Description = "Unpack Z component from Vector",
|
Description = "Unpack Z component from Vector",
|
||||||
Flags = NodeFlags.AllGraphs,
|
Flags = NodeFlags.AllGraphs,
|
||||||
ConnectionsHints = ConnectionsHint.Vector,
|
ConnectionsHints = ConnectionsHint.Vector,
|
||||||
Size = new Vector2(160, 30),
|
Size = new Vector2(110, 30),
|
||||||
Elements = new[]
|
Elements = new[]
|
||||||
{
|
{
|
||||||
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
|
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
|
||||||
@@ -528,7 +528,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
Description = "Unpack W component from Vector",
|
Description = "Unpack W component from Vector",
|
||||||
Flags = NodeFlags.AllGraphs,
|
Flags = NodeFlags.AllGraphs,
|
||||||
ConnectionsHints = ConnectionsHint.Vector,
|
ConnectionsHints = ConnectionsHint.Vector,
|
||||||
Size = new Vector2(160, 30),
|
Size = new Vector2(110, 30),
|
||||||
Elements = new[]
|
Elements = new[]
|
||||||
{
|
{
|
||||||
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
|
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
|
||||||
@@ -544,7 +544,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
Description = "Unpack XY components from Vector",
|
Description = "Unpack XY components from Vector",
|
||||||
Flags = NodeFlags.AllGraphs,
|
Flags = NodeFlags.AllGraphs,
|
||||||
ConnectionsHints = ConnectionsHint.Vector,
|
ConnectionsHints = ConnectionsHint.Vector,
|
||||||
Size = new Vector2(160, 30),
|
Size = new Vector2(110, 30),
|
||||||
Elements = new[]
|
Elements = new[]
|
||||||
{
|
{
|
||||||
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
|
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
|
||||||
@@ -558,7 +558,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
Description = "Unpack XZ components from Vector",
|
Description = "Unpack XZ components from Vector",
|
||||||
Flags = NodeFlags.AllGraphs,
|
Flags = NodeFlags.AllGraphs,
|
||||||
ConnectionsHints = ConnectionsHint.Vector,
|
ConnectionsHints = ConnectionsHint.Vector,
|
||||||
Size = new Vector2(160, 30),
|
Size = new Vector2(110, 30),
|
||||||
Elements = new[]
|
Elements = new[]
|
||||||
{
|
{
|
||||||
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
|
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
|
||||||
@@ -572,7 +572,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
Description = "Unpack YZ components from Vector",
|
Description = "Unpack YZ components from Vector",
|
||||||
Flags = NodeFlags.AllGraphs,
|
Flags = NodeFlags.AllGraphs,
|
||||||
ConnectionsHints = ConnectionsHint.Vector,
|
ConnectionsHints = ConnectionsHint.Vector,
|
||||||
Size = new Vector2(160, 30),
|
Size = new Vector2(110, 30),
|
||||||
Elements = new[]
|
Elements = new[]
|
||||||
{
|
{
|
||||||
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
|
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
|
||||||
@@ -588,7 +588,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
Description = "Unpack XYZ components from Vector",
|
Description = "Unpack XYZ components from Vector",
|
||||||
Flags = NodeFlags.AllGraphs,
|
Flags = NodeFlags.AllGraphs,
|
||||||
ConnectionsHints = ConnectionsHint.Vector,
|
ConnectionsHints = ConnectionsHint.Vector,
|
||||||
Size = new Vector2(160, 30),
|
Size = new Vector2(110, 30),
|
||||||
Elements = new[]
|
Elements = new[]
|
||||||
{
|
{
|
||||||
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
|
NodeElementArchetype.Factory.Input(0, "Value", true, null, 0),
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ namespace FlaxEditor.Surface.Elements
|
|||||||
var connections = Connections.ToArray();
|
var connections = Connections.ToArray();
|
||||||
for (int i = 0; i < connections.Length; i++)
|
for (int i = 0; i < connections.Length; i++)
|
||||||
{
|
{
|
||||||
var targetBox = Connections[i];
|
var targetBox = connections[i];
|
||||||
|
|
||||||
// Break connection
|
// Break connection
|
||||||
Connections.Remove(targetBox);
|
Connections.Remove(targetBox);
|
||||||
@@ -565,7 +565,28 @@ namespace FlaxEditor.Surface.Elements
|
|||||||
{
|
{
|
||||||
_isMouseDown = false;
|
_isMouseDown = false;
|
||||||
if (Surface.CanEdit)
|
if (Surface.CanEdit)
|
||||||
Surface.ConnectingStart(this);
|
{
|
||||||
|
if (!IsOutput && HasSingleConnection)
|
||||||
|
{
|
||||||
|
var connectedBox = Connections[0];
|
||||||
|
if (Surface.Undo != null)
|
||||||
|
{
|
||||||
|
var action = new ConnectBoxesAction((InputBox)this, (OutputBox)connectedBox, false);
|
||||||
|
BreakConnection(connectedBox);
|
||||||
|
action.End();
|
||||||
|
Surface.Undo.AddAction(action);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BreakConnection(connectedBox);
|
||||||
|
}
|
||||||
|
Surface.ConnectingStart(connectedBox);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Surface.ConnectingStart(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
base.OnMouseLeave();
|
base.OnMouseLeave();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ namespace FlaxEditor.Surface.Elements
|
|||||||
else if (value is Vector4 valueVec4)
|
else if (value is Vector4 valueVec4)
|
||||||
result = (uint)(arch.BoxID == 0 ? valueVec4.X : arch.BoxID == 1 ? valueVec4.Y : arch.BoxID == 2 ? valueVec4.Z : valueVec4.W);
|
result = (uint)(arch.BoxID == 0 ? valueVec4.X : arch.BoxID == 1 ? valueVec4.Y : arch.BoxID == 2 ? valueVec4.Z : valueVec4.W);
|
||||||
else
|
else
|
||||||
result = 0;
|
result = 0u;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -239,6 +239,32 @@ namespace FlaxEditor.Surface
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates new Unsigned Integer value element description.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">The x location (in node area space).</param>
|
||||||
|
/// <param name="y">The y location (in node area space).</param>
|
||||||
|
/// <param name="valueIndex">The index of the node variable linked as the input. Useful to make a physical connection between input box and default value for it.</param>
|
||||||
|
/// <param name="component">The index of the component to edit. For vectors this can be set to modify only single component of it. Eg. for vec2 value component set to 1 will edit only Y component. Default value -1 will be used to edit whole value.</param>
|
||||||
|
/// <param name="valueMin">The minimum value range.</param>
|
||||||
|
/// <param name="valueMax">The maximum value range.</param>
|
||||||
|
/// <returns>The archetype.</returns>
|
||||||
|
public static NodeElementArchetype UnsignedInteger(float x, float y, int valueIndex = -1, int component = -1, uint valueMin = 0, uint valueMax = 1000000)
|
||||||
|
{
|
||||||
|
return new NodeElementArchetype
|
||||||
|
{
|
||||||
|
Type = NodeElementType.UnsignedIntegerValue,
|
||||||
|
Position = new Vector2(Constants.NodeMarginX + x, Constants.NodeMarginY + Constants.NodeHeaderSize + y),
|
||||||
|
Text = null,
|
||||||
|
Single = false,
|
||||||
|
ValueIndex = valueIndex,
|
||||||
|
ValueMin = valueMin,
|
||||||
|
ValueMax = valueMax,
|
||||||
|
BoxID = -1,
|
||||||
|
ConnectionsType = ScriptType.Null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates new Float value element description.
|
/// Creates new Float value element description.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -94,5 +94,10 @@ namespace FlaxEditor.Surface
|
|||||||
/// The actor picker.
|
/// The actor picker.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Actor = 19,
|
Actor = 19,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The unsigned integer value.
|
||||||
|
/// </summary>
|
||||||
|
UnsignedIntegerValue = 20,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -278,6 +278,9 @@ namespace FlaxEditor.Surface
|
|||||||
case NodeElementType.Actor:
|
case NodeElementType.Actor:
|
||||||
element = new ActorSelect(this, arch);
|
element = new ActorSelect(this, arch);
|
||||||
break;
|
break;
|
||||||
|
case NodeElementType.UnsignedIntegerValue:
|
||||||
|
element = new UnsignedIntegerValue(this, arch);
|
||||||
|
break;
|
||||||
//default: throw new NotImplementedException("Unknown node element type: " + arch.Type);
|
//default: throw new NotImplementedException("Unknown node element type: " + arch.Type);
|
||||||
}
|
}
|
||||||
if (element != null)
|
if (element != null)
|
||||||
@@ -314,12 +317,16 @@ namespace FlaxEditor.Surface
|
|||||||
{
|
{
|
||||||
if (type == ScriptType.Null)
|
if (type == ScriptType.Null)
|
||||||
type = new ScriptType(typeof(object));
|
type = new ScriptType(typeof(object));
|
||||||
|
|
||||||
|
// Try to reuse box
|
||||||
var box = GetBox(id);
|
var box = GetBox(id);
|
||||||
if ((isOut && box is InputBox) || (!isOut && box is OutputBox))
|
if ((isOut && box is InputBox) || (!isOut && box is OutputBox))
|
||||||
{
|
{
|
||||||
box.Dispose();
|
box.Dispose();
|
||||||
box = null;
|
box = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create new if missing
|
||||||
if (box == null)
|
if (box == null)
|
||||||
{
|
{
|
||||||
if (isOut)
|
if (isOut)
|
||||||
@@ -330,10 +337,15 @@ namespace FlaxEditor.Surface
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Sync properties for exiting box
|
||||||
box.Text = text;
|
box.Text = text;
|
||||||
box.CurrentType = type;
|
box.CurrentType = type;
|
||||||
box.Y = Constants.NodeMarginY + Constants.NodeHeaderSize + yLevel * Constants.LayoutOffsetY;
|
box.Y = Constants.NodeMarginY + Constants.NodeHeaderSize + yLevel * Constants.LayoutOffsetY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update box
|
||||||
|
box.OnConnectionsChanged();
|
||||||
|
|
||||||
return box;
|
return box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace FlaxEditor.Surface
|
|||||||
{
|
{
|
||||||
private ContextMenuButton _cmCopyButton;
|
private ContextMenuButton _cmCopyButton;
|
||||||
private ContextMenuButton _cmDuplicateButton;
|
private ContextMenuButton _cmDuplicateButton;
|
||||||
|
private ContextMenuButton _cmFormatNodesConnectionButton;
|
||||||
private ContextMenuButton _cmRemoveNodeConnectionsButton;
|
private ContextMenuButton _cmRemoveNodeConnectionsButton;
|
||||||
private ContextMenuButton _cmRemoveBoxConnectionsButton;
|
private ContextMenuButton _cmRemoveBoxConnectionsButton;
|
||||||
private readonly Vector2 ContextMenuOffset = new Vector2(5);
|
private readonly Vector2 ContextMenuOffset = new Vector2(5);
|
||||||
@@ -216,6 +217,13 @@ namespace FlaxEditor.Surface
|
|||||||
}
|
}
|
||||||
}).Enabled = Nodes.Any(x => x.Breakpoint.Set && x.Breakpoint.Enabled);
|
}).Enabled = Nodes.Any(x => x.Breakpoint.Set && x.Breakpoint.Enabled);
|
||||||
}
|
}
|
||||||
|
menu.AddSeparator();
|
||||||
|
|
||||||
|
_cmFormatNodesConnectionButton = menu.AddButton("Format node(s)", () =>
|
||||||
|
{
|
||||||
|
FormatGraph(SelectedNodes);
|
||||||
|
});
|
||||||
|
_cmFormatNodesConnectionButton.Enabled = HasNodesSelection;
|
||||||
|
|
||||||
menu.AddSeparator();
|
menu.AddSeparator();
|
||||||
_cmRemoveNodeConnectionsButton = menu.AddButton("Remove all connections to that node(s)", () =>
|
_cmRemoveNodeConnectionsButton = menu.AddButton("Remove all connections to that node(s)", () =>
|
||||||
|
|||||||
287
Source/Editor/Surface/VisjectSurface.Formatting.cs
Normal file
287
Source/Editor/Surface/VisjectSurface.Formatting.cs
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using FlaxEngine;
|
||||||
|
using FlaxEditor.Surface.Elements;
|
||||||
|
using FlaxEditor.Surface.Undo;
|
||||||
|
|
||||||
|
namespace FlaxEditor.Surface
|
||||||
|
{
|
||||||
|
public partial class VisjectSurface
|
||||||
|
{
|
||||||
|
// Reference https://github.com/stefnotch/xnode-graph-formatter/blob/812e08e71c7b9b7eb0810dbdfb0a9a1034da6941/Assets/Examples/MathGraph/Editor/MathGraphEditor.cs
|
||||||
|
|
||||||
|
private class NodeFormattingData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Starting from 0 at the main nodes
|
||||||
|
/// </summary>
|
||||||
|
public int Layer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Position in the layer
|
||||||
|
/// </summary>
|
||||||
|
public int Offset;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How far the subtree needs to be moved additionally
|
||||||
|
/// </summary>
|
||||||
|
public int SubtreeOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Formats a graph where the nodes can be disjointed.
|
||||||
|
/// Uses the Sugiyama method
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodes">List of nodes</param>
|
||||||
|
protected void FormatGraph(List<SurfaceNode> nodes)
|
||||||
|
{
|
||||||
|
if (nodes.Count <= 1 || !CanEdit) return;
|
||||||
|
|
||||||
|
var nodesToVisit = new HashSet<SurfaceNode>(nodes);
|
||||||
|
|
||||||
|
// While we haven't formatted every node
|
||||||
|
while (nodesToVisit.Count > 0)
|
||||||
|
{
|
||||||
|
// Run a search in both directions
|
||||||
|
var connectedNodes = new List<SurfaceNode>();
|
||||||
|
var queue = new Queue<SurfaceNode>();
|
||||||
|
|
||||||
|
var startNode = nodesToVisit.First();
|
||||||
|
nodesToVisit.Remove(startNode);
|
||||||
|
queue.Enqueue(startNode);
|
||||||
|
|
||||||
|
while (queue.Count > 0)
|
||||||
|
{
|
||||||
|
var node = queue.Dequeue();
|
||||||
|
connectedNodes.Add(node);
|
||||||
|
|
||||||
|
for (int i = 0; i < node.Elements.Count; i++)
|
||||||
|
{
|
||||||
|
if (node.Elements[i] is Box box)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < box.Connections.Count; j++)
|
||||||
|
{
|
||||||
|
if (nodesToVisit.Contains(box.Connections[j].ParentNode))
|
||||||
|
{
|
||||||
|
nodesToVisit.Remove(box.Connections[j].ParentNode);
|
||||||
|
queue.Enqueue(box.Connections[j].ParentNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FormatConnectedGraph(connectedNodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Formats a graph where all nodes are connected
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodes">List of connected nodes</param>
|
||||||
|
protected void FormatConnectedGraph(List<SurfaceNode> nodes)
|
||||||
|
{
|
||||||
|
if (nodes.Count <= 1 || !CanEdit) return;
|
||||||
|
|
||||||
|
var boundingBox = GetNodesBounds(nodes);
|
||||||
|
|
||||||
|
var nodeData = nodes.ToDictionary(n => n, n => new NodeFormattingData { });
|
||||||
|
|
||||||
|
// Rightmost nodes with none of our nodes to the right of them
|
||||||
|
var endNodes = nodes
|
||||||
|
.Where(n => !n.GetBoxes().Any(b => b.IsOutput && b.Connections.Any(c => nodeData.ContainsKey(c.ParentNode))))
|
||||||
|
.OrderBy(n => n.Top) // Keep their relative order
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// Longest path layering
|
||||||
|
int maxLayer = SetLayers(nodeData, endNodes);
|
||||||
|
|
||||||
|
// Set the vertical offsets
|
||||||
|
int maxOffset = SetOffsets(nodeData, endNodes, maxLayer);
|
||||||
|
|
||||||
|
// Layout the nodes
|
||||||
|
|
||||||
|
// Get the largest nodes in the Y and X direction
|
||||||
|
float[] widths = new float[maxLayer + 1];
|
||||||
|
float[] heights = new float[maxOffset + 1];
|
||||||
|
for (int i = 0; i < nodes.Count; i++)
|
||||||
|
{
|
||||||
|
if (nodeData.TryGetValue(nodes[i], out var data))
|
||||||
|
{
|
||||||
|
if (nodes[i].Width > widths[data.Layer])
|
||||||
|
{
|
||||||
|
widths[data.Layer] = nodes[i].Width;
|
||||||
|
}
|
||||||
|
if (nodes[i].Height > heights[data.Offset])
|
||||||
|
{
|
||||||
|
heights[data.Offset] = nodes[i].Height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 minDistanceBetweenNodes = new Vector2(30, 30);
|
||||||
|
|
||||||
|
// Figure out the node positions (aligned to a grid)
|
||||||
|
float[] nodeXPositions = new float[widths.Length];
|
||||||
|
for (int i = 1; i < widths.Length; i++)
|
||||||
|
{
|
||||||
|
// Go from right to left (backwards) through the nodes
|
||||||
|
nodeXPositions[i] = nodeXPositions[i - 1] + minDistanceBetweenNodes.X + widths[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
float[] nodeYPositions = new float[heights.Length];
|
||||||
|
for (int i = 1; i < heights.Length; i++)
|
||||||
|
{
|
||||||
|
// Go from top to bottom through the nodes
|
||||||
|
nodeYPositions[i] = nodeYPositions[i - 1] + heights[i - 1] + minDistanceBetweenNodes.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the node positions
|
||||||
|
var undoActions = new List<MoveNodesAction>();
|
||||||
|
var topRightPosition = endNodes[0].Location;
|
||||||
|
for (int i = 0; i < nodes.Count; i++)
|
||||||
|
{
|
||||||
|
if (nodeData.TryGetValue(nodes[i], out var data))
|
||||||
|
{
|
||||||
|
Vector2 newLocation = new Vector2(-nodeXPositions[data.Layer], nodeYPositions[data.Offset]) + topRightPosition;
|
||||||
|
Vector2 locationDelta = newLocation - nodes[i].Location;
|
||||||
|
nodes[i].Location = newLocation;
|
||||||
|
|
||||||
|
if (Undo != null)
|
||||||
|
undoActions.Add(new MoveNodesAction(Context, new[] { nodes[i].ID }, locationDelta));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkAsEdited(false);
|
||||||
|
Undo?.AddAction(new MultiUndoAction(undoActions, "Format nodes"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Assigns a layer to every node
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodeData">The exta node data</param>
|
||||||
|
/// <param name="endNodes">The end nodes</param>
|
||||||
|
/// <returns>The number of the maximum layer</returns>
|
||||||
|
private int SetLayers(Dictionary<SurfaceNode, NodeFormattingData> nodeData, List<SurfaceNode> endNodes)
|
||||||
|
{
|
||||||
|
// Longest path layering
|
||||||
|
int maxLayer = 0;
|
||||||
|
var stack = new Stack<SurfaceNode>(endNodes);
|
||||||
|
|
||||||
|
while (stack.Count > 0)
|
||||||
|
{
|
||||||
|
var node = stack.Pop();
|
||||||
|
int layer = nodeData[node].Layer;
|
||||||
|
|
||||||
|
for (int i = 0; i < node.Elements.Count; i++)
|
||||||
|
{
|
||||||
|
if (node.Elements[i] is InputBox box && box.HasAnyConnection)
|
||||||
|
{
|
||||||
|
var childNode = box.Connections[0].ParentNode;
|
||||||
|
|
||||||
|
if (nodeData.TryGetValue(childNode, out var data))
|
||||||
|
{
|
||||||
|
int nodeLayer = Math.Max(data.Layer, layer + 1);
|
||||||
|
data.Layer = nodeLayer;
|
||||||
|
if (nodeLayer > maxLayer)
|
||||||
|
{
|
||||||
|
maxLayer = nodeLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
stack.Push(childNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maxLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the node offsets
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="nodeData">The exta node data</param>
|
||||||
|
/// <param name="endNodes">The end nodes</param>
|
||||||
|
/// <param name="maxLayer">The number of the maximum layer</param>
|
||||||
|
/// <returns>The number of the maximum offset</returns>
|
||||||
|
private int SetOffsets(Dictionary<SurfaceNode, NodeFormattingData> nodeData, List<SurfaceNode> endNodes, int maxLayer)
|
||||||
|
{
|
||||||
|
int maxOffset = 0;
|
||||||
|
|
||||||
|
// Keeps track of the largest offset (Y axis) for every layer
|
||||||
|
int[] offsets = new int[maxLayer + 1];
|
||||||
|
|
||||||
|
var visitedNodes = new HashSet<SurfaceNode>();
|
||||||
|
|
||||||
|
void SetOffsets(SurfaceNode node, NodeFormattingData straightParentData)
|
||||||
|
{
|
||||||
|
if (!nodeData.TryGetValue(node, out var data)) return;
|
||||||
|
|
||||||
|
// If we realize that the current node would collide with an already existing node in this layer
|
||||||
|
if (data.Layer >= 0 && offsets[data.Layer] > data.Offset)
|
||||||
|
{
|
||||||
|
// Move the entire sub-tree down
|
||||||
|
straightParentData.SubtreeOffset = Math.Max(straightParentData.SubtreeOffset, offsets[data.Layer] - data.Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keeps track of the offset of the last direct child we visited
|
||||||
|
int childOffset = data.Offset;
|
||||||
|
bool straightChild = true;
|
||||||
|
|
||||||
|
// Run the algorithm for every child
|
||||||
|
for (int i = 0; i < node.Elements.Count; i++)
|
||||||
|
{
|
||||||
|
if (node.Elements[i] is InputBox box && box.HasAnyConnection)
|
||||||
|
{
|
||||||
|
var childNode = box.Connections[0].ParentNode;
|
||||||
|
if (!visitedNodes.Contains(childNode) && nodeData.TryGetValue(childNode, out var childData))
|
||||||
|
{
|
||||||
|
visitedNodes.Add(childNode);
|
||||||
|
childData.Offset = childOffset;
|
||||||
|
SetOffsets(childNode, straightChild ? straightParentData : childData);
|
||||||
|
childOffset = childData.Offset + 1;
|
||||||
|
straightChild = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.Layer >= 0)
|
||||||
|
{
|
||||||
|
// When coming out of the recursion, apply the extra subtree offsets
|
||||||
|
data.Offset += straightParentData.SubtreeOffset;
|
||||||
|
if (data.Offset > maxOffset)
|
||||||
|
{
|
||||||
|
maxOffset = data.Offset;
|
||||||
|
}
|
||||||
|
offsets[data.Layer] = data.Offset + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// An imaginary final node
|
||||||
|
var endNodeData = new NodeFormattingData { Layer = -1 };
|
||||||
|
int childOffset = 0;
|
||||||
|
bool straightChild = true;
|
||||||
|
|
||||||
|
for (int i = 0; i < endNodes.Count; i++)
|
||||||
|
{
|
||||||
|
if (nodeData.TryGetValue(endNodes[i], out var childData))
|
||||||
|
{
|
||||||
|
visitedNodes.Add(endNodes[i]);
|
||||||
|
childData.Offset = childOffset;
|
||||||
|
SetOffsets(endNodes[i], straightChild ? endNodeData : childData);
|
||||||
|
childOffset = childData.Offset + 1;
|
||||||
|
straightChild = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,9 @@ namespace FlaxEditor.Surface
|
|||||||
|
|
||||||
private class InputBracket
|
private class InputBracket
|
||||||
{
|
{
|
||||||
|
private readonly float DefaultWidth = 120f;
|
||||||
private readonly Margin _padding = new Margin(10f);
|
private readonly Margin _padding = new Margin(10f);
|
||||||
|
|
||||||
public Box Box { get; }
|
public Box Box { get; }
|
||||||
public Vector2 EndBracketPosition { get; }
|
public Vector2 EndBracketPosition { get; }
|
||||||
public List<SurfaceNode> Nodes { get; } = new List<SurfaceNode>();
|
public List<SurfaceNode> Nodes { get; } = new List<SurfaceNode>();
|
||||||
@@ -33,7 +35,7 @@ namespace FlaxEditor.Surface
|
|||||||
public InputBracket(Box box, Vector2 nodePosition)
|
public InputBracket(Box box, Vector2 nodePosition)
|
||||||
{
|
{
|
||||||
Box = box;
|
Box = box;
|
||||||
EndBracketPosition = nodePosition;
|
EndBracketPosition = nodePosition + new Vector2(DefaultWidth, 0);
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,11 +49,10 @@ namespace FlaxEditor.Surface
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
area = new Rectangle(EndBracketPosition, new Vector2(120f, 80f));
|
area = new Rectangle(EndBracketPosition, new Vector2(DefaultWidth, 80f));
|
||||||
}
|
}
|
||||||
_padding.ExpandRectangle(ref area);
|
_padding.ExpandRectangle(ref area);
|
||||||
Vector2 endPoint = area.Location + new Vector2(area.Width, area.Height / 2f);
|
Vector2 offset = EndBracketPosition - area.UpperRight;
|
||||||
Vector2 offset = EndBracketPosition - endPoint;
|
|
||||||
area.Location += offset;
|
area.Location += offset;
|
||||||
Area = area;
|
Area = area;
|
||||||
if (!offset.IsZero)
|
if (!offset.IsZero)
|
||||||
@@ -99,18 +100,6 @@ namespace FlaxEditor.Surface
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event Window.MouseWheelDelegate CustomMouseWheel;
|
public event Window.MouseWheelDelegate CustomMouseWheel;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the node under the mouse location.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The node or null if no intersection.</returns>
|
|
||||||
public SurfaceNode GetNodeUnderMouse()
|
|
||||||
{
|
|
||||||
var pos = _rootControl.PointFromParent(ref _mousePos);
|
|
||||||
if (_rootControl.GetChildAt(pos) is SurfaceNode node)
|
|
||||||
return node;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the control under the mouse location.
|
/// Gets the control under the mouse location.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -118,9 +107,7 @@ namespace FlaxEditor.Surface
|
|||||||
public SurfaceControl GetControlUnderMouse()
|
public SurfaceControl GetControlUnderMouse()
|
||||||
{
|
{
|
||||||
var pos = _rootControl.PointFromParent(ref _mousePos);
|
var pos = _rootControl.PointFromParent(ref _mousePos);
|
||||||
if (_rootControl.GetChildAtRecursive(pos) is SurfaceControl control)
|
return _rootControl.GetChildAt(pos) as SurfaceControl;
|
||||||
return control;
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateSelectionRectangle()
|
private void UpdateSelectionRectangle()
|
||||||
@@ -464,15 +451,7 @@ namespace FlaxEditor.Surface
|
|||||||
{
|
{
|
||||||
// Check if any control is under the mouse
|
// Check if any control is under the mouse
|
||||||
_cmStartPos = location;
|
_cmStartPos = location;
|
||||||
if (controlUnderMouse != null)
|
if (controlUnderMouse == null)
|
||||||
{
|
|
||||||
if (!HasNodesSelection)
|
|
||||||
Select(controlUnderMouse);
|
|
||||||
|
|
||||||
// Show secondary context menu
|
|
||||||
ShowSecondaryCM(_cmStartPos, controlUnderMouse);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Show primary context menu
|
// Show primary context menu
|
||||||
ShowPrimaryMenu(_cmStartPos);
|
ShowPrimaryMenu(_cmStartPos);
|
||||||
@@ -708,31 +687,38 @@ namespace FlaxEditor.Surface
|
|||||||
|
|
||||||
private Vector2 FindEmptySpace(Box box)
|
private Vector2 FindEmptySpace(Box box)
|
||||||
{
|
{
|
||||||
int boxIndex = 0;
|
Vector2 distanceBetweenNodes = new Vector2(30, 30);
|
||||||
|
|
||||||
var node = box.ParentNode;
|
var node = box.ParentNode;
|
||||||
|
|
||||||
|
// Same height as node
|
||||||
|
float yLocation = node.Top;
|
||||||
|
|
||||||
for (int i = 0; i < node.Elements.Count; i++)
|
for (int i = 0; i < node.Elements.Count; i++)
|
||||||
{
|
{
|
||||||
// Box on the same side above the current box
|
|
||||||
if (node.Elements[i] is Box nodeBox && nodeBox.IsOutput == box.IsOutput && nodeBox.Y < box.Y)
|
if (node.Elements[i] is Box nodeBox && nodeBox.IsOutput == box.IsOutput && nodeBox.Y < box.Y)
|
||||||
{
|
{
|
||||||
boxIndex++;
|
// Below connected node
|
||||||
|
yLocation = Mathf.Max(yLocation, nodeBox.ParentNode.Bottom + distanceBetweenNodes.Y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Dodge the other nodes
|
// TODO: Dodge the other nodes
|
||||||
|
|
||||||
Vector2 distanceBetweenNodes = new Vector2(40, 20);
|
float xLocation = node.Location.X;
|
||||||
const float NodeHeight = 120;
|
if (box.IsOutput)
|
||||||
|
{
|
||||||
|
xLocation += node.Width + distanceBetweenNodes.X;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xLocation += -120 - distanceBetweenNodes.X;
|
||||||
|
}
|
||||||
|
|
||||||
float direction = box.IsOutput ? 1 : -1;
|
return new Vector2(
|
||||||
|
xLocation,
|
||||||
Vector2 newNodeLocation = node.Location +
|
yLocation
|
||||||
new Vector2(
|
);
|
||||||
(node.Width + distanceBetweenNodes.X) * direction,
|
|
||||||
boxIndex * (NodeHeight + distanceBetweenNodes.Y)
|
|
||||||
);
|
|
||||||
|
|
||||||
return newNodeLocation;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,8 +188,16 @@ namespace FlaxEditor.Viewport.Cameras
|
|||||||
if (input.IsPanning)
|
if (input.IsPanning)
|
||||||
{
|
{
|
||||||
var panningSpeed = 0.8f;
|
var panningSpeed = 0.8f;
|
||||||
position -= right * (mouseDelta.X * panningSpeed);
|
if (Viewport.InvertPanning)
|
||||||
position -= up * (mouseDelta.Y * panningSpeed);
|
{
|
||||||
|
position += up * (mouseDelta.Y * panningSpeed);
|
||||||
|
position += right * (mouseDelta.X * panningSpeed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
position -= right * (mouseDelta.X * panningSpeed);
|
||||||
|
position -= up * (mouseDelta.Y * panningSpeed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move
|
// Move
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ namespace FlaxEditor.Viewport
|
|||||||
private float _orthoSize = 1.0f;
|
private float _orthoSize = 1.0f;
|
||||||
private bool _isOrtho = false;
|
private bool _isOrtho = false;
|
||||||
private float _wheelMovementChangeDeltaSum = 0;
|
private float _wheelMovementChangeDeltaSum = 0;
|
||||||
|
private bool _invertPanning;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Speed of the mouse.
|
/// Speed of the mouse.
|
||||||
@@ -403,6 +404,15 @@ namespace FlaxEditor.Viewport
|
|||||||
set => _isOrtho = value;
|
set => _isOrtho = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets if the panning direction is inverted.
|
||||||
|
/// </summary>
|
||||||
|
public bool InvertPanning
|
||||||
|
{
|
||||||
|
get => _invertPanning;
|
||||||
|
set => _invertPanning = value;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The input actions collection to processed during user input.
|
/// The input actions collection to processed during user input.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -434,6 +444,7 @@ namespace FlaxEditor.Viewport
|
|||||||
_nearPlane = options.Viewport.DefaultNearPlane;
|
_nearPlane = options.Viewport.DefaultNearPlane;
|
||||||
_farPlane = options.Viewport.DefaultFarPlane;
|
_farPlane = options.Viewport.DefaultFarPlane;
|
||||||
_fieldOfView = options.Viewport.DefaultFieldOfView;
|
_fieldOfView = options.Viewport.DefaultFieldOfView;
|
||||||
|
_invertPanning = options.Viewport.DefaultInvertPanning;
|
||||||
|
|
||||||
Editor.Instance.Options.OptionsChanged += OnEditorOptionsChanged;
|
Editor.Instance.Options.OptionsChanged += OnEditorOptionsChanged;
|
||||||
OnEditorOptionsChanged(options);
|
OnEditorOptionsChanged(options);
|
||||||
@@ -454,7 +465,7 @@ namespace FlaxEditor.Viewport
|
|||||||
var button = camSpeedCM.AddButton(v.ToString());
|
var button = camSpeedCM.AddButton(v.ToString());
|
||||||
button.Tag = v;
|
button.Tag = v;
|
||||||
}
|
}
|
||||||
camSpeedCM.ButtonClicked += (button) => MovementSpeed = (float)button.Tag;
|
camSpeedCM.ButtonClicked += button => MovementSpeed = (float)button.Tag;
|
||||||
camSpeedCM.VisibleChanged += WidgetCamSpeedShowHide;
|
camSpeedCM.VisibleChanged += WidgetCamSpeedShowHide;
|
||||||
camSpeedButton.Parent = camSpeed;
|
camSpeedButton.Parent = camSpeed;
|
||||||
camSpeed.Parent = this;
|
camSpeed.Parent = this;
|
||||||
@@ -515,9 +526,9 @@ namespace FlaxEditor.Viewport
|
|||||||
// Orthographic
|
// Orthographic
|
||||||
{
|
{
|
||||||
var ortho = ViewWidgetButtonMenu.AddButton("Orthographic");
|
var ortho = ViewWidgetButtonMenu.AddButton("Orthographic");
|
||||||
var orthoValue = new CheckBox(75, 2, _isOrtho);
|
var orthoValue = new CheckBox(90, 2, _isOrtho);
|
||||||
orthoValue.Parent = ortho;
|
orthoValue.Parent = ortho;
|
||||||
orthoValue.StateChanged += (checkBox) =>
|
orthoValue.StateChanged += checkBox =>
|
||||||
{
|
{
|
||||||
if (checkBox.Checked != _isOrtho)
|
if (checkBox.Checked != _isOrtho)
|
||||||
{
|
{
|
||||||
@@ -543,10 +554,10 @@ namespace FlaxEditor.Viewport
|
|||||||
// Field of View
|
// Field of View
|
||||||
{
|
{
|
||||||
var fov = ViewWidgetButtonMenu.AddButton("Field Of View");
|
var fov = ViewWidgetButtonMenu.AddButton("Field Of View");
|
||||||
var fovValue = new FloatValueBox(1, 75, 2, 50.0f, 35.0f, 160.0f, 0.1f);
|
var fovValue = new FloatValueBox(1, 90, 2, 70.0f, 35.0f, 160.0f, 0.1f);
|
||||||
fovValue.Parent = fov;
|
fovValue.Parent = fov;
|
||||||
fovValue.ValueChanged += () => _fieldOfView = fovValue.Value;
|
fovValue.ValueChanged += () => _fieldOfView = fovValue.Value;
|
||||||
ViewWidgetButtonMenu.VisibleChanged += (control) =>
|
ViewWidgetButtonMenu.VisibleChanged += control =>
|
||||||
{
|
{
|
||||||
fov.Visible = !_isOrtho;
|
fov.Visible = !_isOrtho;
|
||||||
fovValue.Value = _fieldOfView;
|
fovValue.Value = _fieldOfView;
|
||||||
@@ -556,10 +567,10 @@ namespace FlaxEditor.Viewport
|
|||||||
// Ortho Scale
|
// Ortho Scale
|
||||||
{
|
{
|
||||||
var orthoSize = ViewWidgetButtonMenu.AddButton("Ortho Scale");
|
var orthoSize = ViewWidgetButtonMenu.AddButton("Ortho Scale");
|
||||||
var orthoSizeValue = new FloatValueBox(_orthoSize, 75, 2, 50.0f, 0.001f, 100000.0f, 0.01f);
|
var orthoSizeValue = new FloatValueBox(_orthoSize, 90, 2, 70.0f, 0.001f, 100000.0f, 0.01f);
|
||||||
orthoSizeValue.Parent = orthoSize;
|
orthoSizeValue.Parent = orthoSize;
|
||||||
orthoSizeValue.ValueChanged += () => _orthoSize = orthoSizeValue.Value;
|
orthoSizeValue.ValueChanged += () => _orthoSize = orthoSizeValue.Value;
|
||||||
ViewWidgetButtonMenu.VisibleChanged += (control) =>
|
ViewWidgetButtonMenu.VisibleChanged += control =>
|
||||||
{
|
{
|
||||||
orthoSize.Visible = _isOrtho;
|
orthoSize.Visible = _isOrtho;
|
||||||
orthoSizeValue.Value = _orthoSize;
|
orthoSizeValue.Value = _orthoSize;
|
||||||
@@ -569,7 +580,7 @@ namespace FlaxEditor.Viewport
|
|||||||
// Near Plane
|
// Near Plane
|
||||||
{
|
{
|
||||||
var nearPlane = ViewWidgetButtonMenu.AddButton("Near Plane");
|
var nearPlane = ViewWidgetButtonMenu.AddButton("Near Plane");
|
||||||
var nearPlaneValue = new FloatValueBox(2.0f, 75, 2, 50.0f, 0.001f, 1000.0f);
|
var nearPlaneValue = new FloatValueBox(2.0f, 90, 2, 70.0f, 0.001f, 1000.0f);
|
||||||
nearPlaneValue.Parent = nearPlane;
|
nearPlaneValue.Parent = nearPlane;
|
||||||
nearPlaneValue.ValueChanged += () => _nearPlane = nearPlaneValue.Value;
|
nearPlaneValue.ValueChanged += () => _nearPlane = nearPlaneValue.Value;
|
||||||
ViewWidgetButtonMenu.VisibleChanged += control => nearPlaneValue.Value = _nearPlane;
|
ViewWidgetButtonMenu.VisibleChanged += control => nearPlaneValue.Value = _nearPlane;
|
||||||
@@ -578,7 +589,7 @@ namespace FlaxEditor.Viewport
|
|||||||
// Far Plane
|
// Far Plane
|
||||||
{
|
{
|
||||||
var farPlane = ViewWidgetButtonMenu.AddButton("Far Plane");
|
var farPlane = ViewWidgetButtonMenu.AddButton("Far Plane");
|
||||||
var farPlaneValue = new FloatValueBox(1000, 75, 2, 50.0f, 10.0f);
|
var farPlaneValue = new FloatValueBox(1000, 90, 2, 70.0f, 10.0f);
|
||||||
farPlaneValue.Parent = farPlane;
|
farPlaneValue.Parent = farPlane;
|
||||||
farPlaneValue.ValueChanged += () => _farPlane = farPlaneValue.Value;
|
farPlaneValue.ValueChanged += () => _farPlane = farPlaneValue.Value;
|
||||||
ViewWidgetButtonMenu.VisibleChanged += control => farPlaneValue.Value = _farPlane;
|
ViewWidgetButtonMenu.VisibleChanged += control => farPlaneValue.Value = _farPlane;
|
||||||
@@ -587,7 +598,7 @@ namespace FlaxEditor.Viewport
|
|||||||
// Brightness
|
// Brightness
|
||||||
{
|
{
|
||||||
var brightness = ViewWidgetButtonMenu.AddButton("Brightness");
|
var brightness = ViewWidgetButtonMenu.AddButton("Brightness");
|
||||||
var brightnessValue = new FloatValueBox(1.0f, 75, 2, 50.0f, 0.001f, 10.0f, 0.001f);
|
var brightnessValue = new FloatValueBox(1.0f, 90, 2, 70.0f, 0.001f, 10.0f, 0.001f);
|
||||||
brightnessValue.Parent = brightness;
|
brightnessValue.Parent = brightness;
|
||||||
brightnessValue.ValueChanged += () => Brightness = brightnessValue.Value;
|
brightnessValue.ValueChanged += () => Brightness = brightnessValue.Value;
|
||||||
ViewWidgetButtonMenu.VisibleChanged += control => brightnessValue.Value = Brightness;
|
ViewWidgetButtonMenu.VisibleChanged += control => brightnessValue.Value = Brightness;
|
||||||
@@ -596,11 +607,26 @@ namespace FlaxEditor.Viewport
|
|||||||
// Resolution
|
// Resolution
|
||||||
{
|
{
|
||||||
var resolution = ViewWidgetButtonMenu.AddButton("Resolution");
|
var resolution = ViewWidgetButtonMenu.AddButton("Resolution");
|
||||||
var resolutionValue = new FloatValueBox(1.0f, 75, 2, 50.0f, 0.1f, 4.0f, 0.001f);
|
var resolutionValue = new FloatValueBox(1.0f, 90, 2, 70.0f, 0.1f, 4.0f, 0.001f);
|
||||||
resolutionValue.Parent = resolution;
|
resolutionValue.Parent = resolution;
|
||||||
resolutionValue.ValueChanged += () => ResolutionScale = resolutionValue.Value;
|
resolutionValue.ValueChanged += () => ResolutionScale = resolutionValue.Value;
|
||||||
ViewWidgetButtonMenu.VisibleChanged += control => resolutionValue.Value = ResolutionScale;
|
ViewWidgetButtonMenu.VisibleChanged += control => resolutionValue.Value = ResolutionScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invert Panning
|
||||||
|
{
|
||||||
|
var invert = ViewWidgetButtonMenu.AddButton("Invert Panning");
|
||||||
|
var invertValue = new CheckBox(90, 2, _invertPanning);
|
||||||
|
invertValue.Parent = invert;
|
||||||
|
invertValue.StateChanged += checkBox =>
|
||||||
|
{
|
||||||
|
if (checkBox.Checked != _invertPanning)
|
||||||
|
{
|
||||||
|
_invertPanning = checkBox.Checked;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ViewWidgetButtonMenu.VisibleChanged += control => invertValue.Checked = _invertPanning;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link for task event
|
// Link for task event
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ namespace FlaxEditor.Viewport.Previews
|
|||||||
// Preview LOD
|
// Preview LOD
|
||||||
{
|
{
|
||||||
var previewLOD = ViewWidgetButtonMenu.AddButton("Preview LOD");
|
var previewLOD = ViewWidgetButtonMenu.AddButton("Preview LOD");
|
||||||
var previewLODValue = new IntValueBox(-1, 75, 2, 50.0f, -1, 10, 0.02f);
|
var previewLODValue = new IntValueBox(-1, 90, 2, 70.0f, -1, 10, 0.02f);
|
||||||
previewLODValue.Parent = previewLOD;
|
previewLODValue.Parent = previewLOD;
|
||||||
previewLODValue.ValueChanged += () => _previewModel.ForcedLOD = previewLODValue.Value;
|
previewLODValue.ValueChanged += () => _previewModel.ForcedLOD = previewLODValue.Value;
|
||||||
ViewWidgetButtonMenu.VisibleChanged += control => previewLODValue.Value = _previewModel.ForcedLOD;
|
ViewWidgetButtonMenu.VisibleChanged += control => previewLODValue.Value = _previewModel.ForcedLOD;
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ namespace FlaxEditor.Viewport.Previews
|
|||||||
// Preview LOD
|
// Preview LOD
|
||||||
{
|
{
|
||||||
var previewLOD = ViewWidgetButtonMenu.AddButton("Preview LOD");
|
var previewLOD = ViewWidgetButtonMenu.AddButton("Preview LOD");
|
||||||
var previewLODValue = new IntValueBox(-1, 75, 2, 50.0f, -1, 10, 0.02f);
|
var previewLODValue = new IntValueBox(-1, 90, 2, 70.0f, -1, 10, 0.02f);
|
||||||
previewLODValue.Parent = previewLOD;
|
previewLODValue.Parent = previewLOD;
|
||||||
previewLODValue.ValueChanged += () => _previewModel.ForcedLOD = previewLODValue.Value;
|
previewLODValue.ValueChanged += () => _previewModel.ForcedLOD = previewLODValue.Value;
|
||||||
ViewWidgetButtonMenu.VisibleChanged += control => previewLODValue.Value = _previewModel.ForcedLOD;
|
ViewWidgetButtonMenu.VisibleChanged += control => previewLODValue.Value = _previewModel.ForcedLOD;
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ namespace FlaxEditor.Viewport.Previews
|
|||||||
if (useWidgets)
|
if (useWidgets)
|
||||||
{
|
{
|
||||||
var playbackDuration = ViewWidgetButtonMenu.AddButton("Duration");
|
var playbackDuration = ViewWidgetButtonMenu.AddButton("Duration");
|
||||||
var playbackDurationValue = new FloatValueBox(_playbackDuration, 75, 2, 50.0f, 0.1f, 1000000.0f, 0.1f);
|
var playbackDurationValue = new FloatValueBox(_playbackDuration, 90, 2, 70.0f, 0.1f, 1000000.0f, 0.1f);
|
||||||
playbackDurationValue.Parent = playbackDuration;
|
playbackDurationValue.Parent = playbackDuration;
|
||||||
playbackDurationValue.ValueChanged += () => PlaybackDuration = playbackDurationValue.Value;
|
playbackDurationValue.ValueChanged += () => PlaybackDuration = playbackDurationValue.Value;
|
||||||
ViewWidgetButtonMenu.VisibleChanged += control => playbackDurationValue.Value = PlaybackDuration;
|
ViewWidgetButtonMenu.VisibleChanged += control => playbackDurationValue.Value = PlaybackDuration;
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
_presenter.Modified += MarkAsEdited;
|
_presenter.Modified += MarkAsEdited;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnScriptsReloadBegin()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
ScriptsBuilder.ScriptsReloadBegin -= OnScriptsReloadBegin;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Save()
|
public override void Save()
|
||||||
{
|
{
|
||||||
@@ -76,6 +82,10 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
_presenter.Select(_object);
|
_presenter.Select(_object);
|
||||||
ClearEditedFlag();
|
ClearEditedFlag();
|
||||||
|
|
||||||
|
// Auto-close on scripting reload if json asset is from game scripts (it might be reloaded)
|
||||||
|
if (_object != null && FlaxEngine.Scripting.IsTypeFromGameScripts(_object.GetType()))
|
||||||
|
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
|
||||||
|
|
||||||
base.OnAssetLoaded();
|
base.OnAssetLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ namespace FlaxEditor.Windows
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void ExportSelection()
|
private void ExportSelection()
|
||||||
{
|
{
|
||||||
if(FileSystem.ShowBrowseFolderDialog(Editor.Windows.MainWindow, null, "Select the output folder", out var outputFolder))
|
if (FileSystem.ShowBrowseFolderDialog(Editor.Windows.MainWindow, null, "Select the output folder", out var outputFolder))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var selection = _view.Selection;
|
var selection = _view.Selection;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ void CollisionsHelper::ClosestPointPointLine(const Vector2& point, const Vector2
|
|||||||
Vector2 n = p1 - p0;
|
Vector2 n = p1 - p0;
|
||||||
|
|
||||||
const float length = n.Length();
|
const float length = n.Length();
|
||||||
if (length < 1e-10)
|
if (length < 1e-10f)
|
||||||
{
|
{
|
||||||
// Both points are the same, just give any
|
// Both points are the same, just give any
|
||||||
result = p0;
|
result = p0;
|
||||||
@@ -24,7 +24,7 @@ void CollisionsHelper::ClosestPointPointLine(const Vector2& point, const Vector2
|
|||||||
n /= length;
|
n /= length;
|
||||||
|
|
||||||
const float dot = Vector2::Dot(n, p);
|
const float dot = Vector2::Dot(n, p);
|
||||||
if (dot <= 0.0)
|
if (dot <= 0.0f)
|
||||||
{
|
{
|
||||||
// Before first point
|
// Before first point
|
||||||
result = p0;
|
result = p0;
|
||||||
@@ -41,6 +41,45 @@ void CollisionsHelper::ClosestPointPointLine(const Vector2& point, const Vector2
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2 CollisionsHelper::ClosestPointPointLine(const Vector2& point, const Vector2& p0, const Vector2& p1)
|
||||||
|
{
|
||||||
|
Vector2 result;
|
||||||
|
ClosestPointPointLine(point, p0, p1, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollisionsHelper::ClosestPointPointLine(const Vector3& point, const Vector3& p0, const Vector3& p1, Vector3& result)
|
||||||
|
{
|
||||||
|
const Vector3 p = point - p0;
|
||||||
|
Vector3 n = p1 - p0;
|
||||||
|
const float length = n.Length();
|
||||||
|
if (length < 1e-10f)
|
||||||
|
{
|
||||||
|
result = p0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
n /= length;
|
||||||
|
const float dot = Vector3::Dot(n, p);
|
||||||
|
if (dot <= 0.0f)
|
||||||
|
{
|
||||||
|
result = p0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dot >= length)
|
||||||
|
{
|
||||||
|
result = p1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result = p0 + n * dot;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 CollisionsHelper::ClosestPointPointLine(const Vector3& point, const Vector3& p0, const Vector3& p1)
|
||||||
|
{
|
||||||
|
Vector3 result;
|
||||||
|
ClosestPointPointLine(point, p0, p1, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void CollisionsHelper::ClosestPointPointTriangle(const Vector3& point, const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3, Vector3& result)
|
void CollisionsHelper::ClosestPointPointTriangle(const Vector3& point, const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3, Vector3& result)
|
||||||
{
|
{
|
||||||
// Source: Real-Time Collision Detection by Christer Ericson
|
// Source: Real-Time Collision Detection by Christer Ericson
|
||||||
@@ -101,6 +140,13 @@ void CollisionsHelper::ClosestPointPointTriangle(const Vector3& point, const Vec
|
|||||||
result = vertex1 + ab * v2 + ac * w2; //= u*vertex1 + v*vertex2 + w*vertex3, u = va * denom = 1.0f - v - w
|
result = vertex1 + ab * v2 + ac * w2; //= u*vertex1 + v*vertex2 + w*vertex3, u = va * denom = 1.0f - v - w
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector3 CollisionsHelper::ClosestPointPointTriangle(const Vector3& point, const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3)
|
||||||
|
{
|
||||||
|
Vector3 result;
|
||||||
|
ClosestPointPointTriangle(point, vertex1, vertex2, vertex3, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void CollisionsHelper::ClosestPointPlanePoint(const Plane& plane, const Vector3& point, Vector3& result)
|
void CollisionsHelper::ClosestPointPlanePoint(const Plane& plane, const Vector3& point, Vector3& result)
|
||||||
{
|
{
|
||||||
// Source: Real-Time Collision Detection by Christer Ericson
|
// Source: Real-Time Collision Detection by Christer Ericson
|
||||||
@@ -112,6 +158,13 @@ void CollisionsHelper::ClosestPointPlanePoint(const Plane& plane, const Vector3&
|
|||||||
result = point - t * plane.Normal;
|
result = point - t * plane.Normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector3 CollisionsHelper::ClosestPointPlanePoint(const Plane& plane, const Vector3& point)
|
||||||
|
{
|
||||||
|
Vector3 result;
|
||||||
|
ClosestPointPlanePoint(plane, point, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void CollisionsHelper::ClosestPointBoxPoint(const BoundingBox& box, const Vector3& point, Vector3& result)
|
void CollisionsHelper::ClosestPointBoxPoint(const BoundingBox& box, const Vector3& point, Vector3& result)
|
||||||
{
|
{
|
||||||
// Source: Real-Time Collision Detection by Christer Ericson
|
// Source: Real-Time Collision Detection by Christer Ericson
|
||||||
@@ -122,6 +175,13 @@ void CollisionsHelper::ClosestPointBoxPoint(const BoundingBox& box, const Vector
|
|||||||
Vector3::Min(temp, box.Maximum, result);
|
Vector3::Min(temp, box.Maximum, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector3 CollisionsHelper::ClosestPointBoxPoint(const BoundingBox& box, const Vector3& point)
|
||||||
|
{
|
||||||
|
Vector3 result;
|
||||||
|
ClosestPointBoxPoint(box, point, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void CollisionsHelper::ClosestPointRectanglePoint(const Rectangle& rect, const Vector2& point, Vector2& result)
|
void CollisionsHelper::ClosestPointRectanglePoint(const Rectangle& rect, const Vector2& point, Vector2& result)
|
||||||
{
|
{
|
||||||
Vector2 temp, end;
|
Vector2 temp, end;
|
||||||
@@ -130,6 +190,13 @@ void CollisionsHelper::ClosestPointRectanglePoint(const Rectangle& rect, const V
|
|||||||
Vector2::Min(temp, end, result);
|
Vector2::Min(temp, end, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2 CollisionsHelper::ClosestPointRectanglePoint(const Rectangle& rect, const Vector2& point)
|
||||||
|
{
|
||||||
|
Vector2 result;
|
||||||
|
ClosestPointRectanglePoint(rect, point, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void CollisionsHelper::ClosestPointSpherePoint(const BoundingSphere& sphere, const Vector3& point, Vector3& result)
|
void CollisionsHelper::ClosestPointSpherePoint(const BoundingSphere& sphere, const Vector3& point, Vector3& result)
|
||||||
{
|
{
|
||||||
// Source: Jorgy343
|
// Source: Jorgy343
|
||||||
@@ -147,6 +214,13 @@ void CollisionsHelper::ClosestPointSpherePoint(const BoundingSphere& sphere, con
|
|||||||
result += sphere.Center;
|
result += sphere.Center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector3 CollisionsHelper::ClosestPointSpherePoint(const BoundingSphere& sphere, const Vector3& point)
|
||||||
|
{
|
||||||
|
Vector3 result;
|
||||||
|
ClosestPointSpherePoint(sphere, point, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void CollisionsHelper::ClosestPointSphereSphere(const BoundingSphere& sphere1, const BoundingSphere& sphere2, Vector3& result)
|
void CollisionsHelper::ClosestPointSphereSphere(const BoundingSphere& sphere1, const BoundingSphere& sphere2, Vector3& result)
|
||||||
{
|
{
|
||||||
// Source: Jorgy343
|
// Source: Jorgy343
|
||||||
@@ -164,6 +238,13 @@ void CollisionsHelper::ClosestPointSphereSphere(const BoundingSphere& sphere1, c
|
|||||||
result += sphere1.Center;
|
result += sphere1.Center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector3 CollisionsHelper::ClosestPointSphereSphere(const BoundingSphere& sphere1, const BoundingSphere& sphere2)
|
||||||
|
{
|
||||||
|
Vector3 result;
|
||||||
|
ClosestPointSphereSphere(sphere1, sphere2, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
float CollisionsHelper::DistancePlanePoint(const Plane& plane, const Vector3& point)
|
float CollisionsHelper::DistancePlanePoint(const Plane& plane, const Vector3& point)
|
||||||
{
|
{
|
||||||
// Source: Real-Time Collision Detection by Christer Ericson
|
// Source: Real-Time Collision Detection by Christer Ericson
|
||||||
@@ -821,7 +902,6 @@ bool CollisionsHelper::RayIntersectsBox(const Ray& ray, const BoundingBox& box,
|
|||||||
d = Math::Abs(size.Z - Math::Abs(localPoint.Z));
|
d = Math::Abs(size.Z - Math::Abs(localPoint.Z));
|
||||||
if (d < dMin)
|
if (d < dMin)
|
||||||
{
|
{
|
||||||
dMin = d;
|
|
||||||
normal = Vector3(0, 0, Math::Sign(localPoint.Z));
|
normal = Vector3(0, 0, Math::Sign(localPoint.Z));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -990,15 +1070,11 @@ PlaneIntersectionType CollisionsHelper::PlaneIntersectsBox(const Plane& plane, c
|
|||||||
min.Z = plane.Normal.Z >= 0.0f ? box.Maximum.Z : box.Minimum.Z;
|
min.Z = plane.Normal.Z >= 0.0f ? box.Maximum.Z : box.Minimum.Z;
|
||||||
|
|
||||||
float distance = Vector3::Dot(plane.Normal, max);
|
float distance = Vector3::Dot(plane.Normal, max);
|
||||||
|
|
||||||
if (distance + plane.D > Plane::DistanceEpsilon)
|
if (distance + plane.D > Plane::DistanceEpsilon)
|
||||||
return PlaneIntersectionType::Front;
|
return PlaneIntersectionType::Front;
|
||||||
|
|
||||||
distance = Vector3::Dot(plane.Normal, min);
|
distance = Vector3::Dot(plane.Normal, min);
|
||||||
|
|
||||||
if (distance + plane.D < Plane::DistanceEpsilon)
|
if (distance + plane.D < Plane::DistanceEpsilon)
|
||||||
return PlaneIntersectionType::Back;
|
return PlaneIntersectionType::Back;
|
||||||
|
|
||||||
return PlaneIntersectionType::Intersecting;
|
return PlaneIntersectionType::Intersecting;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1012,10 +1088,8 @@ PlaneIntersectionType CollisionsHelper::PlaneIntersectsSphere(const Plane& plane
|
|||||||
|
|
||||||
if (distance > sphere.Radius)
|
if (distance > sphere.Radius)
|
||||||
return PlaneIntersectionType::Front;
|
return PlaneIntersectionType::Front;
|
||||||
|
|
||||||
if (distance < -sphere.Radius)
|
if (distance < -sphere.Radius)
|
||||||
return PlaneIntersectionType::Back;
|
return PlaneIntersectionType::Back;
|
||||||
|
|
||||||
return PlaneIntersectionType::Intersecting;
|
return PlaneIntersectionType::Intersecting;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1023,13 +1097,10 @@ bool CollisionsHelper::BoxIntersectsBox(const BoundingBox& box1, const BoundingB
|
|||||||
{
|
{
|
||||||
if (box1.Minimum.X > box2.Maximum.X || box2.Minimum.X > box1.Maximum.X)
|
if (box1.Minimum.X > box2.Maximum.X || box2.Minimum.X > box1.Maximum.X)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (box1.Minimum.Y > box2.Maximum.Y || box2.Minimum.Y > box1.Maximum.Y)
|
if (box1.Minimum.Y > box2.Maximum.Y || box2.Minimum.Y > box1.Maximum.Y)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (box1.Minimum.Z > box2.Maximum.Z || box2.Minimum.Z > box1.Maximum.Z)
|
if (box1.Minimum.Z > box2.Maximum.Z || box2.Minimum.Z > box1.Maximum.Z)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,33 @@ public:
|
|||||||
/// <param name="result">When the method completes, contains the closest point between the two objects.</param>
|
/// <param name="result">When the method completes, contains the closest point between the two objects.</param>
|
||||||
static void ClosestPointPointLine(const Vector2& point, const Vector2& p0, const Vector2& p1, Vector2& result);
|
static void ClosestPointPointLine(const Vector2& point, const Vector2& p0, const Vector2& p1, Vector2& result);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the closest point between a point and a line.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="point">The point to test.</param>
|
||||||
|
/// <param name="p0">The line first point.</param>
|
||||||
|
/// <param name="p1">The line second point.</param>
|
||||||
|
/// <returns>The closest point between the two objects.</result>
|
||||||
|
static Vector2 ClosestPointPointLine(const Vector2& point, const Vector2& p0, const Vector2& p1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the closest point between a point and a line.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="point">The point to test.</param>
|
||||||
|
/// <param name="p0">The line first point.</param>
|
||||||
|
/// <param name="p1">The line second point.</param>
|
||||||
|
/// <param name="result">When the method completes, contains the closest point between the two objects.</param>
|
||||||
|
static void ClosestPointPointLine(const Vector3& point, const Vector3& p0, const Vector3& p1, Vector3& result);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the closest point between a point and a line.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="point">The point to test.</param>
|
||||||
|
/// <param name="p0">The line first point.</param>
|
||||||
|
/// <param name="p1">The line second point.</param>
|
||||||
|
/// <returns>The closest point between the two objects.</result>
|
||||||
|
static Vector3 ClosestPointPointLine(const Vector3& point, const Vector3& p0, const Vector3& p1);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines the closest point between a point and a triangle.
|
/// Determines the closest point between a point and a triangle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -82,6 +109,16 @@ public:
|
|||||||
/// <param name="result">When the method completes, contains the closest point between the two objects.</param>
|
/// <param name="result">When the method completes, contains the closest point between the two objects.</param>
|
||||||
static void ClosestPointPointTriangle(const Vector3& point, const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3, Vector3& result);
|
static void ClosestPointPointTriangle(const Vector3& point, const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3, Vector3& result);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the closest point between a point and a triangle.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="point">The point to test.</param>
|
||||||
|
/// <param name="vertex1">The first vertex to test.</param>
|
||||||
|
/// <param name="vertex2">The second vertex to test.</param>
|
||||||
|
/// <param name="vertex3">The third vertex to test.</param>
|
||||||
|
/// <returns>The closest point between the two objects.</returns>
|
||||||
|
static Vector3 ClosestPointPointTriangle(const Vector3& point, const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines the closest point between a <see cref="Plane" /> and a point.
|
/// Determines the closest point between a <see cref="Plane" /> and a point.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -90,6 +127,14 @@ public:
|
|||||||
/// <param name="result">When the method completes, contains the closest point between the two objects.</param>
|
/// <param name="result">When the method completes, contains the closest point between the two objects.</param>
|
||||||
static void ClosestPointPlanePoint(const Plane& plane, const Vector3& point, Vector3& result);
|
static void ClosestPointPlanePoint(const Plane& plane, const Vector3& point, Vector3& result);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the closest point between a <see cref="Plane" /> and a point.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="plane">The plane to test.</param>
|
||||||
|
/// <param name="point">The point to test.</param>
|
||||||
|
/// <returns>The closest point between the two objects.</returns>
|
||||||
|
static Vector3 ClosestPointPlanePoint(const Plane& plane, const Vector3& point);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines the closest point between a <see cref="BoundingBox" /> and a point.
|
/// Determines the closest point between a <see cref="BoundingBox" /> and a point.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -98,6 +143,14 @@ public:
|
|||||||
/// <param name="result">When the method completes, contains the closest point between the two objects.</param>
|
/// <param name="result">When the method completes, contains the closest point between the two objects.</param>
|
||||||
static void ClosestPointBoxPoint(const BoundingBox& box, const Vector3& point, Vector3& result);
|
static void ClosestPointBoxPoint(const BoundingBox& box, const Vector3& point, Vector3& result);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the closest point between a <see cref="BoundingBox" /> and a point.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="box">The box to test.</param>
|
||||||
|
/// <param name="point">The point to test.</param>
|
||||||
|
/// <returns>The closest point between the two objects.</returns>
|
||||||
|
static Vector3 ClosestPointBoxPoint(const BoundingBox& box, const Vector3& point);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines the closest point between a <see cref="Rectangle" /> and a point.
|
/// Determines the closest point between a <see cref="Rectangle" /> and a point.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -106,6 +159,14 @@ public:
|
|||||||
/// <param name="result">When the method completes, contains the closest point between the two objects.</param>
|
/// <param name="result">When the method completes, contains the closest point between the two objects.</param>
|
||||||
static void ClosestPointRectanglePoint(const Rectangle& rect, const Vector2& point, Vector2& result);
|
static void ClosestPointRectanglePoint(const Rectangle& rect, const Vector2& point, Vector2& result);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the closest point between a <see cref="Rectangle" /> and a point.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rect">The rectangle to test.</param>
|
||||||
|
/// <param name="point">The point to test.</param>
|
||||||
|
/// <returns>The closest point between the two objects.</returns>
|
||||||
|
static Vector2 ClosestPointRectanglePoint(const Rectangle& rect, const Vector2& point);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines the closest point between a <see cref="BoundingSphere" /> and a point.
|
/// Determines the closest point between a <see cref="BoundingSphere" /> and a point.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -114,6 +175,14 @@ public:
|
|||||||
/// <param name="result">When the method completes, contains the closest point between the two objects; or, if the point is directly in the center of the sphere, contains <see cref="Vector3.Zero" />.</param>
|
/// <param name="result">When the method completes, contains the closest point between the two objects; or, if the point is directly in the center of the sphere, contains <see cref="Vector3.Zero" />.</param>
|
||||||
static void ClosestPointSpherePoint(const BoundingSphere& sphere, const Vector3& point, Vector3& result);
|
static void ClosestPointSpherePoint(const BoundingSphere& sphere, const Vector3& point, Vector3& result);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the closest point between a <see cref="BoundingSphere" /> and a point.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sphere">The sphere to test.</param>
|
||||||
|
/// <param name="point">The point to test.</param>
|
||||||
|
/// <returns>The closest point between the two objects; or, if the point is directly in the center of the sphere, contains <see cref="Vector3.Zero" />.</return>
|
||||||
|
static Vector3 ClosestPointSpherePoint(const BoundingSphere& sphere, const Vector3& point);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines the closest point between a <see cref="BoundingSphere" /> and a <see cref="BoundingSphere" />.
|
/// Determines the closest point between a <see cref="BoundingSphere" /> and a <see cref="BoundingSphere" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -127,6 +196,19 @@ public:
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
static void ClosestPointSphereSphere(const BoundingSphere& sphere1, const BoundingSphere& sphere2, Vector3& result);
|
static void ClosestPointSphereSphere(const BoundingSphere& sphere1, const BoundingSphere& sphere2, Vector3& result);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines the closest point between a <see cref="BoundingSphere" /> and a <see cref="BoundingSphere" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sphere1">The first sphere to test.</param>
|
||||||
|
/// <param name="sphere2">The second sphere to test.</param>
|
||||||
|
/// <returns>The closest point between the two objects; or, if the point is directly in the center of the sphere, contains <see cref="Vector3.Zero" />.</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// If the two spheres are overlapping, but not directly on top of each other, the closest point
|
||||||
|
/// is the 'closest' point of intersection. This can also be considered is the deepest point of
|
||||||
|
/// intersection.
|
||||||
|
/// </remarks>
|
||||||
|
static Vector3 ClosestPointSphereSphere(const BoundingSphere& sphere1, const BoundingSphere& sphere2);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines the distance between a <see cref="Plane" /> and a point.
|
/// Determines the distance between a <see cref="Plane" /> and a point.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ namespace FlaxEngine
|
|||||||
/// Mesh data will be cached and uploaded to the GPU with a delay.
|
/// Mesh data will be cached and uploaded to the GPU with a delay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="vertices">The mesh vertices positions. Cannot be null.</param>
|
/// <param name="vertices">The mesh vertices positions. Cannot be null.</param>
|
||||||
/// <param name="triangles">The mesh index buffer (triangles). Uses 32-bit stride buffer. Cannot be null.</param>
|
/// <param name="triangles">The mesh index buffer (clockwise triangles). Uses 32-bit stride buffer. Cannot be null.</param>
|
||||||
/// <param name="normals">The normal vectors (per vertex).</param>
|
/// <param name="normals">The normal vectors (per vertex).</param>
|
||||||
/// <param name="tangents">The normal vectors (per vertex). Use null to compute them from normal vectors.</param>
|
/// <param name="tangents">The normal vectors (per vertex). Use null to compute them from normal vectors.</param>
|
||||||
/// <param name="uv">The texture coordinates (per vertex).</param>
|
/// <param name="uv">The texture coordinates (per vertex).</param>
|
||||||
@@ -163,7 +163,7 @@ namespace FlaxEngine
|
|||||||
/// Mesh data will be cached and uploaded to the GPU with a delay.
|
/// Mesh data will be cached and uploaded to the GPU with a delay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="vertices">The mesh vertices positions. Cannot be null.</param>
|
/// <param name="vertices">The mesh vertices positions. Cannot be null.</param>
|
||||||
/// <param name="triangles">The mesh index buffer (triangles). Uses 32-bit stride buffer. Cannot be null.</param>
|
/// <param name="triangles">The mesh index buffer (clockwise triangles). Uses 32-bit stride buffer. Cannot be null.</param>
|
||||||
/// <param name="normals">The normal vectors (per vertex).</param>
|
/// <param name="normals">The normal vectors (per vertex).</param>
|
||||||
/// <param name="tangents">The normal vectors (per vertex). Use null to compute them from normal vectors.</param>
|
/// <param name="tangents">The normal vectors (per vertex). Use null to compute them from normal vectors.</param>
|
||||||
/// <param name="uv">The texture coordinates (per vertex).</param>
|
/// <param name="uv">The texture coordinates (per vertex).</param>
|
||||||
@@ -210,7 +210,7 @@ namespace FlaxEngine
|
|||||||
/// Mesh data will be cached and uploaded to the GPU with a delay.
|
/// Mesh data will be cached and uploaded to the GPU with a delay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="vertices">The mesh vertices positions. Cannot be null.</param>
|
/// <param name="vertices">The mesh vertices positions. Cannot be null.</param>
|
||||||
/// <param name="triangles">The mesh index buffer (triangles). Uses 16-bit stride buffer. Cannot be null.</param>
|
/// <param name="triangles">The mesh index buffer (clockwise triangles). Uses 16-bit stride buffer. Cannot be null.</param>
|
||||||
/// <param name="normals">The normal vectors (per vertex).</param>
|
/// <param name="normals">The normal vectors (per vertex).</param>
|
||||||
/// <param name="tangents">The tangent vectors (per vertex). Use null to compute them from normal vectors.</param>
|
/// <param name="tangents">The tangent vectors (per vertex). Use null to compute them from normal vectors.</param>
|
||||||
/// <param name="uv">The texture coordinates (per vertex).</param>
|
/// <param name="uv">The texture coordinates (per vertex).</param>
|
||||||
@@ -257,7 +257,7 @@ namespace FlaxEngine
|
|||||||
/// Mesh data will be cached and uploaded to the GPU with a delay.
|
/// Mesh data will be cached and uploaded to the GPU with a delay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="vertices">The mesh vertices positions. Cannot be null.</param>
|
/// <param name="vertices">The mesh vertices positions. Cannot be null.</param>
|
||||||
/// <param name="triangles">The mesh index buffer (triangles). Uses 16-bit stride buffer. Cannot be null.</param>
|
/// <param name="triangles">The mesh index buffer (clockwise triangles). Uses 16-bit stride buffer. Cannot be null.</param>
|
||||||
/// <param name="normals">The normal vectors (per vertex).</param>
|
/// <param name="normals">The normal vectors (per vertex).</param>
|
||||||
/// <param name="tangents">The tangent vectors (per vertex). Use null to compute them from normal vectors.</param>
|
/// <param name="tangents">The tangent vectors (per vertex). Use null to compute them from normal vectors.</param>
|
||||||
/// <param name="uv">The texture coordinates (per vertex).</param>
|
/// <param name="uv">The texture coordinates (per vertex).</param>
|
||||||
|
|||||||
@@ -10,6 +10,127 @@
|
|||||||
#include "Engine/Serialization/MemoryReadStream.h"
|
#include "Engine/Serialization/MemoryReadStream.h"
|
||||||
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
|
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
template<typename IndexType>
|
||||||
|
bool UpdateMesh(Mesh* mesh, uint32 vertexCount, uint32 triangleCount, Vector3* vertices, IndexType* triangles, Vector3* normals, Vector3* tangents, Vector2* uvs, Color32* colors)
|
||||||
|
{
|
||||||
|
auto model = mesh->GetModel();
|
||||||
|
CHECK_RETURN(model && model->IsVirtual(), true);
|
||||||
|
CHECK_RETURN(triangles && vertices, true);
|
||||||
|
|
||||||
|
// Pack mesh data into vertex buffers
|
||||||
|
Array<VB1ElementType> vb1;
|
||||||
|
Array<VB2ElementType> vb2;
|
||||||
|
vb1.Resize(vertexCount);
|
||||||
|
if (normals)
|
||||||
|
{
|
||||||
|
if (tangents)
|
||||||
|
{
|
||||||
|
for (uint32 i = 0; i < vertexCount; i++)
|
||||||
|
{
|
||||||
|
const Vector3 normal = normals[i];
|
||||||
|
const Vector3 tangent = tangents[i];
|
||||||
|
|
||||||
|
// Calculate bitangent sign
|
||||||
|
Vector3 bitangent = Vector3::Normalize(Vector3::Cross(normal, tangent));
|
||||||
|
byte sign = static_cast<byte>(Vector3::Dot(Vector3::Cross(bitangent, normal), tangent) < 0.0f ? 1 : 0);
|
||||||
|
|
||||||
|
// Set tangent frame
|
||||||
|
vb1[i].Tangent = Float1010102(tangent * 0.5f + 0.5f, sign);
|
||||||
|
vb1[i].Normal = Float1010102(normal * 0.5f + 0.5f, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (uint32 i = 0; i < vertexCount; i++)
|
||||||
|
{
|
||||||
|
const Vector3 normal = normals[i];
|
||||||
|
|
||||||
|
// Calculate tangent
|
||||||
|
Vector3 c1 = Vector3::Cross(normal, Vector3::UnitZ);
|
||||||
|
Vector3 c2 = Vector3::Cross(normal, Vector3::UnitY);
|
||||||
|
Vector3 tangent;
|
||||||
|
if (c1.LengthSquared() > c2.LengthSquared())
|
||||||
|
tangent = c1;
|
||||||
|
else
|
||||||
|
tangent = c2;
|
||||||
|
|
||||||
|
// Calculate bitangent sign
|
||||||
|
Vector3 bitangent = Vector3::Normalize(Vector3::Cross(normal, tangent));
|
||||||
|
byte sign = static_cast<byte>(Vector3::Dot(Vector3::Cross(bitangent, normal), tangent) < 0.0f ? 1 : 0);
|
||||||
|
|
||||||
|
// Set tangent frame
|
||||||
|
vb1[i].Tangent = Float1010102(tangent * 0.5f + 0.5f, sign);
|
||||||
|
vb1[i].Normal = Float1010102(normal * 0.5f + 0.5f, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Set default tangent frame
|
||||||
|
const auto n = Float1010102(Vector3::UnitZ);
|
||||||
|
const auto t = Float1010102(Vector3::UnitX);
|
||||||
|
for (uint32 i = 0; i < vertexCount; i++)
|
||||||
|
{
|
||||||
|
vb1[i].Normal = n;
|
||||||
|
vb1[i].Tangent = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (uvs)
|
||||||
|
{
|
||||||
|
for (uint32 i = 0; i < vertexCount; i++)
|
||||||
|
vb1[i].TexCoord = Half2(uvs[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto v = Half2(0, 0);
|
||||||
|
for (uint32 i = 0; i < vertexCount; i++)
|
||||||
|
vb1[i].TexCoord = v;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto v = Half2(0, 0);
|
||||||
|
for (uint32 i = 0; i < vertexCount; i++)
|
||||||
|
vb1[i].LightmapUVs = v;
|
||||||
|
}
|
||||||
|
if (colors)
|
||||||
|
{
|
||||||
|
vb2.Resize(vertexCount);
|
||||||
|
for (uint32 i = 0; i < vertexCount; i++)
|
||||||
|
vb2[i].Color = colors[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return mesh->UpdateMesh(vertexCount, triangleCount, (VB0ElementType*)vertices, vb1.Get(), vb2.HasItems() ? vb2.Get() : nullptr, triangles);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename IndexType>
|
||||||
|
bool UpdateMesh(Mesh* mesh, uint32 vertexCount, uint32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj)
|
||||||
|
{
|
||||||
|
ASSERT((uint32)mono_array_length(verticesObj) >= vertexCount);
|
||||||
|
ASSERT((uint32)mono_array_length(trianglesObj) / 3 >= triangleCount);
|
||||||
|
auto vertices = (Vector3*)(void*)mono_array_addr_with_size(verticesObj, sizeof(Vector3), 0);
|
||||||
|
auto triangles = (IndexType*)(void*)mono_array_addr_with_size(trianglesObj, sizeof(IndexType), 0);
|
||||||
|
const auto normals = normalsObj ? (Vector3*)(void*)mono_array_addr_with_size(normalsObj, sizeof(Vector3), 0) : nullptr;
|
||||||
|
const auto tangents = tangentsObj ? (Vector3*)(void*)mono_array_addr_with_size(tangentsObj, sizeof(Vector3), 0) : nullptr;
|
||||||
|
const auto uvs = uvObj ? (Vector2*)(void*)mono_array_addr_with_size(uvObj, sizeof(Vector2), 0) : nullptr;
|
||||||
|
const auto colors = colorsObj ? (Color32*)(void*)mono_array_addr_with_size(colorsObj, sizeof(Color32), 0) : nullptr;
|
||||||
|
return UpdateMesh<IndexType>(mesh, vertexCount, triangleCount, vertices, triangles, normals, tangents, uvs, colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename IndexType>
|
||||||
|
bool UpdateTriangles(Mesh* mesh, int32 triangleCount, MonoArray* trianglesObj)
|
||||||
|
{
|
||||||
|
const auto model = mesh->GetModel();
|
||||||
|
ASSERT(model && model->IsVirtual() && trianglesObj);
|
||||||
|
|
||||||
|
// Get buffer data
|
||||||
|
ASSERT((int32)mono_array_length(trianglesObj) / 3 >= triangleCount);
|
||||||
|
auto ib = (IndexType*)(void*)mono_array_addr_with_size(trianglesObj, sizeof(IndexType), 0);
|
||||||
|
|
||||||
|
return mesh->UpdateTriangles(triangleCount, ib);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, void* ib, bool use16BitIndices)
|
bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, void* ib, bool use16BitIndices)
|
||||||
{
|
{
|
||||||
Unload();
|
Unload();
|
||||||
@@ -31,6 +152,16 @@ bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType*
|
|||||||
return failed;
|
return failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint16* triangles, Vector3* normals, Vector3* tangents, Vector2* uvs, Color32* colors)
|
||||||
|
{
|
||||||
|
return ::UpdateMesh<uint16>(this, vertexCount, triangleCount, vertices, triangles, normals, tangents, uvs, colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint32* triangles, Vector3* normals, Vector3* tangents, Vector2* uvs, Color32* colors)
|
||||||
|
{
|
||||||
|
return ::UpdateMesh<uint32>(this, vertexCount, triangleCount, vertices, triangles, normals, tangents, uvs, colors);
|
||||||
|
}
|
||||||
|
|
||||||
bool Mesh::UpdateTriangles(uint32 triangleCount, void* ib, bool use16BitIndices)
|
bool Mesh::UpdateTriangles(uint32 triangleCount, void* ib, bool use16BitIndices)
|
||||||
{
|
{
|
||||||
// Cache data
|
// Cache data
|
||||||
@@ -384,108 +515,9 @@ ScriptingObject* Mesh::GetParentModel()
|
|||||||
return _model;
|
return _model;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename IndexType>
|
|
||||||
bool UpdateMesh(Mesh* mesh, uint32 vertexCount, uint32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj)
|
|
||||||
{
|
|
||||||
auto model = mesh->GetModel();
|
|
||||||
ASSERT(model && model->IsVirtual() && verticesObj && trianglesObj);
|
|
||||||
|
|
||||||
// Get buffers data
|
|
||||||
ASSERT((uint32)mono_array_length(verticesObj) >= vertexCount);
|
|
||||||
ASSERT((uint32)mono_array_length(trianglesObj) / 3 >= triangleCount);
|
|
||||||
auto vb0 = (Vector3*)(void*)mono_array_addr_with_size(verticesObj, sizeof(Vector3), 0);
|
|
||||||
auto ib = (IndexType*)(void*)mono_array_addr_with_size(trianglesObj, sizeof(IndexType), 0);
|
|
||||||
Array<VB1ElementType> vb1;
|
|
||||||
Array<VB2ElementType> vb2;
|
|
||||||
vb1.Resize(vertexCount);
|
|
||||||
if (normalsObj)
|
|
||||||
{
|
|
||||||
const auto normals = (Vector3*)(void*)mono_array_addr_with_size(normalsObj, sizeof(Vector3), 0);
|
|
||||||
if (tangentsObj)
|
|
||||||
{
|
|
||||||
const auto tangents = (Vector3*)(void*)mono_array_addr_with_size(tangentsObj, sizeof(Vector3), 0);
|
|
||||||
for (uint32 i = 0; i < vertexCount; i++)
|
|
||||||
{
|
|
||||||
// Peek normal and tangent
|
|
||||||
const Vector3 normal = normals[i];
|
|
||||||
const Vector3 tangent = tangents[i];
|
|
||||||
|
|
||||||
// Calculate bitangent sign
|
|
||||||
Vector3 bitangent = Vector3::Normalize(Vector3::Cross(normal, tangent));
|
|
||||||
byte sign = static_cast<byte>(Vector3::Dot(Vector3::Cross(bitangent, normal), tangent) < 0.0f ? 1 : 0);
|
|
||||||
|
|
||||||
// Set tangent frame
|
|
||||||
vb1[i].Tangent = Float1010102(tangent * 0.5f + 0.5f, sign);
|
|
||||||
vb1[i].Normal = Float1010102(normal * 0.5f + 0.5f, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (uint32 i = 0; i < vertexCount; i++)
|
|
||||||
{
|
|
||||||
// Peek normal
|
|
||||||
const Vector3 normal = normals[i];
|
|
||||||
|
|
||||||
// Calculate tangent
|
|
||||||
Vector3 c1 = Vector3::Cross(normal, Vector3::UnitZ);
|
|
||||||
Vector3 c2 = Vector3::Cross(normal, Vector3::UnitY);
|
|
||||||
Vector3 tangent;
|
|
||||||
if (c1.LengthSquared() > c2.LengthSquared())
|
|
||||||
tangent = c1;
|
|
||||||
else
|
|
||||||
tangent = c2;
|
|
||||||
|
|
||||||
// Calculate bitangent sign
|
|
||||||
Vector3 bitangent = Vector3::Normalize(Vector3::Cross(normal, tangent));
|
|
||||||
byte sign = static_cast<byte>(Vector3::Dot(Vector3::Cross(bitangent, normal), tangent) < 0.0f ? 1 : 0);
|
|
||||||
|
|
||||||
// Set tangent frame
|
|
||||||
vb1[i].Tangent = Float1010102(tangent * 0.5f + 0.5f, sign);
|
|
||||||
vb1[i].Normal = Float1010102(normal * 0.5f + 0.5f, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const auto n = Float1010102(Vector3::UnitZ);
|
|
||||||
const auto t = Float1010102(Vector3::UnitX);
|
|
||||||
for (uint32 i = 0; i < vertexCount; i++)
|
|
||||||
{
|
|
||||||
vb1[i].Normal = n;
|
|
||||||
vb1[i].Tangent = t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (uvObj)
|
|
||||||
{
|
|
||||||
const auto uvs = (Vector2*)(void*)mono_array_addr_with_size(uvObj, sizeof(Vector2), 0);
|
|
||||||
for (uint32 i = 0; i < vertexCount; i++)
|
|
||||||
vb1[i].TexCoord = Half2(uvs[i]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto v = Half2(0, 0);
|
|
||||||
for (uint32 i = 0; i < vertexCount; i++)
|
|
||||||
vb1[i].TexCoord = v;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto v = Half2(0, 0);
|
|
||||||
for (uint32 i = 0; i < vertexCount; i++)
|
|
||||||
vb1[i].LightmapUVs = v;
|
|
||||||
}
|
|
||||||
if (colorsObj)
|
|
||||||
{
|
|
||||||
vb2.Resize(vertexCount);
|
|
||||||
const auto colors = (Color32*)(void*)mono_array_addr_with_size(colorsObj, sizeof(Color32), 0);
|
|
||||||
for (uint32 i = 0; i < vertexCount; i++)
|
|
||||||
vb2[i].Color = colors[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return mesh->UpdateMesh(vertexCount, triangleCount, (VB0ElementType*)vb0, vb1.Get(), vb2.HasItems() ? vb2.Get() : nullptr, ib);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Mesh::UpdateMeshInt(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj)
|
bool Mesh::UpdateMeshInt(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj)
|
||||||
{
|
{
|
||||||
return ::UpdateMesh<int32>(this, (uint32)vertexCount, (uint32)triangleCount, verticesObj, trianglesObj, normalsObj, tangentsObj, uvObj, colorsObj);
|
return ::UpdateMesh<uint32>(this, (uint32)vertexCount, (uint32)triangleCount, verticesObj, trianglesObj, normalsObj, tangentsObj, uvObj, colorsObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mesh::UpdateMeshUShort(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj)
|
bool Mesh::UpdateMeshUShort(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj)
|
||||||
@@ -493,22 +525,9 @@ bool Mesh::UpdateMeshUShort(int32 vertexCount, int32 triangleCount, MonoArray* v
|
|||||||
return ::UpdateMesh<uint16>(this, (uint32)vertexCount, (uint32)triangleCount, verticesObj, trianglesObj, normalsObj, tangentsObj, uvObj, colorsObj);
|
return ::UpdateMesh<uint16>(this, (uint32)vertexCount, (uint32)triangleCount, verticesObj, trianglesObj, normalsObj, tangentsObj, uvObj, colorsObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename IndexType>
|
|
||||||
bool UpdateTriangles(Mesh* mesh, int32 triangleCount, MonoArray* trianglesObj)
|
|
||||||
{
|
|
||||||
auto model = mesh->GetModel();
|
|
||||||
ASSERT(model && model->IsVirtual() && trianglesObj);
|
|
||||||
|
|
||||||
// Get buffer data
|
|
||||||
ASSERT((int32)mono_array_length(trianglesObj) / 3 >= triangleCount);
|
|
||||||
auto ib = (IndexType*)(void*)mono_array_addr_with_size(trianglesObj, sizeof(IndexType), 0);
|
|
||||||
|
|
||||||
return mesh->UpdateTriangles(triangleCount, ib);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Mesh::UpdateTrianglesInt(int32 triangleCount, MonoArray* trianglesObj)
|
bool Mesh::UpdateTrianglesInt(int32 triangleCount, MonoArray* trianglesObj)
|
||||||
{
|
{
|
||||||
return ::UpdateTriangles<int32>(this, triangleCount, trianglesObj);
|
return ::UpdateTriangles<uint32>(this, triangleCount, trianglesObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mesh::UpdateTrianglesUShort(int32 triangleCount, MonoArray* trianglesObj)
|
bool Mesh::UpdateTrianglesUShort(int32 triangleCount, MonoArray* trianglesObj)
|
||||||
|
|||||||
@@ -216,9 +216,9 @@ public:
|
|||||||
/// <param name="vb0">The first vertex buffer data.</param>
|
/// <param name="vb0">The first vertex buffer data.</param>
|
||||||
/// <param name="vb1">The second vertex buffer data.</param>
|
/// <param name="vb1">The second vertex buffer data.</param>
|
||||||
/// <param name="vb2">The third vertex buffer data.</param>
|
/// <param name="vb2">The third vertex buffer data.</param>
|
||||||
/// <param name="ib">The index buffer.</param>
|
/// <param name="ib">The index buffer in clockwise order.</param>
|
||||||
/// <returns>True if failed, otherwise false.</returns>
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, int32* ib)
|
FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, uint32* ib)
|
||||||
{
|
{
|
||||||
return UpdateMesh(vertexCount, triangleCount, vb0, vb1, vb2, ib, false);
|
return UpdateMesh(vertexCount, triangleCount, vb0, vb1, vb2, ib, false);
|
||||||
}
|
}
|
||||||
@@ -231,7 +231,7 @@ public:
|
|||||||
/// <param name="vb0">The first vertex buffer data.</param>
|
/// <param name="vb0">The first vertex buffer data.</param>
|
||||||
/// <param name="vb1">The second vertex buffer data.</param>
|
/// <param name="vb1">The second vertex buffer data.</param>
|
||||||
/// <param name="vb2">The third vertex buffer data.</param>
|
/// <param name="vb2">The third vertex buffer data.</param>
|
||||||
/// <param name="ib">The index buffer.</param>
|
/// <param name="ib">The index buffer in clockwise order.</param>
|
||||||
/// <returns>True if failed, otherwise false.</returns>
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, uint16* ib)
|
FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, uint16* ib)
|
||||||
{
|
{
|
||||||
@@ -240,17 +240,51 @@ public:
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the model mesh (used by the virtual models created with Init rather than Load).
|
/// Updates the model mesh (used by the virtual models created with Init rather than Load).
|
||||||
|
/// Can be used only for virtual assets (see <see cref="Asset.IsVirtual"/> and <see cref="Content.CreateVirtualAsset{T}"/>).
|
||||||
|
/// Mesh data will be cached and uploaded to the GPU with a delay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="vertexCount">The amount of vertices in the vertex buffer.</param>
|
/// <param name="vertexCount">The amount of vertices in the vertex buffer.</param>
|
||||||
/// <param name="triangleCount">The amount of triangles in the index buffer.</param>
|
/// <param name="triangleCount">The amount of triangles in the index buffer.</param>
|
||||||
/// <param name="vb0">The first vertex buffer data.</param>
|
/// <param name="vb0">The first vertex buffer data.</param>
|
||||||
/// <param name="vb1">The second vertex buffer data.</param>
|
/// <param name="vb1">The second vertex buffer data.</param>
|
||||||
/// <param name="vb2">The third vertex buffer data.</param>
|
/// <param name="vb2">The third vertex buffer data.</param>
|
||||||
/// <param name="ib">The index buffer.</param>
|
/// <param name="ib">The index buffer in clockwise order.</param>
|
||||||
/// <param name="use16BitIndices">True if index buffer uses 16-bit index buffer, otherwise 32-bit.</param>
|
/// <param name="use16BitIndices">True if index buffer uses 16-bit index buffer, otherwise 32-bit.</param>
|
||||||
/// <returns>True if failed, otherwise false.</returns>
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, void* ib, bool use16BitIndices);
|
bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, void* ib, bool use16BitIndices);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the model mesh (used by the virtual models created with Init rather than Load).
|
||||||
|
/// Can be used only for virtual assets (see <see cref="Asset.IsVirtual"/> and <see cref="Content.CreateVirtualAsset{T}"/>).
|
||||||
|
/// Mesh data will be cached and uploaded to the GPU with a delay.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vertexCount">The amount of vertices in the vertex buffer.</param>
|
||||||
|
/// <param name="triangleCount">The amount of triangles in the index buffer.</param>
|
||||||
|
/// <param name="vertices">The mesh vertices positions. Cannot be null.</param>
|
||||||
|
/// <param name="triangles">The mesh index buffer (clockwise triangles). Uses 32-bit stride buffer. Cannot be null.</param>
|
||||||
|
/// <param name="normals">The normal vectors (per vertex).</param>
|
||||||
|
/// <param name="tangents">The normal vectors (per vertex). Use null to compute them from normal vectors.</param>
|
||||||
|
/// <param name="uvs">The texture coordinates (per vertex).</param>
|
||||||
|
/// <param name="colors">The vertex colors (per vertex).</param>
|
||||||
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
|
bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint16* triangles, Vector3* normals = nullptr, Vector3* tangents = nullptr, Vector2* uvs = nullptr, Color32* colors = nullptr);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the model mesh (used by the virtual models created with Init rather than Load).
|
||||||
|
/// Can be used only for virtual assets (see <see cref="Asset.IsVirtual"/> and <see cref="Content.CreateVirtualAsset{T}"/>).
|
||||||
|
/// Mesh data will be cached and uploaded to the GPU with a delay.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vertexCount">The amount of vertices in the vertex buffer.</param>
|
||||||
|
/// <param name="triangleCount">The amount of triangles in the index buffer.</param>
|
||||||
|
/// <param name="vertices">The mesh vertices positions. Cannot be null.</param>
|
||||||
|
/// <param name="triangles">The mesh index buffer (clockwise triangles). Uses 32-bit stride buffer. Cannot be null.</param>
|
||||||
|
/// <param name="normals">The normal vectors (per vertex).</param>
|
||||||
|
/// <param name="tangents">The normal vectors (per vertex). Use null to compute them from normal vectors.</param>
|
||||||
|
/// <param name="uvs">The texture coordinates (per vertex).</param>
|
||||||
|
/// <param name="colors">The vertex colors (per vertex).</param>
|
||||||
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
|
bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint32* triangles, Vector3* normals = nullptr, Vector3* tangents = nullptr, Vector2* uvs = nullptr, Color32* colors = nullptr);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -259,7 +293,7 @@ public:
|
|||||||
/// <param name="triangleCount">The amount of triangles in the index buffer.</param>
|
/// <param name="triangleCount">The amount of triangles in the index buffer.</param>
|
||||||
/// <param name="ib">The index buffer.</param>
|
/// <param name="ib">The index buffer.</param>
|
||||||
/// <returns>True if failed, otherwise false.</returns>
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
FORCE_INLINE bool UpdateTriangles(uint32 triangleCount, int32* ib)
|
FORCE_INLINE bool UpdateTriangles(uint32 triangleCount, uint32* ib)
|
||||||
{
|
{
|
||||||
return UpdateTriangles(triangleCount, ib, false);
|
return UpdateTriangles(triangleCount, ib, false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ public:
|
|||||||
/// <param name="vertexCount">The amount of vertices in the vertex buffer.</param>
|
/// <param name="vertexCount">The amount of vertices in the vertex buffer.</param>
|
||||||
/// <param name="triangleCount">The amount of triangles in the index buffer.</param>
|
/// <param name="triangleCount">The amount of triangles in the index buffer.</param>
|
||||||
/// <param name="vb">The vertex buffer data.</param>
|
/// <param name="vb">The vertex buffer data.</param>
|
||||||
/// <param name="ib">The index buffer.</param>
|
/// <param name="ib">The index buffer in clockwise order.</param>
|
||||||
/// <returns>True if failed, otherwise false.</returns>
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0SkinnedElementType* vb, int32* ib)
|
FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0SkinnedElementType* vb, int32* ib)
|
||||||
{
|
{
|
||||||
@@ -176,7 +176,7 @@ public:
|
|||||||
/// <param name="vertexCount">The amount of vertices in the vertex buffer.</param>
|
/// <param name="vertexCount">The amount of vertices in the vertex buffer.</param>
|
||||||
/// <param name="triangleCount">The amount of triangles in the index buffer.</param>
|
/// <param name="triangleCount">The amount of triangles in the index buffer.</param>
|
||||||
/// <param name="vb">The vertex buffer data.</param>
|
/// <param name="vb">The vertex buffer data.</param>
|
||||||
/// <param name="ib">The index buffer.</param>
|
/// <param name="ib">The index buffer, clockwise order.</param>
|
||||||
/// <returns>True if failed, otherwise false.</returns>
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0SkinnedElementType* vb, uint16* ib)
|
FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0SkinnedElementType* vb, uint16* ib)
|
||||||
{
|
{
|
||||||
@@ -189,7 +189,7 @@ public:
|
|||||||
/// <param name="vertexCount">The amount of vertices in the vertex buffer.</param>
|
/// <param name="vertexCount">The amount of vertices in the vertex buffer.</param>
|
||||||
/// <param name="triangleCount">The amount of triangles in the index buffer.</param>
|
/// <param name="triangleCount">The amount of triangles in the index buffer.</param>
|
||||||
/// <param name="vb">The vertex buffer data.</param>
|
/// <param name="vb">The vertex buffer data.</param>
|
||||||
/// <param name="ib">The index buffer.</param>
|
/// <param name="ib">The index buffer in clockwise order.</param>
|
||||||
/// <param name="use16BitIndices">True if index buffer uses 16-bit index buffer, otherwise 32-bit.</param>
|
/// <param name="use16BitIndices">True if index buffer uses 16-bit index buffer, otherwise 32-bit.</param>
|
||||||
/// <returns>True if failed, otherwise false.</returns>
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0SkinnedElementType* vb, void* ib, bool use16BitIndices);
|
bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0SkinnedElementType* vb, void* ib, bool use16BitIndices);
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ namespace FlaxEngine
|
|||||||
/// Mesh data will be cached and uploaded to the GPU with a delay.
|
/// Mesh data will be cached and uploaded to the GPU with a delay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="vertices">The mesh vertices positions. Cannot be null.</param>
|
/// <param name="vertices">The mesh vertices positions. Cannot be null.</param>
|
||||||
/// <param name="triangles">The mesh index buffer (triangles). Uses 32-bit stride buffer. Cannot be null.</param>
|
/// <param name="triangles">The mesh index buffer (clockwise triangles). Uses 32-bit stride buffer. Cannot be null.</param>
|
||||||
/// <param name="blendIndices">The skinned mesh blend indices buffer. Contains indices of the skeleton bones (up to 4 bones per vertex) to use for vertex position blending. Cannot be null.</param>
|
/// <param name="blendIndices">The skinned mesh blend indices buffer. Contains indices of the skeleton bones (up to 4 bones per vertex) to use for vertex position blending. Cannot be null.</param>
|
||||||
/// <param name="blendWeights">The skinned mesh blend weights buffer (normalized). Contains weights per blend bone (up to 4 bones per vertex) of the skeleton bones to mix for vertex position blending. Cannot be null.</param>
|
/// <param name="blendWeights">The skinned mesh blend weights buffer (normalized). Contains weights per blend bone (up to 4 bones per vertex) of the skeleton bones to mix for vertex position blending. Cannot be null.</param>
|
||||||
/// <param name="normals">The normal vectors (per vertex).</param>
|
/// <param name="normals">The normal vectors (per vertex).</param>
|
||||||
@@ -140,7 +140,7 @@ namespace FlaxEngine
|
|||||||
/// Mesh data will be cached and uploaded to the GPU with a delay.
|
/// Mesh data will be cached and uploaded to the GPU with a delay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="vertices">The mesh vertices positions. Cannot be null.</param>
|
/// <param name="vertices">The mesh vertices positions. Cannot be null.</param>
|
||||||
/// <param name="triangles">The mesh index buffer (triangles). Uses 16-bit stride buffer. Cannot be null.</param>
|
/// <param name="triangles">The mesh index buffer (clockwise triangles). Uses 16-bit stride buffer. Cannot be null.</param>
|
||||||
/// <param name="blendIndices">The skinned mesh blend indices buffer. Contains indices of the skeleton bones (up to 4 bones per vertex) to use for vertex position blending. Cannot be null.</param>
|
/// <param name="blendIndices">The skinned mesh blend indices buffer. Contains indices of the skeleton bones (up to 4 bones per vertex) to use for vertex position blending. Cannot be null.</param>
|
||||||
/// <param name="blendWeights">The skinned mesh blend weights buffer (normalized). Contains weights per blend bone (up to 4 bones per vertex) of the skeleton bones to mix for vertex position blending. Cannot be null.</param>
|
/// <param name="blendWeights">The skinned mesh blend weights buffer (normalized). Contains weights per blend bone (up to 4 bones per vertex) of the skeleton bones to mix for vertex position blending. Cannot be null.</param>
|
||||||
/// <param name="normals">The normal vectors (per vertex).</param>
|
/// <param name="normals">The normal vectors (per vertex).</param>
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ void CharacterController::SetHeight(const float value)
|
|||||||
|
|
||||||
void CharacterController::SetSlopeLimit(float value)
|
void CharacterController::SetSlopeLimit(float value)
|
||||||
{
|
{
|
||||||
value = Math::Clamp(value, 0.0f, 90.0f);
|
value = Math::Clamp(value, 0.0f, 89.0f);
|
||||||
if (Math::NearEqual(value, _slopeLimit))
|
if (Math::NearEqual(value, _slopeLimit))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ void CharacterController::CreateActor()
|
|||||||
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
||||||
const float minSize = 0.001f;
|
const float minSize = 0.001f;
|
||||||
desc.height = Math::Max(Math::Abs(_height) * scaling, minSize);
|
desc.height = Math::Max(Math::Abs(_height) * scaling, minSize);
|
||||||
desc.radius = Math::Max(Math::Abs(_radius) * scaling, minSize);
|
desc.radius = Math::Max(Math::Abs(_radius) * scaling - desc.contactOffset, minSize);
|
||||||
|
|
||||||
// Create controller
|
// Create controller
|
||||||
_controller = (PxCapsuleController*)Physics::GetControllerManager()->createController(desc);
|
_controller = (PxCapsuleController*)Physics::GetControllerManager()->createController(desc);
|
||||||
@@ -202,7 +202,7 @@ void CharacterController::UpdateSize() const
|
|||||||
{
|
{
|
||||||
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
||||||
const float minSize = 0.001f;
|
const float minSize = 0.001f;
|
||||||
const float radius = Math::Max(Math::Abs(_radius) * scaling, minSize);
|
const float radius = Math::Max(Math::Abs(_radius) * scaling - Math::Max(_contactOffset, ZeroTolerance), minSize);
|
||||||
const float height = Math::Max(Math::Abs(_height) * scaling, minSize);
|
const float height = Math::Max(Math::Abs(_height) * scaling, minSize);
|
||||||
|
|
||||||
_controller->setRadius(radius);
|
_controller->setRadius(radius);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "WindowsFileSystem.h"
|
#include "WindowsFileSystem.h"
|
||||||
#include "Engine/Platform/File.h"
|
#include "Engine/Platform/File.h"
|
||||||
#include "Engine/Platform/Window.h"
|
#include "Engine/Platform/Window.h"
|
||||||
|
#include "Engine/Platform/Windows/ComPtr.h"
|
||||||
#include "Engine/Core/Types/StringView.h"
|
#include "Engine/Core/Types/StringView.h"
|
||||||
#include "../Win32/IncludeWindowsHeaders.h"
|
#include "../Win32/IncludeWindowsHeaders.h"
|
||||||
|
|
||||||
@@ -293,41 +294,39 @@ bool WindowsFileSystem::ShowBrowseFolderDialog(Window* parentWindow, const Strin
|
|||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
// Allocate memory for the filenames
|
// Randomly generated GUID used for storing the last location of this dialog
|
||||||
int32 maxPathSize = 2 * MAX_PATH;
|
const Guid folderGuid(0x53890ed9, 0xa55e47ba, 0xa970bdae, 0x72acedff);
|
||||||
Array<Char> pathBuffer;
|
|
||||||
pathBuffer.Resize(maxPathSize);
|
|
||||||
pathBuffer[0] = 0;
|
|
||||||
|
|
||||||
// Setup description
|
ComPtr<IFileOpenDialog> fd;
|
||||||
BROWSEINFOW bi;
|
if (SUCCEEDED(CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&fd))))
|
||||||
ZeroMemory(&bi, sizeof(bi));
|
|
||||||
if (parentWindow)
|
|
||||||
bi.hwndOwner = static_cast<HWND>(parentWindow->GetNativePtr());
|
|
||||||
bi.lpszTitle = title.HasChars() ? title.Get() : nullptr;
|
|
||||||
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
|
|
||||||
bi.lpfn = BrowseCallbackProc;
|
|
||||||
bi.lParam = (LPARAM)(initialDirectory.HasChars() ? initialDirectory.Get() : nullptr);
|
|
||||||
|
|
||||||
LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
|
|
||||||
|
|
||||||
if (pidl != nullptr)
|
|
||||||
{
|
{
|
||||||
// Get the name of the folder and put it in path
|
DWORD options;
|
||||||
SHGetPathFromIDList(pidl, pathBuffer.Get());
|
fd->GetOptions(&options);
|
||||||
|
fd->SetOptions(options | FOS_PICKFOLDERS | FOS_NOCHANGEDIR);
|
||||||
|
|
||||||
if (pathBuffer[0] != 0)
|
if (title.HasChars())
|
||||||
{
|
fd->SetTitle(title.Get());
|
||||||
path = pathBuffer.Get();
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free memory used
|
// Associate the last selected folder with this GUID instead of overwriting the global one
|
||||||
IMalloc* imalloc = 0;
|
fd->SetClientGuid(*reinterpret_cast<const GUID*>(&folderGuid));
|
||||||
if (SUCCEEDED(SHGetMalloc(&imalloc)))
|
|
||||||
|
ComPtr<IShellItem> defaultFolder;
|
||||||
|
if (SUCCEEDED(SHCreateItemFromParsingName(initialDirectory.Get(), NULL, IID_PPV_ARGS(&defaultFolder))))
|
||||||
|
fd->SetFolder(defaultFolder);
|
||||||
|
|
||||||
|
if (SUCCEEDED(fd->Show(parentWindow->GetHWND())))
|
||||||
{
|
{
|
||||||
imalloc->Free(pidl);
|
ComPtr<IShellItem> si;
|
||||||
imalloc->Release();
|
if (SUCCEEDED(fd->GetResult(&si)))
|
||||||
|
{
|
||||||
|
LPWSTR resultPath;
|
||||||
|
if (SUCCEEDED(si->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &resultPath)))
|
||||||
|
{
|
||||||
|
path = resultPath;
|
||||||
|
CoTaskMemFree(resultPath);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -274,8 +274,10 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
|
|||||||
// Compute depth difference
|
// Compute depth difference
|
||||||
auto depthDiff = writeLocal(VariantType::Float, String::Format(TEXT("{0} * ViewFar - {1}"), sceneDepth.Value, posVS.Value), node);
|
auto depthDiff = writeLocal(VariantType::Float, String::Format(TEXT("{0} * ViewFar - {1}"), sceneDepth.Value, posVS.Value), node);
|
||||||
|
|
||||||
|
auto fadeDistance = tryGetValue(node->GetBox(0), node->Values[0]).AsFloat();
|
||||||
|
|
||||||
// Apply smoothing factor and clamp the result
|
// Apply smoothing factor and clamp the result
|
||||||
value = writeLocal(VariantType::Float, String::Format(TEXT("saturate({0} / {1})"), depthDiff.Value, node->Values[0].AsFloat), node);
|
value = writeLocal(VariantType::Float, String::Format(TEXT("saturate({0} / {1})"), depthDiff.Value, fadeDistance.Value), node);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Material Function
|
// Material Function
|
||||||
@@ -337,6 +339,59 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value)
|
|||||||
case 25:
|
case 25:
|
||||||
value = Value(VariantType::Vector3, TEXT("GetObjectSize(input)"));
|
value = Value(VariantType::Vector3, TEXT("GetObjectSize(input)"));
|
||||||
break;
|
break;
|
||||||
|
// Blend Normals
|
||||||
|
case 26:
|
||||||
|
{
|
||||||
|
const auto baseNormal = tryGetValue(node->GetBox(0), Value::Zero).AsVector3();
|
||||||
|
const auto additionalNormal = tryGetValue(node->GetBox(1), Value::Zero).AsVector3();
|
||||||
|
const String text = String::Format(TEXT("float3((float2({0}.xy) + float2({1}.xy) * 2.0), sqrt(saturate(1.0 - dot((float2({0}.xy) + float2({1}.xy) * 2.0).xy, (float2({0}.xy) + float2({1}.xy) * 2.0).xy))))"), baseNormal.Value, additionalNormal.Value);
|
||||||
|
value = writeLocal(ValueType::Vector3, text, node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Rotator
|
||||||
|
case 27:
|
||||||
|
{
|
||||||
|
auto uv = tryGetValue(node->GetBox(0), getUVs).AsVector2();
|
||||||
|
auto center = tryGetValue(node->GetBox(1), Value::Zero).AsVector2();
|
||||||
|
auto rotationAngle = tryGetValue(node->GetBox(2), Value::Zero).AsFloat();
|
||||||
|
|
||||||
|
const auto x1 = writeLocal(ValueType::Vector2, String::Format(TEXT("({0} * -1) + {1}"), center.Value, uv.Value), node);
|
||||||
|
const auto raCosSin = writeLocal(ValueType::Vector2, String::Format(TEXT("float2(cos({0}), sin({0}))"), rotationAngle.Value), node);
|
||||||
|
|
||||||
|
const auto dotB1 = writeLocal(ValueType::Vector2, String::Format(TEXT("float2({0}.x, {0}.y * -1)"), raCosSin.Value), node);
|
||||||
|
const auto dotB2 = writeLocal(ValueType::Vector2, String::Format(TEXT("float2({0}.y, {0}.x)"), raCosSin.Value), node);
|
||||||
|
|
||||||
|
value = writeLocal(ValueType::Vector2, String::Format(TEXT("{3} + float2(dot({0},{1}), dot({0},{2}))"), x1.Value, dotB1.Value, dotB2.Value, center.Value), node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Sphere Mask
|
||||||
|
case 28:
|
||||||
|
{
|
||||||
|
Value a = tryGetValue(node->GetBox(0), 0, Value::Zero);
|
||||||
|
Value b = tryGetValue(node->GetBox(1), 1, Value::Zero).Cast(a.Type);
|
||||||
|
Value radius = tryGetValue(node->GetBox(2), node->Values[0]).AsFloat();
|
||||||
|
Value hardness = tryGetValue(node->GetBox(3), node->Values[1]).AsFloat();
|
||||||
|
Value invert = tryGetValue(node->GetBox(4), node->Values[2]).AsBool();
|
||||||
|
|
||||||
|
// Get distance and apply radius
|
||||||
|
auto x1 = writeLocal(ValueType::Float, String::Format(TEXT("distance({0},{1}) * (1 / {2})"), a.Value, b.Value, radius.Value), node);
|
||||||
|
|
||||||
|
// Apply hardness, use 0.991 as max since any value above will result in harsh aliasing
|
||||||
|
auto x2 = writeLocal(ValueType::Float, String::Format(TEXT("saturate((1 - {0}) * (1 / (1 - clamp({1}, 0, 0.991f))))"), x1.Value, hardness.Value), node);
|
||||||
|
|
||||||
|
value = writeLocal(ValueType::Float, String::Format(TEXT("{0} ? (1 - {1}) : {1}"), invert.Value, x2.Value), node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Tiling & Offset
|
||||||
|
case 29:
|
||||||
|
{
|
||||||
|
auto uv = tryGetValue(node->GetBox(0), getUVs).AsVector2();
|
||||||
|
auto tiling = tryGetValue(node->GetBox(1), node->Values[0]).AsVector2();
|
||||||
|
auto offset = tryGetValue(node->GetBox(2), node->Values[1]).AsVector2();
|
||||||
|
|
||||||
|
value = writeLocal(ValueType::Vector2, String::Format(TEXT("{0} * {1} + {2}"), uv.Value, tiling.Value, offset.Value), node);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,6 +190,16 @@ bool TextureTool::ExportTextureDirectXTex(ImageType type, const StringView& path
|
|||||||
}
|
}
|
||||||
img = tmp.GetImage(0, 0, 0);
|
img = tmp.GetImage(0, 0, 0);
|
||||||
}
|
}
|
||||||
|
else if (image.format == DXGI_FORMAT_R10G10B10A2_UNORM || image.format == DXGI_FORMAT_R11G11B10_FLOAT)
|
||||||
|
{
|
||||||
|
result = DirectX::Convert(image, DXGI_FORMAT_R8G8B8A8_UNORM, DirectX::TEX_FILTER_DEFAULT, DirectX::TEX_THRESHOLD_DEFAULT, tmp);
|
||||||
|
if (FAILED(result))
|
||||||
|
{
|
||||||
|
LOG(Error, "Cannot convert texture, error: {0:x}", static_cast<uint32>(result));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
img = tmp.GetImage(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
DirectX::WICCodecs codec;
|
DirectX::WICCodecs codec;
|
||||||
switch (type)
|
switch (type)
|
||||||
|
|||||||
@@ -401,6 +401,18 @@ void ShaderGenerator::ProcessGroupMath(Box* box, Node* node, Value& value)
|
|||||||
{
|
{
|
||||||
value = writeFunction1(node, tryGetValue(node->GetBox(0), Value::Zero), TEXT("radians"));
|
value = writeFunction1(node, tryGetValue(node->GetBox(0), Value::Zero), TEXT("radians"));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
// Remap
|
||||||
|
case 48:
|
||||||
|
{
|
||||||
|
const auto inVal = tryGetValue(node->GetBox(0), node->Values[0].AsFloat);
|
||||||
|
const auto rangeA = tryGetValue(node->GetBox(1), node->Values[1].AsVector2());
|
||||||
|
const auto rangeB = tryGetValue(node->GetBox(2), node->Values[2].AsVector2());
|
||||||
|
const auto clamp = tryGetValue(node->GetBox(3), node->Values[3]).AsBool();
|
||||||
|
|
||||||
|
const auto mapFunc = String::Format(TEXT("{2}.x + ({0} - {1}.x) * ({2}.y - {2}.x) / ({1}.y - {1}.x)"), inVal.Value, rangeA.Value, rangeB.Value);
|
||||||
|
value = writeLocal(ValueType::Float, String::Format(TEXT("{2} ? clamp({0}, {1}.x, {1}.y) : {0}"), mapFunc, rangeB.Value, clamp.Value), node);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -371,6 +371,20 @@ void VisjectExecutor::ProcessGroupMath(Box* box, Node* node, Value& value)
|
|||||||
if (value.Type.Type == VariantType::Enum)
|
if (value.Type.Type == VariantType::Enum)
|
||||||
value.AsUint64 = value.AsUint64 | (uint64)tryGetValue(node->GetBox(1), Value::Zero);
|
value.AsUint64 = value.AsUint64 | (uint64)tryGetValue(node->GetBox(1), Value::Zero);
|
||||||
break;
|
break;
|
||||||
|
// Remap
|
||||||
|
case 48:
|
||||||
|
{
|
||||||
|
const float inVal = tryGetValue(node->GetBox(0), node->Values[0]).AsFloat;
|
||||||
|
const Vector2 rangeA = tryGetValue(node->GetBox(1), node->Values[1]).AsVector2();
|
||||||
|
const Vector2 rangeB = tryGetValue(node->GetBox(2), node->Values[2]).AsVector2();
|
||||||
|
const bool clamp = tryGetValue(node->GetBox(3), node->Values[3]).AsBool;
|
||||||
|
|
||||||
|
auto mapFunc = rangeB.X + (inVal - rangeA.X) * (rangeB.Y - rangeB.X) / (rangeA.Y - rangeA.X);
|
||||||
|
|
||||||
|
// Clamp value?
|
||||||
|
value = clamp ? Math::Clamp(mapFunc, rangeB.X, rangeB.Y) : mapFunc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ namespace Flax.Build.NativeCpp
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Optimization = false;
|
public bool Optimization = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables the whole program optimization.
|
||||||
|
/// </summary>
|
||||||
|
public bool WholeProgramOptimization = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables functions level linking support.
|
/// Enables functions level linking support.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -131,6 +136,7 @@ namespace Flax.Build.NativeCpp
|
|||||||
RuntimeTypeInfo = RuntimeTypeInfo,
|
RuntimeTypeInfo = RuntimeTypeInfo,
|
||||||
Inlining = Inlining,
|
Inlining = Inlining,
|
||||||
Optimization = Optimization,
|
Optimization = Optimization,
|
||||||
|
WholeProgramOptimization = WholeProgramOptimization,
|
||||||
FunctionLevelLinking = FunctionLevelLinking,
|
FunctionLevelLinking = FunctionLevelLinking,
|
||||||
DebugInformation = DebugInformation,
|
DebugInformation = DebugInformation,
|
||||||
UseDebugCRT = UseDebugCRT,
|
UseDebugCRT = UseDebugCRT,
|
||||||
|
|||||||
@@ -256,6 +256,7 @@ namespace Flax.Build
|
|||||||
options.CompileEnv.IntrinsicFunctions = false;
|
options.CompileEnv.IntrinsicFunctions = false;
|
||||||
options.CompileEnv.BufferSecurityCheck = true;
|
options.CompileEnv.BufferSecurityCheck = true;
|
||||||
options.CompileEnv.Inlining = false;
|
options.CompileEnv.Inlining = false;
|
||||||
|
options.CompileEnv.WholeProgramOptimization = false;
|
||||||
|
|
||||||
options.LinkEnv.DebugInformation = true;
|
options.LinkEnv.DebugInformation = true;
|
||||||
options.LinkEnv.LinkTimeCodeGeneration = false;
|
options.LinkEnv.LinkTimeCodeGeneration = false;
|
||||||
@@ -273,11 +274,11 @@ namespace Flax.Build
|
|||||||
options.CompileEnv.IntrinsicFunctions = true;
|
options.CompileEnv.IntrinsicFunctions = true;
|
||||||
options.CompileEnv.BufferSecurityCheck = true;
|
options.CompileEnv.BufferSecurityCheck = true;
|
||||||
options.CompileEnv.Inlining = true;
|
options.CompileEnv.Inlining = true;
|
||||||
//options.CompileEnv.WholeProgramOptimization = true;
|
options.CompileEnv.WholeProgramOptimization = false;
|
||||||
|
|
||||||
options.LinkEnv.DebugInformation = true;
|
options.LinkEnv.DebugInformation = true;
|
||||||
options.LinkEnv.LinkTimeCodeGeneration = true;
|
options.LinkEnv.LinkTimeCodeGeneration = false;
|
||||||
options.LinkEnv.UseIncrementalLinking = false;
|
options.LinkEnv.UseIncrementalLinking = true;
|
||||||
options.LinkEnv.Optimization = true;
|
options.LinkEnv.Optimization = true;
|
||||||
break;
|
break;
|
||||||
case TargetConfiguration.Release:
|
case TargetConfiguration.Release:
|
||||||
@@ -291,7 +292,7 @@ namespace Flax.Build
|
|||||||
options.CompileEnv.IntrinsicFunctions = true;
|
options.CompileEnv.IntrinsicFunctions = true;
|
||||||
options.CompileEnv.BufferSecurityCheck = false;
|
options.CompileEnv.BufferSecurityCheck = false;
|
||||||
options.CompileEnv.Inlining = true;
|
options.CompileEnv.Inlining = true;
|
||||||
//options.CompileEnv.WholeProgramOptimization = true;
|
options.CompileEnv.WholeProgramOptimization = true;
|
||||||
|
|
||||||
options.LinkEnv.DebugInformation = false;
|
options.LinkEnv.DebugInformation = false;
|
||||||
options.LinkEnv.LinkTimeCodeGeneration = true;
|
options.LinkEnv.LinkTimeCodeGeneration = true;
|
||||||
|
|||||||
@@ -467,8 +467,11 @@ namespace Flax.Build.Platforms
|
|||||||
// Frame-Pointer Omission
|
// Frame-Pointer Omission
|
||||||
commonArgs.Add("/Oy");
|
commonArgs.Add("/Oy");
|
||||||
|
|
||||||
// Whole Program Optimization
|
if (compileEnvironment.WholeProgramOptimization)
|
||||||
commonArgs.Add("/GL");
|
{
|
||||||
|
// Whole Program Optimization
|
||||||
|
commonArgs.Add("/GL");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -721,7 +724,7 @@ namespace Flax.Build.Platforms
|
|||||||
args.Add("/PDBALTPATH:%_PDB%");
|
args.Add("/PDBALTPATH:%_PDB%");
|
||||||
|
|
||||||
// Optimize
|
// Optimize
|
||||||
if (linkEnvironment.Optimization)
|
if (linkEnvironment.Optimization && !linkEnvironment.UseIncrementalLinking)
|
||||||
{
|
{
|
||||||
// Generate an EXE checksum
|
// Generate an EXE checksum
|
||||||
args.Add("/RELEASE");
|
args.Add("/RELEASE");
|
||||||
|
|||||||
Reference in New Issue
Block a user