Basic reroute nodes

This commit is contained in:
stefnotch
2021-02-25 20:22:54 +01:00
parent bcc036f808
commit 9265f23681
4 changed files with 195 additions and 18 deletions

View File

@@ -983,6 +983,115 @@ namespace FlaxEditor.Surface.Archetypes
}
}
private class RerouteNode : SurfaceNode
{
public static readonly Vector2 DefaultSize = new Vector2(16);
private bool _deleteNode;
/// <inheritdoc />
protected override bool ShowTooltip => false;
/// <inheritdoc />
public RerouteNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
: base(id, context, nodeArch, groupArch)
{
Size = DefaultSize;
Title = string.Empty;
BackgroundColor = Color.Transparent;
}
/// <inheritdoc />
public override void OnSurfaceLoaded()
{
base.OnSurfaceLoaded();
var inputBox = GetBox(0);
var outputBox = GetBox(1);
inputBox.Location = Vector2.Zero;
outputBox.Location = Vector2.Zero;
inputBox.Visible = false;
outputBox.Visible = false;
}
/// <inheritdoc />
public override void ConnectionTick(Box box)
{
base.ConnectionTick(box);
var inputBox = GetBox(0);
var outputBox = GetBox(1);
_deleteNode = !inputBox.HasAnyConnection;
outputBox.Visible = !outputBox.HasAnyConnection;
}
/*public override void OnDeleted()
{
var inputBox = GetBox(0);
var outputBox = GetBox(1);
var connectionA = inputBox.HasAnyConnection ? inputBox.Connections[0] : null; // This doesn't work
var connectionB = outputBox.HasAnyConnection ? outputBox.Connections[0] : null;
base.OnDeleted();
if (connectionA != null && connectionB != null)
{
connectionA.CreateConnection(connectionB); // TODO: handle undo
}
}*/
public override void Update(float deltaTime)
{
base.Update(deltaTime);
if (_deleteNode)
{
_deleteNode = false;
Surface.Delete(this); // TODO: handle undo
}
}
/// <inheritdoc />
public override bool CanSelect(ref Vector2 location)
{
return new Rectangle(Location, DefaultSize).Contains(ref location);
}
/// <inheritdoc />
protected override void UpdateRectangles()
{
_headerRect = Rectangle.Empty;
_closeButtonRect = Rectangle.Empty;
_footerRect = Rectangle.Empty;
}
public override void Draw()
{
var style = Surface.Style;
var inputBox = GetBox(0);
var connectionColor = style.Colors.Default;
if (inputBox.HasAnyConnection)
{
var hints = inputBox.Connections[0].ParentNode.Archetype.ConnectionsHints;
Surface.Style.GetConnectionColor(inputBox.Connections[0].CurrentType, hints, out connectionColor);
}
//float barHeight = 4;
//Render2D.FillRectangle(new Rectangle(DefaultSize.X / 2, (DefaultSize.Y - barHeight) / 2, barHeight * 4, barHeight), connectionColor);
SpriteHandle icon = style.Icons.BoxClose;
Render2D.DrawSprite(icon, new Rectangle(Vector2.Zero, DefaultSize), connectionColor);
base.Draw();
}
}
/// <summary>
/// The nodes for that group.
/// </summary>
@@ -1438,6 +1547,23 @@ namespace FlaxEditor.Surface.Archetypes
NodeElementArchetype.Factory.Input(0, string.Empty, true, typeof(object), 1),
}
},
new NodeArchetype
{
TypeID = 29,
Title = "Reroute",
Create = (id, context, arch, groupArch) => new RerouteNode(id, context, arch, groupArch),
Description = "Reroute a connection.",
Flags = NodeFlags.NoCloseButton | NodeFlags.NoSpawnViaGUI | NodeFlags.AllGraphs,
Size = RerouteNode.DefaultSize,
ConnectionsHints = ConnectionsHint.All,
IndependentBoxes = new int[] { 0 },
DependentBoxes = new int[] { 1 },
Elements = new[]
{
NodeElementArchetype.Factory.Input(0, string.Empty, true, null, 0),
NodeElementArchetype.Factory.Output(0, string.Empty, null, 1),
}
},
};
}
}

View File

