Merge branch 'Chikinsupu-Visject-ConvertConstantToParameter'

This commit is contained in:
Wojtek Figat
2023-11-06 08:41:45 +01:00
7 changed files with 148 additions and 27 deletions

View File

@@ -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,109 @@ namespace FlaxEditor.Surface.Archetypes
[HideInEditor]
public static class Constants
{
/// <summary>
/// A special type of node that adds the functionality to convert nodes to parameters.
/// </summary>
internal class ConvertToParameterNode : SurfaceNode
{
private readonly ScriptType _type;
private readonly Func<object[], object> _convertFunction;
/// <inheritdoc />
public ConvertToParameterNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch, ScriptType type, Func<object[], object> convertFunction = null)
: base(id, context, nodeArch, groupArch)
{
_type = type;
_convertFunction = convertFunction;
}
/// <inheritdoc />
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();
Surface.AddBatchedUndoAction(paramAction);
// 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!");
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++)
{
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);
}
}
editConnectionsAction1.End();
editConnectionsAction2.End();
Surface.AddBatchedUndoAction(editConnectionsAction1);
Surface.AddBatchedUndoAction(editConnectionsAction2);
// Add undo actions and remove constant node
var removeConstantAction = new AddRemoveNodeAction(this, false);
Surface.AddBatchedUndoAction(removeConstantAction);
removeConstantAction.Do();
Surface.MarkAsEdited();
}
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,6 +460,7 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 1,
Title = "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),
@@ -388,6 +493,7 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 2,
Title = "Integer",
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),
@@ -415,6 +521,7 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 3,
Title = "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),
@@ -442,6 +549,7 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 4,
Title = "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),
@@ -472,6 +580,7 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 5,
Title = "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),
@@ -504,6 +613,7 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 6,
Title = "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),
@@ -538,6 +648,7 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 7,
Title = "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),
@@ -570,6 +681,8 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 8,
Title = "Rotation",
Create = (id, context, arch, groupArch) =>
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),
@@ -594,6 +707,7 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 9,
Title = "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),
@@ -644,7 +758,8 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 12,
Title = "Unsigned Integer",
AlternativeTitles = new[] { "UInt" , "U Int" },
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),
@@ -684,6 +799,7 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 15,
Title = "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),
@@ -701,6 +817,7 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 16,
Title = "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),
@@ -721,6 +838,7 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 17,
Title = "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),
@@ -743,6 +861,7 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 18,
Title = "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),

View File

@@ -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 Constants.ConvertToParameterNode(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 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),
@@ -154,6 +157,7 @@ namespace FlaxEditor.Surface.Archetypes
{
TypeID = 4,
Title = "Normal Map",
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),

View File

@@ -93,7 +93,7 @@ namespace FlaxEditor.Surface
}
/// <inheritdoc />
protected override NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId)
protected internal override NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId)
{
groupId = 6;
return Archetypes.Parameters.Nodes[1];

View File

@@ -3,7 +3,6 @@
using System;
using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.Utilities;
namespace FlaxEditor.Surface
{
@@ -27,7 +26,7 @@ namespace FlaxEditor.Surface
/// <summary>
/// Parameter unique ID
/// </summary>
public Guid ID;
public Guid ID = Guid.Empty;
/// <summary>
/// Parameter name
@@ -49,23 +48,5 @@ namespace FlaxEditor.Surface
/// </summary>
[NoSerialize, HideInEditor]
public readonly SurfaceMeta Meta = new SurfaceMeta();
/// <summary>
/// Creates the new parameter of the given type.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="name">The name.</param>
/// <returns>The created parameter.</returns>
public static SurfaceParameter Create(ScriptType type, string name)
{
return new SurfaceParameter
{
ID = Guid.NewGuid(),
IsPublic = true,
Name = name,
Type = type,
Value = TypeUtils.GetDefaultValue(type),
};
}
}
}

View File

@@ -151,7 +151,7 @@ namespace FlaxEditor.Surface
/// </summary>
/// <param name="groupId">The group ID.</param>
/// <returns>The node archetype.</returns>
protected virtual NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId)
protected internal virtual NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId)
{
groupId = 6;
return Archetypes.Parameters.Nodes[0];

View File

@@ -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
/// </summary>
public IVisjectSurfaceWindow Window;
/// <summary>
/// The identifier of the parameter. Empty to auto generate it.
/// </summary>
public Guid Id = Guid.NewGuid();
/// <summary>
/// True if adding, false if removing parameter.
/// </summary>
@@ -278,6 +284,11 @@ namespace FlaxEditor.Surface
/// </summary>
public ScriptType Type;
/// <summary>
/// The value to initialize the parameter with. Can be null to use default one for the parameter type.
/// </summary>
public object InitValue;
/// <inheritdoc />
public string ActionString => IsAdd ? "Add parameter" : "Remove parameter";
@@ -304,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);
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<Texture>("Engine/Textures/NormalTexture");
Window.VisjectSurface.Parameters.Insert(Index, param);
@@ -1060,7 +1078,6 @@ namespace FlaxEditor.Surface
public virtual void OnParamRemoveUndo()
{
_refreshPropertiesOnLoad = true;
//_propertiesEditor.BuildLayoutOnUpdate();
_propertiesEditor.BuildLayout();
}

View File

@@ -144,7 +144,7 @@ namespace FlaxEditor.Surface
}
/// <inheritdoc />
protected override NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId)
protected internal override NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId)
{
groupId = 6;
return Archetypes.Parameters.Nodes[2];