diff --git a/OpenRA.Game/Map/Map.cs b/OpenRA.Game/Map/Map.cs index 52a0186f0b51..bc9912addb4b 100644 --- a/OpenRA.Game/Map/Map.cs +++ b/OpenRA.Game/Map/Map.cs @@ -824,6 +824,14 @@ public WDist DistanceAboveTerrain(WPos pos) return new WDist(delta.Z); } + public WVec Offset(CVec delta, int dz) + { + if (Grid.Type == MapGridType.Rectangular) + return new WVec(1024 * delta.X, 1024 * delta.Y, 0); + + return new WVec(724 * (delta.X - delta.Y), 724 * (delta.X + delta.Y), 724 * dz); + } + /// /// The size of the map Height step in world units /// diff --git a/OpenRA.Mods.Common/EditorBrushes/EditorResourceBrush.cs b/OpenRA.Mods.Common/EditorBrushes/EditorResourceBrush.cs index 8407327a13a5..b2a98414c045 100644 --- a/OpenRA.Mods.Common/EditorBrushes/EditorResourceBrush.cs +++ b/OpenRA.Mods.Common/EditorBrushes/EditorResourceBrush.cs @@ -10,7 +10,6 @@ #endregion using System.Collections.Generic; -using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; @@ -23,8 +22,9 @@ public sealed class EditorResourceBrush : IEditorBrush readonly WorldRenderer worldRenderer; readonly World world; readonly EditorViewportControllerWidget editorWidget; - readonly SpriteWidget preview; readonly EditorActionManager editorActionManager; + readonly EditorCursorLayer editorCursor; + readonly int cursorToken; AddResourcesEditorAction action; bool resourceAdded; @@ -36,21 +36,10 @@ public EditorResourceBrush(EditorViewportControllerWidget editorWidget, Resource worldRenderer = wr; world = wr.World; editorActionManager = world.WorldActor.Trait(); + editorCursor = world.WorldActor.Trait(); action = new AddResourcesEditorAction(world.Map, ResourceType); - preview = editorWidget.Get("DRAG_LAYER_PREVIEW"); - preview.Palette = resource.Palette; - preview.GetScale = () => worldRenderer.Viewport.Zoom; - preview.IsVisible = () => editorWidget.CurrentBrush == this; - - var variant = resource.Sequences.FirstOrDefault(); - var sequence = wr.World.Map.Rules.Sequences.GetSequence("resources", variant); - var sprite = sequence.GetSprite(resource.MaxDensity - 1); - preview.GetSprite = () => sprite; - - // The preview widget may be rendered by the higher-level code before it is ticked. - // Force a manual tick to ensure the bounds are set correctly for this first draw. - Tick(); + cursorToken = editorCursor.SetResource(wr, resource); } public bool HandleMouseInput(MouseInput mi) @@ -70,6 +59,9 @@ public bool HandleMouseInput(MouseInput mi) return false; } + if (editorCursor.CurrentToken != cursorToken) + return false; + var cell = worldRenderer.Viewport.ViewToWorld(mi.Location); if (mi.Button == MouseButton.Left && mi.Event != MouseInputEvent.Up && AllowResourceAt(cell)) @@ -111,20 +103,12 @@ public bool AllowResourceAt(CPos cell) return ResourceType.AllowOnRamps || tileInfo.RampType == 0; } - public void Tick() - { - var cell = worldRenderer.Viewport.ViewToWorld(Viewport.LastMousePos); - var offset = WVec.Zero; - var location = world.Map.CenterOfCell(cell) + offset; - - var cellScreenPosition = worldRenderer.ScreenPxPosition(location); - var cellScreenPixel = worldRenderer.Viewport.WorldToViewPx(cellScreenPosition); + public void Tick() { } - preview.Bounds.X = cellScreenPixel.X; - preview.Bounds.Y = cellScreenPixel.Y; + public void Dispose() + { + editorCursor.Clear(cursorToken); } - - public void Dispose() { } } struct CellResource diff --git a/OpenRA.Mods.Common/EditorBrushes/EditorTileBrush.cs b/OpenRA.Mods.Common/EditorBrushes/EditorTileBrush.cs index 31d908a38993..55631ff0c3c2 100644 --- a/OpenRA.Mods.Common/EditorBrushes/EditorTileBrush.cs +++ b/OpenRA.Mods.Common/EditorBrushes/EditorTileBrush.cs @@ -14,7 +14,6 @@ using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; -using OpenRA.Primitives; namespace OpenRA.Mods.Common.Widgets { @@ -25,32 +24,26 @@ public sealed class EditorTileBrush : IEditorBrush readonly WorldRenderer worldRenderer; readonly World world; readonly EditorViewportControllerWidget editorWidget; - readonly TerrainTemplatePreviewWidget preview; - readonly Rectangle bounds; readonly EditorActionManager editorActionManager; + readonly EditorCursorLayer editorCursor; + readonly int cursorToken; bool painting; - public EditorTileBrush(EditorViewportControllerWidget editorWidget, ushort template, WorldRenderer wr) + public EditorTileBrush(EditorViewportControllerWidget editorWidget, ushort id, WorldRenderer wr) { this.editorWidget = editorWidget; - Template = template; worldRenderer = wr; world = wr.World; - editorActionManager = world.WorldActor.Trait(); + editorCursor = world.WorldActor.Trait(); - preview = editorWidget.Get("DRAG_TILE_PREVIEW"); - preview.GetScale = () => worldRenderer.Viewport.Zoom; - preview.IsVisible = () => editorWidget.CurrentBrush == this; - - preview.Template = world.Map.Rules.TileSet.Templates.First(t => t.Value.Id == template).Value; - var grid = world.Map.Grid; - bounds = worldRenderer.Theater.TemplateBounds(preview.Template, grid.TileSize, grid.Type); + Template = id; + worldRenderer = wr; + world = wr.World; - // The preview widget may be rendered by the higher-level code before it is ticked. - // Force a manual tick to ensure the bounds are set correctly for this first draw. - Tick(); + var template = world.Map.Rules.TileSet.Templates.First(t => t.Value.Id == id).Value; + cursorToken = editorCursor.SetTerrainTemplate(wr, template); } public bool HandleMouseInput(MouseInput mi) @@ -84,6 +77,9 @@ public bool HandleMouseInput(MouseInput mi) if (mi.Event != MouseInputEvent.Down && mi.Event != MouseInputEvent.Move) return true; + if (editorCursor.CurrentToken != cursorToken) + return false; + var cell = worldRenderer.Viewport.ViewToWorld(mi.Location); var isMoving = mi.Event == MouseInputEvent.Move; @@ -205,23 +201,12 @@ bool PlacementOverlapsSameTemplate(TerrainTemplateInfo template, CPos cell) return false; } - public void Tick() + public void Tick() { } + + public void Dispose() { - var cell = worldRenderer.Viewport.ViewToWorld(Viewport.LastMousePos); - var offset = WVec.Zero; - var location = world.Map.CenterOfCell(cell) + offset; - - var cellScreenPosition = worldRenderer.ScreenPxPosition(location); - var cellScreenPixel = worldRenderer.Viewport.WorldToViewPx(cellScreenPosition); - var zoom = worldRenderer.Viewport.Zoom; - - preview.Bounds.X = cellScreenPixel.X + (int)(zoom * bounds.X); - preview.Bounds.Y = cellScreenPixel.Y + (int)(zoom * bounds.Y); - preview.Bounds.Width = (int)(zoom * bounds.Width); - preview.Bounds.Height = (int)(zoom * bounds.Height); + editorCursor.Clear(cursorToken); } - - public void Dispose() { } } class PaintTileEditorAction : IEditorAction diff --git a/OpenRA.Mods.Common/Traits/World/EditorCursorLayer.cs b/OpenRA.Mods.Common/Traits/World/EditorCursorLayer.cs index 0ec0aae54178..beaeeb963bdd 100644 --- a/OpenRA.Mods.Common/Traits/World/EditorCursorLayer.cs +++ b/OpenRA.Mods.Common/Traits/World/EditorCursorLayer.cs @@ -16,7 +16,7 @@ namespace OpenRA.Mods.Common.Traits { - public enum EditorCursorType { None, Actor } + public enum EditorCursorType { None, Actor, TerrainTemplate, Resource } [Desc("Required for the map editor to work. Attach this to the world actor.")] public class EditorCursorLayerInfo : ITraitInfo, Requires @@ -40,6 +40,12 @@ public class EditorCursorLayer : ITickRender, IRenderAboveShroud, IRenderAnnotat WVec actorCenterOffset; bool actorSharesCell; + public TerrainTemplateInfo TerrainTemplate { get; private set; } + public ResourceTypeInfo Resource { get; private set; } + CPos terrainOrResourceCell; + bool terrainOrResourceDirty; + readonly List terrainOrResourcePreview = new List(); + public EditorCursorLayer(Actor self, EditorCursorLayerInfo info) { this.info = info; @@ -54,7 +60,50 @@ void ITickRender.TickRender(WorldRenderer wr, Actor self) if (wr.World.Type != WorldType.Editor) return; - if (Actor != null) + if (Type == EditorCursorType.TerrainTemplate || Type == EditorCursorType.Resource) + { + var cell = wr.Viewport.ViewToWorld(Viewport.LastMousePos); + if (terrainOrResourceCell != cell || terrainOrResourceDirty) + { + terrainOrResourceCell = cell; + terrainOrResourceDirty = false; + terrainOrResourcePreview.Clear(); + var pos = world.Map.CenterOfCell(cell); + + if (Type == EditorCursorType.TerrainTemplate) + { + var i = 0; + for (var y = 0; y < TerrainTemplate.Size.Y; y++) + { + for (var x = 0; x < TerrainTemplate.Size.X; x++) + { + var tile = new TerrainTile(TerrainTemplate.Id, (byte)i++); + var tileInfo = world.Map.Rules.TileSet.GetTileInfo(tile); + + // Empty tile + if (tileInfo == null) + continue; + + var sprite = wr.Theater.TileSprite(tile, 0); + var offset = world.Map.Offset(new CVec(x, y), tileInfo.Height); + var palette = wr.Palette(TerrainTemplate.Palette ?? TileSet.TerrainPaletteInternalName); + + terrainOrResourcePreview.Add(new SpriteRenderable(sprite, pos, offset, 0, palette, 1, false)); + } + } + } + else + { + var variant = Resource.Sequences.FirstOrDefault(); + var sequence = wr.World.Map.Rules.Sequences.GetSequence("resources", variant); + var sprite = sequence.GetSprite(Resource.MaxDensity - 1); + var palette = wr.Palette(Resource.Palette); + + terrainOrResourcePreview.Add(new SpriteRenderable(sprite, pos, WVec.Zero, 0, palette, 1, false)); + } + } + } + else if (Type == EditorCursorType.Actor) { // Offset mouse position by the center offset (in world pixels) var worldPx = wr.Viewport.ViewToWorldPx(Viewport.LastMousePos) - wr.ScreenPxOffset(actorCenterOffset); @@ -99,6 +148,9 @@ IEnumerable IRenderAboveShroud.RenderAboveShroud(Actor self, WorldR if (wr.World.Type != WorldType.Editor) return NoRenderables; + if (Type == EditorCursorType.TerrainTemplate || Type == EditorCursorType.Resource) + return terrainOrResourcePreview; + if (Type == EditorCursorType.Actor) return Actor.Render().OrderBy(WorldRenderer.RenderableScreenZPositionComparisonKey); @@ -112,7 +164,7 @@ public IEnumerable RenderAnnotations(Actor self, WorldRenderer wr) if (wr.World.Type != WorldType.Editor) return NoRenderables; - return Actor != null ? Actor.RenderAnnotations() : NoRenderables; + return Type == EditorCursorType.Actor ? Actor.RenderAnnotations() : NoRenderables; } bool IRenderAnnotations.SpatiallyPartitionable { get { return false; } } @@ -154,6 +206,34 @@ public int SetActor(WorldRenderer wr, ActorInfo actor, PlayerReference owner) Type = EditorCursorType.Actor; Actor = new EditorActorPreview(wr, null, reference, owner); + TerrainTemplate = null; + Resource = null; + + return ++CurrentToken; + } + + public int SetTerrainTemplate(WorldRenderer wr, TerrainTemplateInfo template) + { + terrainOrResourceCell = wr.Viewport.ViewToWorld(wr.Viewport.WorldToViewPx(Viewport.LastMousePos)); + + Type = EditorCursorType.TerrainTemplate; + TerrainTemplate = template; + Actor = null; + Resource = null; + terrainOrResourceDirty = true; + + return ++CurrentToken; + } + + public int SetResource(WorldRenderer wr, ResourceTypeInfo resource) + { + terrainOrResourceCell = wr.Viewport.ViewToWorld(wr.Viewport.WorldToViewPx(Viewport.LastMousePos)); + + Type = EditorCursorType.Resource; + Resource = resource; + Actor = null; + TerrainTemplate = null; + terrainOrResourceDirty = true; return ++CurrentToken; } @@ -165,6 +245,8 @@ public void Clear(int token) Type = EditorCursorType.None; Actor = null; + TerrainTemplate = null; + Resource = null; } } } diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs index 51e13e2ae763..32953ab63cdc 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs @@ -20,6 +20,7 @@ public class LayerSelectorLogic : ChromeLogic { readonly EditorViewportControllerWidget editor; readonly WorldRenderer worldRenderer; + readonly EditorCursorLayer editorCursor; readonly ScrollPanelWidget layerTemplateList; readonly ScrollItemWidget layerPreviewTemplate; @@ -29,6 +30,7 @@ public LayerSelectorLogic(Widget widget, WorldRenderer worldRenderer) { this.worldRenderer = worldRenderer; editor = widget.Parent.Get("MAP_EDITOR"); + editorCursor = worldRenderer.World.WorldActor.Trait(); layerTemplateList = widget.Get("LAYERTEMPLATE_LIST"); layerTemplateList.Layout = new GridLayout(layerTemplateList); @@ -46,7 +48,7 @@ void IntializeLayerPreview(Widget widget) foreach (var resource in resources) { var newResourcePreviewTemplate = ScrollItemWidget.Setup(layerPreviewTemplate, - () => { var brush = editor.CurrentBrush as EditorResourceBrush; return brush != null && brush.ResourceType == resource; }, + () => editorCursor.Type == EditorCursorType.Resource && editorCursor.Resource == resource, () => editor.SetBrush(new EditorResourceBrush(editor, resource, worldRenderer))); newResourcePreviewTemplate.Bounds.X = 0; diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/TileSelectorLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/TileSelectorLogic.cs index 2e13243764bb..4551f3062d51 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/TileSelectorLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/TileSelectorLogic.cs @@ -12,6 +12,7 @@ using System; using System.Linq; using OpenRA.Graphics; +using OpenRA.Mods.Common.Traits; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic @@ -36,6 +37,7 @@ public TileSelectorTemplate(TerrainTemplateInfo template) readonly TileSet tileset; readonly TileSelectorTemplate[] allTemplates; + readonly EditorCursorLayer editorCursor; [ObjectCreator.UseCtor] public TileSelectorLogic(Widget widget, World world, WorldRenderer worldRenderer) @@ -43,6 +45,7 @@ public TileSelectorLogic(Widget widget, World world, WorldRenderer worldRenderer { tileset = world.Map.Rules.TileSet; allTemplates = tileset.Templates.Values.Select(t => new TileSelectorTemplate(t)).ToArray(); + editorCursor = world.WorldActor.Trait(); allCategories = allTemplates.SelectMany(t => t.Categories) .Distinct() @@ -98,7 +101,7 @@ protected override void InitializePreviews() var tileId = t.Template.Id; var item = ScrollItemWidget.Setup(ItemTemplate, - () => { var brush = Editor.CurrentBrush as EditorTileBrush; return brush != null && brush.Template == tileId; }, + () => editorCursor.Type == EditorCursorType.TerrainTemplate && editorCursor.TerrainTemplate.Id == tileId, () => Editor.SetBrush(new EditorTileBrush(Editor, tileId, WorldRenderer))); var preview = item.Get("TILE_PREVIEW"); diff --git a/mods/cnc/chrome/editor.yaml b/mods/cnc/chrome/editor.yaml index 08784ffd1338..6dc4924505fc 100644 --- a/mods/cnc/chrome/editor.yaml +++ b/mods/cnc/chrome/editor.yaml @@ -220,10 +220,6 @@ Container@EDITOR_WORLD_ROOT: TooltipContainer: TOOLTIP_CONTAINER TooltipTemplate: SIMPLE_TOOLTIP Children: - TerrainTemplatePreview@DRAG_TILE_PREVIEW: - Visible: false - Sprite@DRAG_LAYER_PREVIEW: - Visible: false Background@ACTOR_EDIT_PANEL: Background: panel-black Width: 269 diff --git a/mods/common/chrome/editor.yaml b/mods/common/chrome/editor.yaml index 7dc2958caf0b..3ac15a1ae5ce 100644 --- a/mods/common/chrome/editor.yaml +++ b/mods/common/chrome/editor.yaml @@ -211,10 +211,6 @@ Container@EDITOR_WORLD_ROOT: TooltipContainer: TOOLTIP_CONTAINER TooltipTemplate: SIMPLE_TOOLTIP Children: - TerrainTemplatePreview@DRAG_TILE_PREVIEW: - Visible: false - Sprite@DRAG_LAYER_PREVIEW: - Visible: false Background@ACTOR_EDIT_PANEL: X: 32 Y: 32