@@ -13,6 +13,11 @@ namespace FlaxEditor.Surface.Elements
[HideInEditor]
public class OutputBox : Box
{
/// <summary>
/// Distance for the mouse to be considered above the connection
/// </summary>
public float MouseOverConnectionDistance => 100f / Surface.ViewScale;
/// <inheritdoc />
public OutputBox(SurfaceNode parentNode, NodeElementArchetype archetype)
: base(parentNode, archetype, archetype.Position + new Vector2(parentNode.Archetype.Size.X, 0))
@@ -44,6 +49,18 @@ namespace FlaxEditor.Surface.Elements
*/
}
/// <summary>
/// Checks if a point intersects a connection
/// </summary>
/// <param name="targetBox">The other box.</param>
/// <param name="mousePosition">The mouse position</param>
public bool IntersectsConnection(Box targetBox, ref Vector2 mousePosition)
{
var startPos = Parent.PointToParent(Center);
Vector2 endPos = targetBox.Parent.PointToParent(targetBox.Center);
return IntersectsConnection(ref startPos, ref endPos, ref mousePosition, MouseOverConnectionDistance);
}
/// <summary>
/// Checks if a point intersects a bezier curve
/// </summary>
@@ -53,8 +70,6 @@ namespace FlaxEditor.Surface.Elements
/// <param name="distance">Distance at which its an intersection</param>
public static bool IntersectsConnection(ref Vector2 start, ref Vector2 end, ref Vector2 point, float distance)
{
// Maybe I should make this a non-static method and automatically read the Surface.ViewScale?
// Pretty much a point in rectangle check
if ((point.X - start.X) * (end.X - point.X) < 0) return false;
@@ -82,6 +97,7 @@ namespace FlaxEditor.Surface.Elements
float t = i * segmentCountInv;
Bezier(ref start, ref control1, ref control2, ref end, t, out p);
// Maybe it would be reasonable to return the point?
CollisionsHelper.ClosestPointPointLine(ref point, ref oldp, ref p, out Vector2 result);
if (Vector2.DistanceSquared(point, result) <= squaredDistance)
{
@@ -106,22 +122,21 @@ namespace FlaxEditor.Surface.Elements
/// </summary>
public void DrawConnections(ref Vector2 mousePosition)
{
float mouseOverDistance = MouseOverConnectionDistance;
// Draw all the connections
var center = Size * 0.5f;
var tmp = PointToParent(ref center);
var startPos = Parent.PointToParent(ref tmp);
var startPos = Parent.PointToParent(Center);
var startHighlight = ConnectionsHighlightIntensity;
for (int i = 0; i < Connections.Count; i++)
{
Box targetBox = Connections[i];
tmp = targetBox.PointToParent(ref center);
Vector2 endPos = targetBox.Parent.PointToParent(ref tmp);
Vector2 endPos = targetBox.Parent.PointToParent(targetBox.Center);
var highlight = 1 + Mathf.Max(startHighlight, targetBox.ConnectionsHighlightIntensity);
var color = _currentTypeColor * highlight;
if (IntersectsConnection(ref startPos, ref endPos, ref mousePosition, 100f / Surface.ViewScale))
// TODO: Figure out how to only draw the topmost connection
if (IntersectsConnection(ref startPos, ref endPos, ref mousePosition, mouseOverDistance))
{
highlight += 2;
highlight += 1;
}
DrawConnection(ref startPos, ref endPos, ref color, highlight);
@@ -134,11 +149,8 @@ namespace FlaxEditor.Surface.Elements
public void DrawSelectedConnection(Box targetBox)
{
// Draw all the connections
var center = Size * 0.5f;
var tmp = PointToParent(ref center);
var startPos = Parent.PointToParent(ref tmp);
tmp = targetBox.PointToParent(ref center);
Vector2 endPos = targetBox.Parent.PointToParent(ref tmp);
var startPos = Parent.PointToParent(Center);
Vector2 endPos = targetBox.Parent.PointToParent(targetBox.Center);
DrawConnection(ref startPos, ref endPos, ref _currentTypeColor, 2);
}

View File

@@ -125,6 +125,7 @@ namespace FlaxEditor.Surface
AutoFocus = false;
TooltipText = nodeArch.Description;
CullChildren = false;
BackgroundColor = Style.Current.BackgroundNormal;
if (Archetype.DefaultValues != null)
{
@@ -947,7 +948,7 @@ namespace FlaxEditor.Surface
// Background
var backgroundRect = new Rectangle(Vector2.Zero, Size);
Render2D.FillRectangle(backgroundRect, style.BackgroundNormal);
Render2D.FillRectangle(backgroundRect, BackgroundColor);
// Breakpoint hit
if (Breakpoint.Hit)

View File

@@ -274,12 +274,24 @@ namespace FlaxEditor.Surface
bool handled = base.OnMouseDoubleClick(location, button);
if (!handled)
CustomMouseDoubleClick?.Invoke(ref location, button, ref handled);
if (handled)
if (!handled)
{
return true;
var mousePos = _rootControl.PointFromParent(ref _mousePos);
if (IntersectsConnection(mousePos, out OutputBox outputBox, out Box connectedBox))
{
var rerouteNode = Context.SpawnNode(7, 29, mousePos);
// TODO: Undo action
outputBox.BreakConnection(connectedBox);
outputBox.CreateConnection(rerouteNode.GetBoxes().First(b => !b.IsOutput));
rerouteNode.GetBoxes().First(b => b.IsOutput).CreateConnection(connectedBox);
handled = true;
}
}
return false;
return handled;
}
/// <inheritdoc />
@@ -815,5 +827,31 @@ namespace FlaxEditor.Surface
yLocation
);
}
private bool IntersectsConnection(Vector2 mousePosition, out OutputBox outputBox, out Box connectedBox)
{
for (int i = 0; i < Nodes.Count; i++)
{
for (int j = 0; j < Nodes[i].Elements.Count; j++)
{
if (Nodes[i].Elements[j] is OutputBox ob)
{
for (int k = 0; k < ob.Connections.Count; k++)
{
if (ob.IntersectsConnection(ob.Connections[k], ref mousePosition))
{
outputBox = ob;
connectedBox = ob.Connections[k];
return true;
}
}
}
}
}
outputBox = null;
connectedBox = null;
return false;
}
}
}