Add multi-resolution badge support.

This commit is contained in:
Paul Chote
2020-02-11 21:57:45 +00:00
committed by abcdefg30
parent de4a7cecf0
commit 84df61c672
6 changed files with 134 additions and 54 deletions

View File

@@ -23,41 +23,22 @@ namespace OpenRA
public class PlayerDatabase : IGlobalModData
{
public readonly string Profile = "https://forum.openra.net/openra/info/";
public readonly int IconSize = 24;
[FieldLoader.Ignore]
readonly object syncObject = new object();
[FieldLoader.Ignore]
readonly Dictionary<string, Sprite> spriteCache = new Dictionary<string, Sprite>();
// 128x128 is large enough for 25 unique 24x24 sprites
// 512x512 is large enough for 49 unique 72x72 badges
// or 100 unique 42x42 badges
// or 441 unique 24x24 badges
// or some combination of the above if the DPI changes ingame
[FieldLoader.Ignore]
SheetBuilder sheetBuilder;
public PlayerBadge LoadBadge(MiniYaml yaml)
{
if (sheetBuilder == null)
{
sheetBuilder = new SheetBuilder(SheetType.BGRA, 128);
[FieldLoader.Ignore]
Cache<Pair<PlayerBadge, int>, Sprite> iconCache;
// We must manually force the buffer creation to avoid a crash
// that is indirectly triggered by rendering from a Sheet that
// has not yet been written to.
sheetBuilder.Current.CreateBuffer();
}
var labelNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Label");
var icon24Node = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon24");
if (labelNode == null || icon24Node == null)
return null;
Sprite sprite;
lock (syncObject)
Sprite LoadSprite(string url, int density)
{
if (!spriteCache.TryGetValue(icon24Node.Value.Value, out sprite))
{
sprite = spriteCache[icon24Node.Value.Value] = sheetBuilder.Allocate(new Size(24, 24));
sprite.Sheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear;
var spriteSize = IconSize * density;
var sprite = sheetBuilder.Allocate(new Size(spriteSize, spriteSize), 1f / density);
Action<DownloadDataCompletedEventArgs> onComplete = i =>
{
@@ -67,7 +48,7 @@ namespace OpenRA
try
{
var icon = new Png(new MemoryStream(i.Result));
if (icon.Width == 24 && icon.Height == 24)
if (icon.Width == spriteSize && icon.Height == spriteSize)
{
Game.RunAfterTick(() =>
{
@@ -79,11 +60,61 @@ namespace OpenRA
catch { }
};
new Download(icon24Node.Value.Value, _ => { }, onComplete);
}
new Download(url, _ => { }, onComplete);
return sprite;
}
return new PlayerBadge(labelNode.Value.Value, sprite);
Sheet CreateSheet()
{
var sheet = new Sheet(SheetType.BGRA, new Size(512, 512));
// We must manually force the buffer creation to avoid a crash
// that is indirectly triggered by rendering from a Sheet that
// has not yet been written to.
sheet.CreateBuffer();
sheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear;
return sheet;
}
public PlayerBadge LoadBadge(MiniYaml yaml)
{
if (sheetBuilder == null)
{
sheetBuilder = new SheetBuilder(SheetType.BGRA, CreateSheet);
iconCache = new Cache<Pair<PlayerBadge, int>, Sprite>(p =>
{
if (p.Second > 2 && !string.IsNullOrEmpty(p.First.Icon3x))
return LoadSprite(p.First.Icon3x, 3);
if (p.Second > 1 && !string.IsNullOrEmpty(p.First.Icon2x))
return LoadSprite(p.First.Icon2x, 2);
return LoadSprite(p.First.Icon, 1);
});
}
var labelNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Label");
var icon24Node = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon24");
var icon48Node = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon48");
var icon72Node = yaml.Nodes.FirstOrDefault(n => n.Key == "Icon72");
if (labelNode == null)
return null;
return new PlayerBadge(
labelNode.Value.Value,
icon24Node != null ? icon24Node.Value.Value : null,
icon48Node != null ? icon48Node.Value.Value : null,
icon72Node != null ? icon72Node.Value.Value : null);
}
public Sprite GetIcon(PlayerBadge badge)
{
var ws = Game.Renderer.WindowScale;
var density = ws > 2 ? 3 : ws > 1 ? 2 : 1;
return iconCache[Pair.New(badge, density)];
}
}
}

View File

@@ -11,7 +11,6 @@
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
namespace OpenRA
{
@@ -59,12 +58,16 @@ namespace OpenRA
public class PlayerBadge
{
public readonly string Label;
public readonly Sprite Icon24;
public readonly string Icon;
public readonly string Icon2x;
public readonly string Icon3x;
public PlayerBadge(string label, Sprite icon24)
public PlayerBadge(string label, string icon, string icon2x, string icon3x)
{
Label = label;
Icon24 = icon24;
Icon = icon;
Icon2x = icon2x;
Icon3x = icon3x;
}
}
}

View File

@@ -0,0 +1,46 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 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 OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
public class BadgeWidget : Widget
{
public PlayerBadge Badge;
readonly PlayerDatabase playerDatabase;
[ObjectCreator.UseCtor]
public BadgeWidget(ModData modData)
{
playerDatabase = modData.Manifest.Get<PlayerDatabase>();
}
protected BadgeWidget(BadgeWidget other)
: base(other)
{
Badge = other.Badge;
playerDatabase = other.playerDatabase;
}
public override Widget Clone() { return new BadgeWidget(this); }
public override void Draw()
{
if (Badge == null)
return;
var icon = playerDatabase.GetIcon(Badge);
if (icon != null)
Game.Renderer.RgbaSpriteRenderer.DrawSprite(icon, RenderOrigin);
}
}
}

View File

@@ -270,7 +270,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
// Negotiate the label length that the tooltip will allow
var maxLabelWidth = 0;
var templateIcon = badgeTemplate.Get<SpriteWidget>("ICON");
var templateIcon = badgeTemplate.Get("ICON");
var templateLabel = badgeTemplate.Get<LabelWidget>("LABEL");
var templateLabelFont = Game.Renderer.Fonts[templateLabel.Font];
foreach (var badge in profile.Badges)
@@ -285,8 +285,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic
foreach (var badge in profile.Badges)
{
var b = badgeTemplate.Clone();
var icon = b.Get<SpriteWidget>("ICON");
icon.GetSprite = () => badge.Icon24;
var icon = b.Get<BadgeWidget>("ICON");
icon.Badge = badge;
var label = b.Get<LabelWidget>("LABEL");
var labelFont = Game.Renderer.Fonts[label.Font];

View File

@@ -216,7 +216,7 @@ Container@PLAYER_PROFILE_BADGES_INSERT:
Width: PARENT_RIGHT
Height: 25
Children:
Sprite@ICON:
Badge@ICON:
X: 6
Y: 1
Width: 24

View File

@@ -217,7 +217,7 @@ Container@PLAYER_PROFILE_BADGES_INSERT:
Width: PARENT_RIGHT
Height: 25
Children:
Sprite@ICON:
Badge@ICON:
X: 6
Y: 1
Width: 24