Rework multi-resolution sprite handling:
- Sprite.Bounds now refers to rectangles in the source image. Use this when copying pixels, etc. - Sprite.Size now refers to sizes in effective pixel coordinates. Use this when rendering. - Sheet.DPIScale has been removed. - "Density" term is introduced to refer to the number of artwork pixels per effective pixel.
This commit is contained in:
@@ -54,10 +54,10 @@ namespace OpenRA.Graphics
|
||||
|
||||
public static IReadOnlyDictionary<string, Collection> Collections { get; private set; }
|
||||
static Dictionary<string, Collection> collections;
|
||||
static Dictionary<string, Sheet> cachedSheets;
|
||||
static Dictionary<string, Pair<Sheet, int>> cachedSheets;
|
||||
static Dictionary<string, Dictionary<string, Sprite>> cachedSprites;
|
||||
static Dictionary<string, Sprite[]> cachedPanelSprites;
|
||||
static Dictionary<Collection, Sheet> cachedCollectionSheets;
|
||||
static Dictionary<Collection, Pair<Sheet, int>> cachedCollectionSheets;
|
||||
|
||||
static IReadOnlyFileSystem fileSystem;
|
||||
static float dpiScale = 1;
|
||||
@@ -72,10 +72,10 @@ namespace OpenRA.Graphics
|
||||
|
||||
fileSystem = modData.DefaultFileSystem;
|
||||
collections = new Dictionary<string, Collection>();
|
||||
cachedSheets = new Dictionary<string, Sheet>();
|
||||
cachedSheets = new Dictionary<string, Pair<Sheet, int>>();
|
||||
cachedSprites = new Dictionary<string, Dictionary<string, Sprite>>();
|
||||
cachedPanelSprites = new Dictionary<string, Sprite[]>();
|
||||
cachedCollectionSheets = new Dictionary<Collection, Sheet>();
|
||||
cachedCollectionSheets = new Dictionary<Collection, Pair<Sheet, int>>();
|
||||
|
||||
Collections = new ReadOnlyDictionary<string, Collection>(collections);
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
if (cachedSheets != null)
|
||||
foreach (var sheet in cachedSheets.Values)
|
||||
sheet.Dispose();
|
||||
sheet.First.Dispose();
|
||||
|
||||
collections = null;
|
||||
cachedSheets = null;
|
||||
@@ -108,47 +108,43 @@ namespace OpenRA.Graphics
|
||||
collections.Add(name, FieldLoader.Load<Collection>(yaml));
|
||||
}
|
||||
|
||||
static Sheet SheetForCollection(Collection c)
|
||||
static Pair<Sheet, int> SheetForCollection(Collection c)
|
||||
{
|
||||
Sheet sheet;
|
||||
Pair<Sheet, int> sheetDensity;
|
||||
|
||||
// Outer cache avoids recalculating image names
|
||||
if (!cachedCollectionSheets.TryGetValue(c, out sheet))
|
||||
if (!cachedCollectionSheets.TryGetValue(c, out sheetDensity))
|
||||
{
|
||||
string sheetImage;
|
||||
float sheetScale;
|
||||
var image = c.Image;
|
||||
var density = 1;
|
||||
if (dpiScale > 2 && !string.IsNullOrEmpty(c.Image3x))
|
||||
{
|
||||
sheetImage = c.Image3x;
|
||||
sheetScale = 3;
|
||||
image = c.Image3x;
|
||||
density = 3;
|
||||
}
|
||||
else if (dpiScale > 1 && !string.IsNullOrEmpty(c.Image2x))
|
||||
{
|
||||
sheetImage = c.Image2x;
|
||||
sheetScale = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
sheetImage = c.Image;
|
||||
sheetScale = 1;
|
||||
image = c.Image2x;
|
||||
density = 2;
|
||||
}
|
||||
|
||||
// Inner cache makes sure we share sheets between collections
|
||||
if (!cachedSheets.TryGetValue(sheetImage, out sheet))
|
||||
if (!cachedSheets.TryGetValue(image, out sheetDensity))
|
||||
{
|
||||
using (var stream = fileSystem.Open(sheetImage))
|
||||
Sheet sheet;
|
||||
using (var stream = fileSystem.Open(image))
|
||||
sheet = new Sheet(SheetType.BGRA, stream);
|
||||
|
||||
sheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear;
|
||||
sheet.DPIScale = sheetScale;
|
||||
|
||||
cachedSheets.Add(sheetImage, sheet);
|
||||
sheetDensity = Pair.New(sheet, density);
|
||||
cachedSheets.Add(image, sheetDensity);
|
||||
}
|
||||
|
||||
cachedCollectionSheets.Add(c, sheet);
|
||||
cachedCollectionSheets.Add(c, sheetDensity);
|
||||
}
|
||||
|
||||
return sheet;
|
||||
return sheetDensity;
|
||||
}
|
||||
|
||||
public static Sprite GetImage(string collectionName, string imageName)
|
||||
@@ -174,14 +170,14 @@ namespace OpenRA.Graphics
|
||||
return null;
|
||||
|
||||
// Cache the sprite
|
||||
var sheet = SheetForCollection(collection);
|
||||
var sheetDensity = SheetForCollection(collection);
|
||||
if (cachedCollection == null)
|
||||
{
|
||||
cachedCollection = new Dictionary<string, Sprite>();
|
||||
cachedSprites.Add(collectionName, cachedCollection);
|
||||
}
|
||||
|
||||
var image = new Sprite(sheet, mi, TextureChannel.RGBA);
|
||||
var image = new Sprite(sheetDensity.First, sheetDensity.Second * mi, TextureChannel.RGBA, 1f / sheetDensity.Second);
|
||||
cachedCollection.Add(imageName, image);
|
||||
|
||||
return image;
|
||||
@@ -214,7 +210,7 @@ namespace OpenRA.Graphics
|
||||
}
|
||||
|
||||
// Cache the sprites
|
||||
var sheet = SheetForCollection(collection);
|
||||
var sheetDensity = SheetForCollection(collection);
|
||||
var pr = collection.PanelRegion;
|
||||
var ps = collection.PanelSides;
|
||||
|
||||
@@ -231,7 +227,7 @@ namespace OpenRA.Graphics
|
||||
Pair.New(PanelSides.Bottom | PanelSides.Right, new Rectangle(pr[0] + pr[2] + pr[4], pr[1] + pr[3] + pr[5], pr[6], pr[7]))
|
||||
};
|
||||
|
||||
sprites = sides.Select(x => ps.HasSide(x.First) ? new Sprite(sheet, x.Second, TextureChannel.RGBA) : null)
|
||||
sprites = sides.Select(x => ps.HasSide(x.First) ? new Sprite(sheetDensity.First, sheetDensity.Second * x.Second, TextureChannel.RGBA, 1f / sheetDensity.Second) : null)
|
||||
.ToArray();
|
||||
}
|
||||
else
|
||||
|
||||
@@ -25,7 +25,6 @@ namespace OpenRA.Graphics
|
||||
|
||||
public readonly Size Size;
|
||||
public readonly SheetType Type;
|
||||
public float DPIScale = 1f;
|
||||
|
||||
public byte[] GetData()
|
||||
{
|
||||
|
||||
@@ -88,9 +88,9 @@ namespace OpenRA.Graphics
|
||||
return rect;
|
||||
}
|
||||
|
||||
public Sprite Add(Png src)
|
||||
public Sprite Add(Png src, float scale = 1f)
|
||||
{
|
||||
var rect = Allocate(new Size(src.Width, src.Height));
|
||||
var rect = Allocate(new Size(src.Width, src.Height), scale);
|
||||
Util.FastCopyIntoSprite(rect, src);
|
||||
current.CommitBufferedData();
|
||||
return rect;
|
||||
@@ -114,8 +114,8 @@ namespace OpenRA.Graphics
|
||||
return (TextureChannel)nextChannel;
|
||||
}
|
||||
|
||||
public Sprite Allocate(Size imageSize) { return Allocate(imageSize, 0, float3.Zero); }
|
||||
public Sprite Allocate(Size imageSize, float zRamp, float3 spriteOffset)
|
||||
public Sprite Allocate(Size imageSize, float scale = 1f) { return Allocate(imageSize, 0, float3.Zero, scale); }
|
||||
public Sprite Allocate(Size imageSize, float zRamp, float3 spriteOffset, float scale = 1f)
|
||||
{
|
||||
if (imageSize.Width + p.X + margin > current.Size.Width)
|
||||
{
|
||||
@@ -143,7 +143,7 @@ namespace OpenRA.Graphics
|
||||
p = int2.Zero;
|
||||
}
|
||||
|
||||
var rect = new Sprite(current, new Rectangle(p.X + margin, p.Y + margin, imageSize.Width, imageSize.Height), zRamp, spriteOffset, channel, BlendMode.Alpha);
|
||||
var rect = new Sprite(current, new Rectangle(p.X + margin, p.Y + margin, imageSize.Width, imageSize.Height), zRamp, spriteOffset, channel, BlendMode.Alpha, scale);
|
||||
p += new int2(imageSize.Width + margin, 0);
|
||||
|
||||
return rect;
|
||||
|
||||
@@ -26,25 +26,25 @@ namespace OpenRA.Graphics
|
||||
public readonly float3 FractionalOffset;
|
||||
public readonly float Top, Left, Bottom, Right;
|
||||
|
||||
public Sprite(Sheet sheet, Rectangle bounds, TextureChannel channel)
|
||||
: this(sheet, bounds, 0, float2.Zero, channel) { }
|
||||
public Sprite(Sheet sheet, Rectangle bounds, TextureChannel channel, float scale = 1)
|
||||
: this(sheet, bounds, 0, float2.Zero, channel, BlendMode.Alpha, scale) { }
|
||||
|
||||
public Sprite(Sheet sheet, Rectangle bounds, float zRamp, float3 offset, TextureChannel channel, BlendMode blendMode = BlendMode.Alpha)
|
||||
public Sprite(Sheet sheet, Rectangle bounds, float zRamp, float3 offset, TextureChannel channel, BlendMode blendMode = BlendMode.Alpha, float scale = 1f)
|
||||
{
|
||||
Sheet = sheet;
|
||||
Bounds = bounds;
|
||||
Offset = offset;
|
||||
ZRamp = zRamp;
|
||||
Channel = channel;
|
||||
Size = new float3(bounds.Size.Width, bounds.Size.Height, bounds.Size.Height * zRamp);
|
||||
Size = scale * new float3(bounds.Size.Width, bounds.Size.Height, bounds.Size.Height * zRamp);
|
||||
BlendMode = blendMode;
|
||||
FractionalOffset = Size.Z != 0 ? offset / Size :
|
||||
new float3(offset.X / Size.X, offset.Y / Size.Y, 0);
|
||||
|
||||
Left = (float)Math.Min(bounds.Left, bounds.Right) * sheet.DPIScale / sheet.Size.Width;
|
||||
Top = (float)Math.Min(bounds.Top, bounds.Bottom) * sheet.DPIScale / sheet.Size.Height;
|
||||
Right = (float)Math.Max(bounds.Left, bounds.Right) * sheet.DPIScale / sheet.Size.Width;
|
||||
Bottom = (float)Math.Max(bounds.Top, bounds.Bottom) * sheet.DPIScale / sheet.Size.Height;
|
||||
Left = (float)Math.Min(bounds.Left, bounds.Right) / sheet.Size.Width;
|
||||
Top = (float)Math.Min(bounds.Top, bounds.Bottom) / sheet.Size.Height;
|
||||
Right = (float)Math.Max(bounds.Left, bounds.Right) / sheet.Size.Width;
|
||||
Bottom = (float)Math.Max(bounds.Top, bounds.Bottom) / sheet.Size.Height;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,10 +61,10 @@ namespace OpenRA.Graphics
|
||||
SecondarySheet = secondarySheet;
|
||||
SecondaryBounds = secondaryBounds;
|
||||
SecondaryChannel = secondaryChannel;
|
||||
SecondaryLeft = (float)Math.Min(secondaryBounds.Left, secondaryBounds.Right) * secondarySheet.DPIScale / s.Sheet.Size.Width;
|
||||
SecondaryTop = (float)Math.Min(secondaryBounds.Top, secondaryBounds.Bottom) * secondarySheet.DPIScale / s.Sheet.Size.Height;
|
||||
SecondaryRight = (float)Math.Max(secondaryBounds.Left, secondaryBounds.Right) * secondarySheet.DPIScale / s.Sheet.Size.Width;
|
||||
SecondaryBottom = (float)Math.Max(secondaryBounds.Top, secondaryBounds.Bottom) * secondarySheet.DPIScale / s.Sheet.Size.Height;
|
||||
SecondaryLeft = (float)Math.Min(secondaryBounds.Left, secondaryBounds.Right) / s.Sheet.Size.Width;
|
||||
SecondaryTop = (float)Math.Min(secondaryBounds.Top, secondaryBounds.Bottom) / s.Sheet.Size.Height;
|
||||
SecondaryRight = (float)Math.Max(secondaryBounds.Left, secondaryBounds.Right) / s.Sheet.Size.Width;
|
||||
SecondaryBottom = (float)Math.Max(secondaryBounds.Top, secondaryBounds.Bottom) / s.Sheet.Size.Height;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -117,6 +117,8 @@ namespace OpenRA.Primitives
|
||||
return rect == Intersect(this, rect);
|
||||
}
|
||||
|
||||
public static Rectangle operator *(int a, Rectangle b) { return new Rectangle(a * b.X, a * b.Y, a * b.Width, a * b.Height); }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{{X={0},Y={1},Width={2},Height={3}}}", X, Y, Width, Height);
|
||||
|
||||
Reference in New Issue
Block a user