Merge remote-tracking branch 'origin/master' into 1.10

# Conflicts:
#	Source/Editor/SceneGraph/Actors/StaticModelNode.cs
#	Source/Engine/Graphics/Models/Mesh.cs
#	Source/Engine/Graphics/Models/ModelData.h
This commit is contained in:
Wojtek Figat
2025-03-13 11:23:01 +01:00
34 changed files with 834 additions and 99 deletions

View File

@@ -182,6 +182,54 @@ namespace FlaxEditor.SceneGraph
return null;
}
/// <summary>
/// Get all nested actor nodes under this actor node.
/// </summary>
/// <returns>An array of ActorNodes</returns>
public ActorNode[] GetAllChildActorNodes()
{
var nodes = new List<ActorNode>();
GetAllChildActorNodes(nodes);
return nodes.ToArray();
}
/// <summary>
/// Get all nested actor nodes under this actor node.
/// </summary>
/// <param name="nodes">The output list to fill with results.</param>
public void GetAllChildActorNodes(List<ActorNode> nodes)
{
var children = ChildNodes;
if (children == null)
return;
for (int i = 0; i < children.Count; i++)
{
if (children[i] is ActorNode node)
{
nodes.Add(node);
node.GetAllChildActorNodes(nodes);
}
}
}
/// <summary>
/// Whether an actor node can be selected with a selector.
/// </summary>
/// <returns>True if the actor node can be selected</returns>
public virtual bool CanSelectActorNodeWithSelector()
{
return Actor && Actor.HideFlags is not (HideFlags.DontSelect or HideFlags.FullyHidden) && Actor is not EmptyActor && IsActive;
}
/// <summary>
/// The selection points used to check if an actor node can be selected.
/// </summary>
/// <returns>The points to use if the actor can be selected.</returns>
public virtual Vector3[] GetActorSelectionPoints()
{
return Actor.EditorBox.GetCorners();
}
/// <summary>
/// Gets a value indicating whether this actor can be used to create prefab from it (as a root).
/// </summary>

View File

@@ -58,5 +58,11 @@ namespace FlaxEditor.SceneGraph.Actors
return Camera.Internal_IntersectsItselfEditor(FlaxEngine.Object.GetUnmanagedPtr(_actor), ref ray.Ray, out distance);
}
/// <inheritdoc />
public override Vector3[] GetActorSelectionPoints()
{
return [Actor.Position];
}
}
}

View File

@@ -33,6 +33,12 @@ namespace FlaxEditor.SceneGraph.Actors
}
}
/// <inheritdoc />
public override bool CanSelectActorNodeWithSelector()
{
return false;
}
/// <summary>
/// Gets the scene.
/// </summary>

View File

