Files
FlaxEngine/Source/Editor/Surface/ParticleEmitterSurface.cs
Saas a98a76f6e5 fix box spacing and (auto calculate) node height
- Work in progress but enough progress to commit because it basically works, it's just a bit ugly
- Node height is now recalculated every time a new element is added to the node
- Introduced `Archetype.UseFixedSize` for special nodes like *Color Gradient* or *Curve* that must rely on hardcoded size for now because the auto sizing does not take elements like the gradient editor or curve editor into account (ideally in the future it will)
- Fixed input and output box spacing (still some 1px offsets that I'm unsure where they are from, could be placebo though)
2025-12-20 00:02:11 +01:00

158 lines
5.4 KiB
C#

// Copyright (c) Wojciech Figat. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using FlaxEditor.Content;
using FlaxEditor.Scripting;
using FlaxEditor.Surface.Archetypes;
using FlaxEngine;
namespace FlaxEditor.Surface
{
/// <summary>
/// The Visject Surface implementation for the particle emitter graph editor.
/// </summary>
/// <seealso cref="FlaxEditor.Surface.VisjectSurface" />
[HideInEditor]
public class ParticleEmitterSurface : VisjectSurface
{
internal FlaxEditor.Surface.Archetypes.Particles.ParticleEmitterNode _rootNode;
/// <summary>
/// Gets the root node of the emitter graph.
/// </summary>
public FlaxEditor.Surface.Archetypes.Particles.ParticleEmitterNode RootNode => _rootNode;
/// <inheritdoc />
public override bool UseContextMenuDescriptionPanel => true;
/// <inheritdoc />
public ParticleEmitterSurface(IVisjectSurfaceOwner owner, Action onSave, FlaxEditor.Undo undo)
: base(owner, onSave, undo)
{
}
/// <inheritdoc />
public override string GetTypeName(ScriptType type)
{
if (type.Type == typeof(FlaxEngine.Object))
return "Texture";
return base.GetTypeName(type);
}
/// <summary>
/// Arranges the particle modules nodes.
/// </summary>
public void ArrangeModulesNodes()
{
if (IsLayoutLocked)
return;
if (_rootNode == null)
throw new InvalidOperationException("Missing root node.");
IsLayoutLocked = true;
var modulesGroups = Nodes.OfType<ParticleModules.ParticleModuleNode>().GroupBy(x => x.ModuleType).ToList();
modulesGroups.Sort((a, b) => a.Key.CompareTo(b.Key));
var width = _rootNode.Width;
var rootPos = _rootNode.Location;
var pos = rootPos;
pos.Y += Constants.NodeHeaderHeight + 1.0f + 7 * Constants.LayoutOffsetY + 6.0f + 4.0f;
for (int i = 0; i < _rootNode.Headers.Length; i++)
{
var header = _rootNode.Headers[i];
var modulesStart = pos - rootPos;
var modules = modulesGroups.FirstOrDefault(x => x.Key == header.ModuleType);
pos.Y += Constants.NodeHeaderHeight + 2.0f;
if (modules != null)
{
foreach (var module in modules)
{
var height = module.Height;
module.Bounds = new Rectangle(pos.X, pos.Y, width, height);
pos.Y += height;
}
}
pos.Y += 20.0f;
var modulesEnd = pos - rootPos;
header.Bounds = new Rectangle(modulesStart.X, modulesStart.Y, width, modulesEnd.Y - modulesStart.Y);
}
_rootNode.Height = pos.Y - _rootNode.Location.Y;
IsLayoutLocked = false;
PerformLayout();
}
/// <inheritdoc />
public override bool CanUseNodeType(GroupArchetype groupArchetype, NodeArchetype nodeArchetype)
{
return (nodeArchetype.Flags & NodeFlags.ParticleEmitterGraph) != 0 && base.CanUseNodeType(groupArchetype, nodeArchetype);
}
/// <inheritdoc />
protected internal override NodeArchetype GetParameterGetterNodeArchetype(out ushort groupId)
{
groupId = 6;
return Archetypes.Parameters.Nodes[1];
}
/// <inheritdoc />
protected override bool ValidateDragItem(AssetItem assetItem)
{
if (assetItem.IsOfType<Texture>())
return true;
if (assetItem.IsOfType<CubeTexture>())
return true;
if (assetItem.IsOfType<ParticleEmitterFunction>())
return true;
if (assetItem.IsOfType<GameplayGlobals>())
return true;
return base.ValidateDragItem(assetItem);
}
/// <inheritdoc />
protected override void HandleDragDropAssets(List<AssetItem> objects, DragDropEventArgs args)
{
for (int i = 0; i < objects.Count; i++)
{
var assetItem = objects[i];
SurfaceNode node = null;
if (assetItem.IsOfType<Texture>())
{
node = Context.SpawnNode(5, 11, args.SurfaceLocation, new object[] { assetItem.ID });
}
else if (assetItem.IsOfType<CubeTexture>())
{
node = Context.SpawnNode(5, 12, args.SurfaceLocation, new object[] { assetItem.ID });
}
else if (assetItem.IsOfType<ParticleEmitterFunction>())
{
node = Context.SpawnNode(14, 300, args.SurfaceLocation, new object[] { assetItem.ID });
}
else if (assetItem.IsOfType<GameplayGlobals>())
{
node = Context.SpawnNode(7, 16, args.SurfaceLocation, new object[]
{
assetItem.ID,
string.Empty,
});
}
if (node != null)
{
args.SurfaceLocation.X += node.Width + 10;
}
}
base.HandleDragDropAssets(objects, args);
}
}
}