229 lines
7.2 KiB
C#
229 lines
7.2 KiB
C#
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
|
|
|
using System;
|
|
using FlaxEditor.GUI.Tabs;
|
|
using FlaxEditor.Modules;
|
|
using FlaxEditor.SceneGraph.Actors;
|
|
using FlaxEngine;
|
|
using FlaxEngine.GUI;
|
|
|
|
namespace FlaxEditor.Tools.Terrain
|
|
{
|
|
/// <summary>
|
|
/// Terrain carving tab. Supports different modes for terrain editing including: carving, painting and managing tools.
|
|
/// </summary>
|
|
/// <seealso cref="Tab" />
|
|
[HideInEditor]
|
|
public class CarveTab : Tab
|
|
{
|
|
private readonly Tabs _modes;
|
|
private readonly ContainerControl _noTerrainPanel;
|
|
private readonly Button _createTerrainButton;
|
|
|
|
/// <summary>
|
|
/// The editor instance.
|
|
/// </summary>
|
|
public readonly Editor Editor;
|
|
|
|
/// <summary>
|
|
/// The cached selected terrain. It's synchronized with <see cref="SceneEditingModule.Selection"/>.
|
|
/// </summary>
|
|
public FlaxEngine.Terrain SelectedTerrain;
|
|
|
|
/// <summary>
|
|
/// Occurs when selected terrain gets changed (to a different value).
|
|
/// </summary>
|
|
public event Action SelectedTerrainChanged;
|
|
|
|
/// <summary>
|
|
/// The sculpt tab;
|
|
/// </summary>
|
|
public SculptTab Sculpt;
|
|
|
|
/// <summary>
|
|
/// The paint tab;
|
|
/// </summary>
|
|
public PaintTab Paint;
|
|
|
|
/// <summary>
|
|
/// The edit tab;
|
|
/// </summary>
|
|
public EditTab Edit;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="CarveTab"/> class.
|
|
/// </summary>
|
|
/// <param name="icon">The icon.</param>
|
|
/// <param name="editor">The editor instance.</param>
|
|
public CarveTab(SpriteHandle icon, Editor editor)
|
|
: base(string.Empty, icon)
|
|
{
|
|
Level.SceneLoaded += OnSceneLoaded;
|
|
Editor = editor;
|
|
Editor.SceneEditing.SelectionChanged += OnSelectionChanged;
|
|
|
|
Selected += OnSelected;
|
|
|
|
_modes = new Tabs
|
|
{
|
|
Orientation = Orientation.Vertical,
|
|
UseScroll = true,
|
|
Offsets = Margin.Zero,
|
|
AnchorPreset = AnchorPresets.StretchAll,
|
|
TabsSize = new Float2(50, 32),
|
|
Parent = this
|
|
};
|
|
|
|
// Init tool modes
|
|
InitSculptMode();
|
|
InitPaintMode();
|
|
InitEditMode();
|
|
|
|
_modes.SelectedTabIndex = 0;
|
|
|
|
_noTerrainPanel = new ContainerControl
|
|
{
|
|
AnchorPreset = AnchorPresets.StretchAll,
|
|
Offsets = Margin.Zero,
|
|
BackgroundColor = Style.Current.Background,
|
|
Parent = this
|
|
};
|
|
var noTerrainLabel = new Label
|
|
{
|
|
Text = "Select terrain to edit\nor\n\n\n\n",
|
|
AnchorPreset = AnchorPresets.StretchAll,
|
|
Offsets = Margin.Zero,
|
|
Parent = _noTerrainPanel
|
|
};
|
|
|
|
var buttonText = "Create new terrain";
|
|
_createTerrainButton = new Button
|
|
{
|
|
Text = buttonText,
|
|
AnchorPreset = AnchorPresets.MiddleCenter,
|
|
Offsets = new Margin(-60, 120, -12, 24),
|
|
Parent = _noTerrainPanel,
|
|
Enabled = false
|
|
};
|
|
var textSize = Style.Current.FontMedium.MeasureText(buttonText);
|
|
if (_createTerrainButton.Width < textSize.X)
|
|
{
|
|
_createTerrainButton.LocalX -= (textSize.X - _createTerrainButton.Width) / 2;
|
|
_createTerrainButton.Width = textSize.X + 6;
|
|
}
|
|
|
|
_createTerrainButton.Clicked += OnCreateNewTerrainClicked;
|
|
OnSelectionChanged();
|
|
}
|
|
|
|
private void OnSceneLoaded(Scene arg1, Guid arg2)
|
|
{
|
|
_createTerrainButton.Enabled = true;
|
|
|
|
Level.SceneUnloaded += OnSceneUnloaded;
|
|
Level.SceneLoaded -= OnSceneLoaded;
|
|
}
|
|
|
|
private void OnSceneUnloaded(Scene arg1, Guid arg2)
|
|
{
|
|
_createTerrainButton.Enabled = false;
|
|
|
|
Level.SceneLoaded += OnSceneLoaded;
|
|
Level.SceneUnloaded -= OnSceneUnloaded;
|
|
}
|
|
|
|
private void OnSelected(Tab tab)
|
|
{
|
|
// Auto select first terrain actor to make usage easier
|
|
if (Editor.SceneEditing.SelectionCount == 1 && Editor.SceneEditing.Selection[0] is SceneGraph.ActorNode actorNode && actorNode.Actor is FlaxEngine.Terrain)
|
|
return;
|
|
var actor = Level.FindActor<FlaxEngine.Terrain>();
|
|
if (actor)
|
|
{
|
|
Editor.SceneEditing.Select(actor);
|
|
}
|
|
}
|
|
|
|
private void OnCreateNewTerrainClicked()
|
|
{
|
|
Editor.UI.CreateTerrain();
|
|
}
|
|
|
|
private void OnSelectionChanged()
|
|
{
|
|
var terrainNode = Editor.SceneEditing.SelectionCount > 0 ? Editor.SceneEditing.Selection[0] as TerrainNode : null;
|
|
var terrain = terrainNode?.Actor as FlaxEngine.Terrain;
|
|
if (terrain != SelectedTerrain)
|
|
{
|
|
SelectedTerrain = terrain;
|
|
SelectedTerrainChanged?.Invoke();
|
|
}
|
|
|
|
_noTerrainPanel.Visible = terrain == null;
|
|
_modes.Visible = !_noTerrainPanel.Visible;
|
|
}
|
|
|
|
private void InitSculptMode()
|
|
{
|
|
var tab = _modes.AddTab(Sculpt = new SculptTab(this, Editor.Windows.EditWin.Viewport.SculptTerrainGizmo));
|
|
tab.Selected += OnTabSelected;
|
|
}
|
|
|
|
private void InitPaintMode()
|
|
{
|
|
var tab = _modes.AddTab(Paint = new PaintTab(this, Editor.Windows.EditWin.Viewport.PaintTerrainGizmo));
|
|
tab.Selected += OnTabSelected;
|
|
}
|
|
|
|
private void InitEditMode()
|
|
{
|
|
var tab = _modes.AddTab(Edit = new EditTab(this, Editor.Windows.EditWin.Viewport.EditTerrainGizmo));
|
|
tab.Selected += OnTabSelected;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override void OnSelected()
|
|
{
|
|
base.OnSelected();
|
|
|
|
UpdateGizmoMode();
|
|
}
|
|
|
|
private void OnTabSelected(Tab tab)
|
|
{
|
|
UpdateGizmoMode();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the active viewport gizmo mode based on the current mode.
|
|
/// </summary>
|
|
private void UpdateGizmoMode()
|
|
{
|
|
switch (_modes.SelectedTabIndex)
|
|
{
|
|
case 0:
|
|
Editor.Windows.EditWin.Viewport.Gizmos.SetActiveMode<SculptTerrainGizmoMode>();
|
|
break;
|
|
case 1:
|
|
Editor.Windows.EditWin.Viewport.Gizmos.SetActiveMode<PaintTerrainGizmoMode>();
|
|
break;
|
|
case 2:
|
|
Editor.Windows.EditWin.Viewport.Gizmos.SetActiveMode<EditTerrainGizmoMode>();
|
|
break;
|
|
default: throw new IndexOutOfRangeException("Invalid carve tab mode.");
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override void OnDestroy()
|
|
{
|
|
if (_createTerrainButton.Enabled)
|
|
Level.SceneUnloaded -= OnSceneUnloaded;
|
|
else
|
|
Level.SceneLoaded -= OnSceneLoaded;
|
|
|
|
base.OnDestroy();
|
|
}
|
|
}
|
|
}
|