@@ -24,6 +24,9 @@ namespace FlaxEditor.SceneGraph.Actors
public sealed class StaticModelNode : ActorNode
{
private Dictionary<IntPtr, Float3[]> _vertices;
private Vector3[] _selectionPoints;
private Transform _selectionPointsTransform;
private Model _selectionPointsModel;
/// <inheritdoc />
public StaticModelNode(Actor actor)
@@ -31,6 +34,16 @@ namespace FlaxEditor.SceneGraph.Actors
{
}
/// <inheritdoc />
public override void OnDispose()
{
_vertices = null;
_selectionPoints = null;
_selectionPointsModel = null;
base.OnDispose();
}
/// <inheritdoc />
public override bool OnVertexSnap(ref Ray ray, Real hitDistance, out Vector3 result)
{
@@ -91,6 +104,45 @@ namespace FlaxEditor.SceneGraph.Actors
contextMenu.AddButton("Add collider", () => OnAddMeshCollider(window)).Enabled = ((StaticModel)Actor).Model != null;
}
/// <inheritdoc />
public override Vector3[] GetActorSelectionPoints()
{
if (Actor is StaticModel sm && sm.Model)
{
// Try to use cache
var model = sm.Model;
var transform = Actor.Transform;
if (_selectionPoints != null &&
_selectionPointsTransform == transform &&
_selectionPointsModel == model)
return _selectionPoints;
Profiler.BeginEvent("GetActorSelectionPoints");
// Check collision proxy points for more accurate selection
var vecPoints = new List<Vector3>();
var m = model.LODs[0];
foreach (var mesh in m.Meshes)
{
var points = mesh.GetCollisionProxyPoints();
vecPoints.EnsureCapacity(vecPoints.Count + points.Length);
for (int i = 0; i < points.Length; i++)
{
vecPoints.Add(transform.LocalToWorld(points[i]));
}
}
Profiler.EndEvent();
if (vecPoints.Count != 0)
{
_selectionPoints = vecPoints.ToArray();
_selectionPointsTransform = transform;
_selectionPointsModel = model;
return _selectionPoints;
}
}
return base.GetActorSelectionPoints();
}
private void OnAddMeshCollider(EditorWindow window)
{
// Allow collider to be added to evey static model selection

View File

@@ -78,5 +78,11 @@ namespace FlaxEditor.SceneGraph.Actors
if (Actor is UICanvas uiCanvas && uiCanvas.Is3D)
DebugDraw.DrawWireBox(uiCanvas.Bounds, Color.BlueViolet);
}
/// <inheritdoc />
public override bool CanSelectActorNodeWithSelector()
{
return Actor is UICanvas uiCanvas && uiCanvas.Is3D && base.CanSelectActorNodeWithSelector();
}
}
}

View File

@@ -40,5 +40,31 @@ namespace FlaxEditor.SceneGraph.Actors
control.PerformLayout();
}
}
/// <inheritdoc />
public override bool CanSelectActorNodeWithSelector()
{
// Check if control and skip if canvas is 2D
if (Actor is not UIControl uiControl)
return false;
UICanvas canvas = null;
var controlParent = uiControl.Parent;
while (controlParent != null && controlParent is not Scene)
{
if (controlParent is UICanvas uiCanvas)
{
canvas = uiCanvas;
break;
}
controlParent = controlParent.Parent;
}
if (canvas != null)
{
if (canvas.Is2D)
return false;
}
return base.CanSelectActorNodeWithSelector();
}
}
}

View File

@@ -166,7 +166,7 @@ namespace FlaxEditor.SceneGraph.GUI
/// <param name="filterText">The filter text.</param>
public void UpdateFilter(string filterText)
{
// SKip hidden actors
// Skip hidden actors
var actor = Actor;
if (actor != null && (actor.HideFlags & HideFlags.HideInHierarchy) != 0)
return;
@@ -238,7 +238,7 @@ namespace FlaxEditor.SceneGraph.GUI
}
else
{
if (Actor !=null)
if (Actor != null)
{
var actorTypeText = trimmedFilter.Replace("a:", "", StringComparison.OrdinalIgnoreCase).Trim();
var name = TypeUtils.GetTypeDisplayName(Actor.GetType());
@@ -248,6 +248,26 @@ namespace FlaxEditor.SceneGraph.GUI
}
}
}
// Check for control type
else if (trimmedFilter.Contains("c:", StringComparison.OrdinalIgnoreCase))
{
if (trimmedFilter.Equals("c:", StringComparison.OrdinalIgnoreCase))
{
if (Actor != null)
hasFilter = true;
}
else
{
if (Actor != null && Actor is UIControl uic && uic.Control != null)
{
var controlTypeText = trimmedFilter.Replace("c:", "", StringComparison.OrdinalIgnoreCase).Trim();
var name = TypeUtils.GetTypeDisplayName(uic.Control.GetType());
var nameNoSpaces = name.Replace(" ", "");
if (name.Contains(controlTypeText, StringComparison.OrdinalIgnoreCase) || nameNoSpaces.Contains(controlTypeText, StringComparison.OrdinalIgnoreCase))
hasFilter = true;
}
}
}
// Match text
else
{