From 7e9d29122387898fe49989db057e2726cd0a54d5 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 7 Mar 2021 17:25:06 +0000 Subject: [PATCH] Add IResourceRenderer interface. --- .../EditorBrushes/EditorResourceBrush.cs | 4 +- OpenRA.Mods.Common/Traits/Harvester.cs | 2 +- .../Traits/World/EditorCursorLayer.cs | 25 +++--- .../Traits/World/ResourceRenderer.cs | 43 +++++++++- OpenRA.Mods.Common/TraitsInterfaces.cs | 10 +++ .../Logic/Editor/LayerSelectorLogic.cs | 43 +++++----- .../Widgets/Logic/Ingame/WorldTooltipLogic.cs | 2 +- .../Widgets/ResourcePreviewWidget.cs | 80 +++++++++++++++++++ .../Widgets/ViewportControllerWidget.cs | 12 +-- mods/cnc/chrome/editor.yaml | 2 +- mods/common/chrome/editor.yaml | 2 +- 11 files changed, 172 insertions(+), 53 deletions(-) create mode 100644 OpenRA.Mods.Common/Widgets/ResourcePreviewWidget.cs diff --git a/OpenRA.Mods.Common/EditorBrushes/EditorResourceBrush.cs b/OpenRA.Mods.Common/EditorBrushes/EditorResourceBrush.cs index 2a04c3da0e..525f83b726 100644 --- a/OpenRA.Mods.Common/EditorBrushes/EditorResourceBrush.cs +++ b/OpenRA.Mods.Common/EditorBrushes/EditorResourceBrush.cs @@ -29,10 +29,10 @@ namespace OpenRA.Mods.Common.Widgets AddResourcesEditorAction action; bool resourceAdded; - public EditorResourceBrush(EditorViewportControllerWidget editorWidget, ResourceTypeInfo resource, WorldRenderer wr) + public EditorResourceBrush(EditorViewportControllerWidget editorWidget, ResourceType resource, WorldRenderer wr) { this.editorWidget = editorWidget; - ResourceType = resource; + ResourceType = resource.Info; worldRenderer = wr; world = wr.World; editorActionManager = world.WorldActor.Trait(); diff --git a/OpenRA.Mods.Common/Traits/Harvester.cs b/OpenRA.Mods.Common/Traits/Harvester.cs index 17fa0e971d..885d0bb69f 100644 --- a/OpenRA.Mods.Common/Traits/Harvester.cs +++ b/OpenRA.Mods.Common/Traits/Harvester.cs @@ -386,7 +386,7 @@ namespace OpenRA.Mods.Common.Traits return false; var info = self.Info.TraitInfo(); - var res = self.World.WorldActor.TraitsImplementing() + var res = self.World.WorldActor.TraitsImplementing() .Select(r => r.GetRenderedResourceType(location)) .FirstOrDefault(r => r != null && info.Resources.Contains(r.Info.Type)); diff --git a/OpenRA.Mods.Common/Traits/World/EditorCursorLayer.cs b/OpenRA.Mods.Common/Traits/World/EditorCursorLayer.cs index 06119262fa..d585102c85 100644 --- a/OpenRA.Mods.Common/Traits/World/EditorCursorLayer.cs +++ b/OpenRA.Mods.Common/Traits/World/EditorCursorLayer.cs @@ -27,12 +27,13 @@ namespace OpenRA.Mods.Common.Traits public override object Create(ActorInitializer init) { return new EditorCursorLayer(init.Self, this); } } - public class EditorCursorLayer : ITickRender, IRenderAboveShroud, IRenderAnnotations + public class EditorCursorLayer : IWorldLoaded, ITickRender, IRenderAboveShroud, IRenderAnnotations { readonly EditorCursorLayerInfo info; readonly EditorActorLayer editorLayer; readonly ITiledTerrainRenderer terrainRenderer; readonly World world; + IResourceRenderer[] resourceRenderers; public int CurrentToken { get; private set; } public EditorCursorType Type { get; private set; } @@ -43,7 +44,7 @@ namespace OpenRA.Mods.Common.Traits bool actorSharesCell; public TerrainTemplateInfo TerrainTemplate { get; private set; } - public ResourceTypeInfo Resource { get; private set; } + public ResourceType Resource { get; private set; } CPos terrainOrResourceCell; bool terrainOrResourceDirty; readonly List terrainOrResourcePreview = new List(); @@ -58,6 +59,11 @@ namespace OpenRA.Mods.Common.Traits Type = EditorCursorType.None; } + void IWorldLoaded.WorldLoaded(World w, WorldRenderer wr) + { + resourceRenderers = w.WorldActor.TraitsImplementing().ToArray(); + } + void ITickRender.TickRender(WorldRenderer wr, Actor self) { if (wr.World.Type != WorldType.Editor) @@ -71,21 +77,12 @@ namespace OpenRA.Mods.Common.Traits terrainOrResourceCell = cell; terrainOrResourceDirty = false; terrainOrResourcePreview.Clear(); - var pos = world.Map.CenterOfCell(cell); + var pos = world.Map.CenterOfCell(cell); if (Type == EditorCursorType.TerrainTemplate) terrainOrResourcePreview.AddRange(terrainRenderer.RenderPreview(wr, TerrainTemplate, pos)); 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); - var alpha = sequence.GetAlpha(Resource.MaxDensity - 1); - - var tintModifiers = sequence.IgnoreWorldTint ? TintModifiers.IgnoreWorldTint : TintModifiers.None; - terrainOrResourcePreview.Add(new SpriteRenderable(sprite, pos, WVec.Zero, 0, palette, 1f, alpha, float3.Ones, tintModifiers, false)); - } + terrainOrResourcePreview.AddRange(resourceRenderers.SelectMany(r => r.RenderPreview(wr, Resource, pos))); } } else if (Type == EditorCursorType.Actor) @@ -202,7 +199,7 @@ namespace OpenRA.Mods.Common.Traits return ++CurrentToken; } - public int SetResource(WorldRenderer wr, ResourceTypeInfo resource) + public int SetResource(WorldRenderer wr, ResourceType resource) { terrainOrResourceCell = wr.Viewport.ViewToWorld(wr.Viewport.WorldToViewPx(Viewport.LastMousePos)); diff --git a/OpenRA.Mods.Common/Traits/World/ResourceRenderer.cs b/OpenRA.Mods.Common/Traits/World/ResourceRenderer.cs index edb2e16fd7..009e6c98d9 100644 --- a/OpenRA.Mods.Common/Traits/World/ResourceRenderer.cs +++ b/OpenRA.Mods.Common/Traits/World/ResourceRenderer.cs @@ -28,11 +28,12 @@ namespace OpenRA.Mods.Common.Traits public override object Create(ActorInitializer init) { return new ResourceRenderer(init.Self, this); } } - public class ResourceRenderer : IWorldLoaded, IRenderOverlay, ITickRender, INotifyActorDisposing + public class ResourceRenderer : IResourceRenderer, IWorldLoaded, IRenderOverlay, ITickRender, INotifyActorDisposing { protected readonly IResourceLayer ResourceLayer; protected readonly CellLayer RenderContent; protected readonly ResourceRendererInfo Info; + protected readonly World World; readonly HashSet dirty = new HashSet(); readonly Queue cleanDirty = new Queue(); @@ -42,7 +43,7 @@ namespace OpenRA.Mods.Common.Traits public ResourceRenderer(Actor self, ResourceRendererInfo info) { Info = info; - + World = self.World; ResourceLayer = self.Trait(); ResourceLayer.CellChanged += AddDirtyCell; @@ -198,7 +199,43 @@ namespace OpenRA.Mods.Common.Traits return t.Variants.Keys.Random(Game.CosmeticRandom); } - public ResourceType GetRenderedResourceType(CPos cell) { return RenderContent[cell].Type; } + protected virtual ResourceType GetRenderedResourceType(CPos cell) { return RenderContent[cell].Type; } + + protected virtual string GetRenderedResourceTooltip(CPos cell) { return RenderContent[cell].Type?.Info.Name; } + + IEnumerable IResourceRenderer.ResourceTypes => World.WorldActor.TraitsImplementing(); + + ResourceType IResourceRenderer.GetRenderedResourceType(CPos cell) { return GetRenderedResourceType(cell); } + + string IResourceRenderer.GetRenderedResourceTooltip(CPos cell) { return GetRenderedResourceTooltip(cell); } + + IEnumerable IResourceRenderer.RenderUIPreview(WorldRenderer wr, ResourceType resourceType, int2 origin, float scale) + { + var sequence = resourceType.Variants.First().Value; + var sprite = sequence.GetSprite(sequence.Length - 1); + var shadow = sequence.GetShadow(sequence.Length - 1, WAngle.Zero); + var palette = resourceType.Palette; + + if (shadow != null) + yield return new UISpriteRenderable(shadow, WPos.Zero, origin, 0, palette, scale); + + yield return new UISpriteRenderable(sprite, WPos.Zero, origin, 0, palette, scale); + } + + IEnumerable IResourceRenderer.RenderPreview(WorldRenderer wr, ResourceType resourceType, WPos origin) + { + var sequence = resourceType.Variants.First().Value; + var sprite = sequence.GetSprite(sequence.Length - 1); + var shadow = sequence.GetShadow(sequence.Length - 1, WAngle.Zero); + var alpha = sequence.GetAlpha(sequence.Length - 1); + var palette = resourceType.Palette; + var tintModifiers = sequence.IgnoreWorldTint ? TintModifiers.IgnoreWorldTint : TintModifiers.None; + + if (shadow != null) + yield return new SpriteRenderable(shadow, origin, WVec.Zero, 0, palette, sequence.Scale, alpha, float3.Ones, tintModifiers, false); + + yield return new SpriteRenderable(sprite, origin, WVec.Zero, 0, palette, sequence.Scale, alpha, float3.Ones, tintModifiers, false); + } public readonly struct RendererCellContents { diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs index 0c4be4a6b7..baf92b6d99 100644 --- a/OpenRA.Mods.Common/TraitsInterfaces.cs +++ b/OpenRA.Mods.Common/TraitsInterfaces.cs @@ -662,4 +662,14 @@ namespace OpenRA.Mods.Common.Traits IEnumerable RenderUIPreview(WorldRenderer wr, TerrainTemplateInfo template, int2 origin, float scale); IEnumerable RenderPreview(WorldRenderer wr, TerrainTemplateInfo template, WPos origin); } + + [RequireExplicitImplementation] + public interface IResourceRenderer + { + IEnumerable ResourceTypes { get; } + ResourceType GetRenderedResourceType(CPos cell); + string GetRenderedResourceTooltip(CPos cell); + IEnumerable RenderUIPreview(WorldRenderer wr, ResourceType resourceType, int2 origin, float scale); + IEnumerable RenderPreview(WorldRenderer wr, ResourceType resourceType, WPos origin); + } } diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs index 66e3d62064..7936890e80 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs @@ -43,35 +43,30 @@ namespace OpenRA.Mods.Common.Widgets.Logic { layerTemplateList.RemoveChildren(); var rules = worldRenderer.World.Map.Rules; - var resources = rules.Actors["world"].TraitInfos(); var tileSize = worldRenderer.World.Map.Grid.TileSize; - foreach (var resource in resources) + foreach (var resourceRenderer in worldRenderer.World.WorldActor.TraitsImplementing()) { - var newResourcePreviewTemplate = ScrollItemWidget.Setup(layerPreviewTemplate, - () => editorCursor.Type == EditorCursorType.Resource && editorCursor.Resource == resource, - () => editor.SetBrush(new EditorResourceBrush(editor, resource, worldRenderer))); + foreach (var resourceType in resourceRenderer.ResourceTypes) + { + var newResourcePreviewTemplate = ScrollItemWidget.Setup(layerPreviewTemplate, + () => editorCursor.Type == EditorCursorType.Resource && editorCursor.Resource == resourceType, + () => editor.SetBrush(new EditorResourceBrush(editor, resourceType, worldRenderer))); - newResourcePreviewTemplate.Bounds.X = 0; - newResourcePreviewTemplate.Bounds.Y = 0; + newResourcePreviewTemplate.Bounds.X = 0; + newResourcePreviewTemplate.Bounds.Y = 0; - var layerPreview = newResourcePreviewTemplate.Get("LAYER_PREVIEW"); - layerPreview.IsVisible = () => true; - layerPreview.GetPalette = () => resource.Palette; + var layerPreview = newResourcePreviewTemplate.Get("LAYER_PREVIEW"); + layerPreview.IsVisible = () => true; + layerPreview.ResourceType = resourceType; + layerPreview.Bounds.Width = tileSize.Width; + layerPreview.Bounds.Height = tileSize.Height; + newResourcePreviewTemplate.Bounds.Width = tileSize.Width + (layerPreview.Bounds.X * 2); + newResourcePreviewTemplate.Bounds.Height = tileSize.Height + (layerPreview.Bounds.Y * 2); + newResourcePreviewTemplate.IsVisible = () => true; + newResourcePreviewTemplate.GetTooltipText = () => resourceType.Info.Type; - var variant = resource.Sequences.FirstOrDefault(); - var sequence = rules.Sequences.GetSequence("resources", variant); - var frame = sequence.Frames?.Last() ?? resource.MaxDensity - 1; - layerPreview.GetSprite = () => sequence.GetSprite(frame); - - layerPreview.Bounds.Width = tileSize.Width; - layerPreview.Bounds.Height = tileSize.Height; - newResourcePreviewTemplate.Bounds.Width = tileSize.Width + (layerPreview.Bounds.X * 2); - newResourcePreviewTemplate.Bounds.Height = tileSize.Height + (layerPreview.Bounds.Y * 2); - - newResourcePreviewTemplate.IsVisible = () => true; - newResourcePreviewTemplate.GetTooltipText = () => resource.Type; - - layerTemplateList.AddChild(newResourcePreviewTemplate); + layerTemplateList.AddChild(newResourcePreviewTemplate); + } } } } diff --git a/OpenRA.Mods.Common/Widgets/Logic/Ingame/WorldTooltipLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Ingame/WorldTooltipLogic.cs index e4372d1a23..c44a2f0a4b 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Ingame/WorldTooltipLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Ingame/WorldTooltipLogic.cs @@ -57,7 +57,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic labelText = "Unrevealed Terrain"; break; case WorldTooltipType.Resource: - labelText = viewport.ResourceTooltip.Info.Name; + labelText = viewport.ResourceTooltip; break; case WorldTooltipType.Actor: { diff --git a/OpenRA.Mods.Common/Widgets/ResourcePreviewWidget.cs b/OpenRA.Mods.Common/Widgets/ResourcePreviewWidget.cs new file mode 100644 index 0000000000..4fb0e7ae74 --- /dev/null +++ b/OpenRA.Mods.Common/Widgets/ResourcePreviewWidget.cs @@ -0,0 +1,80 @@ +#region Copyright & License Information +/* + * Copyright 2007-2021 The OpenRA Developers (see AUTHORS) + * 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; +using System.IO; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Terrain; +using OpenRA.Mods.Common.Traits; +using OpenRA.Primitives; +using OpenRA.Widgets; + +namespace OpenRA.Mods.Common.Widgets +{ + public class ResourcePreviewWidget : Widget + { + public Func GetScale = () => 1f; + + readonly WorldRenderer worldRenderer; + readonly IResourceRenderer[] resourceRenderers; + readonly Size tileSize; + + ResourceType resourceType; + IResourceRenderer resourceRenderer; + + public ResourceType ResourceType + { + get => resourceType; + + set + { + resourceType = value; + if (resourceType != null) + resourceRenderer = resourceRenderers.FirstOrDefault(r => r.ResourceTypes.Contains(resourceType)); + else + resourceRenderer = null; + } + } + + [ObjectCreator.UseCtor] + public ResourcePreviewWidget(WorldRenderer worldRenderer, World world) + { + this.worldRenderer = worldRenderer; + resourceRenderers = world.WorldActor.TraitsImplementing().ToArray(); + tileSize = world.Map.Grid.TileSize; + } + + protected ResourcePreviewWidget(ResourcePreviewWidget other) + : base(other) + { + GetScale = other.GetScale; + worldRenderer = other.worldRenderer; + resourceRenderers = other.resourceRenderers; + tileSize = other.tileSize; + resourceType = other.resourceType; + resourceRenderer = other.resourceRenderer; + } + + public override Widget Clone() { return new ResourcePreviewWidget(this); } + + public override void Draw() + { + if (resourceRenderer == null) + return; + + var scale = GetScale(); + var origin = RenderOrigin + new int2((RenderBounds.Size.Width - tileSize.Width) / 2, (RenderBounds.Size.Height - tileSize.Height) / 2); + foreach (var r in resourceRenderer.RenderUIPreview(worldRenderer, resourceType, origin, scale)) + r.PrepareRender(worldRenderer).Render(worldRenderer); + } + } +} diff --git a/OpenRA.Mods.Common/Widgets/ViewportControllerWidget.cs b/OpenRA.Mods.Common/Widgets/ViewportControllerWidget.cs index c9d72f605f..09d67d66e3 100644 --- a/OpenRA.Mods.Common/Widgets/ViewportControllerWidget.cs +++ b/OpenRA.Mods.Common/Widgets/ViewportControllerWidget.cs @@ -25,7 +25,7 @@ namespace OpenRA.Mods.Common.Widgets public class ViewportControllerWidget : Widget { readonly ModData modData; - readonly IEnumerable resourceRenderers; + readonly IEnumerable resourceRenderers; public readonly HotkeyReference ZoomInKey = new HotkeyReference(); public readonly HotkeyReference ZoomOutKey = new HotkeyReference(); @@ -52,7 +52,7 @@ namespace OpenRA.Mods.Common.Widgets public ITooltip ActorTooltip { get; private set; } public IProvideTooltipInfo[] ActorTooltipExtra { get; private set; } public FrozenActor FrozenActorTooltip { get; private set; } - public ResourceType ResourceTooltip { get; private set; } + public string ResourceTooltip { get; private set; } static readonly Dictionary ScrollCursors = new Dictionary { @@ -145,7 +145,7 @@ namespace OpenRA.Mods.Common.Widgets tooltipContainer = Exts.Lazy(() => Ui.Root.Get(TooltipContainer)); - resourceRenderers = world.WorldActor.TraitsImplementing().ToArray(); + resourceRenderers = world.WorldActor.TraitsImplementing().ToArray(); } public override void Initialize(WidgetArgs args) @@ -269,11 +269,11 @@ namespace OpenRA.Mods.Common.Widgets foreach (var resourceRenderer in resourceRenderers) { - var resource = resourceRenderer.GetRenderedResourceType(cell); - if (resource != null) + var resourceTooltip = resourceRenderer.GetRenderedResourceTooltip(cell); + if (resourceTooltip != null) { TooltipType = WorldTooltipType.Resource; - ResourceTooltip = resource; + ResourceTooltip = resourceTooltip; break; } } diff --git a/mods/cnc/chrome/editor.yaml b/mods/cnc/chrome/editor.yaml index 63afc0b75c..a04b3bd126 100644 --- a/mods/cnc/chrome/editor.yaml +++ b/mods/cnc/chrome/editor.yaml @@ -444,7 +444,7 @@ Container@EDITOR_WORLD_ROOT: IgnoreChildMouseOver: true TooltipContainer: TOOLTIP_CONTAINER Children: - Sprite@LAYER_PREVIEW: + ResourcePreview@LAYER_PREVIEW: X: 4 Y: 4 Visible: false diff --git a/mods/common/chrome/editor.yaml b/mods/common/chrome/editor.yaml index fbfc994d07..2f90423a79 100644 --- a/mods/common/chrome/editor.yaml +++ b/mods/common/chrome/editor.yaml @@ -417,7 +417,7 @@ Container@EDITOR_WORLD_ROOT: IgnoreChildMouseOver: true TooltipContainer: TOOLTIP_CONTAINER Children: - Sprite@LAYER_PREVIEW: + ResourcePreview@LAYER_PREVIEW: X: 4 Y: 4 Visible: false