Add selection drawing and picking gizmo to Foliage Types editing tab

This commit is contained in:
2026-04-30 18:19:12 +02:00
parent 24675ace93
commit 7a569d4f14
10 changed files with 239 additions and 25 deletions
@@ -17,7 +17,7 @@ namespace FlaxEditor.Tools.Foliage
private int _selectedInstanceIndex = -1;
/// <summary>
/// The foliage painting gizmo.
/// The foliage editing gizmo.
/// </summary>
public EditFoliageGizmo Gizmo;
@@ -66,8 +66,6 @@ namespace FlaxEditor.Tools.Foliage
base.Init(owner);
Gizmo = new EditFoliageGizmo(owner, this);
SelectionOutline = FlaxEngine.Object.New<EditFoliageSelectionOutline>();
SelectionOutline.GizmoMode = this;
}
/// <inheritdoc />
@@ -84,6 +82,11 @@ namespace FlaxEditor.Tools.Foliage
base.OnActivated();
Owner.Gizmos.Active = Gizmo;
if (SelectionOutline == null)
{
SelectionOutline = FlaxEngine.Object.New<EditFoliageSelectionOutline>();
SelectionOutline.GizmoMode = this;
}
((MainEditorGizmoViewport)Owner).OverrideSelectionOutline(SelectionOutline);
SelectedInstanceIndex = -1;
}
@@ -6,7 +6,7 @@ using FlaxEngine;
namespace FlaxEditor.Tools.Foliage
{
/// <summary>
/// The custom outline for drawing the selected foliage instances outlines.
/// The custom outline for drawing the selected foliage instance.
/// </summary>
/// <seealso cref="FlaxEditor.Gizmo.SelectionOutline" />
[HideInEditor]
+2 -3
View File
@@ -5,7 +5,6 @@ using System.Collections.Generic;
using FlaxEditor.GUI.Tabs;
using FlaxEditor.Modules;
using FlaxEditor.SceneGraph.Actors;
using FlaxEditor.Viewport.Modes;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -214,7 +213,7 @@ namespace FlaxEditor.Tools.Foliage
private void InitSculptMode()
{
var tab = _modes.AddTab(FoliageTypes = new FoliageTypesTab(this));
var tab = _modes.AddTab(FoliageTypes = new FoliageTypesTab(this, Editor.Windows.EditWin.Viewport.EditFoliageTypesGizmo));
tab.Selected += OnTabSelected;
}
@@ -251,7 +250,7 @@ namespace FlaxEditor.Tools.Foliage
switch (_modes.SelectedTabIndex)
{
case 0:
Editor.Windows.EditWin.Viewport.Gizmos.SetActiveMode<NoGizmoMode>();
Editor.Windows.EditWin.Viewport.Gizmos.SetActiveMode<FoliageTypesGizmoMode>();
break;
case 1:
Editor.Windows.EditWin.Viewport.Gizmos.SetActiveMode<PaintFoliageGizmoMode>();
@@ -0,0 +1,44 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEditor.Gizmo;
namespace FlaxEditor.Tools.Foliage
{
/// <summary>
/// Gizmo for editing foliage types.
/// </summary>
public sealed class FoliageTypesGizmo : GizmoBase
{
/// <summary>
/// The parent mode.
/// </summary>
public readonly FoliageTypesGizmoMode GizmoMode;
/// <summary>
/// Initializes a new instance of the <see cref="EditFoliageGizmo"/> class.
/// </summary>
/// <param name="owner">The owner.</param>
/// <param name="mode">The mode.</param>
public FoliageTypesGizmo(IGizmoOwner owner, FoliageTypesGizmoMode mode)
: base(owner)
{
GizmoMode = mode;
}
/// <inheritdoc />
public override void Pick()
{
// Get mouse ray and try to hit foliage instance
var foliage = GizmoMode.SelectedFoliage;
if (!foliage)
return;
var ray = Owner.MouseRay;
if (foliage.Intersects(ref ray, out _, out _, out var instanceIndex))
{
// Select hit instance type
var instance = foliage.GetInstance(instanceIndex);
GizmoMode.SelectedTypeIndex = instance.Type;
}
}
}
}
@@ -0,0 +1,86 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEditor.Gizmo;
using FlaxEditor.SceneGraph.Actors;
using FlaxEditor.Viewport;
using FlaxEditor.Viewport.Modes;
namespace FlaxEditor.Tools.Foliage
{
/// <summary>
/// Foliage types editing mode.
/// </summary>
/// <seealso cref="FlaxEditor.Viewport.Modes.EditorGizmoMode" />
public class FoliageTypesGizmoMode : EditorGizmoMode
{
/// <summary>
/// The foliage types gizmo.
/// </summary>
public FoliageTypesGizmo Gizmo;
/// <summary>
/// The foliage type editing selection outline.
/// </summary>
public FoliageTypesOutline SelectionOutline;
/// <summary>
/// The selected foliage type index.
/// </summary>
public int SelectedTypeIndex
{
get => Editor.Instance.Windows.ToolboxWin.Foliage.SelectedFoliageTypeIndex;
set => Editor.Instance.Windows.ToolboxWin.Foliage.SelectedFoliageTypeIndex = value;
}
/// <summary>
/// Gets the selected foliage actor (see <see cref="Modules.SceneEditingModule"/>).
/// </summary>
public FlaxEngine.Foliage SelectedFoliage
{
get
{
var sceneEditing = Editor.Instance.SceneEditing;
var foliageNode = sceneEditing.SelectionCount == 1 ? sceneEditing.Selection[0] as FoliageNode : null;
return (FlaxEngine.Foliage)foliageNode?.Actor;
}
}
/// <inheritdoc />
public override void Init(IGizmoOwner owner)
{
base.Init(owner);
Gizmo = new FoliageTypesGizmo(owner, this);
}
/// <inheritdoc />
public override void Dispose()
{
FlaxEngine.Object.Destroy(ref SelectionOutline);
base.Dispose();
}
/// <inheritdoc />
public override void OnActivated()
{
base.OnActivated();
Owner.Gizmos.Active = Gizmo;
if (SelectionOutline == null)
{
SelectionOutline = FlaxEngine.Object.New<FoliageTypesOutline>();
SelectionOutline.GizmoMode = this;
}
((MainEditorGizmoViewport)Owner).OverrideSelectionOutline(SelectionOutline);
}
/// <inheritdoc />
public override void OnDeactivated()
{
((MainEditorGizmoViewport)Owner).OverrideSelectionOutline(null);
base.OnDeactivated();
}
}
}
@@ -0,0 +1,62 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEditor.Gizmo;
using FlaxEngine;
namespace FlaxEditor.Tools.Foliage
{
/// <summary>
/// The custom outline for drawing the selected foliage type.
/// </summary>
/// <seealso cref="FlaxEditor.Gizmo.SelectionOutline" />
[HideInEditor]
public class FoliageTypesOutline : SelectionOutline
{
/// <summary>
/// The parent mode.
/// </summary>
public FoliageTypesGizmoMode GizmoMode;
/// <inheritdoc />
public override bool CanRender()
{
if (!HasDataReady)
return false;
var foliage = GizmoMode.SelectedFoliage;
if (!foliage)
return false;
var typeIndex = GizmoMode.SelectedTypeIndex;
if (typeIndex < 0 || typeIndex >= foliage.FoliageTypesCount)
return false;
return true;
}
/// <inheritdoc />
public override void Render(GPUContext context, ref RenderContext renderContext, GPUTexture input, GPUTexture output)
{
base.Render(context, ref renderContext, input, output);
// Restore debug option
var foliage = GizmoMode.SelectedFoliage;
if (foliage)
foliage._drawFoliageType = -1;
}
/// <inheritdoc />
protected override void DrawSelectionDepth(GPUContext context, SceneRenderTask task, GPUTexture customDepth)
{
var foliage = GizmoMode.SelectedFoliage;
if (!foliage)
return;
var typeIndex = GizmoMode.SelectedTypeIndex;
if (typeIndex < 0 || typeIndex >= foliage.FoliageTypesCount)
return;
// Draw instances of the given type
foliage._drawFoliageType = typeIndex;
_actors.Add(foliage);
Renderer.DrawSceneDepth(context, task, customDepth, _actors);
}
}
}
@@ -334,7 +334,8 @@ namespace FlaxEditor.Tools.Foliage
/// Initializes a new instance of the <see cref="FoliageTypesTab"/> class.
/// </summary>
/// <param name="tab">The parent tab.</param>
public FoliageTypesTab(FoliageTab tab)
/// <param name="mode">The gizmo mode.</param>
public FoliageTypesTab(FoliageTab tab, FoliageTypesGizmoMode mode)
: base("Foliage Types")
{
Tab = tab;
@@ -179,12 +179,17 @@ namespace FlaxEditor.Viewport
public Tools.Terrain.EditTerrainGizmoMode EditTerrainGizmo;
/// <summary>
/// The paint foliage gizmo.
/// The edit foliage types gizmo.
/// </summary>
public Tools.Foliage.FoliageTypesGizmoMode EditFoliageTypesGizmo;
/// <summary>
/// The paint foliage instances gizmo.
/// </summary>
public Tools.Foliage.PaintFoliageGizmoMode PaintFoliageGizmo;
/// <summary>
/// The edit foliage gizmo.
/// The edit foliage instances gizmo.
/// </summary>
public Tools.Foliage.EditFoliageGizmoMode EditFoliageGizmo;
@@ -276,6 +281,7 @@ namespace FlaxEditor.Viewport
Gizmos.AddMode(SculptTerrainGizmo = new Tools.Terrain.SculptTerrainGizmoMode());
Gizmos.AddMode(PaintTerrainGizmo = new Tools.Terrain.PaintTerrainGizmoMode());
Gizmos.AddMode(EditTerrainGizmo = new Tools.Terrain.EditTerrainGizmoMode());
Gizmos.AddMode(EditFoliageTypesGizmo = new Tools.Foliage.FoliageTypesGizmoMode());
Gizmos.AddMode(PaintFoliageGizmo = new Tools.Foliage.PaintFoliageGizmoMode());
Gizmos.AddMode(EditFoliageGizmo = new Tools.Foliage.EditFoliageGizmoMode());
@@ -343,10 +349,12 @@ namespace FlaxEditor.Viewport
/// <param name="customSelectionOutline">The custom selection outline or null if use default one.</param>
public void OverrideSelectionOutline(SelectionOutline customSelectionOutline)
{
if (Task == null)
return;
if (_customSelectionOutline != null)
{
Task.RemoveCustomPostFx(_customSelectionOutline);
Object.Destroy(ref _customSelectionOutline);
Task.AddCustomPostFx(customSelectionOutline ? customSelectionOutline : SelectionOutline);
}
else if (customSelectionOutline != null)
@@ -857,8 +865,8 @@ namespace FlaxEditor.Viewport
if (_task != null)
{
// Release if task is not used to save screenshot for project icon
ReleaseTaskResources();
Object.Destroy(ref _task);
ReleaseResources();
}
base.OnDestroy();
@@ -874,6 +882,7 @@ namespace FlaxEditor.Viewport
_savedTask = _task;
_savedBackBuffer = _backBuffer;
ReleaseTaskResources();
_task = null;
_backBuffer = null;
}
@@ -884,20 +893,20 @@ namespace FlaxEditor.Viewport
{
_savedTask.Enabled = false;
Object.Destroy(_savedTask);
ReleaseResources();
ReleaseTaskResources();
_savedTask = null;
}
Object.Destroy(ref _savedBackBuffer);
}
private void ReleaseResources()
private void ReleaseTaskResources()
{
if (Task)
if (_task)
{
Task.RemoveCustomPostFx(SelectionOutline);
Task.RemoveCustomPostFx(EditorPrimitives);
Task.RemoveCustomPostFx(_editorSpritesRenderer);
Task.RemoveCustomPostFx(_customSelectionOutline);
_task.RemoveCustomPostFx(SelectionOutline);
_task.RemoveCustomPostFx(EditorPrimitives);
_task.RemoveCustomPostFx(_editorSpritesRenderer);
_task.RemoveCustomPostFx(_customSelectionOutline);
}
Object.Destroy(ref SelectionOutline);
Object.Destroy(ref EditorPrimitives);
+9 -5
View File
@@ -29,7 +29,7 @@
#include <ThirdParty/LZ4/lz4.h>
#define FOLIAGE_GET_DRAW_MODES(renderContext, type) (type._drawModes & renderContext.View.Pass & renderContext.View.GetShadowsDrawPassMask(type.ShadowsMode))
#define FOLIAGE_CAN_DRAW(renderContext, type) (type.IsReady() && FOLIAGE_GET_DRAW_MODES(renderContext, type) != DrawPass::None && type.Model->CanBeRendered())
#define FOLIAGE_CAN_DRAW(renderContext, type) (type.IsReady() && type._canDraw && FOLIAGE_GET_DRAW_MODES(renderContext, type) != DrawPass::None && type.Model->CanBeRendered())
Foliage::Foliage(const SpawnParams& params)
: Actor(params)
@@ -620,14 +620,18 @@ void Foliage::PreDraw(const RenderView& view)
}
// Cache data per foliage instance type
for (FoliageType& type : FoliageTypes)
InitType(view, type);
for (int32 i = 0; i < FoliageTypes.Count(); i++)
InitType(view, i);
}
void Foliage::InitType(const RenderView& view, FoliageType& type)
void Foliage::InitType(const RenderView& view, int32 typeIndex)
{
FoliageType& type = FoliageTypes[typeIndex];
const DrawPass drawModes = type._drawModes & view.Pass & view.GetShadowsDrawPassMask(type.ShadowsMode);
type._canDraw = type.IsReady() && drawModes != DrawPass::None && type.Model && type.Model->CanBeRendered();
#if USE_EDITOR
type._canDraw &= _drawFoliageType == -1 || _drawFoliageType == typeIndex;
#endif
bool drawModesDirty = false;
for (int32 j = 0; j < type.Entries.Count(); j++)
{
@@ -1286,7 +1290,7 @@ void Foliage::Draw(RenderContext& renderContext)
// Draw single foliage instance projection into Global Surface Atlas
auto& instance = *(FoliageInstance*)GlobalSurfaceAtlasPass::Instance()->GetCurrentActorObject();
auto& type = FoliageTypes[instance.Type];
InitType(renderContext.View, type);
InitType(renderContext.View, instance.Type);
Matrix world;
const Transform transform = _transform.LocalToWorld(instance.Transform);
renderContext.View.GetWorldMatrix(transform, world);
+7 -1
View File
@@ -217,7 +217,7 @@ private:
#endif
void PreDraw(const RenderView& view);
void InitType(const RenderView& view, FoliageType& type);
void InitType(const RenderView& view, int32 typeIndex);
void UpdateBounds();
public:
@@ -231,6 +231,12 @@ public:
/// <returns>True whether the two objects intersected, otherwise false.</returns>
API_FUNCTION() bool Intersects(API_PARAM(Ref) const Ray& ray, API_PARAM(Out) Real& distance, API_PARAM(Out) Vector3& normal, API_PARAM(Out) int32& instanceIndex);
private:
#if USE_EDITOR
// Debug filter to draw only specific foliage type (in editor).
API_FIELD(Internal) int32 _drawFoliageType = -1;
#endif
public:
// [Actor]
void Draw(RenderContext& renderContext) override;