Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editor mirror tiles layer #21317

Merged
merged 1 commit into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
56 changes: 56 additions & 0 deletions OpenRA.Game/Graphics/MarkerTileRenderable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#region Copyright & License Information
/*
* Copyright (c) The OpenRA Developers and Contributors
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion

using System.Linq;
using OpenRA.Primitives;

namespace OpenRA.Graphics
{
public class MarkerTileRenderable : IRenderable, IFinalizedRenderable
{
readonly CPos pos;
readonly Color color;

public MarkerTileRenderable(CPos pos, Color color)
{
this.pos = pos;
this.color = color;
}

public WPos Pos => WPos.Zero;
public int ZOffset => 0;
public bool IsDecoration => true;

public IRenderable WithZOffset(int newOffset) { return this; }

public IRenderable OffsetBy(in WVec vec)
{
return new MarkerTileRenderable(pos, color);
}

public IRenderable AsDecoration() { return this; }

public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; }
public void Render(WorldRenderer wr)
{
var map = wr.World.Map;
var r = map.Grid.Ramps[map.Ramp[pos]];
var wpos = map.CenterOfCell(pos) - new WVec(0, 0, r.CenterHeightOffset);

var corners = r.Corners.Select(corner => wr.Viewport.WorldToViewPx(wr.Screen3DPosition(wpos + corner))).ToList();

Game.Renderer.RgbaColorRenderer.FillRect(corners[0], corners[1], corners[2], corners[3], color);
}

public void RenderDebugGeometry(WorldRenderer wr) { }
public Rectangle ScreenBounds(WorldRenderer wr) { return Rectangle.Empty; }
}
}
234 changes: 234 additions & 0 deletions OpenRA.Mods.Common/EditorBrushes/EditorMarkerLayerBrush.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
#region Copyright & License Information
/*
* Copyright (c) The OpenRA Developers and Contributors
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion

using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;

namespace OpenRA.Mods.Common.Widgets
{
public sealed class EditorMarkerLayerBrush : IEditorBrush
{
public int? Template;

readonly WorldRenderer worldRenderer;
readonly World world;
readonly EditorActionManager editorActionManager;
readonly MarkerLayerOverlay markerLayerOverlay;
readonly EditorViewportControllerWidget editorWidget;

PaintMarkerTileEditorAction action;
bool painting;

public EditorMarkerLayerBrush(EditorViewportControllerWidget editorWidget, int? id, WorldRenderer wr)
{
this.editorWidget = editorWidget;
worldRenderer = wr;
world = wr.World;

editorActionManager = world.WorldActor.Trait<EditorActionManager>();
markerLayerOverlay = world.WorldActor.Trait<MarkerLayerOverlay>();

Template = id;
worldRenderer = wr;
world = wr.World;
action = new PaintMarkerTileEditorAction(Template, markerLayerOverlay);
}

public bool HandleMouseInput(MouseInput mi)
{
if (mi.Button != MouseButton.Left && mi.Button != MouseButton.Right)
return false;

if (mi.Button == MouseButton.Right)
{
if (mi.Event == MouseInputEvent.Up)
{
editorWidget.ClearBrush();
return true;
}

return false;
}

var cell = worldRenderer.Viewport.ViewToWorld(mi.Location);

if (mi.Button == MouseButton.Left && mi.Event != MouseInputEvent.Up)
{
action.Add(cell);
painting = true;
}
else if (painting && mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Up)
{
if (action.DidPaintTiles)
editorActionManager.Add(action);

action = new PaintMarkerTileEditorAction(Template, markerLayerOverlay);
painting = false;
}

return true;
}

public void Tick() { }

public void Dispose() { }
}

readonly struct PaintMarkerTile
{
public readonly CPos Cell;
public readonly int? Previous;

public PaintMarkerTile(CPos cell, int? previous)
{
Cell = cell;
Previous = previous;
}
}

class PaintMarkerTileEditorAction : IEditorAction
{
[TranslationReference("amount", "type")]
const string AddedMarkerTiles = "notification-added-marker-tiles";

[TranslationReference("amount")]
const string RemovedMarkerTiles = "notification-removed-marker-tiles";

public string Text { get; private set; }

readonly int? type;
readonly MarkerLayerOverlay markerLayerOverlay;

readonly List<PaintMarkerTile> paintTiles = new();

public bool DidPaintTiles => paintTiles.Count > 0;

public PaintMarkerTileEditorAction(
int? type,
MarkerLayerOverlay markerLayerOverlay)
{
this.markerLayerOverlay = markerLayerOverlay;
this.type = type;
}

public void Execute()
{
}

public void Do()
{
foreach (var paintTile in paintTiles)
markerLayerOverlay.SetTile(paintTile.Cell, type);
}

public void Undo()
{
foreach (var paintTile in paintTiles)
markerLayerOverlay.SetTile(paintTile.Cell, paintTile.Previous);
}

public void Add(CPos target)
{
foreach (var cell in markerLayerOverlay.CalculateMirrorPositions(target))
{
var existing = markerLayerOverlay.CellLayer[cell];
if (existing == type)
continue;

paintTiles.Add(new PaintMarkerTile(cell, existing));
markerLayerOverlay.SetTile(cell, type);
}

if (type != null)
Text = TranslationProvider.GetString(AddedMarkerTiles, Translation.Arguments("amount", paintTiles.Count, "type", type));
else
Text = TranslationProvider.GetString(RemovedMarkerTiles, Translation.Arguments("amount", paintTiles.Count));
}
}

class ClearSelectedMarkerTilesEditorAction : IEditorAction
{
[TranslationReference("amount", "type")]
const string ClearedSelectedMarkerTiles = "notification-cleared-selected-marker-tiles";

public string Text { get; }

readonly MarkerLayerOverlay markerLayerOverlay;
readonly HashSet<CPos> tiles;
readonly int tile;

public ClearSelectedMarkerTilesEditorAction(
int tile,
MarkerLayerOverlay markerLayerOverlay)
{
this.tile = tile;
this.markerLayerOverlay = markerLayerOverlay;

tiles = new HashSet<CPos>(markerLayerOverlay.Tiles[tile]);

Text = TranslationProvider.GetString(ClearedSelectedMarkerTiles, Translation.Arguments("amount", tiles.Count, "type", tile));
}

public void Execute()
{
Do();
}

public void Do()
{
markerLayerOverlay.ClearSelected(tile);
}

public void Undo()
{
markerLayerOverlay.SetSelected(tile, tiles);
}
}

class ClearAllMarkerTilesEditorAction : IEditorAction
{
[TranslationReference("amount")]
const string ClearedAllMarkerTiles = "notification-cleared-all-marker-tiles";

public string Text { get; }

readonly MarkerLayerOverlay markerLayerOverlay;
readonly Dictionary<int, HashSet<CPos>> tiles;

public ClearAllMarkerTilesEditorAction(
MarkerLayerOverlay markerLayerOverlay)
{
this.markerLayerOverlay = markerLayerOverlay;
tiles = new Dictionary<int, HashSet<CPos>>(markerLayerOverlay.Tiles);

var allTilesCount = tiles.Values.Select(x => x.Count).Sum();

Text = TranslationProvider.GetString(ClearedAllMarkerTiles, Translation.Arguments("amount", allTilesCount));
}

public void Execute()
{
Do();
}

public void Do()
{
markerLayerOverlay.ClearAll();
}

public void Undo()
{
markerLayerOverlay.SetAll(tiles);
}
}
}