|
|
@ -66,119 +66,69 @@ public partial class TerrainEditingControls |
|
|
|
new Vector2(tile.X + 0.5f, tile.Y + 0.5f)) < distanceSqr); |
|
|
|
new Vector2(tile.X + 0.5f, tile.Y + 0.5f)) < distanceSqr); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
UpdateEditToolMesh(terrain, ToolShape switch { |
|
|
|
var tiles = (ToolShape switch { |
|
|
|
// TODO: Edit corner, not full tile. |
|
|
|
// TODO: Edit corner, not full tile. |
|
|
|
ToolShape.Corner => [tile], |
|
|
|
ToolShape.Corner => [tile], |
|
|
|
ToolShape.Circle => GetTilesInRadius(), |
|
|
|
ToolShape.Circle => GetTilesInRadius(), |
|
|
|
ToolShape.Square => GetTilesInSquare(), |
|
|
|
ToolShape.Square => GetTilesInSquare(), |
|
|
|
_ => throw new InvalidOperationException(), |
|
|
|
_ => throw new InvalidOperationException(), |
|
|
|
}); |
|
|
|
}).ToHashSet(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: Handle different tool modes, such as painting. |
|
|
|
|
|
|
|
// TODO: Add a flatten tool mode: Flattens everything selected to nearest corner height. |
|
|
|
|
|
|
|
// TODO: Allow click-dragging which doesn't affect already changed tiles / corners. |
|
|
|
|
|
|
|
// TODO: Support undo and redo. |
|
|
|
|
|
|
|
// TODO: Support "disconnected" mode which can create vertical cliffs. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Raise / lower the terrain if left / right mouse button is pressed. |
|
|
|
|
|
|
|
if ((mouse is InputEventMouseButton { ButtonIndex: var button, Pressed: true }) |
|
|
|
|
|
|
|
&& (button is MouseButton.Left or MouseButton.Right)) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
GetViewport().SetInputAsHandled(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const float AdjustHeight = 0.5f; |
|
|
|
|
|
|
|
var amount = (button == MouseButton.Left) |
|
|
|
|
|
|
|
? AdjustHeight : -AdjustHeight; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Find corners that are "connected" and should be raised. |
|
|
|
|
|
|
|
var corners = new HashSet<(TilePos Position, Corner Corner)>(); |
|
|
|
|
|
|
|
foreach (var pos in tiles) { |
|
|
|
|
|
|
|
var tile2 = terrain.GetTile(pos); |
|
|
|
|
|
|
|
foreach (var corner2 in Enum.GetValues<Corner>()) { |
|
|
|
|
|
|
|
var height = tile2.Height[corner2]; |
|
|
|
|
|
|
|
foreach (var (neighborPos, neighborCorner) in GetNeighbors(pos, corner2)) { |
|
|
|
|
|
|
|
if (tiles.Contains(neighborPos)) continue; |
|
|
|
|
|
|
|
var neighborHeight = terrain.GetTile(neighborPos).Height[neighborCorner]; |
|
|
|
|
|
|
|
if (neighborHeight == height) corners.Add((neighborPos, neighborCorner)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Raise connected corners. |
|
|
|
|
|
|
|
foreach (var group in corners.GroupBy(e => e.Position, e => e.Corner)) { |
|
|
|
|
|
|
|
var pos = group.Key; |
|
|
|
|
|
|
|
var tile2 = terrain.GetTile(pos); |
|
|
|
|
|
|
|
foreach (var corner2 in group) |
|
|
|
|
|
|
|
tile2.Height[corner2] += amount; |
|
|
|
|
|
|
|
terrain.SetTile(pos, tile2); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Raise selected tiles themselves. |
|
|
|
|
|
|
|
foreach (var pos in tiles) { |
|
|
|
|
|
|
|
var tile2 = terrain.GetTile(pos); |
|
|
|
|
|
|
|
tile2.Height.Adjust(amount); |
|
|
|
|
|
|
|
terrain.SetTile(pos, tile2); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
terrain.UpdateMeshAndShape(); |
|
|
|
|
|
|
|
terrain.NotifyPropertyListChanged(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UpdateEditToolMesh(terrain, tiles); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
ClearEditToolMesh(); |
|
|
|
ClearEditToolMesh(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// if (_isSelecting && (ev is InputEventMouseButton { ButtonIndex: MouseButton.Left, Pressed: false })) { |
|
|
|
|
|
|
|
// _isSelecting = false; |
|
|
|
|
|
|
|
// GetViewport().SetInputAsHandled(); |
|
|
|
|
|
|
|
// return; |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if ((ev is InputEventMouseButton { ButtonIndex: var wheel, Pressed: var pressed, ShiftPressed: true }) |
|
|
|
|
|
|
|
// && (wheel is MouseButton.WheelUp or MouseButton.WheelDown) && (_selection != null)) |
|
|
|
|
|
|
|
// { |
|
|
|
|
|
|
|
// // NOTE: Potential bug in the Godot editor? |
|
|
|
|
|
|
|
// // Does it zoom both when mouse wheel is "pressed" and "released"? |
|
|
|
|
|
|
|
// // Because just cancelling one of them still causes zooming to occur. |
|
|
|
|
|
|
|
// GetViewport().SetInputAsHandled(); |
|
|
|
|
|
|
|
// if (!pressed) return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// const float AdjustHeight = 0.5f; |
|
|
|
|
|
|
|
// var amount = (wheel == MouseButton.WheelUp) |
|
|
|
|
|
|
|
// ? AdjustHeight : -AdjustHeight; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// var selection = TileRegion.From(_selection.Value); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // Raise connected corners. |
|
|
|
|
|
|
|
// foreach (var innerCorner in Enum.GetValues<Corner>()) { |
|
|
|
|
|
|
|
// var outerCorner = innerCorner.GetOpposite(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// var innerPos = selection.GetTileFor(innerCorner); |
|
|
|
|
|
|
|
// var outerPos = innerPos.GetNeighbor(innerCorner); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// var outerTile = terrain.GetTile(outerPos); |
|
|
|
|
|
|
|
// var innerHeight = terrain.GetTile(innerPos).Height[innerCorner]; |
|
|
|
|
|
|
|
// var outerHeight = outerTile.Height[outerCorner]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if (IsEqualApprox(outerHeight, innerHeight)) { |
|
|
|
|
|
|
|
// outerTile.Height[outerCorner] = innerHeight + amount; |
|
|
|
|
|
|
|
// terrain.SetTile(outerPos, outerTile); |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // Raise connected sides. |
|
|
|
|
|
|
|
// foreach (var side in Enum.GetValues<Side>()) { |
|
|
|
|
|
|
|
// foreach (var innerPos in selection.GetTilesFor(side)) { |
|
|
|
|
|
|
|
// var outerPos = innerPos.GetNeighbor(side); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// var innerTile = terrain.GetTile(innerPos); |
|
|
|
|
|
|
|
// var outerTile = terrain.GetTile(outerPos); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// var (innerCorner1, innerCorner2) = side.GetCorners(); |
|
|
|
|
|
|
|
// var (outerCorner1, outerCorner2) = side.GetOpposite().GetCorners(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// var changed = false; |
|
|
|
|
|
|
|
// var matchingCorners = new[]{ (innerCorner1, outerCorner1), (innerCorner2, outerCorner2) }; |
|
|
|
|
|
|
|
// foreach (var (innerCorner, outerCorner) in matchingCorners) { |
|
|
|
|
|
|
|
// var innerHeight = innerTile.Height[innerCorner]; |
|
|
|
|
|
|
|
// var outerHeight = outerTile.Height[outerCorner]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if (IsEqualApprox(outerHeight, innerHeight)) { |
|
|
|
|
|
|
|
// outerTile.Height[outerCorner] = innerHeight + amount; |
|
|
|
|
|
|
|
// changed = true; |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
// if (changed) terrain.SetTile(outerPos, outerTile); |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // Raise selected tiles themselves. |
|
|
|
|
|
|
|
// foreach (var pos in selection.GetAllTiles()) { |
|
|
|
|
|
|
|
// var tile = terrain.GetTile(pos); |
|
|
|
|
|
|
|
// tile.Height.Adjust(amount); |
|
|
|
|
|
|
|
// terrain.SetTile(pos, tile); |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// terrain.UpdateMeshAndShape(); |
|
|
|
|
|
|
|
// terrain.NotifyPropertyListChanged(); |
|
|
|
|
|
|
|
// return; |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if ((ev is InputEventMouseButton { ButtonIndex: var wheel2, Pressed: var pressed2, CtrlPressed: true }) |
|
|
|
|
|
|
|
// && (wheel2 is MouseButton.WheelUp or MouseButton.WheelDown) && (_selection != null)) |
|
|
|
|
|
|
|
// { |
|
|
|
|
|
|
|
// GetViewport().SetInputAsHandled(); |
|
|
|
|
|
|
|
// if (!pressed2) return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// var amount = (wheel2 == MouseButton.WheelUp) ? 1 : -1; |
|
|
|
|
|
|
|
// var selection = TileRegion.From(_selection.Value); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// foreach (var pos in selection.GetAllTiles()) { |
|
|
|
|
|
|
|
// var tile = terrain.GetTile(pos); |
|
|
|
|
|
|
|
// tile.TexturePrimary = PosMod(tile.TexturePrimary + amount, 4); |
|
|
|
|
|
|
|
// terrain.SetTile(pos, tile); |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// terrain.UpdateMeshAndShape(); |
|
|
|
|
|
|
|
// terrain.NotifyPropertyListChanged(); |
|
|
|
|
|
|
|
// return; |
|
|
|
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if (ev is InputEventMouseMotion) |
|
|
|
|
|
|
|
// _unhandledMotion = true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if ((ev is InputEventMouse mouse) && viewport.GetVisibleRect().HasPoint(mouse.Position)) |
|
|
|
|
|
|
|
// OnInputRayCastTerrain(terrain, mouse); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void UpdateEditToolMesh(Terrain terrain, IEnumerable<TilePos> tiles) |
|
|
|
void UpdateEditToolMesh(Terrain terrain, IEnumerable<TilePos> tiles) |
|
|
@ -255,4 +205,13 @@ public partial class TerrainEditingControls |
|
|
|
|
|
|
|
|
|
|
|
return (tile, corner); |
|
|
|
return (tile, corner); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static readonly Dictionary<Corner, (int X, int Y, Corner Opposite)[]> _offsetLookup = new(){ |
|
|
|
|
|
|
|
[Corner.TopLeft ] = [(-1, -1, Corner.BottomRight), (-1, 0, Corner.TopRight ), (0, -1, Corner.BottomLeft )], |
|
|
|
|
|
|
|
[Corner.TopRight ] = [(+1, -1, Corner.BottomLeft ), (+1, 0, Corner.TopLeft ), (0, -1, Corner.BottomRight)], |
|
|
|
|
|
|
|
[Corner.BottomRight] = [(+1, +1, Corner.TopLeft ), (+1, 0, Corner.BottomLeft ), (0, +1, Corner.TopRight )], |
|
|
|
|
|
|
|
[Corner.BottomLeft ] = [(-1, +1, Corner.TopRight ), (-1, 0, Corner.BottomRight), (0, +1, Corner.TopLeft )], |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
static IEnumerable<(TilePos, Corner)> GetNeighbors(TilePos pos, Corner corner) |
|
|
|
|
|
|
|
=> _offsetLookup[corner].Select(e => (new TilePos(pos.X + e.X, pos.Y + e.Y), e.Opposite)); |
|
|
|
} |
|
|
|
} |
|
|
|