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();
}