diff --git a/OpenRA.Game/Graphics/Viewport.cs b/OpenRA.Game/Graphics/Viewport.cs index b2b5b7ee4e..ab1221c0fb 100644 --- a/OpenRA.Game/Graphics/Viewport.cs +++ b/OpenRA.Game/Graphics/Viewport.cs @@ -227,14 +227,14 @@ namespace OpenRA.Graphics var vd = graphicSettings.ViewportDistance; if (viewportSizes.AllowNativeZoom && vd == WorldViewport.Native) - minZoom = 1; + minZoom = viewportSizes.DefaultScale; else { var range = viewportSizes.GetSizeRange(vd); - minZoom = CalculateMinimumZoom(range.X, range.Y); + minZoom = CalculateMinimumZoom(range.X, range.Y) * viewportSizes.DefaultScale; } - maxZoom = Math.Min(minZoom * viewportSizes.MaxZoomScale, Game.Renderer.NativeResolution.Height * 1f / viewportSizes.MaxZoomWindowHeight); + maxZoom = Math.Min(minZoom * viewportSizes.MaxZoomScale, Game.Renderer.NativeResolution.Height * viewportSizes.DefaultScale / viewportSizes.MaxZoomWindowHeight); if (unlockMinZoom) { diff --git a/OpenRA.Game/WorldViewportSizes.cs b/OpenRA.Game/WorldViewportSizes.cs index 0218591fa2..a8d421284a 100644 --- a/OpenRA.Game/WorldViewportSizes.cs +++ b/OpenRA.Game/WorldViewportSizes.cs @@ -19,6 +19,7 @@ namespace OpenRA public readonly int2 MediumWindowHeights = new int2(600, 900); public readonly int2 FarWindowHeights = new int2(900, 1300); + public readonly float DefaultScale = 1.0f; public readonly float MaxZoomScale = 2.0f; public readonly int MaxZoomWindowHeight = 240; public readonly bool AllowNativeZoom = true; diff --git a/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs b/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs index ab6f9b63ac..8fc926a065 100644 --- a/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs +++ b/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs @@ -177,10 +177,10 @@ namespace OpenRA.Mods.Common.Traits var sprite = tileCache.TileSprite(tile, 0); var u = gridType == MapGridType.Rectangular ? x : (x - y) / 2f; var v = gridType == MapGridType.Rectangular ? y : (x + y) / 2f; - var offset = (new float2(u * ts.Width, (v - 0.5f * tileInfo.Height) * ts.Height) - 0.5f * sprite.Size.XY).ToInt2(); + var offset = scale * (new float2(u * ts.Width, (v - 0.5f * tileInfo.Height) * ts.Height) - 0.5f * sprite.Size.XY); var palette = template.Palette ?? terrainInfo.Palette; - yield return new UISpriteRenderable(sprite, WPos.Zero, origin + offset, 0, wr.Palette(palette), scale); + yield return new UISpriteRenderable(sprite, WPos.Zero, origin + offset.ToInt2(), 0, wr.Palette(palette), scale); } } } diff --git a/OpenRA.Mods.Common/Widgets/ActorPreviewWidget.cs b/OpenRA.Mods.Common/Widgets/ActorPreviewWidget.cs index 01981b60d3..16823c18f1 100644 --- a/OpenRA.Mods.Common/Widgets/ActorPreviewWidget.cs +++ b/OpenRA.Mods.Common/Widgets/ActorPreviewWidget.cs @@ -25,14 +25,16 @@ namespace OpenRA.Mods.Common.Widgets public Func GetScale = () => 1f; readonly WorldRenderer worldRenderer; + readonly WorldViewportSizes viewportSizes; IActorPreview[] preview = Array.Empty(); public int2 PreviewOffset { get; private set; } public int2 IdealPreviewSize { get; private set; } [ObjectCreator.UseCtor] - public ActorPreviewWidget(WorldRenderer worldRenderer) + public ActorPreviewWidget(ModData modData, WorldRenderer worldRenderer) { + viewportSizes = modData.Manifest.Get(); this.worldRenderer = worldRenderer; } @@ -41,6 +43,7 @@ namespace OpenRA.Mods.Common.Widgets { preview = other.preview; worldRenderer = other.worldRenderer; + viewportSizes = other.viewportSizes; } public override Widget Clone() { return new ActorPreviewWidget(this); } @@ -55,14 +58,14 @@ namespace OpenRA.Mods.Common.Widgets // Calculate the preview bounds var r = preview.SelectMany(p => p.ScreenBounds(worldRenderer, WPos.Zero)); var b = r.Union(); - IdealPreviewSize = new int2(b.Width, b.Height); - PreviewOffset = -new int2(b.Left, b.Top) - IdealPreviewSize / 2; + IdealPreviewSize = new int2((int)(b.Width * viewportSizes.DefaultScale), (int)(b.Height * viewportSizes.DefaultScale)); + PreviewOffset = -new int2((int)(b.Left * viewportSizes.DefaultScale), (int)(b.Top * viewportSizes.DefaultScale)) - IdealPreviewSize / 2; } IFinalizedRenderable[] renderables; public override void PrepareRenderables() { - var scale = GetScale(); + var scale = GetScale() * viewportSizes.DefaultScale; var origin = RenderOrigin + PreviewOffset + new int2(RenderBounds.Size.Width / 2, RenderBounds.Size.Height / 2); renderables = preview diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs index 9029a73048..8073eac0bd 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/LayerSelectorLogic.cs @@ -41,8 +41,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic void IntializeLayerPreview() { layerTemplateList.RemoveChildren(); - var rules = worldRenderer.World.Map.Rules; - var tileSize = worldRenderer.World.Map.Grid.TileSize; foreach (var resourceRenderer in worldRenderer.World.WorldActor.TraitsImplementing()) { foreach (var resourceType in resourceRenderer.ResourceTypes) @@ -55,12 +53,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic newResourcePreviewTemplate.Bounds.Y = 0; var layerPreview = newResourcePreviewTemplate.Get("LAYER_PREVIEW"); + var size = layerPreview.IdealPreviewSize; 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); + layerPreview.Bounds.Width = size.Width; + layerPreview.Bounds.Height = size.Height; + newResourcePreviewTemplate.Bounds.Width = size.Width + (layerPreview.Bounds.X * 2); + newResourcePreviewTemplate.Bounds.Height = size.Height + (layerPreview.Bounds.Y * 2); newResourcePreviewTemplate.IsVisible = () => true; newResourcePreviewTemplate.GetTooltipText = () => resourceType; diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/TileSelectorLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/TileSelectorLogic.cs index 0e8b297a9c..97a589d710 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/TileSelectorLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/TileSelectorLogic.cs @@ -38,7 +38,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic } readonly ITemplatedTerrainInfo terrainInfo; - readonly ITiledTerrainRenderer terrainRenderer; readonly TileSelectorTemplate[] allTemplates; readonly EditorCursorLayer editorCursor; @@ -50,10 +49,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic if (terrainInfo == null) throw new InvalidDataException("TileSelectorLogic requires a template-based tileset."); - terrainRenderer = world.WorldActor.TraitOrDefault(); - if (terrainRenderer == null) - throw new InvalidDataException("TileSelectorLogic requires a tile-based terrain renderer."); - allTemplates = terrainInfo.Templates.Values.Select(t => new TileSelectorTemplate(t)).ToArray(); editorCursor = world.WorldActor.Trait(); @@ -115,18 +110,16 @@ namespace OpenRA.Mods.Common.Widgets.Logic () => Editor.SetBrush(new EditorTileBrush(Editor, tileId, WorldRenderer))); var preview = item.Get("TILE_PREVIEW"); - var template = terrainInfo.Templates[tileId]; - var bounds = terrainRenderer.TemplateBounds(template); + preview.SetTemplate(terrainInfo.Templates[tileId]); // Scale templates to fit within the panel var scale = 1f; - while (scale * bounds.Width > ItemTemplate.Bounds.Width) - scale /= 2; + if (scale * preview.IdealPreviewSize.X > ItemTemplate.Bounds.Width) + scale = (ItemTemplate.Bounds.Width - Panel.ItemSpacing) / (float)preview.IdealPreviewSize.X; - preview.Template = template; preview.GetScale = () => scale; - preview.Bounds.Width = (int)(scale * bounds.Width); - preview.Bounds.Height = (int)(scale * bounds.Height); + preview.Bounds.Width = (int)(scale * preview.IdealPreviewSize.X); + preview.Bounds.Height = (int)(scale * preview.IdealPreviewSize.Y); item.Bounds.Width = preview.Bounds.Width + 2 * preview.Bounds.X; item.Bounds.Height = preview.Bounds.Height + 2 * preview.Bounds.Y; diff --git a/OpenRA.Mods.Common/Widgets/ResourcePreviewWidget.cs b/OpenRA.Mods.Common/Widgets/ResourcePreviewWidget.cs index 2dd24f39d1..5142d71b81 100644 --- a/OpenRA.Mods.Common/Widgets/ResourcePreviewWidget.cs +++ b/OpenRA.Mods.Common/Widgets/ResourcePreviewWidget.cs @@ -23,6 +23,7 @@ namespace OpenRA.Mods.Common.Widgets public Func GetScale = () => 1f; readonly WorldRenderer worldRenderer; + readonly WorldViewportSizes viewportSizes; readonly IResourceRenderer[] resourceRenderers; readonly Size tileSize; @@ -43,12 +44,18 @@ namespace OpenRA.Mods.Common.Widgets } } + public Size IdealPreviewSize { get; private set; } + [ObjectCreator.UseCtor] - public ResourcePreviewWidget(WorldRenderer worldRenderer, World world) + public ResourcePreviewWidget(ModData modData, WorldRenderer worldRenderer, World world) { this.worldRenderer = worldRenderer; + viewportSizes = modData.Manifest.Get(); resourceRenderers = world.WorldActor.TraitsImplementing().ToArray(); tileSize = world.Map.Grid.TileSize; + IdealPreviewSize = new Size( + (int)(viewportSizes.DefaultScale * tileSize.Width), + (int)(viewportSizes.DefaultScale * tileSize.Height)); } protected ResourcePreviewWidget(ResourcePreviewWidget other) @@ -56,10 +63,12 @@ namespace OpenRA.Mods.Common.Widgets { GetScale = other.GetScale; worldRenderer = other.worldRenderer; + viewportSizes = other.viewportSizes; resourceRenderers = other.resourceRenderers; tileSize = other.tileSize; resourceType = other.resourceType; resourceRenderer = other.resourceRenderer; + IdealPreviewSize = other.IdealPreviewSize; } public override Widget Clone() { return new ResourcePreviewWidget(this); } @@ -69,8 +78,11 @@ namespace OpenRA.Mods.Common.Widgets if (resourceRenderer == null) return; - var scale = GetScale(); - var origin = RenderOrigin + new int2((RenderBounds.Size.Width - tileSize.Width) / 2, (RenderBounds.Size.Height - tileSize.Height) / 2); + var scale = GetScale() * viewportSizes.DefaultScale; + var origin = RenderOrigin + new int2( + (int)(0.5f * (RenderBounds.Size.Width - scale * tileSize.Width)), + (int)(0.5f * (RenderBounds.Size.Height - scale * tileSize.Height))); + foreach (var r in resourceRenderer.RenderUIPreview(worldRenderer, resourceType, origin, scale)) r.PrepareRender(worldRenderer).Render(worldRenderer); } diff --git a/OpenRA.Mods.Common/Widgets/TerrainTemplatePreviewWidget.cs b/OpenRA.Mods.Common/Widgets/TerrainTemplatePreviewWidget.cs index b2787855a1..01d32efa8d 100644 --- a/OpenRA.Mods.Common/Widgets/TerrainTemplatePreviewWidget.cs +++ b/OpenRA.Mods.Common/Widgets/TerrainTemplatePreviewWidget.cs @@ -13,7 +13,6 @@ using System; using OpenRA.Graphics; using OpenRA.Mods.Common.Terrain; using OpenRA.Mods.Common.Traits; -using OpenRA.Primitives; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets @@ -24,28 +23,19 @@ namespace OpenRA.Mods.Common.Widgets readonly ITiledTerrainRenderer terrainRenderer; readonly WorldRenderer worldRenderer; + readonly WorldViewportSizes viewportSizes; TerrainTemplateInfo template; - Rectangle bounds; - public TerrainTemplateInfo Template - { - get => template; - - set - { - template = value; - if (template == null) - return; - - bounds = terrainRenderer.TemplateBounds(template); - } - } + public int2 PreviewOffset { get; private set; } + public int2 IdealPreviewSize { get; private set; } [ObjectCreator.UseCtor] - public TerrainTemplatePreviewWidget(WorldRenderer worldRenderer, World world) + public TerrainTemplatePreviewWidget(ModData modData, WorldRenderer worldRenderer, World world) { this.worldRenderer = worldRenderer; + viewportSizes = modData.Manifest.Get(); + terrainRenderer = world.WorldActor.TraitOrDefault(); if (terrainRenderer == null) throw new YamlException("TerrainTemplatePreviewWidget requires a tile-based terrain renderer."); @@ -55,21 +45,32 @@ namespace OpenRA.Mods.Common.Widgets : base(other) { worldRenderer = other.worldRenderer; + viewportSizes = other.viewportSizes; terrainRenderer = other.terrainRenderer; - Template = other.Template; + template = other.template; GetScale = other.GetScale; } public override Widget Clone() { return new TerrainTemplatePreviewWidget(this); } + public void SetTemplate(TerrainTemplateInfo template) + { + this.template = template; + var b = terrainRenderer.TemplateBounds(template); + IdealPreviewSize = new int2((int)(b.Width * viewportSizes.DefaultScale), (int)(b.Height * viewportSizes.DefaultScale)); + + // Measured from the middle of the widget to the middle of the top-left cell of the template + PreviewOffset = -new int2((int)(b.Left * viewportSizes.DefaultScale), (int)(b.Top * viewportSizes.DefaultScale)) - IdealPreviewSize / 2; + } + public override void Draw() { if (template == null) return; - var scale = GetScale(); - var sb = new Rectangle((int)(scale * bounds.X), (int)(scale * bounds.Y), (int)(scale * bounds.Width), (int)(scale * bounds.Height)); - var origin = RenderOrigin + new int2((RenderBounds.Size.Width - sb.Width) / 2 - sb.X, (RenderBounds.Size.Height - sb.Height) / 2 - sb.Y); + var scale = GetScale() * viewportSizes.DefaultScale; + var origin = RenderOrigin + PreviewOffset + new int2(RenderBounds.Size.Width / 2, RenderBounds.Size.Height / 2); + foreach (var r in terrainRenderer.RenderUIPreview(worldRenderer, template, origin, scale)) r.PrepareRender(worldRenderer).Render(worldRenderer); }