You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
3.9 KiB
134 lines
3.9 KiB
2 months ago
|
[Tool]
|
||
|
public partial class Terrain
|
||
|
{
|
||
|
bool _unhandledMouseMotion = false; // Used to detect when mouse moves off the terrain.
|
||
|
Vector2I? _tileHover = null; // Position of currently hovered tile.
|
||
|
bool _isSelecting = false; // Whether left mouse is held down to select tiles.
|
||
|
(Vector2I Start, Vector2I End)? _selection = null;
|
||
|
|
||
|
public override void _Input(InputEvent ev)
|
||
|
{
|
||
|
if (!IsEditing()) return;
|
||
|
|
||
|
if (_isSelecting && ev is InputEventMouseButton { ButtonIndex: MouseButton.Left, Pressed: false }) {
|
||
|
_isSelecting = false;
|
||
|
GetViewport().SetInputAsHandled();
|
||
|
}
|
||
|
|
||
|
if ((ev is InputEventMouseButton { ButtonIndex: var wheel, ShiftPressed: true })
|
||
|
&& (wheel is MouseButton.WheelUp or MouseButton.WheelDown))
|
||
|
{
|
||
|
const float AdjustHeight = 0.5f;
|
||
|
var value = (wheel == MouseButton.WheelUp) ? 1.0f : -1.0f;
|
||
|
foreach (var tile in GetSelectedTiles())
|
||
|
AdjustTileHeight(tile, value * AdjustHeight);
|
||
|
if (_selection != null)
|
||
|
UpdateMeshAndShape();
|
||
|
NotifyPropertyListChanged();
|
||
|
GetViewport().SetInputAsHandled();
|
||
|
}
|
||
|
|
||
|
if (ev is InputEventMouseMotion)
|
||
|
_unhandledMouseMotion = true;
|
||
|
}
|
||
|
|
||
|
public override void _InputEvent(Camera3D camera, InputEvent ev, Vector3 position, Vector3 normal, int shapeIdx)
|
||
|
{
|
||
|
if (!IsEditing()) return;
|
||
|
|
||
|
var localPos = ToLocal(position);
|
||
|
var tilePos = ToTilePos(localPos);
|
||
|
|
||
|
if (ev is InputEventMouseButton { ButtonIndex: MouseButton.Left, Pressed: true }) {
|
||
|
_selection = (tilePos, tilePos);
|
||
|
_isSelecting = true;
|
||
|
GetViewport().SetInputAsHandled();
|
||
|
}
|
||
|
|
||
|
if (ev is InputEventMouseMotion) {
|
||
|
_unhandledMouseMotion = false;
|
||
|
_tileHover = tilePos;
|
||
|
if (_isSelecting) _selection = _selection.Value with { End = tilePos };
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void _Process(double delta)
|
||
|
{
|
||
|
if (!IsEditing()) {
|
||
|
_tileHover = null;
|
||
|
_selection = null;
|
||
|
_isSelecting = false;
|
||
|
}
|
||
|
|
||
|
if (_unhandledMouseMotion)
|
||
|
_tileHover = null;
|
||
|
|
||
|
if ((_tileHover != null) || (_selection != null)) {
|
||
|
var mesh = GetOrCreateMesh("EditToolMesh");
|
||
|
mesh.ClearSurfaces();
|
||
|
mesh.SurfaceBegin(Mesh.PrimitiveType.Lines);
|
||
|
|
||
|
|
||
|
void AddLine(Vector3 start, Vector3 end) {
|
||
|
mesh.SurfaceAddVertex(start);
|
||
|
mesh.SurfaceAddVertex(end);
|
||
|
}
|
||
|
|
||
|
void AddQuad(Vector3 topLeft, Vector3 topRight,
|
||
|
Vector3 bottomLeft, Vector3 bottomRight) {
|
||
|
AddLine(topLeft , topRight );
|
||
|
AddLine(topRight , bottomRight);
|
||
|
AddLine(bottomRight, bottomLeft );
|
||
|
AddLine(bottomLeft , topLeft );
|
||
|
}
|
||
|
|
||
|
if (_tileHover is Vector2I hover) {
|
||
|
var corners = GetGridCorners(hover);
|
||
|
var margin = 0.1f;
|
||
|
mesh.SurfaceSetColor(Colors.Black);
|
||
|
AddQuad(
|
||
|
corners.TopLeft + new Vector3(-margin, 0, -margin),
|
||
|
corners.TopRight + new Vector3(+margin, 0, -margin),
|
||
|
corners.BottomLeft + new Vector3(-margin, 0, +margin),
|
||
|
corners.BottomRight + new Vector3(+margin, 0, +margin)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
mesh.SurfaceSetColor(Colors.Blue);
|
||
|
foreach (var tilePos in GetSelectedTiles()) {
|
||
|
var corners = GetGridCorners(tilePos);
|
||
|
AddQuad(corners.TopLeft, corners.TopRight, corners.BottomLeft, corners.BottomRight);
|
||
|
}
|
||
|
|
||
|
mesh.SurfaceEnd();
|
||
|
mesh.SurfaceSetMaterial(0, _editToolMaterial);
|
||
|
} else {
|
||
|
var meshInstance = (MeshInstance3D)GetNodeOrNull("EditToolMesh");
|
||
|
var mesh = (ImmediateMesh)meshInstance?.Mesh;
|
||
|
mesh?.ClearSurfaces();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool IsEditing()
|
||
|
{
|
||
|
if (Engine.IsEditorHint()) {
|
||
|
var selection = EditorInterface.Singleton.GetSelection();
|
||
|
return selection.GetSelectedNodes().Contains(this);
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
IEnumerable<Vector2I> GetSelectedTiles()
|
||
|
{
|
||
|
if (_selection is not (Vector2I start, Vector2I end)) yield break;
|
||
|
// Ensure start.X/Y is smaller than end.X/Y.
|
||
|
(start, end) = (new(Min(start.X, end.X), Min(start.Y, end.Y)),
|
||
|
new(Max(start.X, end.X), Max(start.Y, end.Y)));
|
||
|
// Go over all tiles in the range and yield each one.
|
||
|
for (var x = start.X; x <= end.X; x++)
|
||
|
for (var y = start.Y; y <= end.Y; y++)
|
||
|
yield return new(x, y);
|
||
|
}
|
||
|
}
|