From dcec847d50d21b04344cd1caecf3096041a49250 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Wed, 11 Oct 2023 20:01:56 +0200 Subject: [PATCH 01/12] - Basic constants can now be converted to parameters --- Source/Editor/Surface/Archetypes/Constants.cs | 82 +++++++++++++++++++ Source/Editor/Surface/SurfaceParameter.cs | 4 +- Source/Editor/Surface/VisjectSurfaceWindow.cs | 7 +- 3 files changed, 90 insertions(+), 3 deletions(-) diff --git a/Source/Editor/Surface/Archetypes/Constants.cs b/Source/Editor/Surface/Archetypes/Constants.cs index cbe7822e3..e3cbd1b86 100644 --- a/Source/Editor/Surface/Archetypes/Constants.cs +++ b/Source/Editor/Surface/Archetypes/Constants.cs @@ -7,11 +7,13 @@ using Real = System.Single; #endif using System; +using System.Linq; using System.Reflection; using FlaxEditor.CustomEditors.Editors; using FlaxEditor.GUI; using FlaxEditor.Scripting; using FlaxEditor.Surface.Elements; +using FlaxEditor.Surface.Undo; using FlaxEngine; using FlaxEngine.GUI; using FlaxEngine.Utilities; @@ -347,6 +349,75 @@ namespace FlaxEditor.Surface.Archetypes } } + private class ConstantNode : SurfaceNode + { + private ScriptType _type; + + /// + public ConstantNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch, ScriptType type) + : base(id, context, nodeArch, groupArch) + { + _type = type; + } + + /// + public override void OnShowSecondaryContextMenu(FlaxEditor.GUI.ContextMenu.ContextMenu menu, Float2 location) + { + base.OnShowSecondaryContextMenu(menu, location); + + menu.AddSeparator(); + menu.AddButton("Convert to Parameter", OnConvertToParameter); + } + + private void OnConvertToParameter() + { + if(Surface.Owner is not IVisjectSurfaceWindow window) + throw new Exception("Surface owner is not a Visject Surface Window"); + + Asset asset = Surface.Owner.SurfaceAsset; + if (asset == null || !asset.IsLoaded) + { + Editor.LogError("Asset is null or not loaded"); + return; + } + + var paramIndex = Surface.Parameters.Count; + var paramAction = new AddRemoveParamAction + { + Window = window, + IsAdd = true, + Name = Utilities.Utils.IncrementNameNumber("New parameter", x => OnParameterRenameValidate(null, x)), + Type = _type, + Index = paramIndex, + InitValue = Values[0], + }; + paramAction.Do(); + + var parameterGuid = Surface.Parameters[paramIndex].ID; + + bool undoEnabled = Surface.Undo.Enabled; + Surface.Undo.Enabled = false; + SurfaceNode node = Surface.Context.SpawnNode(6, 1, this.Location, new object[] {parameterGuid}); + Surface.Undo.Enabled = undoEnabled; + + if (node is not Parameters.SurfaceNodeParamsGet getNode) + throw new Exception("Node is not a ParamsGet node!"); + + var spawnNodeAction = new AddRemoveNodeAction(getNode, true); + var removeConstantAction = new AddRemoveNodeAction(this, false); + + Surface.AddBatchedUndoAction(new MultiUndoAction(paramAction, spawnNodeAction, removeConstantAction)); + removeConstantAction.Do(); + } + + private bool OnParameterRenameValidate(RenamePopup popup, string value) + { + if(Surface.Owner is not IVisjectSurfaceWindow window) + throw new Exception("Surface owner is not a Visject Surface Window"); + return !string.IsNullOrWhiteSpace(value) && window.VisjectSurface.Parameters.All(x => x.Name != value); + } + } + /// /// The nodes for that group. /// @@ -356,6 +427,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 1, Title = "Bool", + Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(bool))), Description = "Constant boolean value", Flags = NodeFlags.AllGraphs, Size = new Float2(110, 20), @@ -388,6 +460,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 2, Title = "Integer", + Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(int))), Description = "Constant integer value", Flags = NodeFlags.AllGraphs, Size = new Float2(110, 20), @@ -415,6 +488,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 3, Title = "Float", + Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(float))), Description = "Constant floating point", Flags = NodeFlags.AllGraphs, Size = new Float2(110, 20), @@ -442,6 +516,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 4, Title = "Float2", + Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(Float2))), Description = "Constant Float2", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 60), @@ -472,6 +547,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 5, Title = "Float3", + Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(Float3))), Description = "Constant Float3", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 80), @@ -504,6 +580,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 6, Title = "Float4", + Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(Float4))), Description = "Constant Float4", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 100), @@ -538,6 +615,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 7, Title = "Color", + Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(Color))), Description = "RGBA color", Flags = NodeFlags.AllGraphs, Size = new Float2(70, 100), @@ -644,6 +722,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 12, Title = "Unsigned Integer", + Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(Float3))), Description = "Constant unsigned integer value", Flags = NodeFlags.AllGraphs, Size = new Float2(170, 20), @@ -700,6 +779,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 16, Title = "Vector2", + Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(Vector2))), Description = "Constant Vector2", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 60), @@ -720,6 +800,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 17, Title = "Vector3", + Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(Vector3))), Description = "Constant Vector3", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 80), @@ -742,6 +823,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 18, Title = "Vector4", + Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(Vector4))), Description = "Constant Vector4", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 100), diff --git a/Source/Editor/Surface/SurfaceParameter.cs b/Source/Editor/Surface/SurfaceParameter.cs index 6eafdc2aa..e74b44eb9 100644 --- a/Source/Editor/Surface/SurfaceParameter.cs +++ b/Source/Editor/Surface/SurfaceParameter.cs @@ -56,7 +56,7 @@ namespace FlaxEditor.Surface /// The type. /// The name. /// The created parameter. - public static SurfaceParameter Create(ScriptType type, string name) + public static SurfaceParameter Create(ScriptType type, string name, object initValue = null) { return new SurfaceParameter { @@ -64,7 +64,7 @@ namespace FlaxEditor.Surface IsPublic = true, Name = name, Type = type, - Value = TypeUtils.GetDefaultValue(type), + Value = initValue ?? TypeUtils.GetDefaultValue(type), }; } } diff --git a/Source/Editor/Surface/VisjectSurfaceWindow.cs b/Source/Editor/Surface/VisjectSurfaceWindow.cs index 305121e11..e1d39083c 100644 --- a/Source/Editor/Surface/VisjectSurfaceWindow.cs +++ b/Source/Editor/Surface/VisjectSurfaceWindow.cs @@ -278,6 +278,11 @@ namespace FlaxEditor.Surface /// public ScriptType Type; + /// + /// The value to initialize the parameter with. (Can be null) + /// + public object InitValue; + /// public string ActionString => IsAdd ? "Add parameter" : "Remove parameter"; @@ -304,7 +309,7 @@ namespace FlaxEditor.Surface var type = Type; if (IsAdd && type.Type == typeof(NormalMap)) type = new ScriptType(typeof(Texture)); - var param = SurfaceParameter.Create(type, Name); + var param = SurfaceParameter.Create(type, Name, InitValue); if (IsAdd && Type.Type == typeof(NormalMap)) param.Value = FlaxEngine.Content.LoadAsyncInternal("Engine/Textures/NormalTexture"); Window.VisjectSurface.Parameters.Insert(Index, param); From 447030f53ad3e9940fb6062524d6e51ad4009371 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Mon, 16 Oct 2023 20:19:18 +0200 Subject: [PATCH 02/12] - Spawned get parameter node now reconnects to all boxes from the converted node --- Source/Editor/Surface/Archetypes/Constants.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Source/Editor/Surface/Archetypes/Constants.cs b/Source/Editor/Surface/Archetypes/Constants.cs index e3cbd1b86..0e9049a42 100644 --- a/Source/Editor/Surface/Archetypes/Constants.cs +++ b/Source/Editor/Surface/Archetypes/Constants.cs @@ -381,6 +381,7 @@ namespace FlaxEditor.Surface.Archetypes return; } + // Add parameter to editor var paramIndex = Surface.Parameters.Count; var paramAction = new AddRemoveParamAction { @@ -403,6 +404,26 @@ namespace FlaxEditor.Surface.Archetypes if (node is not Parameters.SurfaceNodeParamsGet getNode) throw new Exception("Node is not a ParamsGet node!"); + // Recreate connections of constant node + // Constant nodes and parameter nodes should have the same ports, so we can just iterate through the connections + var boxes = GetBoxes(); + for (int i = 0;i < boxes.Count; i++) + { + Box box = boxes[i]; + if (!box.HasAnyConnection) + continue; + + if (!getNode.TryGetBox(i, out Box paramBox)) + continue; + + // Iterating backwards, because the CreateConnection method deletes entries from the box connections when target box IsSingle is set to true + for (int k = box.Connections.Count-1; k >= 0; k--) + { + Box connectedBox = box.Connections[k]; + paramBox.CreateConnection(connectedBox); + } + } + var spawnNodeAction = new AddRemoveNodeAction(getNode, true); var removeConstantAction = new AddRemoveNodeAction(this, false); From 3afb6cc88e1fb7a42a226b8156b399e9b54283f8 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Thu, 19 Oct 2023 14:02:46 +0200 Subject: [PATCH 03/12] - Renamed ConstantNode to ConvertableNode - Moved ConvertableNode into it's own class - Added support for custom conversion code (currently only used by rotation) - Added support for Texture, Normal Map, Cube Texture, Uint, Double, String, Quaternion/Rotation --- Source/Editor/Surface/Archetypes/Constants.cs | 118 +++--------------- .../Surface/Archetypes/ConvertableNode.cs | 105 ++++++++++++++++ Source/Editor/Surface/Archetypes/Textures.cs | 4 + 3 files changed, 126 insertions(+), 101 deletions(-) create mode 100644 Source/Editor/Surface/Archetypes/ConvertableNode.cs diff --git a/Source/Editor/Surface/Archetypes/Constants.cs b/Source/Editor/Surface/Archetypes/Constants.cs index 0e9049a42..581b87e0e 100644 --- a/Source/Editor/Surface/Archetypes/Constants.cs +++ b/Source/Editor/Surface/Archetypes/Constants.cs @@ -348,96 +348,6 @@ namespace FlaxEditor.Surface.Archetypes SetValue(0, array); } } - - private class ConstantNode : SurfaceNode - { - private ScriptType _type; - - /// - public ConstantNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch, ScriptType type) - : base(id, context, nodeArch, groupArch) - { - _type = type; - } - - /// - public override void OnShowSecondaryContextMenu(FlaxEditor.GUI.ContextMenu.ContextMenu menu, Float2 location) - { - base.OnShowSecondaryContextMenu(menu, location); - - menu.AddSeparator(); - menu.AddButton("Convert to Parameter", OnConvertToParameter); - } - - private void OnConvertToParameter() - { - if(Surface.Owner is not IVisjectSurfaceWindow window) - throw new Exception("Surface owner is not a Visject Surface Window"); - - Asset asset = Surface.Owner.SurfaceAsset; - if (asset == null || !asset.IsLoaded) - { - Editor.LogError("Asset is null or not loaded"); - return; - } - - // Add parameter to editor - var paramIndex = Surface.Parameters.Count; - var paramAction = new AddRemoveParamAction - { - Window = window, - IsAdd = true, - Name = Utilities.Utils.IncrementNameNumber("New parameter", x => OnParameterRenameValidate(null, x)), - Type = _type, - Index = paramIndex, - InitValue = Values[0], - }; - paramAction.Do(); - - var parameterGuid = Surface.Parameters[paramIndex].ID; - - bool undoEnabled = Surface.Undo.Enabled; - Surface.Undo.Enabled = false; - SurfaceNode node = Surface.Context.SpawnNode(6, 1, this.Location, new object[] {parameterGuid}); - Surface.Undo.Enabled = undoEnabled; - - if (node is not Parameters.SurfaceNodeParamsGet getNode) - throw new Exception("Node is not a ParamsGet node!"); - - // Recreate connections of constant node - // Constant nodes and parameter nodes should have the same ports, so we can just iterate through the connections - var boxes = GetBoxes(); - for (int i = 0;i < boxes.Count; i++) - { - Box box = boxes[i]; - if (!box.HasAnyConnection) - continue; - - if (!getNode.TryGetBox(i, out Box paramBox)) - continue; - - // Iterating backwards, because the CreateConnection method deletes entries from the box connections when target box IsSingle is set to true - for (int k = box.Connections.Count-1; k >= 0; k--) - { - Box connectedBox = box.Connections[k]; - paramBox.CreateConnection(connectedBox); - } - } - - var spawnNodeAction = new AddRemoveNodeAction(getNode, true); - var removeConstantAction = new AddRemoveNodeAction(this, false); - - Surface.AddBatchedUndoAction(new MultiUndoAction(paramAction, spawnNodeAction, removeConstantAction)); - removeConstantAction.Do(); - } - - private bool OnParameterRenameValidate(RenamePopup popup, string value) - { - if(Surface.Owner is not IVisjectSurfaceWindow window) - throw new Exception("Surface owner is not a Visject Surface Window"); - return !string.IsNullOrWhiteSpace(value) && window.VisjectSurface.Parameters.All(x => x.Name != value); - } - } /// /// The nodes for that group. @@ -448,7 +358,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 1, Title = "Bool", - Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(bool))), + Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(bool))), Description = "Constant boolean value", Flags = NodeFlags.AllGraphs, Size = new Float2(110, 20), @@ -481,7 +391,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 2, Title = "Integer", - Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(int))), + Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(int))), Description = "Constant integer value", Flags = NodeFlags.AllGraphs, Size = new Float2(110, 20), @@ -509,7 +419,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 3, Title = "Float", - Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(float))), + Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(float))), Description = "Constant floating point", Flags = NodeFlags.AllGraphs, Size = new Float2(110, 20), @@ -537,7 +447,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 4, Title = "Float2", - Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(Float2))), + Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Float2))), Description = "Constant Float2", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 60), @@ -568,7 +478,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 5, Title = "Float3", - Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(Float3))), + Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Float3))), Description = "Constant Float3", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 80), @@ -601,7 +511,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 6, Title = "Float4", - Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(Float4))), + Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Float4))), Description = "Constant Float4", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 100), @@ -636,7 +546,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 7, Title = "Color", - Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(Color))), + Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Color))), Description = "RGBA color", Flags = NodeFlags.AllGraphs, Size = new Float2(70, 100), @@ -669,6 +579,10 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 8, Title = "Rotation", + // TODO: Way too long and ugly - find a better way to add conversion + Create = (id, context, arch, groupArch) => + new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Quaternion)), + values => Quaternion.Euler((float)values[0], (float)values[1], (float)values[2])), Description = "Euler angle rotation", Flags = NodeFlags.AnimGraph | NodeFlags.VisualScriptGraph | NodeFlags.ParticleEmitterGraph, Size = new Float2(110, 60), @@ -693,6 +607,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 9, Title = "String", + Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(string))), Description = "Text", Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph, Size = new Float2(200, 20), @@ -743,7 +658,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 12, Title = "Unsigned Integer", - Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(Float3))), + Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(uint))), Description = "Constant unsigned integer value", Flags = NodeFlags.AllGraphs, Size = new Float2(170, 20), @@ -783,6 +698,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 15, Title = "Double", + Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(double))), Description = "Constant floating point", Flags = NodeFlags.AllGraphs, Size = new Float2(110, 20), @@ -800,7 +716,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 16, Title = "Vector2", - Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(Vector2))), + Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Vector2))), Description = "Constant Vector2", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 60), @@ -821,7 +737,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 17, Title = "Vector3", - Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(Vector3))), + Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Vector3))), Description = "Constant Vector3", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 80), @@ -844,7 +760,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 18, Title = "Vector4", - Create = (id, context, arch, groupArch) => new ConstantNode(id, context, arch, groupArch, new ScriptType(typeof(Vector4))), + Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Vector4))), Description = "Constant Vector4", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 100), diff --git a/Source/Editor/Surface/Archetypes/ConvertableNode.cs b/Source/Editor/Surface/Archetypes/ConvertableNode.cs new file mode 100644 index 000000000..4e798009a --- /dev/null +++ b/Source/Editor/Surface/Archetypes/ConvertableNode.cs @@ -0,0 +1,105 @@ +using System; +using System.Linq; +using FlaxEditor.GUI; +using FlaxEditor.Scripting; +using FlaxEditor.Surface.Elements; +using FlaxEditor.Surface.Undo; +using FlaxEngine; + +namespace FlaxEditor.Surface.Archetypes; + +/// +/// +/// +internal class ConvertableNode : SurfaceNode +{ + private ScriptType _type; + private Func _convertFunction; + + /// + public ConvertableNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch, ScriptType type, Func convertFunction = null) + : base(id, context, nodeArch, groupArch) + { + _type = type; + _convertFunction = convertFunction; + } + + /// + public override void OnShowSecondaryContextMenu(FlaxEditor.GUI.ContextMenu.ContextMenu menu, Float2 location) + { + base.OnShowSecondaryContextMenu(menu, location); + + menu.AddSeparator(); + menu.AddButton("Convert to Parameter", OnConvertToParameter); + } + + private void OnConvertToParameter() + { + if(Surface.Owner is not IVisjectSurfaceWindow window) + throw new Exception("Surface owner is not a Visject Surface Window"); + + Asset asset = Surface.Owner.SurfaceAsset; + if (asset == null || !asset.IsLoaded) + { + Editor.LogError("Asset is null or not loaded"); + return; + } + + // Add parameter to editor + var paramIndex = Surface.Parameters.Count; + object initValue = _convertFunction == null ? Values[0] : _convertFunction.Invoke(Values); + var paramAction = new AddRemoveParamAction + { + Window = window, + IsAdd = true, + Name = Utilities.Utils.IncrementNameNumber("New parameter", x => OnParameterRenameValidate(null, x)), + Type = _type, + Index = paramIndex, + InitValue = initValue, + }; + paramAction.Do(); + + var parameterGuid = Surface.Parameters[paramIndex].ID; + + bool undoEnabled = Surface.Undo.Enabled; + Surface.Undo.Enabled = false; + SurfaceNode node = Surface.Context.SpawnNode(6, 1, this.Location, new object[] {parameterGuid}); + Surface.Undo.Enabled = undoEnabled; + + if (node is not Parameters.SurfaceNodeParamsGet getNode) + throw new Exception("Node is not a ParamsGet node!"); + + // Recreate connections of constant node + // Constant nodes and parameter nodes should have the same ports, so we can just iterate through the connections + var boxes = GetBoxes(); + for (int i = 0;i < boxes.Count; i++) + { + Box box = boxes[i]; + if (!box.HasAnyConnection) + continue; + + if (!getNode.TryGetBox(i, out Box paramBox)) + continue; + + // Iterating backwards, because the CreateConnection method deletes entries from the box connections when target box IsSingle is set to true + for (int k = box.Connections.Count-1; k >= 0; k--) + { + Box connectedBox = box.Connections[k]; + paramBox.CreateConnection(connectedBox); + } + } + + var spawnNodeAction = new AddRemoveNodeAction(getNode, true); + var removeConstantAction = new AddRemoveNodeAction(this, false); + + Surface.AddBatchedUndoAction(new MultiUndoAction(paramAction, spawnNodeAction, removeConstantAction)); + removeConstantAction.Do(); + } + + private bool OnParameterRenameValidate(RenamePopup popup, string value) + { + if(Surface.Owner is not IVisjectSurfaceWindow window) + throw new Exception("Surface owner is not a Visject Surface Window"); + return !string.IsNullOrWhiteSpace(value) && window.VisjectSurface.Parameters.All(x => x.Name != value); + } +} diff --git a/Source/Editor/Surface/Archetypes/Textures.cs b/Source/Editor/Surface/Archetypes/Textures.cs index 18c21ecea..10d7eb18b 100644 --- a/Source/Editor/Surface/Archetypes/Textures.cs +++ b/Source/Editor/Surface/Archetypes/Textures.cs @@ -3,6 +3,7 @@ using System; using FlaxEditor.Content.Settings; using FlaxEditor.GUI; +using FlaxEditor.Scripting; using FlaxEngine; namespace FlaxEditor.Surface.Archetypes @@ -95,6 +96,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 1, Title = "Texture", + Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Texture))), Description = "Two dimensional texture object", Flags = NodeFlags.MaterialGraph, Size = new Float2(140, 120), @@ -131,6 +133,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 3, Title = "Cube Texture", + Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(CubeTexture))), Description = "Set of 6 textures arranged in a cube", Flags = NodeFlags.MaterialGraph, Size = new Float2(140, 120), @@ -154,6 +157,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 4, Title = "Normal Map", + Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(NormalMap))), Description = "Two dimensional texture object sampled as a normal map", Flags = NodeFlags.MaterialGraph, Size = new Float2(140, 120), From 41a7aff6d75f914fb806bb4b937dfdfaf86f44e5 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Thu, 19 Oct 2023 14:10:10 +0200 Subject: [PATCH 04/12] - Converting to parameter now also works in Particle and Visual Scripting editor --- Source/Editor/Surface/Archetypes/ConvertableNode.cs | 5 +++-- Source/Editor/Surface/ParticleEmitterSurface.cs | 2 +- Source/Editor/Surface/VisjectSurface.DragDrop.cs | 2 +- Source/Editor/Surface/VisualScriptSurface.cs | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Source/Editor/Surface/Archetypes/ConvertableNode.cs b/Source/Editor/Surface/Archetypes/ConvertableNode.cs index 4e798009a..e7c3c5517 100644 --- a/Source/Editor/Surface/Archetypes/ConvertableNode.cs +++ b/Source/Editor/Surface/Archetypes/ConvertableNode.cs @@ -59,11 +59,12 @@ internal class ConvertableNode : SurfaceNode }; paramAction.Do(); - var parameterGuid = Surface.Parameters[paramIndex].ID; + Guid parameterGuid = Surface.Parameters[paramIndex].ID; bool undoEnabled = Surface.Undo.Enabled; Surface.Undo.Enabled = false; - SurfaceNode node = Surface.Context.SpawnNode(6, 1, this.Location, new object[] {parameterGuid}); + NodeArchetype arch = Surface.GetParameterGetterNodeArchetype(out var groupId); + SurfaceNode node = Surface.Context.SpawnNode(groupId, arch.TypeID, this.Location, new object[] {parameterGuid}); // 1 Visject, 2 particle, 3 VS Surface.Undo.Enabled = undoEnabled; if (node is not Parameters.SurfaceNodeParamsGet getNode) diff --git a/Source/Editor/Surface/ParticleEmitterSurface.cs b/Source/Editor/Surface/ParticleEmitterSurface.cs index 76f96f06c..b7cf83c62 100644 --- a/Source/Editor/Surface/ParticleEmitterSurface.cs +++ b/Source/Editor/Surface/ParticleEmitterSurface.cs @@ -93,7 +93,7 @@ namespace FlaxEditor.Surface } /// - protected override NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId) + protected internal override NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId) { groupId = 6; return Archetypes.Parameters.Nodes[1]; diff --git a/Source/Editor/Surface/VisjectSurface.DragDrop.cs b/Source/Editor/Surface/VisjectSurface.DragDrop.cs index 1728c282f..2ff82c269 100644 --- a/Source/Editor/Surface/VisjectSurface.DragDrop.cs +++ b/Source/Editor/Surface/VisjectSurface.DragDrop.cs @@ -151,7 +151,7 @@ namespace FlaxEditor.Surface /// /// The group ID. /// The node archetype. - protected virtual NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId) + protected internal virtual NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId) { groupId = 6; return Archetypes.Parameters.Nodes[0]; diff --git a/Source/Editor/Surface/VisualScriptSurface.cs b/Source/Editor/Surface/VisualScriptSurface.cs index 902582311..2f8d4cda8 100644 --- a/Source/Editor/Surface/VisualScriptSurface.cs +++ b/Source/Editor/Surface/VisualScriptSurface.cs @@ -144,7 +144,7 @@ namespace FlaxEditor.Surface } /// - protected override NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId) + protected internal override NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId) { groupId = 6; return Archetypes.Parameters.Nodes[2]; From aafdc64b680130d97724a2ef2ceee7a291626a9c Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Thu, 19 Oct 2023 14:14:51 +0200 Subject: [PATCH 05/12] - Cleanup - Typo --- Source/Editor/Surface/Archetypes/Constants.cs | 32 +++++++++---------- ...{ConvertableNode.cs => ConvertibleNode.cs} | 24 +++++++------- Source/Editor/Surface/Archetypes/Textures.cs | 6 ++-- 3 files changed, 30 insertions(+), 32 deletions(-) rename Source/Editor/Surface/Archetypes/{ConvertableNode.cs => ConvertibleNode.cs} (92%) diff --git a/Source/Editor/Surface/Archetypes/Constants.cs b/Source/Editor/Surface/Archetypes/Constants.cs index 581b87e0e..8dcfc8233 100644 --- a/Source/Editor/Surface/Archetypes/Constants.cs +++ b/Source/Editor/Surface/Archetypes/Constants.cs @@ -7,13 +7,11 @@ using Real = System.Single; #endif using System; -using System.Linq; using System.Reflection; using FlaxEditor.CustomEditors.Editors; using FlaxEditor.GUI; using FlaxEditor.Scripting; using FlaxEditor.Surface.Elements; -using FlaxEditor.Surface.Undo; using FlaxEngine; using FlaxEngine.GUI; using FlaxEngine.Utilities; @@ -348,7 +346,7 @@ namespace FlaxEditor.Surface.Archetypes SetValue(0, array); } } - + /// /// The nodes for that group. /// @@ -358,7 +356,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 1, Title = "Bool", - Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(bool))), + Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(bool))), Description = "Constant boolean value", Flags = NodeFlags.AllGraphs, Size = new Float2(110, 20), @@ -391,7 +389,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 2, Title = "Integer", - Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(int))), + Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(int))), Description = "Constant integer value", Flags = NodeFlags.AllGraphs, Size = new Float2(110, 20), @@ -419,7 +417,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 3, Title = "Float", - Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(float))), + Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(float))), Description = "Constant floating point", Flags = NodeFlags.AllGraphs, Size = new Float2(110, 20), @@ -447,7 +445,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 4, Title = "Float2", - Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Float2))), + Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Float2))), Description = "Constant Float2", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 60), @@ -478,7 +476,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 5, Title = "Float3", - Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Float3))), + Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Float3))), Description = "Constant Float3", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 80), @@ -511,7 +509,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 6, Title = "Float4", - Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Float4))), + Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Float4))), Description = "Constant Float4", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 100), @@ -546,7 +544,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 7, Title = "Color", - Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Color))), + Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Color))), Description = "RGBA color", Flags = NodeFlags.AllGraphs, Size = new Float2(70, 100), @@ -581,7 +579,7 @@ namespace FlaxEditor.Surface.Archetypes Title = "Rotation", // TODO: Way too long and ugly - find a better way to add conversion Create = (id, context, arch, groupArch) => - new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Quaternion)), + new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Quaternion)), values => Quaternion.Euler((float)values[0], (float)values[1], (float)values[2])), Description = "Euler angle rotation", Flags = NodeFlags.AnimGraph | NodeFlags.VisualScriptGraph | NodeFlags.ParticleEmitterGraph, @@ -607,7 +605,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 9, Title = "String", - Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(string))), + Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(string))), Description = "Text", Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph, Size = new Float2(200, 20), @@ -658,7 +656,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 12, Title = "Unsigned Integer", - Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(uint))), + Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(uint))), Description = "Constant unsigned integer value", Flags = NodeFlags.AllGraphs, Size = new Float2(170, 20), @@ -698,7 +696,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 15, Title = "Double", - Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(double))), + Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(double))), Description = "Constant floating point", Flags = NodeFlags.AllGraphs, Size = new Float2(110, 20), @@ -716,7 +714,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 16, Title = "Vector2", - Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Vector2))), + Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Vector2))), Description = "Constant Vector2", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 60), @@ -737,7 +735,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 17, Title = "Vector3", - Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Vector3))), + Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Vector3))), Description = "Constant Vector3", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 80), @@ -760,7 +758,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 18, Title = "Vector4", - Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Vector4))), + Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Vector4))), Description = "Constant Vector4", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 100), diff --git a/Source/Editor/Surface/Archetypes/ConvertableNode.cs b/Source/Editor/Surface/Archetypes/ConvertibleNode.cs similarity index 92% rename from Source/Editor/Surface/Archetypes/ConvertableNode.cs rename to Source/Editor/Surface/Archetypes/ConvertibleNode.cs index e7c3c5517..a54c9e0d4 100644 --- a/Source/Editor/Surface/Archetypes/ConvertableNode.cs +++ b/Source/Editor/Surface/Archetypes/ConvertibleNode.cs @@ -9,15 +9,15 @@ using FlaxEngine; namespace FlaxEditor.Surface.Archetypes; /// -/// +/// A special type of node that adds the functionality to convert nodes to parameters /// -internal class ConvertableNode : SurfaceNode +internal class ConvertibleNode : SurfaceNode { - private ScriptType _type; - private Func _convertFunction; + private readonly ScriptType _type; + private readonly Func _convertFunction; /// - public ConvertableNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch, ScriptType type, Func convertFunction = null) + public ConvertibleNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch, ScriptType type, Func convertFunction = null) : base(id, context, nodeArch, groupArch) { _type = type; @@ -37,7 +37,7 @@ internal class ConvertableNode : SurfaceNode { if(Surface.Owner is not IVisjectSurfaceWindow window) throw new Exception("Surface owner is not a Visject Surface Window"); - + Asset asset = Surface.Owner.SurfaceAsset; if (asset == null || !asset.IsLoaded) { @@ -60,7 +60,7 @@ internal class ConvertableNode : SurfaceNode paramAction.Do(); Guid parameterGuid = Surface.Parameters[paramIndex].ID; - + bool undoEnabled = Surface.Undo.Enabled; Surface.Undo.Enabled = false; NodeArchetype arch = Surface.GetParameterGetterNodeArchetype(out var groupId); @@ -69,7 +69,7 @@ internal class ConvertableNode : SurfaceNode if (node is not Parameters.SurfaceNodeParamsGet getNode) throw new Exception("Node is not a ParamsGet node!"); - + // Recreate connections of constant node // Constant nodes and parameter nodes should have the same ports, so we can just iterate through the connections var boxes = GetBoxes(); @@ -81,7 +81,7 @@ internal class ConvertableNode : SurfaceNode if (!getNode.TryGetBox(i, out Box paramBox)) continue; - + // Iterating backwards, because the CreateConnection method deletes entries from the box connections when target box IsSingle is set to true for (int k = box.Connections.Count-1; k >= 0; k--) { @@ -89,14 +89,14 @@ internal class ConvertableNode : SurfaceNode paramBox.CreateConnection(connectedBox); } } - + var spawnNodeAction = new AddRemoveNodeAction(getNode, true); var removeConstantAction = new AddRemoveNodeAction(this, false); - + Surface.AddBatchedUndoAction(new MultiUndoAction(paramAction, spawnNodeAction, removeConstantAction)); removeConstantAction.Do(); } - + private bool OnParameterRenameValidate(RenamePopup popup, string value) { if(Surface.Owner is not IVisjectSurfaceWindow window) diff --git a/Source/Editor/Surface/Archetypes/Textures.cs b/Source/Editor/Surface/Archetypes/Textures.cs index 10d7eb18b..85523961f 100644 --- a/Source/Editor/Surface/Archetypes/Textures.cs +++ b/Source/Editor/Surface/Archetypes/Textures.cs @@ -96,7 +96,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 1, Title = "Texture", - Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(Texture))), + Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Texture))), Description = "Two dimensional texture object", Flags = NodeFlags.MaterialGraph, Size = new Float2(140, 120), @@ -133,7 +133,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 3, Title = "Cube Texture", - Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(CubeTexture))), + Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(CubeTexture))), Description = "Set of 6 textures arranged in a cube", Flags = NodeFlags.MaterialGraph, Size = new Float2(140, 120), @@ -157,7 +157,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 4, Title = "Normal Map", - Create = (id, context, arch, groupArch) => new ConvertableNode(id, context, arch, groupArch, new ScriptType(typeof(NormalMap))), + Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(NormalMap))), Description = "Two dimensional texture object sampled as a normal map", Flags = NodeFlags.MaterialGraph, Size = new Float2(140, 120), From ad6affc863ca63c52c8fff1a1f07634d70b068d0 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Thu, 19 Oct 2023 14:17:28 +0200 Subject: [PATCH 06/12] - More cleanup --- .../Surface/Archetypes/ConvertibleNode.cs | 165 +++++++++--------- 1 file changed, 83 insertions(+), 82 deletions(-) diff --git a/Source/Editor/Surface/Archetypes/ConvertibleNode.cs b/Source/Editor/Surface/Archetypes/ConvertibleNode.cs index a54c9e0d4..44a8147e6 100644 --- a/Source/Editor/Surface/Archetypes/ConvertibleNode.cs +++ b/Source/Editor/Surface/Archetypes/ConvertibleNode.cs @@ -6,101 +6,102 @@ using FlaxEditor.Surface.Elements; using FlaxEditor.Surface.Undo; using FlaxEngine; -namespace FlaxEditor.Surface.Archetypes; - -/// -/// A special type of node that adds the functionality to convert nodes to parameters -/// -internal class ConvertibleNode : SurfaceNode -{ - private readonly ScriptType _type; - private readonly Func _convertFunction; - - /// - public ConvertibleNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch, ScriptType type, Func convertFunction = null) - : base(id, context, nodeArch, groupArch) +namespace FlaxEditor.Surface.Archetypes +{ + /// + /// A special type of node that adds the functionality to convert nodes to parameters + /// + internal class ConvertibleNode : SurfaceNode { - _type = type; - _convertFunction = convertFunction; - } + private readonly ScriptType _type; + private readonly Func _convertFunction; - /// - public override void OnShowSecondaryContextMenu(FlaxEditor.GUI.ContextMenu.ContextMenu menu, Float2 location) - { - base.OnShowSecondaryContextMenu(menu, location); - - menu.AddSeparator(); - menu.AddButton("Convert to Parameter", OnConvertToParameter); - } - - private void OnConvertToParameter() - { - if(Surface.Owner is not IVisjectSurfaceWindow window) - throw new Exception("Surface owner is not a Visject Surface Window"); - - Asset asset = Surface.Owner.SurfaceAsset; - if (asset == null || !asset.IsLoaded) + /// + public ConvertibleNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch, ScriptType type, Func convertFunction = null) + : base(id, context, nodeArch, groupArch) { - Editor.LogError("Asset is null or not loaded"); - return; + _type = type; + _convertFunction = convertFunction; } - // Add parameter to editor - var paramIndex = Surface.Parameters.Count; - object initValue = _convertFunction == null ? Values[0] : _convertFunction.Invoke(Values); - var paramAction = new AddRemoveParamAction + /// + public override void OnShowSecondaryContextMenu(FlaxEditor.GUI.ContextMenu.ContextMenu menu, Float2 location) { - Window = window, - IsAdd = true, - Name = Utilities.Utils.IncrementNameNumber("New parameter", x => OnParameterRenameValidate(null, x)), - Type = _type, - Index = paramIndex, - InitValue = initValue, - }; - paramAction.Do(); + base.OnShowSecondaryContextMenu(menu, location); - Guid parameterGuid = Surface.Parameters[paramIndex].ID; + menu.AddSeparator(); + menu.AddButton("Convert to Parameter", OnConvertToParameter); + } - bool undoEnabled = Surface.Undo.Enabled; - Surface.Undo.Enabled = false; - NodeArchetype arch = Surface.GetParameterGetterNodeArchetype(out var groupId); - SurfaceNode node = Surface.Context.SpawnNode(groupId, arch.TypeID, this.Location, new object[] {parameterGuid}); // 1 Visject, 2 particle, 3 VS - Surface.Undo.Enabled = undoEnabled; - - if (node is not Parameters.SurfaceNodeParamsGet getNode) - throw new Exception("Node is not a ParamsGet node!"); - - // Recreate connections of constant node - // Constant nodes and parameter nodes should have the same ports, so we can just iterate through the connections - var boxes = GetBoxes(); - for (int i = 0;i < boxes.Count; i++) + private void OnConvertToParameter() { - Box box = boxes[i]; - if (!box.HasAnyConnection) - continue; + if (Surface.Owner is not IVisjectSurfaceWindow window) + throw new Exception("Surface owner is not a Visject Surface Window"); - if (!getNode.TryGetBox(i, out Box paramBox)) - continue; - - // Iterating backwards, because the CreateConnection method deletes entries from the box connections when target box IsSingle is set to true - for (int k = box.Connections.Count-1; k >= 0; k--) + Asset asset = Surface.Owner.SurfaceAsset; + if (asset == null || !asset.IsLoaded) { - Box connectedBox = box.Connections[k]; - paramBox.CreateConnection(connectedBox); + Editor.LogError("Asset is null or not loaded"); + return; } + + // Add parameter to editor + var paramIndex = Surface.Parameters.Count; + object initValue = _convertFunction == null ? Values[0] : _convertFunction.Invoke(Values); + var paramAction = new AddRemoveParamAction + { + Window = window, + IsAdd = true, + Name = Utilities.Utils.IncrementNameNumber("New parameter", x => OnParameterRenameValidate(null, x)), + Type = _type, + Index = paramIndex, + InitValue = initValue, + }; + paramAction.Do(); + + Guid parameterGuid = Surface.Parameters[paramIndex].ID; + + bool undoEnabled = Surface.Undo.Enabled; + Surface.Undo.Enabled = false; + NodeArchetype arch = Surface.GetParameterGetterNodeArchetype(out var groupId); + SurfaceNode node = Surface.Context.SpawnNode(groupId, arch.TypeID, this.Location, new object[] { parameterGuid }); // 1 Visject, 2 particle, 3 VS + Surface.Undo.Enabled = undoEnabled; + + if (node is not Parameters.SurfaceNodeParamsGet getNode) + throw new Exception("Node is not a ParamsGet node!"); + + // Recreate connections of constant node + // Constant nodes and parameter nodes should have the same ports, so we can just iterate through the connections + var boxes = GetBoxes(); + for (int i = 0; i < boxes.Count; i++) + { + Box box = boxes[i]; + if (!box.HasAnyConnection) + continue; + + if (!getNode.TryGetBox(i, out Box paramBox)) + continue; + + // Iterating backwards, because the CreateConnection method deletes entries from the box connections when target box IsSingle is set to true + for (int k = box.Connections.Count - 1; k >= 0; k--) + { + Box connectedBox = box.Connections[k]; + paramBox.CreateConnection(connectedBox); + } + } + + var spawnNodeAction = new AddRemoveNodeAction(getNode, true); + var removeConstantAction = new AddRemoveNodeAction(this, false); + + Surface.AddBatchedUndoAction(new MultiUndoAction(paramAction, spawnNodeAction, removeConstantAction)); + removeConstantAction.Do(); } - var spawnNodeAction = new AddRemoveNodeAction(getNode, true); - var removeConstantAction = new AddRemoveNodeAction(this, false); - - Surface.AddBatchedUndoAction(new MultiUndoAction(paramAction, spawnNodeAction, removeConstantAction)); - removeConstantAction.Do(); - } - - private bool OnParameterRenameValidate(RenamePopup popup, string value) - { - if(Surface.Owner is not IVisjectSurfaceWindow window) - throw new Exception("Surface owner is not a Visject Surface Window"); - return !string.IsNullOrWhiteSpace(value) && window.VisjectSurface.Parameters.All(x => x.Name != value); + private bool OnParameterRenameValidate(RenamePopup popup, string value) + { + if (Surface.Owner is not IVisjectSurfaceWindow window) + throw new Exception("Surface owner is not a Visject Surface Window"); + return !string.IsNullOrWhiteSpace(value) && window.VisjectSurface.Parameters.All(x => x.Name != value); + } } } From 4efbed91a4c1f20a6091aa4885f3b566dcbecca8 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Thu, 19 Oct 2023 14:34:10 +0200 Subject: [PATCH 07/12] - Fixed a bug where the wrong boxes got connected - Cleanup --- Source/Editor/Surface/Archetypes/ConvertibleNode.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Editor/Surface/Archetypes/ConvertibleNode.cs b/Source/Editor/Surface/Archetypes/ConvertibleNode.cs index 44a8147e6..eadbee08d 100644 --- a/Source/Editor/Surface/Archetypes/ConvertibleNode.cs +++ b/Source/Editor/Surface/Archetypes/ConvertibleNode.cs @@ -64,7 +64,7 @@ namespace FlaxEditor.Surface.Archetypes bool undoEnabled = Surface.Undo.Enabled; Surface.Undo.Enabled = false; NodeArchetype arch = Surface.GetParameterGetterNodeArchetype(out var groupId); - SurfaceNode node = Surface.Context.SpawnNode(groupId, arch.TypeID, this.Location, new object[] { parameterGuid }); // 1 Visject, 2 particle, 3 VS + SurfaceNode node = Surface.Context.SpawnNode(groupId, arch.TypeID, this.Location, new object[] { parameterGuid }); Surface.Undo.Enabled = undoEnabled; if (node is not Parameters.SurfaceNodeParamsGet getNode) @@ -79,7 +79,7 @@ namespace FlaxEditor.Surface.Archetypes if (!box.HasAnyConnection) continue; - if (!getNode.TryGetBox(i, out Box paramBox)) + if (!getNode.TryGetBox(box.ID, out Box paramBox)) continue; // Iterating backwards, because the CreateConnection method deletes entries from the box connections when target box IsSingle is set to true From 7cb4d279790b6d02c869735f178a2318cf88a1ce Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Thu, 19 Oct 2023 17:23:34 +0200 Subject: [PATCH 08/12] - Minor cleanup and comments --- Source/Editor/Surface/Archetypes/ConvertibleNode.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Editor/Surface/Archetypes/ConvertibleNode.cs b/Source/Editor/Surface/Archetypes/ConvertibleNode.cs index eadbee08d..65d1984e7 100644 --- a/Source/Editor/Surface/Archetypes/ConvertibleNode.cs +++ b/Source/Editor/Surface/Archetypes/ConvertibleNode.cs @@ -59,8 +59,8 @@ namespace FlaxEditor.Surface.Archetypes }; paramAction.Do(); + // Spawn Get Parameter Node based on the added parameter Guid parameterGuid = Surface.Parameters[paramIndex].ID; - bool undoEnabled = Surface.Undo.Enabled; Surface.Undo.Enabled = false; NodeArchetype arch = Surface.GetParameterGetterNodeArchetype(out var groupId); @@ -90,6 +90,7 @@ namespace FlaxEditor.Surface.Archetypes } } + // Add undo actions and remove constant node var spawnNodeAction = new AddRemoveNodeAction(getNode, true); var removeConstantAction = new AddRemoveNodeAction(this, false); From 571f8febf48f7d6311fe7fad4a639f99d107723e Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Sat, 21 Oct 2023 13:11:42 +0200 Subject: [PATCH 09/12] - Moved convertible node file out of archetypes folder into surface folder to be more in line of the project structure (other special nodes like surfacecomment are also just in the surface folder) - Cleanup --- .../Editor/Surface/{Archetypes => }/ConvertibleNode.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) rename Source/Editor/Surface/{Archetypes => }/ConvertibleNode.cs (94%) diff --git a/Source/Editor/Surface/Archetypes/ConvertibleNode.cs b/Source/Editor/Surface/ConvertibleNode.cs similarity index 94% rename from Source/Editor/Surface/Archetypes/ConvertibleNode.cs rename to Source/Editor/Surface/ConvertibleNode.cs index 65d1984e7..9c4a65ab9 100644 --- a/Source/Editor/Surface/Archetypes/ConvertibleNode.cs +++ b/Source/Editor/Surface/ConvertibleNode.cs @@ -1,12 +1,11 @@ using System; using System.Linq; -using FlaxEditor.GUI; using FlaxEditor.Scripting; using FlaxEditor.Surface.Elements; using FlaxEditor.Surface.Undo; using FlaxEngine; -namespace FlaxEditor.Surface.Archetypes +namespace FlaxEditor.Surface { /// /// A special type of node that adds the functionality to convert nodes to parameters @@ -52,7 +51,7 @@ namespace FlaxEditor.Surface.Archetypes { Window = window, IsAdd = true, - Name = Utilities.Utils.IncrementNameNumber("New parameter", x => OnParameterRenameValidate(null, x)), + Name = Utilities.Utils.IncrementNameNumber("New parameter", x => OnParameterRenameValidate(x)), Type = _type, Index = paramIndex, InitValue = initValue, @@ -67,7 +66,7 @@ namespace FlaxEditor.Surface.Archetypes SurfaceNode node = Surface.Context.SpawnNode(groupId, arch.TypeID, this.Location, new object[] { parameterGuid }); Surface.Undo.Enabled = undoEnabled; - if (node is not Parameters.SurfaceNodeParamsGet getNode) + if (node is not Archetypes.Parameters.SurfaceNodeParamsGet getNode) throw new Exception("Node is not a ParamsGet node!"); // Recreate connections of constant node @@ -98,7 +97,7 @@ namespace FlaxEditor.Surface.Archetypes removeConstantAction.Do(); } - private bool OnParameterRenameValidate(RenamePopup popup, string value) + private bool OnParameterRenameValidate(string value) { if (Surface.Owner is not IVisjectSurfaceWindow window) throw new Exception("Surface owner is not a Visject Surface Window"); From 342360f537d44c6d700b59aa65d7208a685c4a30 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 5 Nov 2023 23:21:14 +0100 Subject: [PATCH 10/12] Refactor #1671 --- Source/Editor/Surface/Archetypes/Constants.cs | 130 +++++++++++++++--- Source/Editor/Surface/Archetypes/Textures.cs | 6 +- Source/Editor/Surface/ConvertibleNode.cs | 107 -------------- Source/Editor/Surface/SurfaceParameter.cs | 1 + Source/Editor/Surface/VisjectSurfaceWindow.cs | 3 +- 5 files changed, 117 insertions(+), 130 deletions(-) delete mode 100644 Source/Editor/Surface/ConvertibleNode.cs diff --git a/Source/Editor/Surface/Archetypes/Constants.cs b/Source/Editor/Surface/Archetypes/Constants.cs index 76efc9f60..458fd4af3 100644 --- a/Source/Editor/Surface/Archetypes/Constants.cs +++ b/Source/Editor/Surface/Archetypes/Constants.cs @@ -7,11 +7,12 @@ using Real = System.Single; #endif using System; -using System.Reflection; +using System.Linq; using FlaxEditor.CustomEditors.Editors; using FlaxEditor.GUI; using FlaxEditor.Scripting; using FlaxEditor.Surface.Elements; +using FlaxEditor.Surface.Undo; using FlaxEngine; using FlaxEngine.GUI; using FlaxEngine.Utilities; @@ -24,6 +25,101 @@ namespace FlaxEditor.Surface.Archetypes [HideInEditor] public static class Constants { + /// + /// A special type of node that adds the functionality to convert nodes to parameters. + /// + internal class ConvertToParameterNode : SurfaceNode + { + private readonly ScriptType _type; + private readonly Func _convertFunction; + + /// + public ConvertToParameterNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch, ScriptType type, Func convertFunction = null) + : base(id, context, nodeArch, groupArch) + { + _type = type; + _convertFunction = convertFunction; + } + + /// + public override void OnShowSecondaryContextMenu(FlaxEditor.GUI.ContextMenu.ContextMenu menu, Float2 location) + { + base.OnShowSecondaryContextMenu(menu, location); + + menu.AddSeparator(); + menu.AddButton("Convert to Parameter", OnConvertToParameter); + } + + private void OnConvertToParameter() + { + if (Surface.Owner is not IVisjectSurfaceWindow window) + throw new Exception("Surface owner is not a Visject Surface Window"); + + Asset asset = Surface.Owner.SurfaceAsset; + if (asset == null || !asset.IsLoaded) + { + Editor.LogError("Asset is null or not loaded"); + return; + } + + // Add parameter to editor + var paramIndex = Surface.Parameters.Count; + var initValue = _convertFunction == null ? Values[0] : _convertFunction.Invoke(Values); + var paramAction = new AddRemoveParamAction + { + Window = window, + IsAdd = true, + Name = Utilities.Utils.IncrementNameNumber("New parameter", OnParameterRenameValidate), + Type = _type, + Index = paramIndex, + InitValue = initValue, + }; + paramAction.Do(); + + // Spawn Get Parameter Node based on the added parameter + Guid parameterGuid = Surface.Parameters[paramIndex].ID; + bool undoEnabled = Surface.Undo.Enabled; + Surface.Undo.Enabled = false; + NodeArchetype arch = Surface.GetParameterGetterNodeArchetype(out var groupId); + SurfaceNode node = Surface.Context.SpawnNode(groupId, arch.TypeID, Location, new object[] { parameterGuid }); + Surface.Undo.Enabled = undoEnabled; + if (node is not Parameters.SurfaceNodeParamsGet getNode) + throw new Exception("Node is not a ParamsGet node!"); + + // Recreate connections of constant node + // Constant nodes and parameter nodes should have the same ports, so we can just iterate through the connections + var boxes = GetBoxes(); + for (int i = 0; i < boxes.Count; i++) + { + Box box = boxes[i]; + if (!box.HasAnyConnection) + continue; + if (!getNode.TryGetBox(box.ID, out Box paramBox)) + continue; + + // Iterating backwards, because the CreateConnection method deletes entries from the box connections when target box IsSingle is set to true + for (int k = box.Connections.Count - 1; k >= 0; k--) + { + Box connectedBox = box.Connections[k]; + paramBox.CreateConnection(connectedBox); + } + } + + // Add undo actions and remove constant node + var spawnNodeAction = new AddRemoveNodeAction(getNode, true); + var removeConstantAction = new AddRemoveNodeAction(this, false); + Surface.AddBatchedUndoAction(new MultiUndoAction(paramAction, spawnNodeAction, removeConstantAction)); + removeConstantAction.Do(); + } + + private bool OnParameterRenameValidate(string value) + { + if (Surface.Owner is not IVisjectSurfaceWindow window) + throw new Exception("Surface owner is not a Visject Surface Window"); + return !string.IsNullOrWhiteSpace(value) && window.VisjectSurface.Parameters.All(x => x.Name != value); + } + } + private class EnumNode : SurfaceNode { private EnumComboBox _picker; @@ -356,7 +452,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 1, Title = "Bool", - Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(bool))), + Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(bool))), Description = "Constant boolean value", Flags = NodeFlags.AllGraphs, Size = new Float2(110, 20), @@ -389,7 +485,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 2, Title = "Integer", - Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(int))), + Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(int))), Description = "Constant integer value", Flags = NodeFlags.AllGraphs, Size = new Float2(110, 20), @@ -417,7 +513,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 3, Title = "Float", - Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(float))), + Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(float))), Description = "Constant floating point", Flags = NodeFlags.AllGraphs, Size = new Float2(110, 20), @@ -445,7 +541,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 4, Title = "Float2", - Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Float2))), + Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Float2))), Description = "Constant Float2", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 60), @@ -476,7 +572,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 5, Title = "Float3", - Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Float3))), + Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Float3))), Description = "Constant Float3", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 80), @@ -509,7 +605,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 6, Title = "Float4", - Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Float4))), + Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Float4))), Description = "Constant Float4", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 100), @@ -544,7 +640,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 7, Title = "Color", - Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Color))), + Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Color))), Description = "RGBA color", Flags = NodeFlags.AllGraphs, Size = new Float2(70, 100), @@ -577,10 +673,8 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 8, Title = "Rotation", - // TODO: Way too long and ugly - find a better way to add conversion Create = (id, context, arch, groupArch) => - new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Quaternion)), - values => Quaternion.Euler((float)values[0], (float)values[1], (float)values[2])), + new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Quaternion)), values => Quaternion.Euler((float)values[0], (float)values[1], (float)values[2])), Description = "Euler angle rotation", Flags = NodeFlags.AnimGraph | NodeFlags.VisualScriptGraph | NodeFlags.ParticleEmitterGraph, Size = new Float2(110, 60), @@ -605,7 +699,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 9, Title = "String", - Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(string))), + Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(string))), Description = "Text", Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph, Size = new Float2(200, 20), @@ -656,8 +750,8 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 12, Title = "Unsigned Integer", - AlternativeTitles = new[] { "UInt" , "U Int" }, - Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(uint))), + AlternativeTitles = new[] { "UInt", "U Int" }, + Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(uint))), Description = "Constant unsigned integer value", Flags = NodeFlags.AllGraphs, Size = new Float2(170, 20), @@ -697,7 +791,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 15, Title = "Double", - Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(double))), + Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(double))), Description = "Constant floating point", Flags = NodeFlags.AllGraphs, Size = new Float2(110, 20), @@ -715,7 +809,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 16, Title = "Vector2", - Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Vector2))), + Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Vector2))), Description = "Constant Vector2", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 60), @@ -736,7 +830,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 17, Title = "Vector3", - Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Vector3))), + Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Vector3))), Description = "Constant Vector3", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 80), @@ -759,7 +853,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 18, Title = "Vector4", - Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Vector4))), + Create = (id, context, arch, groupArch) => new ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Vector4))), Description = "Constant Vector4", Flags = NodeFlags.AllGraphs, Size = new Float2(130, 100), diff --git a/Source/Editor/Surface/Archetypes/Textures.cs b/Source/Editor/Surface/Archetypes/Textures.cs index 85523961f..e35af7192 100644 --- a/Source/Editor/Surface/Archetypes/Textures.cs +++ b/Source/Editor/Surface/Archetypes/Textures.cs @@ -96,7 +96,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 1, Title = "Texture", - Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(Texture))), + Create = (id, context, arch, groupArch) => new Constants.ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(Texture))), Description = "Two dimensional texture object", Flags = NodeFlags.MaterialGraph, Size = new Float2(140, 120), @@ -133,7 +133,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 3, Title = "Cube Texture", - Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(CubeTexture))), + Create = (id, context, arch, groupArch) => new Constants.ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(CubeTexture))), Description = "Set of 6 textures arranged in a cube", Flags = NodeFlags.MaterialGraph, Size = new Float2(140, 120), @@ -157,7 +157,7 @@ namespace FlaxEditor.Surface.Archetypes { TypeID = 4, Title = "Normal Map", - Create = (id, context, arch, groupArch) => new ConvertibleNode(id, context, arch, groupArch, new ScriptType(typeof(NormalMap))), + Create = (id, context, arch, groupArch) => new Constants.ConvertToParameterNode(id, context, arch, groupArch, new ScriptType(typeof(NormalMap))), Description = "Two dimensional texture object sampled as a normal map", Flags = NodeFlags.MaterialGraph, Size = new Float2(140, 120), diff --git a/Source/Editor/Surface/ConvertibleNode.cs b/Source/Editor/Surface/ConvertibleNode.cs deleted file mode 100644 index 9c4a65ab9..000000000 --- a/Source/Editor/Surface/ConvertibleNode.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.Linq; -using FlaxEditor.Scripting; -using FlaxEditor.Surface.Elements; -using FlaxEditor.Surface.Undo; -using FlaxEngine; - -namespace FlaxEditor.Surface -{ - /// - /// A special type of node that adds the functionality to convert nodes to parameters - /// - internal class ConvertibleNode : SurfaceNode - { - private readonly ScriptType _type; - private readonly Func _convertFunction; - - /// - public ConvertibleNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch, ScriptType type, Func convertFunction = null) - : base(id, context, nodeArch, groupArch) - { - _type = type; - _convertFunction = convertFunction; - } - - /// - public override void OnShowSecondaryContextMenu(FlaxEditor.GUI.ContextMenu.ContextMenu menu, Float2 location) - { - base.OnShowSecondaryContextMenu(menu, location); - - menu.AddSeparator(); - menu.AddButton("Convert to Parameter", OnConvertToParameter); - } - - private void OnConvertToParameter() - { - if (Surface.Owner is not IVisjectSurfaceWindow window) - throw new Exception("Surface owner is not a Visject Surface Window"); - - Asset asset = Surface.Owner.SurfaceAsset; - if (asset == null || !asset.IsLoaded) - { - Editor.LogError("Asset is null or not loaded"); - return; - } - - // Add parameter to editor - var paramIndex = Surface.Parameters.Count; - object initValue = _convertFunction == null ? Values[0] : _convertFunction.Invoke(Values); - var paramAction = new AddRemoveParamAction - { - Window = window, - IsAdd = true, - Name = Utilities.Utils.IncrementNameNumber("New parameter", x => OnParameterRenameValidate(x)), - Type = _type, - Index = paramIndex, - InitValue = initValue, - }; - paramAction.Do(); - - // Spawn Get Parameter Node based on the added parameter - Guid parameterGuid = Surface.Parameters[paramIndex].ID; - bool undoEnabled = Surface.Undo.Enabled; - Surface.Undo.Enabled = false; - NodeArchetype arch = Surface.GetParameterGetterNodeArchetype(out var groupId); - SurfaceNode node = Surface.Context.SpawnNode(groupId, arch.TypeID, this.Location, new object[] { parameterGuid }); - Surface.Undo.Enabled = undoEnabled; - - if (node is not Archetypes.Parameters.SurfaceNodeParamsGet getNode) - throw new Exception("Node is not a ParamsGet node!"); - - // Recreate connections of constant node - // Constant nodes and parameter nodes should have the same ports, so we can just iterate through the connections - var boxes = GetBoxes(); - for (int i = 0; i < boxes.Count; i++) - { - Box box = boxes[i]; - if (!box.HasAnyConnection) - continue; - - if (!getNode.TryGetBox(box.ID, out Box paramBox)) - continue; - - // Iterating backwards, because the CreateConnection method deletes entries from the box connections when target box IsSingle is set to true - for (int k = box.Connections.Count - 1; k >= 0; k--) - { - Box connectedBox = box.Connections[k]; - paramBox.CreateConnection(connectedBox); - } - } - - // Add undo actions and remove constant node - var spawnNodeAction = new AddRemoveNodeAction(getNode, true); - var removeConstantAction = new AddRemoveNodeAction(this, false); - - Surface.AddBatchedUndoAction(new MultiUndoAction(paramAction, spawnNodeAction, removeConstantAction)); - removeConstantAction.Do(); - } - - private bool OnParameterRenameValidate(string value) - { - if (Surface.Owner is not IVisjectSurfaceWindow window) - throw new Exception("Surface owner is not a Visject Surface Window"); - return !string.IsNullOrWhiteSpace(value) && window.VisjectSurface.Parameters.All(x => x.Name != value); - } - } -} diff --git a/Source/Editor/Surface/SurfaceParameter.cs b/Source/Editor/Surface/SurfaceParameter.cs index e74b44eb9..c22e5bde5 100644 --- a/Source/Editor/Surface/SurfaceParameter.cs +++ b/Source/Editor/Surface/SurfaceParameter.cs @@ -55,6 +55,7 @@ namespace FlaxEditor.Surface /// /// The type. /// The name. + /// The initial value to use. Null to use automatic default value. /// The created parameter. public static SurfaceParameter Create(ScriptType type, string name, object initValue = null) { diff --git a/Source/Editor/Surface/VisjectSurfaceWindow.cs b/Source/Editor/Surface/VisjectSurfaceWindow.cs index d2b9822a1..2232b39e5 100644 --- a/Source/Editor/Surface/VisjectSurfaceWindow.cs +++ b/Source/Editor/Surface/VisjectSurfaceWindow.cs @@ -279,7 +279,7 @@ namespace FlaxEditor.Surface public ScriptType Type; /// - /// The value to initialize the parameter with. (Can be null) + /// The value to initialize the parameter with. Can be null to use default one for the parameter type. /// public object InitValue; @@ -1065,7 +1065,6 @@ namespace FlaxEditor.Surface public virtual void OnParamRemoveUndo() { _refreshPropertiesOnLoad = true; - //_propertiesEditor.BuildLayoutOnUpdate(); _propertiesEditor.BuildLayout(); } From 2c5a5acf33978ad90a1450a68b324c20bf34812a Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Sun, 5 Nov 2023 23:30:39 +0100 Subject: [PATCH 11/12] Add maintaining new param id in undo #1671 --- Source/Editor/Surface/SurfaceParameter.cs | 22 +------------------ Source/Editor/Surface/VisjectSurfaceWindow.cs | 15 ++++++++++++- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/Source/Editor/Surface/SurfaceParameter.cs b/Source/Editor/Surface/SurfaceParameter.cs index c22e5bde5..dae82e111 100644 --- a/Source/Editor/Surface/SurfaceParameter.cs +++ b/Source/Editor/Surface/SurfaceParameter.cs @@ -3,7 +3,6 @@ using System; using FlaxEditor.Scripting; using FlaxEngine; -using FlaxEngine.Utilities; namespace FlaxEditor.Surface { @@ -27,7 +26,7 @@ namespace FlaxEditor.Surface /// /// Parameter unique ID /// - public Guid ID; + public Guid ID = Guid.Empty; /// /// Parameter name @@ -49,24 +48,5 @@ namespace FlaxEditor.Surface /// [NoSerialize, HideInEditor] public readonly SurfaceMeta Meta = new SurfaceMeta(); - - /// - /// Creates the new parameter of the given type. - /// - /// The type. - /// The name. - /// The initial value to use. Null to use automatic default value. - /// The created parameter. - public static SurfaceParameter Create(ScriptType type, string name, object initValue = null) - { - return new SurfaceParameter - { - ID = Guid.NewGuid(), - IsPublic = true, - Name = name, - Type = type, - Value = initValue ?? TypeUtils.GetDefaultValue(type), - }; - } } } diff --git a/Source/Editor/Surface/VisjectSurfaceWindow.cs b/Source/Editor/Surface/VisjectSurfaceWindow.cs index 2232b39e5..cce86d5c0 100644 --- a/Source/Editor/Surface/VisjectSurfaceWindow.cs +++ b/Source/Editor/Surface/VisjectSurfaceWindow.cs @@ -17,6 +17,7 @@ using FlaxEditor.Viewport.Previews; using FlaxEditor.Windows.Assets; using FlaxEngine; using FlaxEngine.GUI; +using FlaxEngine.Utilities; namespace FlaxEditor.Surface { @@ -258,6 +259,11 @@ namespace FlaxEditor.Surface /// public IVisjectSurfaceWindow Window; + /// + /// The identifier of the parameter. Empty to auto generate it. + /// + public Guid Id = Guid.NewGuid(); + /// /// True if adding, false if removing parameter. /// @@ -309,7 +315,14 @@ namespace FlaxEditor.Surface var type = Type; if (IsAdd && type.Type == typeof(NormalMap)) type = new ScriptType(typeof(Texture)); - var param = SurfaceParameter.Create(type, Name, InitValue); + var param = new SurfaceParameter + { + ID = Id, + IsPublic = true, + Name = Name, + Type = type, + Value = InitValue ?? TypeUtils.GetDefaultValue(type), + }; if (IsAdd && Type.Type == typeof(NormalMap)) param.Value = FlaxEngine.Content.LoadAsyncInternal("Engine/Textures/NormalTexture"); Window.VisjectSurface.Parameters.Insert(Index, param); From d79dd4aaf7bfd189fb0c939b47070e4d4ceeb5a4 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 6 Nov 2023 08:41:36 +0100 Subject: [PATCH 12/12] Add undo for `Convert to Parameter` connections change in #1671 --- Source/Editor/Surface/Archetypes/Constants.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Source/Editor/Surface/Archetypes/Constants.cs b/Source/Editor/Surface/Archetypes/Constants.cs index 458fd4af3..e58d917d1 100644 --- a/Source/Editor/Surface/Archetypes/Constants.cs +++ b/Source/Editor/Surface/Archetypes/Constants.cs @@ -75,6 +75,7 @@ namespace FlaxEditor.Surface.Archetypes InitValue = initValue, }; paramAction.Do(); + Surface.AddBatchedUndoAction(paramAction); // Spawn Get Parameter Node based on the added parameter Guid parameterGuid = Surface.Parameters[paramIndex].ID; @@ -85,9 +86,12 @@ namespace FlaxEditor.Surface.Archetypes Surface.Undo.Enabled = undoEnabled; if (node is not Parameters.SurfaceNodeParamsGet getNode) throw new Exception("Node is not a ParamsGet node!"); + Surface.AddBatchedUndoAction(new AddRemoveNodeAction(getNode, true)); // Recreate connections of constant node // Constant nodes and parameter nodes should have the same ports, so we can just iterate through the connections + var editConnectionsAction1 = new EditNodeConnections(Context, this); + var editConnectionsAction2 = new EditNodeConnections(Context, node); var boxes = GetBoxes(); for (int i = 0; i < boxes.Count; i++) { @@ -104,12 +108,16 @@ namespace FlaxEditor.Surface.Archetypes paramBox.CreateConnection(connectedBox); } } + editConnectionsAction1.End(); + editConnectionsAction2.End(); + Surface.AddBatchedUndoAction(editConnectionsAction1); + Surface.AddBatchedUndoAction(editConnectionsAction2); // Add undo actions and remove constant node - var spawnNodeAction = new AddRemoveNodeAction(getNode, true); var removeConstantAction = new AddRemoveNodeAction(this, false); - Surface.AddBatchedUndoAction(new MultiUndoAction(paramAction, spawnNodeAction, removeConstantAction)); + Surface.AddBatchedUndoAction(removeConstantAction); removeConstantAction.Do(); + Surface.MarkAsEdited(); } private bool OnParameterRenameValidate(string value)