Merge branch 'Tryibion-scene-actor-multi-select'
This commit is contained in:
@@ -42,6 +42,7 @@ namespace FlaxEditor.Gizmo
|
||||
private bool _isDuplicating;
|
||||
|
||||
private bool _isTransforming;
|
||||
private bool _isSelected;
|
||||
private Vector3 _lastIntersectionPosition;
|
||||
|
||||
private Quaternion _rotationDelta = Quaternion.Identity;
|
||||
@@ -455,7 +456,7 @@ namespace FlaxEditor.Gizmo
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsControllingMouse => _isTransforming;
|
||||
public override bool IsControllingMouse => _isTransforming || _isSelected;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(float dt)
|
||||
@@ -480,6 +481,7 @@ namespace FlaxEditor.Gizmo
|
||||
// Check if user is holding left mouse button and any axis is selected
|
||||
if (isLeftBtnDown && _activeAxis != Axis.None)
|
||||
{
|
||||
_isSelected = true; // setting later is too late, need to set here for rubber band selection in GizmoViewport
|
||||
switch (_activeMode)
|
||||
{
|
||||
case Mode.Translate:
|
||||
@@ -497,6 +499,7 @@ namespace FlaxEditor.Gizmo
|
||||
}
|
||||
else
|
||||
{
|
||||
_isSelected = false;
|
||||
// If nothing selected, try to select any axis
|
||||
if (!isLeftBtnDown && !Owner.IsRightMouseButtonDown)
|
||||
{
|
||||
@@ -564,6 +567,7 @@ namespace FlaxEditor.Gizmo
|
||||
// Clear cache
|
||||
_accMoveDelta = Vector3.Zero;
|
||||
_lastIntersectionPosition = _intersectPosition = Vector3.Zero;
|
||||
_isSelected = false;
|
||||
EndTransforming();
|
||||
}
|
||||
}
|
||||
|
||||
262
Source/Editor/Gizmo/ViewportRubberBandSelector.cs
Normal file
262
Source/Editor/Gizmo/ViewportRubberBandSelector.cs
Normal file
@@ -0,0 +1,262 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using FlaxEditor.Gizmo;
|
||||
using FlaxEditor.SceneGraph;
|
||||
using FlaxEditor.Viewport;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEngine.Gizmo;
|
||||
|
||||
/// <summary>
|
||||
/// Class for adding viewport rubber band selection.
|
||||
/// </summary>
|
||||
public class ViewportRubberBandSelector
|
||||
{
|
||||
private bool _isRubberBandSpanning;
|
||||
private bool _tryStartRubberBand;
|
||||
private Float2 _cachedStartingMousePosition;
|
||||
private Rectangle _rubberBandRect;
|
||||
private Rectangle _lastRubberBandRect;
|
||||
private List<ActorNode> _nodesCache;
|
||||
private List<SceneGraphNode> _hitsCache;
|
||||
private IGizmoOwner _owner;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a rubber band selector with a designated gizmo owner.
|
||||
/// </summary>
|
||||
/// <param name="owner">The gizmo owner.</param>
|
||||
public ViewportRubberBandSelector(IGizmoOwner owner)
|
||||
{
|
||||
_owner = owner;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triggers the start of a rubber band selection.
|
||||
/// </summary>
|
||||
/// <returns>True if selection started, otherwise false.</returns>
|
||||
public bool TryStartingRubberBandSelection()
|
||||
{
|
||||
if (!_isRubberBandSpanning && !_owner.Gizmos.Active.IsControllingMouse && !_owner.IsRightMouseButtonDown)
|
||||
{
|
||||
_tryStartRubberBand = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release the rubber band selection.
|
||||
/// </summary>
|
||||
/// <returns>Returns true if rubber band is currently spanning</returns>
|
||||
public bool ReleaseRubberBandSelection()
|
||||
{
|
||||
if (_tryStartRubberBand)
|
||||
{
|
||||
_tryStartRubberBand = false;
|
||||
}
|
||||
|
||||
if (_isRubberBandSpanning)
|
||||
{
|
||||
_isRubberBandSpanning = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to create a rubber band selection.
|
||||
/// </summary>
|
||||
/// <param name="canStart">Whether the creation can start.</param>
|
||||
/// <param name="mousePosition">The current mouse position.</param>
|
||||
/// <param name="viewFrustum">The view frustum.</param>
|
||||
public void TryCreateRubberBand(bool canStart, Float2 mousePosition, BoundingFrustum viewFrustum)
|
||||
{
|
||||
if (_isRubberBandSpanning && !canStart)
|
||||
{
|
||||
_isRubberBandSpanning = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_tryStartRubberBand && (Mathf.Abs(_owner.MouseDelta.X) > 0.1f || Mathf.Abs(_owner.MouseDelta.Y) > 0.1f) && canStart)
|
||||
{
|
||||
_isRubberBandSpanning = true;
|
||||
_cachedStartingMousePosition = mousePosition;
|
||||
_rubberBandRect = new Rectangle(_cachedStartingMousePosition, Float2.Zero);
|
||||
_tryStartRubberBand = false;
|
||||
}
|
||||
else if (_isRubberBandSpanning && !_owner.Gizmos.Active.IsControllingMouse && !_owner.IsRightMouseButtonDown)
|
||||
{
|
||||
_rubberBandRect.Width = mousePosition.X - _cachedStartingMousePosition.X;
|
||||
_rubberBandRect.Height = mousePosition.Y - _cachedStartingMousePosition.Y;
|
||||
if (_lastRubberBandRect != _rubberBandRect)
|
||||
{
|
||||
UpdateRubberBand(ref viewFrustum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct ViewportProjection
|
||||
{
|
||||
private Viewport _viewport;
|
||||
private Matrix _viewProjection;
|
||||
|
||||
public void Init(EditorViewport editorViewport)
|
||||
{
|
||||
// Inline EditorViewport.ProjectPoint to save on calculation for large set of points
|
||||
_viewport = new Viewport(0, 0, editorViewport.Width, editorViewport.Height);
|
||||
var frustum = editorViewport.ViewFrustum;
|
||||
_viewProjection = frustum.Matrix;
|
||||
}
|
||||
|
||||
public void ProjectPoint(ref Vector3 worldSpaceLocation, out Float2 viewportSpaceLocation)
|
||||
{
|
||||
_viewport.Project(ref worldSpaceLocation, ref _viewProjection, out var projected);
|
||||
viewportSpaceLocation = new Float2((float)projected.X, (float)projected.Y);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateRubberBand(ref BoundingFrustum viewFrustum)
|
||||
{
|
||||
Profiler.BeginEvent("UpdateRubberBand");
|
||||
|
||||
// Select rubberbanded rect actor nodes
|
||||
var adjustedRect = _rubberBandRect;
|
||||
_lastRubberBandRect = _rubberBandRect;
|
||||
if (adjustedRect.Width < 0 || adjustedRect.Height < 0)
|
||||
{
|
||||
// Make sure we have a well-formed rectangle i.e. size is positive and X/Y is upper left corner
|
||||
var size = adjustedRect.Size;
|
||||
adjustedRect.X = Mathf.Min(adjustedRect.X, adjustedRect.X + adjustedRect.Width);
|
||||
adjustedRect.Y = Mathf.Min(adjustedRect.Y, adjustedRect.Y + adjustedRect.Height);
|
||||
size.X = Mathf.Abs(size.X);
|
||||
size.Y = Mathf.Abs(size.Y);
|
||||
adjustedRect.Size = size;
|
||||
}
|
||||
|
||||
// Get hits from graph nodes
|
||||
if (_nodesCache == null)
|
||||
_nodesCache = new List<ActorNode>();
|
||||
else
|
||||
_nodesCache.Clear();
|
||||
var nodes = _nodesCache;
|
||||
_owner.SceneGraphRoot.GetAllChildActorNodes(nodes);
|
||||
if (_hitsCache == null)
|
||||
_hitsCache = new List<SceneGraphNode>();
|
||||
else
|
||||
_hitsCache.Clear();
|
||||
var hits = _hitsCache;
|
||||
|
||||
// Process all nodes
|
||||
var projection = new ViewportProjection();
|
||||
projection.Init(_owner.Viewport);
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
// Check for custom can select code
|
||||
if (!node.CanSelectActorNodeWithSelector())
|
||||
continue;
|
||||
var a = node.Actor;
|
||||
|
||||
// Skip actor if outside of view frustum
|
||||
var actorBox = a.EditorBox;
|
||||
if (viewFrustum.Contains(actorBox) == ContainmentType.Disjoint)
|
||||
continue;
|
||||
|
||||
// Get valid selection points
|
||||
var points = node.GetActorSelectionPoints();
|
||||
if (LoopOverPoints(points, ref adjustedRect, ref projection))
|
||||
{
|
||||
if (a.HasPrefabLink && _owner is not PrefabWindowViewport)
|
||||
hits.Add(_owner.SceneGraphRoot.Find(a.GetPrefabRoot()));
|
||||
else
|
||||
hits.Add(node);
|
||||
}
|
||||
}
|
||||
|
||||
// Process selection
|
||||
if (_owner.IsControlDown)
|
||||
{
|
||||
var newSelection = new List<SceneGraphNode>();
|
||||
var currentSelection = new List<SceneGraphNode>(_owner.SceneGraphRoot.SceneContext.Selection);
|
||||
newSelection.AddRange(currentSelection);
|
||||
foreach (var hit in hits)
|
||||
{
|
||||
if (currentSelection.Contains(hit))
|
||||
newSelection.Remove(hit);
|
||||
else
|
||||
newSelection.Add(hit);
|
||||
}
|
||||
_owner.Select(newSelection);
|
||||
}
|
||||
else if (Input.GetKey(KeyboardKeys.Shift))
|
||||
{
|
||||
var newSelection = new List<SceneGraphNode>();
|
||||
var currentSelection = new List<SceneGraphNode>(_owner.SceneGraphRoot.SceneContext.Selection);
|
||||
newSelection.AddRange(hits);
|
||||
newSelection.AddRange(currentSelection);
|
||||
_owner.Select(newSelection);
|
||||
}
|
||||
else
|
||||
{
|
||||
_owner.Select(hits);
|
||||
}
|
||||
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
|
||||
private bool LoopOverPoints(Vector3[] points, ref Rectangle adjustedRect, ref ViewportProjection projection)
|
||||
{
|
||||
Profiler.BeginEvent("LoopOverPoints");
|
||||
bool containsAllPoints = points.Length != 0;
|
||||
for (int i = 0; i < points.Length; i++)
|
||||
{
|
||||
projection.ProjectPoint(ref points[i], out var loc);
|
||||
if (!adjustedRect.Contains(loc))
|
||||
{
|
||||
containsAllPoints = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Profiler.EndEvent();
|
||||
return containsAllPoints;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to draw the rubber band. Begins render 2D.
|
||||
/// </summary>
|
||||
/// <param name="context">The GPU Context.</param>
|
||||
/// <param name="target">The GPU texture target.</param>
|
||||
/// <param name="targetDepth">The GPU texture target depth.</param>
|
||||
public void Draw(GPUContext context, GPUTexture target, GPUTexture targetDepth)
|
||||
{
|
||||
// Draw RubberBand for rect selection
|
||||
if (!_isRubberBandSpanning)
|
||||
return;
|
||||
Render2D.Begin(context, target, targetDepth);
|
||||
Draw2D();
|
||||
Render2D.End();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to draw the rubber band. Use if already rendering 2D context.
|
||||
/// </summary>
|
||||
public void Draw2D()
|
||||
{
|
||||
if (!_isRubberBandSpanning)
|
||||
return;
|
||||
Render2D.FillRectangle(_rubberBandRect, Style.Current.Selection);
|
||||
Render2D.DrawRectangle(_rubberBandRect, Style.Current.SelectionBorder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Immediately stops the rubber band.
|
||||
/// </summary>
|
||||
/// <returns>True if rubber band was active before stopping.</returns>
|
||||
public bool StopRubberBand()
|
||||
{
|
||||
var result = _tryStartRubberBand;
|
||||
_isRubberBandSpanning = false;
|
||||
_tryStartRubberBand = false;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,12 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanSelectActorNodeWithSelector()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the scene.
|
||||
/// </summary>
|
||||
|
||||
@@ -24,6 +24,9 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
public sealed class StaticModelNode : ActorNode
|
||||
{
|
||||
private Dictionary<IntPtr, Mesh.Vertex[]> _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)
|
||||
{
|
||||
@@ -88,6 +101,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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,14 @@ using FlaxEditor.Gizmo;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.SceneGraph;
|
||||
using FlaxEditor.Scripting;
|
||||
using FlaxEditor.Tools;
|
||||
using FlaxEditor.Viewport.Modes;
|
||||
using FlaxEditor.Windows;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.Gizmo;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Tools;
|
||||
|
||||
using Object = FlaxEngine.Object;
|
||||
|
||||
namespace FlaxEditor.Viewport
|
||||
@@ -107,6 +111,7 @@ namespace FlaxEditor.Viewport
|
||||
private double _lockedFocusOffset;
|
||||
private readonly ViewportDebugDrawData _debugDrawData = new ViewportDebugDrawData(32);
|
||||
private EditorSpritesRenderer _editorSpritesRenderer;
|
||||
private ViewportRubberBandSelector _rubberBandSelector;
|
||||
|
||||
/// <summary>
|
||||
/// Drag and drop handlers
|
||||
@@ -213,6 +218,9 @@ namespace FlaxEditor.Viewport
|
||||
TransformGizmo.ApplyTransformation += ApplyTransform;
|
||||
TransformGizmo.Duplicate += _editor.SceneEditing.Duplicate;
|
||||
Gizmos.Active = TransformGizmo;
|
||||
|
||||
// Add rubber band selector
|
||||
_rubberBandSelector = new ViewportRubberBandSelector(this);
|
||||
|
||||
// Add grid
|
||||
Grid = new GridGizmo(this);
|
||||
@@ -367,7 +375,10 @@ namespace FlaxEditor.Viewport
|
||||
{
|
||||
Gizmos[i].Draw(ref renderContext);
|
||||
}
|
||||
|
||||
|
||||
// Draw RubberBand for rect selection
|
||||
_rubberBandSelector.Draw(context, target, targetDepth);
|
||||
|
||||
// Draw selected objects debug shapes and visuals
|
||||
if (DrawDebugDraw && (renderContext.View.Flags & ViewFlags.DebugDraw) == ViewFlags.DebugDraw)
|
||||
{
|
||||
@@ -478,6 +489,24 @@ namespace FlaxEditor.Viewport
|
||||
TransformGizmo.EndTransforming();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnLostFocus()
|
||||
{
|
||||
base.OnLostFocus();
|
||||
|
||||
if (_rubberBandSelector.StopRubberBand())
|
||||
EndMouseCapture();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseLeave()
|
||||
{
|
||||
base.OnMouseLeave();
|
||||
|
||||
if (_rubberBandSelector.StopRubberBand())
|
||||
EndMouseCapture();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Focuses the viewport on the current selection of the gizmo.
|
||||
/// </summary>
|
||||
@@ -576,6 +605,27 @@ namespace FlaxEditor.Viewport
|
||||
base.OrientViewport(ref orientation);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseMove(Float2 location)
|
||||
{
|
||||
base.OnMouseMove(location);
|
||||
|
||||
// Don't allow rubber band selection when gizmo is controlling mouse, vertex painting mode, or cloth painting is enabled
|
||||
bool canStart = !((Gizmos.Active.IsControllingMouse || Gizmos.Active is VertexPaintingGizmo || Gizmos.Active is ClothPaintingGizmo) || IsControllingMouse || IsRightMouseButtonDown);
|
||||
_rubberBandSelector.TryCreateRubberBand(canStart, _viewMousePos, ViewFrustum);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnLeftMouseButtonDown()
|
||||
{
|
||||
base.OnLeftMouseButtonDown();
|
||||
|
||||
if (_rubberBandSelector.TryStartingRubberBandSelection())
|
||||
{
|
||||
StartMouseCapture();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnLeftMouseButtonUp()
|
||||
{
|
||||
@@ -583,8 +633,14 @@ namespace FlaxEditor.Viewport
|
||||
if (_prevInput.IsControllingMouse || !Bounds.Contains(ref _viewMousePos))
|
||||
return;
|
||||
|
||||
// Try to pick something with the current gizmo
|
||||
Gizmos.Active?.Pick();
|
||||
// Select rubberbanded rect actor nodes or pick with gizmo
|
||||
if (!_rubberBandSelector.ReleaseRubberBandSelection())
|
||||
{
|
||||
EndMouseCapture();
|
||||
|
||||
// Try to pick something with the current gizmo
|
||||
Gizmos.Active?.Pick();
|
||||
}
|
||||
|
||||
// Keep focus
|
||||
Focus();
|
||||
|
||||
@@ -633,5 +633,16 @@ namespace FlaxEngine
|
||||
throw new Exception("Failed to download mesh data.");
|
||||
return result;
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
/// <summary>
|
||||
/// Gets the collision proxy points for the mesh.
|
||||
/// </summary>
|
||||
/// <returns>The triangle points in the collision proxy.</returns>
|
||||
internal Vector3[] GetCollisionProxyPoints()
|
||||
{
|
||||
return Internal_GetCollisionProxyPoints(__unmanagedPtr, out _);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -847,4 +847,24 @@ MArray* Mesh::DownloadBuffer(bool forceGpu, MTypeObject* resultType, int32 typeI
|
||||
return result;
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
Array<Vector3> Mesh::GetCollisionProxyPoints() const
|
||||
{
|
||||
PROFILE_CPU();
|
||||
Array<Vector3> result;
|
||||
#if USE_PRECISE_MESH_INTERSECTS
|
||||
for (int32 i = 0; i < _collisionProxy.Triangles.Count(); i++)
|
||||
{
|
||||
auto triangle = _collisionProxy.Triangles.Get()[i];
|
||||
result.Add(triangle.V0);
|
||||
result.Add(triangle.V1);
|
||||
result.Add(triangle.V2);
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -320,5 +320,8 @@ private:
|
||||
API_FUNCTION(NoProxy) bool UpdateTrianglesUInt(int32 triangleCount, const MArray* trianglesObj);
|
||||
API_FUNCTION(NoProxy) bool UpdateTrianglesUShort(int32 triangleCount, const MArray* trianglesObj);
|
||||
API_FUNCTION(NoProxy) MArray* DownloadBuffer(bool forceGpu, MTypeObject* resultType, int32 typeI);
|
||||
#if USE_EDITOR
|
||||
API_FUNCTION(NoProxy) Array<Vector3> GetCollisionProxyPoints() const;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user